From python-checkins at python.org Thu Mar 1 00:31:59 2012 From: python-checkins at python.org (brett.cannon) Date: Thu, 01 Mar 2012 00:31:59 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314153_Create_=5FPy?= =?utf8?q?=5Fdevice=5Fencoding=28=29_to_prevent_=5Fio_from_having_to_impor?= =?utf8?q?t?= Message-ID: http://hg.python.org/cpython/rev/c80d9a0bd5a0 changeset: 75353:c80d9a0bd5a0 user: Brett Cannon date: Wed Feb 29 18:31:31 2012 -0500 summary: Issue #14153 Create _Py_device_encoding() to prevent _io from having to import the os module. files: Include/fileutils.h | 2 + Lib/test/test_os.py | 19 ++++++++++++++++ Modules/_io/_iomodule.c | 14 ++--------- Modules/_io/_iomodule.h | 5 +-- Modules/_io/textio.c | 11 +++++--- Modules/posixmodule.c | 30 ++----------------------- Python/fileutils.c | 34 +++++++++++++++++++++++++++++ 7 files changed, 70 insertions(+), 45 deletions(-) diff --git a/Include/fileutils.h b/Include/fileutils.h --- a/Include/fileutils.h +++ b/Include/fileutils.h @@ -5,6 +5,8 @@ extern "C" { #endif +PyAPI_FUNC(PyObject *) _Py_device_encoding(int); + PyAPI_FUNC(wchar_t *) _Py_char2wchar( const char *arg, size_t *size); diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -22,6 +22,8 @@ import socket import itertools import stat +import locale +import codecs try: import threading except ImportError: @@ -1424,6 +1426,22 @@ self.assertEqual(os.fsdecode(bytesfn), fn) + +class DeviceEncodingTests(unittest.TestCase): + + def test_bad_fd(self): + # Return None when an fd doesn't actually exist. + self.assertIsNone(os.device_encoding(123456)) + + @unittest.skipUnless(sys.platform.startswith('win') or + (hasattr(locale, 'nl_langinfo') and hasattr(locale, 'CODESET')), + 'test requires either Windows or nl_langinfo(CODESET)') + def test_device_encoding(self): + encoding = os.device_encoding(0) + self.assertIsNotNone(encoding) + self.assertTrue(codecs.lookup(encoding)) + + class PidTests(unittest.TestCase): @unittest.skipUnless(hasattr(os, 'getppid'), "test needs os.getppid") def test_getppid(self): @@ -1923,6 +1941,7 @@ Win32KillTests, Win32SymlinkTests, FSEncodingTests, + DeviceEncodingTests, PidTests, LoginTests, LinkTests, diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -1,9 +1,9 @@ /* An implementation of the new I/O lib as defined by PEP 3116 - "New I/O" - + Classes defined here: UnsupportedOperation, BlockingIOError. Functions defined here: open(). - + Mostly written by Amaury Forgeot d'Arc */ @@ -510,7 +510,7 @@ /* Basically the "n" format code with the ability to turn None into -1. */ -int +int _PyIO_ConvertSsize_t(PyObject *obj, void *result) { Py_ssize_t limit; if (obj == Py_None) { @@ -537,7 +537,6 @@ _PyIO_State *state = IO_MOD_STATE(mod); if (!state->initialized) return 0; - Py_VISIT(state->os_module); if (state->locale_module != NULL) { Py_VISIT(state->locale_module); } @@ -551,7 +550,6 @@ _PyIO_State *state = IO_MOD_STATE(mod); if (!state->initialized) return 0; - Py_CLEAR(state->os_module); if (state->locale_module != NULL) Py_CLEAR(state->locale_module); Py_CLEAR(state->unsupported_operation); @@ -595,11 +593,6 @@ state = IO_MOD_STATE(m); state->initialized = 0; - /* put os in the module state */ - state->os_module = PyImport_ImportModule("os"); - if (state->os_module == NULL) - goto fail; - #define ADD_TYPE(type, name) \ if (PyType_Ready(type) < 0) \ goto fail; \ @@ -725,7 +718,6 @@ return m; fail: - Py_XDECREF(state->os_module); Py_XDECREF(state->unsupported_operation); Py_DECREF(m); return NULL; diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -50,8 +50,8 @@ `*consumed`. If not found, returns -1 and sets `*consumed` to the number of characters which can be safely put aside until another search. - - NOTE: for performance reasons, `end` must point to a NUL character ('\0'). + + NOTE: for performance reasons, `end` must point to a NUL character ('\0'). Otherwise, the function will scan further and return garbage. */ extern Py_ssize_t _PyIO_find_line_ending( int translated, int universal, PyObject *readnl, @@ -124,7 +124,6 @@ typedef struct { int initialized; - PyObject *os_module; PyObject *locale_module; PyObject *unsupported_operation; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -14,7 +14,6 @@ _Py_IDENTIFIER(close); _Py_IDENTIFIER(_dealloc_warn); _Py_IDENTIFIER(decode); -_Py_IDENTIFIER(device_encoding); _Py_IDENTIFIER(fileno); _Py_IDENTIFIER(flush); _Py_IDENTIFIER(getpreferredencoding); @@ -875,9 +874,13 @@ } } else { - self->encoding = _PyObject_CallMethodId(state->os_module, - &PyId_device_encoding, - "N", fileno); + int fd = (int) PyLong_AsLong(fileno); + Py_DECREF(fileno); + if (fd == -1 && PyErr_Occurred()) { + goto error; + } + + self->encoding = _Py_device_encoding(fd); if (self->encoding == NULL) goto error; else if (!PyUnicode_Check(self->encoding)) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9326,35 +9326,11 @@ device_encoding(PyObject *self, PyObject *args) { int fd; -#if defined(MS_WINDOWS) || defined(MS_WIN64) - UINT cp; -#endif + if (!PyArg_ParseTuple(args, "i:device_encoding", &fd)) return NULL; - if (!_PyVerify_fd(fd) || !isatty(fd)) { - Py_INCREF(Py_None); - return Py_None; - } -#if defined(MS_WINDOWS) || defined(MS_WIN64) - if (fd == 0) - cp = GetConsoleCP(); - else if (fd == 1 || fd == 2) - cp = GetConsoleOutputCP(); - else - cp = 0; - /* GetConsoleCP() and GetConsoleOutputCP() return 0 if the application - has no console */ - if (cp != 0) - return PyUnicode_FromFormat("cp%u", (unsigned int)cp); -#elif defined(CODESET) - { - char *codeset = nl_langinfo(CODESET); - if (codeset != NULL && codeset[0] != 0) - return PyUnicode_FromString(codeset); - } -#endif - Py_INCREF(Py_None); - return Py_None; + + return _Py_device_encoding(fd); } #ifdef __VMS diff --git a/Python/fileutils.c b/Python/fileutils.c --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -3,6 +3,40 @@ # include #endif +#ifdef HAVE_LANGINFO_H +#include +#endif + +PyObject * +_Py_device_encoding(int fd) +{ +#if defined(MS_WINDOWS) || defined(MS_WIN64) + UINT cp; +#endif + if (!_PyVerify_fd(fd) || !isatty(fd)) { + Py_RETURN_NONE; + } +#if defined(MS_WINDOWS) || defined(MS_WIN64) + if (fd == 0) + cp = GetConsoleCP(); + else if (fd == 1 || fd == 2) + cp = GetConsoleOutputCP(); + else + cp = 0; + /* GetConsoleCP() and GetConsoleOutputCP() return 0 if the application + has no console */ + if (cp != 0) + return PyUnicode_FromFormat("cp%u", (unsigned int)cp); +#elif defined(CODESET) + { + char *codeset = nl_langinfo(CODESET); + if (codeset != NULL && codeset[0] != 0) + return PyUnicode_FromString(codeset); + } +#endif + Py_RETURN_NONE; +} + #ifdef HAVE_STAT /* Decode a byte string from the locale encoding with the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 1 01:16:44 2012 From: python-checkins at python.org (philip.jenvey) Date: Thu, 01 Mar 2012 01:16:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_also_skip_test=5Fdevice=5Fe?= =?utf8?q?ncoding_when_stdin_isn=27t_a_tty?= Message-ID: http://hg.python.org/cpython/rev/dd0638da6d51 changeset: 75354:dd0638da6d51 user: Philip Jenvey date: Wed Feb 29 16:16:15 2012 -0800 summary: also skip test_device_encoding when stdin isn't a tty files: Lib/test/test_os.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1433,8 +1433,8 @@ # Return None when an fd doesn't actually exist. self.assertIsNone(os.device_encoding(123456)) - @unittest.skipUnless(sys.platform.startswith('win') or - (hasattr(locale, 'nl_langinfo') and hasattr(locale, 'CODESET')), + @unittest.skipUnless(os.isatty(0) and (sys.platform.startswith('win') or + (hasattr(locale, 'nl_langinfo') and hasattr(locale, 'CODESET'))), 'test requires either Windows or nl_langinfo(CODESET)') def test_device_encoding(self): encoding = os.device_encoding(0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 1 01:22:00 2012 From: python-checkins at python.org (philip.jenvey) Date: Thu, 01 Mar 2012 01:22:00 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_update_skip_reason?= Message-ID: http://hg.python.org/cpython/rev/87dcd948dc74 changeset: 75355:87dcd948dc74 user: Philip Jenvey date: Wed Feb 29 16:21:25 2012 -0800 summary: update skip reason files: Lib/test/test_os.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1435,7 +1435,7 @@ @unittest.skipUnless(os.isatty(0) and (sys.platform.startswith('win') or (hasattr(locale, 'nl_langinfo') and hasattr(locale, 'CODESET'))), - 'test requires either Windows or nl_langinfo(CODESET)') + 'test requires a tty and either Windows or nl_langinfo(CODESET)') def test_device_encoding(self): encoding = os.device_encoding(0) self.assertIsNotNone(encoding) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Mar 1 05:36:41 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 01 Mar 2012 05:36:41 +0100 Subject: [Python-checkins] Daily reference leaks (87dcd948dc74): sum=0 Message-ID: results for 87dcd948dc74 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogf6upG3', '-x'] From python-checkins at python.org Thu Mar 1 13:06:04 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 01 Mar 2012 13:06:04 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_416?= Message-ID: http://hg.python.org/peps/rev/1cb1bad760c6 changeset: 4102:1cb1bad760c6 user: Victor Stinner date: Thu Mar 01 13:06:07 2012 +0100 summary: PEP 416 * Rephrase the first Rationale paragraph * Add 2 more use cases: cache and sandbox * Fix a typo files: pep-0416.txt | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pep-0416.txt b/pep-0416.txt --- a/pep-0416.txt +++ b/pep-0416.txt @@ -19,16 +19,20 @@ Rationale ========= -A frozendict mapping cannot be changed, but its values can be mutable (not -hashable). A frozendict is hashable and so immutable if all values are hashable -(immutable). +A frozendict is a read-only mapping: a key cannot be added nor removed, and a +key is always mapped to the same value. However, frozendict values can be +mutable (not hashable). A frozendict is hashable and so immutable if and only +if all values are hashable (immutable). Use cases of frozendict: + * frozendict can be used to implement a cache * hashable frozendict can be used as a key of a mapping or as a member of set * frozendict helps optimization because the mapping is constant * frozendict avoids the need of a lock when the frozendict is shared by multiple threads or processes, especially hashable frozendict + * frozendict helps to implement a security sandbox with read-only objects, + e.g. freeze __builtins__ mapping Constraints @@ -47,7 +51,7 @@ "Py_hash_t hash;" field * frozendict.__hash__() is implemented using hash(frozenset(self.items())) and caches the result in its private hash attribute - * Register frozendict has a collections.abc.Mapping + * Register frozendict as a collections.abc.Mapping * frozendict can be used with PyDict_GetItem(), but PyDict_SetItem() and PyDict_DelItem() raise a TypeError -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 1 16:32:28 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 01 Mar 2012 16:32:28 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MTU5?= =?utf8?q?=3A_Fix_the_len=28=29_of_weak_containers_=28WeakSet=2C_WeakKeyDi?= =?utf8?q?ctionary=2C?= Message-ID: http://hg.python.org/cpython/rev/1cd0688ff004 changeset: 75356:1cd0688ff004 branch: 3.2 parent: 75348:1c77eadba9dc user: Antoine Pitrou date: Thu Mar 01 16:26:35 2012 +0100 summary: Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, WeakValueDictionary) to return a better approximation when some objects are dead or dying. Moreover, the implementation is now O(1) rather than O(n). Thanks to Yury Selivanov for reporting. files: Lib/_weakrefset.py | 2 +- Lib/test/test_weakref.py | 60 ++++++++++++++++++++++++++++ Lib/test/test_weakset.py | 47 +++++++++++++++++++++ Lib/weakref.py | 4 +- Misc/NEWS | 5 ++ 5 files changed, 115 insertions(+), 3 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -63,7 +63,7 @@ yield item def __len__(self): - return sum(x() is not None for x in self.data) + return len(self.data) - len(self._pending_removals) def __contains__(self, item): try: diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -812,11 +812,71 @@ def __hash__(self): return hash(self.arg) +class RefCycle: + def __init__(self): + self.cycle = self + class MappingTestCase(TestBase): COUNT = 10 + def check_len_cycles(self, dict_type, cons): + N = 20 + items = [RefCycle() for i in range(N)] + dct = dict_type(cons(o) for o in items) + # Keep an iterator alive + it = dct.items() + try: + next(it) + except StopIteration: + pass + del items + gc.collect() + n1 = len(dct) + del it + gc.collect() + n2 = len(dct) + # one item may be kept alive inside the iterator + self.assertIn(n1, (0, 1)) + self.assertEqual(n2, 0) + + def test_weak_keyed_len_cycles(self): + self.check_len_cycles(weakref.WeakKeyDictionary, lambda k: (k, 1)) + + def test_weak_valued_len_cycles(self): + self.check_len_cycles(weakref.WeakValueDictionary, lambda k: (1, k)) + + def check_len_race(self, dict_type, cons): + # Extended sanity checks for len() in the face of cyclic collection + self.addCleanup(gc.set_threshold, *gc.get_threshold()) + for th in range(1, 100): + N = 20 + gc.collect(0) + gc.set_threshold(th, th, th) + items = [RefCycle() for i in range(N)] + dct = dict_type(cons(o) for o in items) + del items + # All items will be collected at next garbage collection pass + it = dct.items() + try: + next(it) + except StopIteration: + pass + n1 = len(dct) + del it + n2 = len(dct) + self.assertGreaterEqual(n1, 0) + self.assertLessEqual(n1, N) + self.assertGreaterEqual(n2, 0) + self.assertLessEqual(n2, n1) + + def test_weak_keyed_len_race(self): + self.check_len_race(weakref.WeakKeyDictionary, lambda k: (k, 1)) + + def test_weak_valued_len_race(self): + self.check_len_race(weakref.WeakValueDictionary, lambda k: (1, k)) + def test_weak_values(self): # # This exercises d.copy(), d.items(), d[], del d[], len(d). diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -17,6 +17,10 @@ class Foo: pass +class RefCycle: + def __init__(self): + self.cycle = self + class TestWeakSet(unittest.TestCase): @@ -359,6 +363,49 @@ s.clear() self.assertEqual(len(s), 0) + def test_len_cycles(self): + N = 20 + items = [RefCycle() for i in range(N)] + s = WeakSet(items) + del items + it = iter(s) + try: + next(it) + except StopIteration: + pass + gc.collect() + n1 = len(s) + del it + gc.collect() + n2 = len(s) + # one item may be kept alive inside the iterator + self.assertIn(n1, (0, 1)) + self.assertEqual(n2, 0) + + def test_len_race(self): + # Extended sanity checks for len() in the face of cyclic collection + self.addCleanup(gc.set_threshold, *gc.get_threshold()) + for th in range(1, 100): + N = 20 + gc.collect(0) + gc.set_threshold(th, th, th) + items = [RefCycle() for i in range(N)] + s = WeakSet(items) + del items + # All items will be collected at next garbage collection pass + it = iter(s) + try: + next(it) + except StopIteration: + pass + n1 = len(s) + del it + n2 = len(s) + self.assertGreaterEqual(n1, 0) + self.assertLessEqual(n1, N) + self.assertGreaterEqual(n2, 0) + self.assertLessEqual(n2, n1) + def test_main(verbose=None): support.run_unittest(TestWeakSet) diff --git a/Lib/weakref.py b/Lib/weakref.py --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -78,7 +78,7 @@ del self.data[key] def __len__(self): - return sum(wr() is not None for wr in self.data.values()) + return len(self.data) - len(self._pending_removals) def __contains__(self, key): try: @@ -290,7 +290,7 @@ return self.data[ref(key)] def __len__(self): - return len(self.data) + return len(self.data) - len(self._pending_removals) def __repr__(self): return "" % id(self) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -127,6 +127,11 @@ Library ------- +- Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, + WeakValueDictionary) to return a better approximation when some objects + are dead or dying. Moreover, the implementation is now O(1) rather than + O(n). + - Issue #13125: Silence spurious test_lib2to3 output when in non-verbose mode. Patch by Mikhail Novikov. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 1 16:32:29 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 01 Mar 2012 16:32:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314159=3A_Fix_the_len=28=29_of_weak_containers_=28We?= =?utf8?q?akSet=2C_WeakKeyDictionary=2C?= Message-ID: http://hg.python.org/cpython/rev/b1b2a29d3d81 changeset: 75357:b1b2a29d3d81 parent: 75355:87dcd948dc74 parent: 75356:1cd0688ff004 user: Antoine Pitrou date: Thu Mar 01 16:28:14 2012 +0100 summary: Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, WeakValueDictionary) to return a better approximation when some objects are dead or dying. Moreover, the implementation is now O(1) rather than O(n). Thanks to Yury Selivanov for reporting. files: Lib/_weakrefset.py | 2 +- Lib/test/test_weakref.py | 60 ++++++++++++++++++++++++++++ Lib/test/test_weakset.py | 47 +++++++++++++++++++++ Lib/weakref.py | 4 +- Misc/NEWS | 5 ++ 5 files changed, 115 insertions(+), 3 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -63,7 +63,7 @@ yield item def __len__(self): - return sum(x() is not None for x in self.data) + return len(self.data) - len(self._pending_removals) def __contains__(self, item): try: diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -812,11 +812,71 @@ def __hash__(self): return hash(self.arg) +class RefCycle: + def __init__(self): + self.cycle = self + class MappingTestCase(TestBase): COUNT = 10 + def check_len_cycles(self, dict_type, cons): + N = 20 + items = [RefCycle() for i in range(N)] + dct = dict_type(cons(o) for o in items) + # Keep an iterator alive + it = dct.items() + try: + next(it) + except StopIteration: + pass + del items + gc.collect() + n1 = len(dct) + del it + gc.collect() + n2 = len(dct) + # one item may be kept alive inside the iterator + self.assertIn(n1, (0, 1)) + self.assertEqual(n2, 0) + + def test_weak_keyed_len_cycles(self): + self.check_len_cycles(weakref.WeakKeyDictionary, lambda k: (k, 1)) + + def test_weak_valued_len_cycles(self): + self.check_len_cycles(weakref.WeakValueDictionary, lambda k: (1, k)) + + def check_len_race(self, dict_type, cons): + # Extended sanity checks for len() in the face of cyclic collection + self.addCleanup(gc.set_threshold, *gc.get_threshold()) + for th in range(1, 100): + N = 20 + gc.collect(0) + gc.set_threshold(th, th, th) + items = [RefCycle() for i in range(N)] + dct = dict_type(cons(o) for o in items) + del items + # All items will be collected at next garbage collection pass + it = dct.items() + try: + next(it) + except StopIteration: + pass + n1 = len(dct) + del it + n2 = len(dct) + self.assertGreaterEqual(n1, 0) + self.assertLessEqual(n1, N) + self.assertGreaterEqual(n2, 0) + self.assertLessEqual(n2, n1) + + def test_weak_keyed_len_race(self): + self.check_len_race(weakref.WeakKeyDictionary, lambda k: (k, 1)) + + def test_weak_valued_len_race(self): + self.check_len_race(weakref.WeakValueDictionary, lambda k: (1, k)) + def test_weak_values(self): # # This exercises d.copy(), d.items(), d[], del d[], len(d). diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -17,6 +17,10 @@ class Foo: pass +class RefCycle: + def __init__(self): + self.cycle = self + class TestWeakSet(unittest.TestCase): @@ -359,6 +363,49 @@ s.clear() self.assertEqual(len(s), 0) + def test_len_cycles(self): + N = 20 + items = [RefCycle() for i in range(N)] + s = WeakSet(items) + del items + it = iter(s) + try: + next(it) + except StopIteration: + pass + gc.collect() + n1 = len(s) + del it + gc.collect() + n2 = len(s) + # one item may be kept alive inside the iterator + self.assertIn(n1, (0, 1)) + self.assertEqual(n2, 0) + + def test_len_race(self): + # Extended sanity checks for len() in the face of cyclic collection + self.addCleanup(gc.set_threshold, *gc.get_threshold()) + for th in range(1, 100): + N = 20 + gc.collect(0) + gc.set_threshold(th, th, th) + items = [RefCycle() for i in range(N)] + s = WeakSet(items) + del items + # All items will be collected at next garbage collection pass + it = iter(s) + try: + next(it) + except StopIteration: + pass + n1 = len(s) + del it + n2 = len(s) + self.assertGreaterEqual(n1, 0) + self.assertLessEqual(n1, N) + self.assertGreaterEqual(n2, 0) + self.assertLessEqual(n2, n1) + def test_main(verbose=None): support.run_unittest(TestWeakSet) diff --git a/Lib/weakref.py b/Lib/weakref.py --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -78,7 +78,7 @@ del self.data[key] def __len__(self): - return sum(wr() is not None for wr in self.data.values()) + return len(self.data) - len(self._pending_removals) def __contains__(self, key): try: @@ -290,7 +290,7 @@ return self.data[ref(key)] def __len__(self): - return len(self.data) + return len(self.data) - len(self._pending_removals) def __repr__(self): return "" % id(self) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -508,6 +508,11 @@ Library ------- +- Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, + WeakValueDictionary) to return a better approximation when some objects + are dead or dying. Moreover, the implementation is now O(1) rather than + O(n). + - Issue #13125: Silence spurious test_lib2to3 output when in non-verbose mode. Patch by Mikhail Novikov. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 1 16:38:55 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 01 Mar 2012 16:38:55 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0MTU5?= =?utf8?q?=3A_Fix_the_len=28=29_of_weak_sets_to_return_a_better_approximat?= =?utf8?q?ion_when?= Message-ID: http://hg.python.org/cpython/rev/b6acfbe2bdbe changeset: 75358:b6acfbe2bdbe branch: 2.7 parent: 75350:3e2c230f4664 user: Antoine Pitrou date: Thu Mar 01 16:26:35 2012 +0100 summary: Issue #14159: Fix the len() of weak sets to return a better approximation when some objects are dead or dying. Moreover, the implementation is now O(1) rather than O(n). Thanks to Yury Selivanov for reporting. files: Lib/_weakrefset.py | 2 +- Lib/test/test_weakref.py | 60 ++++++++++++++++++++++++++++ Lib/test/test_weakset.py | 47 +++++++++++++++++++++ Misc/NEWS | 4 + 4 files changed, 112 insertions(+), 1 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -63,7 +63,7 @@ yield item def __len__(self): - return sum(x() is not None for x in self.data) + return len(self.data) - len(self._pending_removals) def __contains__(self, item): try: diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -815,11 +815,71 @@ def __repr__(self): return "" % self.arg +class RefCycle: + def __init__(self): + self.cycle = self + class MappingTestCase(TestBase): COUNT = 10 + def check_len_cycles(self, dict_type, cons): + N = 20 + items = [RefCycle() for i in range(N)] + dct = dict_type(cons(o) for o in items) + # Keep an iterator alive + it = dct.iteritems() + try: + next(it) + except StopIteration: + pass + del items + gc.collect() + n1 = len(dct) + del it + gc.collect() + n2 = len(dct) + # one item may be kept alive inside the iterator + self.assertIn(n1, (0, 1)) + self.assertEqual(n2, 0) + + def test_weak_keyed_len_cycles(self): + self.check_len_cycles(weakref.WeakKeyDictionary, lambda k: (k, 1)) + + def test_weak_valued_len_cycles(self): + self.check_len_cycles(weakref.WeakValueDictionary, lambda k: (1, k)) + + def check_len_race(self, dict_type, cons): + # Extended sanity checks for len() in the face of cyclic collection + self.addCleanup(gc.set_threshold, *gc.get_threshold()) + for th in range(1, 100): + N = 20 + gc.collect(0) + gc.set_threshold(th, th, th) + items = [RefCycle() for i in range(N)] + dct = dict_type(cons(o) for o in items) + del items + # All items will be collected at next garbage collection pass + it = dct.iteritems() + try: + next(it) + except StopIteration: + pass + n1 = len(dct) + del it + n2 = len(dct) + self.assertGreaterEqual(n1, 0) + self.assertLessEqual(n1, N) + self.assertGreaterEqual(n2, 0) + self.assertLessEqual(n2, n1) + + def test_weak_keyed_len_race(self): + self.check_len_race(weakref.WeakKeyDictionary, lambda k: (k, 1)) + + def test_weak_valued_len_race(self): + self.check_len_race(weakref.WeakValueDictionary, lambda k: (1, k)) + def test_weak_values(self): # # This exercises d.copy(), d.items(), d[], del d[], len(d). diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -30,6 +30,10 @@ def __hash__(self): return hash((SomeClass, self.value)) +class RefCycle(object): + def __init__(self): + self.cycle = self + class TestWeakSet(unittest.TestCase): def setUp(self): @@ -369,6 +373,49 @@ s.clear() self.assertEqual(len(s), 0) + def test_len_cycles(self): + N = 20 + items = [RefCycle() for i in range(N)] + s = WeakSet(items) + del items + it = iter(s) + try: + next(it) + except StopIteration: + pass + gc.collect() + n1 = len(s) + del it + gc.collect() + n2 = len(s) + # one item may be kept alive inside the iterator + self.assertIn(n1, (0, 1)) + self.assertEqual(n2, 0) + + def test_len_race(self): + # Extended sanity checks for len() in the face of cyclic collection + self.addCleanup(gc.set_threshold, *gc.get_threshold()) + for th in range(1, 100): + N = 20 + gc.collect(0) + gc.set_threshold(th, th, th) + items = [RefCycle() for i in range(N)] + s = WeakSet(items) + del items + # All items will be collected at next garbage collection pass + it = iter(s) + try: + next(it) + except StopIteration: + pass + n1 = len(s) + del it + n2 = len(s) + self.assertGreaterEqual(n1, 0) + self.assertLessEqual(n1, N) + self.assertGreaterEqual(n2, 0) + self.assertLessEqual(n2, n1) + def test_main(verbose=None): test_support.run_unittest(TestWeakSet) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -101,6 +101,10 @@ Library ------- +- Issue #14159: Fix the len() of weak sets to return a better approximation + when some objects are dead or dying. Moreover, the implementation is now + O(1) rather than O(n). + - Issue #2945: Make the distutils upload command aware of bdist_rpm products. - Issue #13447: Add a test file to host regression tests for bugs in the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 1 18:08:06 2012 From: python-checkins at python.org (eli.bendersky) Date: Thu, 01 Mar 2012 18:08:06 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Add_missing_=27versionadded?= =?utf8?q?=27_for_shlex=2Equote=3B_closes_=2314165?= Message-ID: http://hg.python.org/cpython/rev/73be78d21003 changeset: 75359:73be78d21003 parent: 75357:b1b2a29d3d81 user: Eli Bendersky date: Thu Mar 01 19:07:55 2012 +0200 summary: Add missing 'versionadded' for shlex.quote; closes #14165 files: Doc/library/shlex.rst | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst --- a/Doc/library/shlex.rst +++ b/Doc/library/shlex.rst @@ -66,6 +66,7 @@ >>> command ['ls', '-l', 'somefile; rm -rf ~'] + .. versionadded:: 3.3 The :mod:`shlex` module defines the following class: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 1 20:51:20 2012 From: python-checkins at python.org (petri.lehtinen) Date: Thu, 01 Mar 2012 20:51:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_sqlite3=3A_Port?= =?utf8?q?_relevant_documentation_changes_from_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/d2cf730de195 changeset: 75360:d2cf730de195 branch: 2.7 parent: 75358:b6acfbe2bdbe user: Petri Lehtinen date: Thu Mar 01 21:28:00 2012 +0200 summary: sqlite3: Port relevant documentation changes from 3.2 Initial patch by Johannes Vogel. Issue #13491. files: Doc/includes/sqlite3/execute_1.py | 11 +++- Doc/includes/sqlite3/execute_2.py | 12 ----- Doc/includes/sqlite3/executemany_2.py | 4 +- Doc/includes/sqlite3/rowclass.py | 8 +- Doc/includes/sqlite3/text_factory.py | 11 +--- Doc/library/sqlite3.rst | 32 ++++++-------- Misc/ACKS | 1 + Misc/NEWS | 3 +- 8 files changed, 35 insertions(+), 47 deletions(-) diff --git a/Doc/includes/sqlite3/execute_1.py b/Doc/includes/sqlite3/execute_1.py --- a/Doc/includes/sqlite3/execute_1.py +++ b/Doc/includes/sqlite3/execute_1.py @@ -1,11 +1,16 @@ import sqlite3 -con = sqlite3.connect("mydb") - +con = sqlite3.connect(":memory:") cur = con.cursor() +cur.execute("create table people (name_last, age)") who = "Yeltsin" age = 72 -cur.execute("select name_last, age from people where name_last=? and age=?", (who, age)) +# This is the qmark style: +cur.execute("insert into people values (?, ?)", (who, age)) + +# And this is the named style: +cur.execute("select * from people where name_last=:who and age=:age", {"who": who, "age": age}) + print cur.fetchone() diff --git a/Doc/includes/sqlite3/execute_2.py b/Doc/includes/sqlite3/execute_2.py deleted file mode 100644 --- a/Doc/includes/sqlite3/execute_2.py +++ /dev/null @@ -1,12 +0,0 @@ -import sqlite3 - -con = sqlite3.connect("mydb") - -cur = con.cursor() - -who = "Yeltsin" -age = 72 - -cur.execute("select name_last, age from people where name_last=:who and age=:age", - {"who": who, "age": age}) -print cur.fetchone() diff --git a/Doc/includes/sqlite3/executemany_2.py b/Doc/includes/sqlite3/executemany_2.py --- a/Doc/includes/sqlite3/executemany_2.py +++ b/Doc/includes/sqlite3/executemany_2.py @@ -1,8 +1,8 @@ import sqlite3 +import string def char_generator(): - import string - for c in string.letters[:26]: + for c in string.lowercase: yield (c,) con = sqlite3.connect(":memory:") diff --git a/Doc/includes/sqlite3/rowclass.py b/Doc/includes/sqlite3/rowclass.py --- a/Doc/includes/sqlite3/rowclass.py +++ b/Doc/includes/sqlite3/rowclass.py @@ -1,12 +1,12 @@ import sqlite3 -con = sqlite3.connect("mydb") +con = sqlite3.connect(":memory:") con.row_factory = sqlite3.Row cur = con.cursor() -cur.execute("select name_last, age from people") +cur.execute("select 'John' as name, 42 as age") for row in cur: - assert row[0] == row["name_last"] - assert row["name_last"] == row["nAmE_lAsT"] + assert row[0] == row["name"] + assert row["name"] == row["nAmE"] assert row[1] == row["age"] assert row[1] == row["AgE"] diff --git a/Doc/includes/sqlite3/text_factory.py b/Doc/includes/sqlite3/text_factory.py --- a/Doc/includes/sqlite3/text_factory.py +++ b/Doc/includes/sqlite3/text_factory.py @@ -3,9 +3,6 @@ con = sqlite3.connect(":memory:") cur = con.cursor() -# Create the table -con.execute("create table person(lastname, firstname)") - AUSTRIA = u"\xd6sterreich" # by default, rows are returned as Unicode @@ -17,7 +14,7 @@ con.text_factory = str cur.execute("select ?", (AUSTRIA,)) row = cur.fetchone() -assert type(row[0]) == str +assert type(row[0]) is str # the bytestrings will be encoded in UTF-8, unless you stored garbage in the # database ... assert row[0] == AUSTRIA.encode("utf-8") @@ -29,15 +26,15 @@ cur.execute("select ?", ("this is latin1 and would normally create errors" + u"\xe4\xf6\xfc".encode("latin1"),)) row = cur.fetchone() -assert type(row[0]) == unicode +assert type(row[0]) is unicode # sqlite3 offers a built-in optimized text_factory that will return bytestring # objects, if the data is in ASCII only, and otherwise return unicode objects con.text_factory = sqlite3.OptimizedUnicode cur.execute("select ?", (AUSTRIA,)) row = cur.fetchone() -assert type(row[0]) == unicode +assert type(row[0]) is unicode cur.execute("select ?", ("Germany",)) row = cur.fetchone() -assert type(row[0]) == str +assert type(row[0]) is str diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -3,7 +3,7 @@ .. module:: sqlite3 :synopsis: A DB-API 2.0 implementation using SQLite 3.x. -.. sectionauthor:: Gerhard H??ring +.. sectionauthor:: Gerhard H?ring .. versionadded:: 2.5 @@ -82,7 +82,7 @@ >>> c = conn.cursor() >>> c.execute('select * from stocks order by price') >>> for row in c: - ... print row + ... print row ... (u'2006-01-05', u'BUY', u'RHAT', 100, 35.14) (u'2006-03-28', u'BUY', u'IBM', 1000, 45.0) @@ -237,7 +237,6 @@ supplied, this must be a custom cursor class that extends :class:`sqlite3.Cursor`. - .. method:: Connection.commit() This method commits the current transaction. If you don't call this method, @@ -357,8 +356,6 @@ .. method:: Connection.set_progress_handler(handler, n) - .. versionadded:: 2.6 - This routine registers a callback. The callback is invoked for every *n* instructions of the SQLite virtual machine. This is useful if you want to get called from SQLite during long-running operations, for example to update @@ -367,29 +364,31 @@ If you want to clear any previously installed progress handler, call the method with :const:`None` for *handler*. + .. versionadded:: 2.6 + .. method:: Connection.enable_load_extension(enabled) - .. versionadded:: 2.7 - This routine allows/disallows the SQLite engine to load SQLite extensions from shared libraries. SQLite extensions can define new functions, aggregates or whole new virtual table implementations. One well-known extension is the fulltext-search extension distributed with SQLite. + Loadable extensions are disabled by default. See [#f1]_. + + .. versionadded:: 2.7 + .. literalinclude:: ../includes/sqlite3/load_extension.py - Loadable extensions are disabled by default. See [#f1]_ - .. method:: Connection.load_extension(path) - .. versionadded:: 2.7 - This routine loads a SQLite extension from a shared library. You have to enable extension loading with :meth:`enable_load_extension` before you can use this routine. - Loadable extensions are disabled by default. See [#f1]_ + Loadable extensions are disabled by default. See [#f1]_. + + .. versionadded:: 2.7 .. attribute:: Connection.row_factory @@ -473,14 +472,10 @@ kinds of placeholders: question marks (qmark style) and named placeholders (named style). - This example shows how to use parameters with qmark style: + Here's an example of both styles: .. literalinclude:: ../includes/sqlite3/execute_1.py - This example shows how to use the named style: - - .. literalinclude:: ../includes/sqlite3/execute_2.py - :meth:`execute` will only execute a single SQL statement. If you try to execute more than one statement with it, it will raise a Warning. Use :meth:`executescript` if you want to execute multiple SQL statements with one @@ -633,7 +628,8 @@ ['date', 'trans', 'symbol', 'qty', 'price'] >>> r['qty'] 100.0 - >>> for member in r: print member + >>> for member in r: + ... print member ... 2006-01-05 BUY diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -879,6 +879,7 @@ Kurt Vile Norman Vine Frank Visser +Johannes Vogel Niki W. Waibel Wojtek Walczak Charles Waldman diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -613,7 +613,8 @@ Documentation ------------- -- Issue #13995: Fix errors in sqlite3's Cursor.rowcount documentation +- Issues #13491 and #13995: Fix many errors in sqlite3 documentation. + Initial patch for #13491 by Johannes Vogel. - Issue #13402: Document absoluteness of sys.executable. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 1 20:51:21 2012 From: python-checkins at python.org (petri.lehtinen) Date: Thu, 01 Mar 2012 20:51:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_sqlite3=3A_Port?= =?utf8?q?_documentation_changes_from_the_2=2E7_branch?= Message-ID: http://hg.python.org/cpython/rev/5f492397ccb8 changeset: 75361:5f492397ccb8 branch: 3.2 parent: 75356:1cd0688ff004 user: Petri Lehtinen date: Thu Mar 01 21:18:34 2012 +0200 summary: sqlite3: Port documentation changes from the 2.7 branch Issue #13491. files: Doc/library/sqlite3.rst | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -3,7 +3,7 @@ .. module:: sqlite3 :synopsis: A DB-API 2.0 implementation using SQLite 3.x. -.. sectionauthor:: Gerhard H??ring +.. sectionauthor:: Gerhard H?ring SQLite is a C library that provides a lightweight disk-based database that @@ -20,6 +20,7 @@ represents the database. Here the data will be stored in the :file:`/tmp/example` file:: + import sqlite3 conn = sqlite3.connect('/tmp/example') You can also supply the special name ``:memory:`` to create a database in RAM. @@ -56,7 +57,7 @@ # Never do this -- insecure! symbol = 'IBM' - c.execute("... where symbol = '%s'" % symbol) + c.execute("select * from stocks where symbol = '%s'" % symbol) # Do this instead t = (symbol,) @@ -64,7 +65,7 @@ # Larger example for t in [('2006-03-28', 'BUY', 'IBM', 1000, 45.00), - ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00), + ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00), ('2006-04-06', 'SELL', 'IBM', 500, 53.00), ]: c.execute('insert into stocks values (?,?,?,?,?)', t) @@ -271,7 +272,6 @@ calling the cursor method, then calls the cursor's :meth:`executemany ` method with the parameters given. - .. method:: Connection.executescript(sql_script) This is a nonstandard shortcut that creates an intermediate cursor object by @@ -376,22 +376,22 @@ aggregates or whole new virtual table implementations. One well-known extension is the fulltext-search extension distributed with SQLite. + Loadable extensions are disabled by default. See [#f1]_. + .. versionadded:: 3.2 .. literalinclude:: ../includes/sqlite3/load_extension.py - Loadable extensions are disabled by default. See [#f1]_. - .. method:: Connection.load_extension(path) This routine loads a SQLite extension from a shared library. You have to enable extension loading with :meth:`enable_load_extension` before you can use this routine. + Loadable extensions are disabled by default. See [#f1]_. + .. versionadded:: 3.2 - Loadable extensions are disabled by default. See [#f1]_. - .. attribute:: Connection.row_factory You can change this attribute to a callable that accepts the cursor and the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 1 20:51:22 2012 From: python-checkins at python.org (petri.lehtinen) Date: Thu, 01 Mar 2012 20:51:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_branch_=273=2E2=27?= Message-ID: http://hg.python.org/cpython/rev/82032c64dd89 changeset: 75362:82032c64dd89 parent: 75359:73be78d21003 parent: 75361:5f492397ccb8 user: Petri Lehtinen date: Thu Mar 01 21:49:39 2012 +0200 summary: Merge branch '3.2' Issue #13491. files: Doc/library/sqlite3.rst | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -3,7 +3,7 @@ .. module:: sqlite3 :synopsis: A DB-API 2.0 implementation using SQLite 3.x. -.. sectionauthor:: Gerhard H??ring +.. sectionauthor:: Gerhard H?ring SQLite is a C library that provides a lightweight disk-based database that @@ -20,6 +20,7 @@ represents the database. Here the data will be stored in the :file:`/tmp/example` file:: + import sqlite3 conn = sqlite3.connect('/tmp/example') You can also supply the special name ``:memory:`` to create a database in RAM. @@ -56,7 +57,7 @@ # Never do this -- insecure! symbol = 'IBM' - c.execute("... where symbol = '%s'" % symbol) + c.execute("select * from stocks where symbol = '%s'" % symbol) # Do this instead t = (symbol,) @@ -64,7 +65,7 @@ # Larger example for t in [('2006-03-28', 'BUY', 'IBM', 1000, 45.00), - ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00), + ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00), ('2006-04-06', 'SELL', 'IBM', 500, 53.00), ]: c.execute('insert into stocks values (?,?,?,?,?)', t) @@ -271,7 +272,6 @@ calling the cursor method, then calls the cursor's :meth:`executemany ` method with the parameters given. - .. method:: Connection.executescript(sql_script) This is a nonstandard shortcut that creates an intermediate cursor object by @@ -392,22 +392,22 @@ aggregates or whole new virtual table implementations. One well-known extension is the fulltext-search extension distributed with SQLite. + Loadable extensions are disabled by default. See [#f1]_. + .. versionadded:: 3.2 .. literalinclude:: ../includes/sqlite3/load_extension.py - Loadable extensions are disabled by default. See [#f1]_. - .. method:: Connection.load_extension(path) This routine loads a SQLite extension from a shared library. You have to enable extension loading with :meth:`enable_load_extension` before you can use this routine. + Loadable extensions are disabled by default. See [#f1]_. + .. versionadded:: 3.2 - Loadable extensions are disabled by default. See [#f1]_. - .. attribute:: Connection.row_factory You can change this attribute to a callable that accepts the cursor and the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 2 02:24:21 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 02 Mar 2012 02:24:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314158?= =?utf8?q?=3A_improved_resilience_to_test_files_left_behind=2E?= Message-ID: http://hg.python.org/cpython/rev/707586c70195 changeset: 75363:707586c70195 branch: 3.2 parent: 75361:5f492397ccb8 user: Vinay Sajip date: Fri Mar 02 01:01:13 2012 +0000 summary: Closes #14158: improved resilience to test files left behind. files: Lib/test/regrtest.py | 27 ++++++++++++++++++++++----- Lib/test/test_base64.py | 5 +++++ Lib/test/test_mailbox.py | 12 ++++++------ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -677,10 +677,10 @@ if bad: print(count(len(bad), "test"), "failed:") printlist(bad) - if environment_changed: - print("{} altered the execution environment:".format( - count(len(environment_changed), "test"))) - printlist(environment_changed) + if environment_changed: + print("{} altered the execution environment:".format( + count(len(environment_changed), "test"))) + printlist(environment_changed) if skipped and not quiet: print(count(len(skipped), "test"), "skipped:") printlist(skipped) @@ -890,7 +890,9 @@ 'logging._handlers', 'logging._handlerList', 'shutil.archive_formats', 'shutil.unpack_formats', 'sys.warnoptions', 'threading._dangling', - 'multiprocessing.process._dangling') + 'multiprocessing.process._dangling', + 'support.TESTFN', + ) def get_sys_argv(self): return id(sys.argv), sys.argv, sys.argv[:] @@ -1020,6 +1022,21 @@ multiprocessing.process._dangling.clear() multiprocessing.process._dangling.update(saved) + def get_support_TESTFN(self): + if os.path.isfile(support.TESTFN): + result = 'f' + elif os.path.isdir(support.TESTFN): + result = 'd' + else: + result = None + return result + def restore_support_TESTFN(self, saved_value): + if saved_value is None: + if os.path.isfile(support.TESTFN): + os.unlink(support.TESTFN) + elif os.path.isdir(support.TESTFN): + shutil.rmtree(support.TESTFN) + def resource_info(self): for name in self.resources: method_suffix = name.replace('.', '_') diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -2,6 +2,7 @@ from test import support import base64 import binascii +import os import sys import subprocess @@ -227,6 +228,10 @@ class TestMain(unittest.TestCase): + def tearDown(self): + if os.path.exists(support.TESTFN): + os.unlink(support.TESTFN) + def get_output(self, *args, **options): args = (sys.executable, '-m', 'base64') + args return subprocess.check_output(args, **options) diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -7,6 +7,7 @@ import email.message import re import io +import shutil import tempfile from test import support import unittest @@ -38,12 +39,7 @@ def _delete_recursively(self, target): # Delete a file or delete a directory recursively if os.path.isdir(target): - for path, dirs, files in os.walk(target, topdown=False): - for name in files: - os.remove(os.path.join(path, name)) - for name in dirs: - os.rmdir(os.path.join(path, name)) - os.rmdir(target) + shutil.rmtree(target) elif os.path.exists(target): os.remove(target) @@ -2029,6 +2025,10 @@ def setUp(self): # create a new maildir mailbox to work with: self._dir = support.TESTFN + if os.path.isdir(self._dir): + shutil.rmtree(self._dir) + elif os.path.isfile(self._dir): + os.unlink(self._dir) os.mkdir(self._dir) os.mkdir(os.path.join(self._dir, "cur")) os.mkdir(os.path.join(self._dir, "tmp")) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 2 02:24:21 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 02 Mar 2012 02:24:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Closes_=2314158=3A_merged_test_file_resilience_fix_from_3=2E?= =?utf8?q?2=2E?= Message-ID: http://hg.python.org/cpython/rev/a92e73dfbff6 changeset: 75364:a92e73dfbff6 parent: 75362:82032c64dd89 parent: 75363:707586c70195 user: Vinay Sajip date: Fri Mar 02 01:24:13 2012 +0000 summary: Closes #14158: merged test file resilience fix from 3.2. files: Lib/test/regrtest.py | 23 +++++++++++++++++++---- Lib/test/test_base64.py | 5 +++++ Lib/test/test_mailbox.py | 12 ++++++------ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -749,10 +749,10 @@ if bad: print(count(len(bad), "test"), "failed:") printlist(bad) - if environment_changed: - print("{} altered the execution environment:".format( - count(len(environment_changed), "test"))) - printlist(environment_changed) + if environment_changed: + print("{} altered the execution environment:".format( + count(len(environment_changed), "test"))) + printlist(environment_changed) if skipped and not quiet: print(count(len(skipped), "test"), "skipped:") printlist(skipped) @@ -970,6 +970,7 @@ 'multiprocessing.process._dangling', 'sysconfig._CONFIG_VARS', 'sysconfig._SCHEMES', 'packaging.command._COMMANDS', 'packaging.database_caches', + 'support.TESTFN', ) def get_sys_argv(self): @@ -1163,6 +1164,20 @@ sysconfig._SCHEMES._sections.clear() sysconfig._SCHEMES._sections.update(saved[2]) + def get_support_TESTFN(self): + if os.path.isfile(support.TESTFN): + result = 'f' + elif os.path.isdir(support.TESTFN): + result = 'd' + else: + result = None + return result + def restore_support_TESTFN(self, saved_value): + if saved_value is None: + if os.path.isfile(support.TESTFN): + os.unlink(support.TESTFN) + elif os.path.isdir(support.TESTFN): + shutil.rmtree(support.TESTFN) def resource_info(self): for name in self.resources: diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -2,6 +2,7 @@ from test import support import base64 import binascii +import os import sys import subprocess @@ -274,6 +275,10 @@ class TestMain(unittest.TestCase): + def tearDown(self): + if os.path.exists(support.TESTFN): + os.unlink(support.TESTFN) + def get_output(self, *args, **options): args = (sys.executable, '-m', 'base64') + args return subprocess.check_output(args, **options) diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -7,6 +7,7 @@ import email.message import re import io +import shutil import tempfile from test import support import unittest @@ -38,12 +39,7 @@ def _delete_recursively(self, target): # Delete a file or delete a directory recursively if os.path.isdir(target): - for path, dirs, files in os.walk(target, topdown=False): - for name in files: - os.remove(os.path.join(path, name)) - for name in dirs: - os.rmdir(os.path.join(path, name)) - os.rmdir(target) + shutil.rmtree(target) elif os.path.exists(target): os.remove(target) @@ -2028,6 +2024,10 @@ def setUp(self): # create a new maildir mailbox to work with: self._dir = support.TESTFN + if os.path.isdir(self._dir): + shutil.rmtree(self._dir) + elif os.path.isfile(self._dir): + os.unlink(self._dir) os.mkdir(self._dir) os.mkdir(os.path.join(self._dir, "cur")) os.mkdir(os.path.join(self._dir, "tmp")) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Mar 2 05:37:34 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 02 Mar 2012 05:37:34 +0100 Subject: [Python-checkins] Daily reference leaks (a92e73dfbff6): sum=0 Message-ID: results for a92e73dfbff6 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogOpRL_3', '-x'] From python-checkins at python.org Fri Mar 2 06:44:07 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 02 Mar 2012 06:44:07 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzExMzc5?= =?utf8?q?=3A_add_a_note_in_xml=2Edom=2Eminidom_suggesting_to_use_etree_in?= =?utf8?q?_some?= Message-ID: http://hg.python.org/cpython/rev/81e606862a89 changeset: 75365:81e606862a89 branch: 3.2 parent: 75356:1cd0688ff004 user: Eli Bendersky date: Fri Mar 02 07:37:13 2012 +0200 summary: Issue #11379: add a note in xml.dom.minidom suggesting to use etree in some cases files: Doc/library/xml.dom.minidom.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -15,6 +15,14 @@ Model interface. It is intended to be simpler than the full DOM and also significantly smaller. +.. note:: + + The :mod:`xml.dom.minidom` module provides an implementation of the W3C-DOM, + with an API similar to that in other programming languages. Users who are + unfamiliar with the W3C-DOM interface or who would like to write less code + for processing XML files should consider using the + :mod:`xml.etree.ElementTree` module instead. + DOM applications typically start by parsing some XML into a DOM. With :mod:`xml.dom.minidom`, this is done through the parse functions:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 2 06:44:08 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 02 Mar 2012 06:44:08 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/009fed42c918 changeset: 75366:009fed42c918 parent: 75364:a92e73dfbff6 parent: 75365:81e606862a89 user: Eli Bendersky date: Fri Mar 02 07:41:23 2012 +0200 summary: Merge 3.2 files: Doc/library/xml.dom.minidom.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -15,6 +15,14 @@ Model interface. It is intended to be simpler than the full DOM and also significantly smaller. +.. note:: + + The :mod:`xml.dom.minidom` module provides an implementation of the W3C-DOM, + with an API similar to that in other programming languages. Users who are + unfamiliar with the W3C-DOM interface or who would like to write less code + for processing XML files should consider using the + :mod:`xml.etree.ElementTree` module instead. + DOM applications typically start by parsing some XML into a DOM. With :mod:`xml.dom.minidom`, this is done through the parse functions:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 2 06:44:10 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 02 Mar 2012 06:44:10 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_3=2E2_heads?= Message-ID: http://hg.python.org/cpython/rev/cb1b75dccc0b changeset: 75367:cb1b75dccc0b branch: 3.2 parent: 75365:81e606862a89 parent: 75363:707586c70195 user: Eli Bendersky date: Fri Mar 02 07:43:08 2012 +0200 summary: merge 3.2 heads files: Doc/library/sqlite3.rst | 16 ++++++++-------- Lib/test/regrtest.py | 27 ++++++++++++++++++++++----- Lib/test/test_base64.py | 5 +++++ Lib/test/test_mailbox.py | 12 ++++++------ 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -3,7 +3,7 @@ .. module:: sqlite3 :synopsis: A DB-API 2.0 implementation using SQLite 3.x. -.. sectionauthor:: Gerhard H??ring +.. sectionauthor:: Gerhard H?ring SQLite is a C library that provides a lightweight disk-based database that @@ -20,6 +20,7 @@ represents the database. Here the data will be stored in the :file:`/tmp/example` file:: + import sqlite3 conn = sqlite3.connect('/tmp/example') You can also supply the special name ``:memory:`` to create a database in RAM. @@ -56,7 +57,7 @@ # Never do this -- insecure! symbol = 'IBM' - c.execute("... where symbol = '%s'" % symbol) + c.execute("select * from stocks where symbol = '%s'" % symbol) # Do this instead t = (symbol,) @@ -64,7 +65,7 @@ # Larger example for t in [('2006-03-28', 'BUY', 'IBM', 1000, 45.00), - ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00), + ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00), ('2006-04-06', 'SELL', 'IBM', 500, 53.00), ]: c.execute('insert into stocks values (?,?,?,?,?)', t) @@ -271,7 +272,6 @@ calling the cursor method, then calls the cursor's :meth:`executemany ` method with the parameters given. - .. method:: Connection.executescript(sql_script) This is a nonstandard shortcut that creates an intermediate cursor object by @@ -376,22 +376,22 @@ aggregates or whole new virtual table implementations. One well-known extension is the fulltext-search extension distributed with SQLite. + Loadable extensions are disabled by default. See [#f1]_. + .. versionadded:: 3.2 .. literalinclude:: ../includes/sqlite3/load_extension.py - Loadable extensions are disabled by default. See [#f1]_. - .. method:: Connection.load_extension(path) This routine loads a SQLite extension from a shared library. You have to enable extension loading with :meth:`enable_load_extension` before you can use this routine. + Loadable extensions are disabled by default. See [#f1]_. + .. versionadded:: 3.2 - Loadable extensions are disabled by default. See [#f1]_. - .. attribute:: Connection.row_factory You can change this attribute to a callable that accepts the cursor and the diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -677,10 +677,10 @@ if bad: print(count(len(bad), "test"), "failed:") printlist(bad) - if environment_changed: - print("{} altered the execution environment:".format( - count(len(environment_changed), "test"))) - printlist(environment_changed) + if environment_changed: + print("{} altered the execution environment:".format( + count(len(environment_changed), "test"))) + printlist(environment_changed) if skipped and not quiet: print(count(len(skipped), "test"), "skipped:") printlist(skipped) @@ -890,7 +890,9 @@ 'logging._handlers', 'logging._handlerList', 'shutil.archive_formats', 'shutil.unpack_formats', 'sys.warnoptions', 'threading._dangling', - 'multiprocessing.process._dangling') + 'multiprocessing.process._dangling', + 'support.TESTFN', + ) def get_sys_argv(self): return id(sys.argv), sys.argv, sys.argv[:] @@ -1020,6 +1022,21 @@ multiprocessing.process._dangling.clear() multiprocessing.process._dangling.update(saved) + def get_support_TESTFN(self): + if os.path.isfile(support.TESTFN): + result = 'f' + elif os.path.isdir(support.TESTFN): + result = 'd' + else: + result = None + return result + def restore_support_TESTFN(self, saved_value): + if saved_value is None: + if os.path.isfile(support.TESTFN): + os.unlink(support.TESTFN) + elif os.path.isdir(support.TESTFN): + shutil.rmtree(support.TESTFN) + def resource_info(self): for name in self.resources: method_suffix = name.replace('.', '_') diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -2,6 +2,7 @@ from test import support import base64 import binascii +import os import sys import subprocess @@ -227,6 +228,10 @@ class TestMain(unittest.TestCase): + def tearDown(self): + if os.path.exists(support.TESTFN): + os.unlink(support.TESTFN) + def get_output(self, *args, **options): args = (sys.executable, '-m', 'base64') + args return subprocess.check_output(args, **options) diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -7,6 +7,7 @@ import email.message import re import io +import shutil import tempfile from test import support import unittest @@ -38,12 +39,7 @@ def _delete_recursively(self, target): # Delete a file or delete a directory recursively if os.path.isdir(target): - for path, dirs, files in os.walk(target, topdown=False): - for name in files: - os.remove(os.path.join(path, name)) - for name in dirs: - os.rmdir(os.path.join(path, name)) - os.rmdir(target) + shutil.rmtree(target) elif os.path.exists(target): os.remove(target) @@ -2029,6 +2025,10 @@ def setUp(self): # create a new maildir mailbox to work with: self._dir = support.TESTFN + if os.path.isdir(self._dir): + shutil.rmtree(self._dir) + elif os.path.isfile(self._dir): + os.unlink(self._dir) os.mkdir(self._dir) os.mkdir(os.path.join(self._dir, "cur")) os.mkdir(os.path.join(self._dir, "tmp")) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 2 06:46:17 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 02 Mar 2012 06:46:17 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzExMzc5?= =?utf8?q?=3A_add_a_note_in_xml=2Edom=2Eminidom_suggesting_to_use_etree_in?= =?utf8?q?_some?= Message-ID: http://hg.python.org/cpython/rev/ccd16ad37544 changeset: 75368:ccd16ad37544 branch: 2.7 parent: 75360:d2cf730de195 user: Eli Bendersky date: Fri Mar 02 07:45:55 2012 +0200 summary: Issue #11379: add a note in xml.dom.minidom suggesting to use etree in some cases files: Doc/library/xml.dom.minidom.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -18,6 +18,14 @@ Model interface. It is intended to be simpler than the full DOM and also significantly smaller. +.. note:: + + The :mod:`xml.dom.minidom` module provides an implementation of the W3C-DOM, + with an API similar to that in other programming languages. Users who are + unfamiliar with the W3C-DOM interface or who would like to write less code + for processing XML files should consider using the + :mod:`xml.etree.ElementTree` module instead. + DOM applications typically start by parsing some XML into a DOM. With :mod:`xml.dom.minidom`, this is done through the parse functions:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 2 18:21:08 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 02 Mar 2012 18:21:08 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MTcy?= =?utf8?q?=3A_Fix_reference_leak_when_marshalling_a_buffer-like_object_=28?= =?utf8?q?other?= Message-ID: http://hg.python.org/cpython/rev/185a6ae76479 changeset: 75369:185a6ae76479 branch: 3.2 parent: 75367:cb1b75dccc0b user: Antoine Pitrou date: Fri Mar 02 18:12:43 2012 +0100 summary: Issue #14172: Fix reference leak when marshalling a buffer-like object (other than a bytes object). files: Lib/test/test_marshal.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ Python/marshal.c | 8 ++++---- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from test import support +import array import marshal import sys import unittest @@ -137,6 +138,27 @@ for constructor in (set, frozenset): self.helper(constructor(self.d.keys())) + +class BufferTestCase(unittest.TestCase, HelperMixin): + + def test_bytearray(self): + b = bytearray(b"abc") + self.helper(b) + new = marshal.loads(marshal.dumps(b)) + self.assertEqual(type(new), bytes) + + def test_memoryview(self): + b = memoryview(b"abc") + self.helper(b) + new = marshal.loads(marshal.dumps(b)) + self.assertEqual(type(new), bytes) + + def test_array(self): + a = array.array('B', b"abc") + new = marshal.loads(marshal.dumps(a)) + self.assertEqual(new, b"abc") + + class BugsTestCase(unittest.TestCase): def test_bug_5888452(self): # Simple-minded check for SF 588452: Debug build crashes @@ -243,6 +265,7 @@ CodeTestCase, ContainerTestCase, ExceptionTestCase, + BufferTestCase, BugsTestCase) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #14172: Fix reference leak when marshalling a buffer-like object + (other than a bytes object). + - Issue #13521: dict.setdefault() now does only one lookup for the given key, making it "atomic" for many purposes. Patch by Filip Gruszczy?ski. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -411,11 +411,12 @@ else if (PyObject_CheckBuffer(v)) { /* Write unknown buffer-style objects as a string */ char *s; - PyBufferProcs *pb = v->ob_type->tp_as_buffer; Py_buffer view; - if ((*pb->bf_getbuffer)(v, &view, PyBUF_SIMPLE) != 0) { + if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) != 0) { w_byte(TYPE_UNKNOWN, p); + p->depth--; p->error = WFERR_UNMARSHALLABLE; + return; } w_byte(TYPE_STRING, p); n = view.len; @@ -427,8 +428,7 @@ } w_long((long)n, p); w_string(s, (int)n, p); - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(v, &view); + PyBuffer_Release(&view); } else { w_byte(TYPE_UNKNOWN, p); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 2 18:21:12 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 02 Mar 2012 18:21:12 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314172=3A_Fix_reference_leak_when_marshalling_a_buff?= =?utf8?q?er-like_object_=28other?= Message-ID: http://hg.python.org/cpython/rev/b1303cf15e01 changeset: 75370:b1303cf15e01 parent: 75366:009fed42c918 parent: 75369:185a6ae76479 user: Antoine Pitrou date: Fri Mar 02 18:16:38 2012 +0100 summary: Issue #14172: Fix reference leak when marshalling a buffer-like object (other than a bytes object). files: Lib/test/test_marshal.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ Python/marshal.c | 8 ++++---- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from test import support +import array import marshal import sys import unittest @@ -154,6 +155,27 @@ for constructor in (set, frozenset): self.helper(constructor(self.d.keys())) + +class BufferTestCase(unittest.TestCase, HelperMixin): + + def test_bytearray(self): + b = bytearray(b"abc") + self.helper(b) + new = marshal.loads(marshal.dumps(b)) + self.assertEqual(type(new), bytes) + + def test_memoryview(self): + b = memoryview(b"abc") + self.helper(b) + new = marshal.loads(marshal.dumps(b)) + self.assertEqual(type(new), bytes) + + def test_array(self): + a = array.array('B', b"abc") + new = marshal.loads(marshal.dumps(a)) + self.assertEqual(new, b"abc") + + class BugsTestCase(unittest.TestCase): def test_bug_5888452(self): # Simple-minded check for SF 588452: Debug build crashes @@ -260,6 +282,7 @@ CodeTestCase, ContainerTestCase, ExceptionTestCase, + BufferTestCase, BugsTestCase) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #14172: Fix reference leak when marshalling a buffer-like object + (other than a bytes object). + - Issue #13521: dict.setdefault() now does only one lookup for the given key, making it "atomic" for many purposes. Patch by Filip Gruszczy?ski. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -409,11 +409,12 @@ else if (PyObject_CheckBuffer(v)) { /* Write unknown buffer-style objects as a string */ char *s; - PyBufferProcs *pb = v->ob_type->tp_as_buffer; Py_buffer view; - if ((*pb->bf_getbuffer)(v, &view, PyBUF_SIMPLE) != 0) { + if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) != 0) { w_byte(TYPE_UNKNOWN, p); + p->depth--; p->error = WFERR_UNMARSHALLABLE; + return; } w_byte(TYPE_STRING, p); n = view.len; @@ -425,8 +426,7 @@ } w_long((long)n, p); w_string(s, (int)n, p); - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(v, &view); + PyBuffer_Release(&view); } else { w_byte(TYPE_UNKNOWN, p); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 2 18:28:13 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 02 Mar 2012 18:28:13 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Simplify_code_in_marshal=2E?= =?utf8?q?c=2E?= Message-ID: http://hg.python.org/cpython/rev/61661842f225 changeset: 75371:61661842f225 user: Antoine Pitrou date: Fri Mar 02 18:22:23 2012 +0100 summary: Simplify code in marshal.c. files: Python/marshal.c | 8 +------- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1239,7 +1239,6 @@ PyMarshal_WriteObjectToString(PyObject *x, int version) { WFILE wf; - PyObject *res = NULL; wf.fp = NULL; wf.readable = NULL; @@ -1273,12 +1272,7 @@ :"object too deeply nested to marshal"); return NULL; } - if (wf.str != NULL) { - /* XXX Quick hack -- need to do this differently */ - res = PyBytes_FromObject(wf.str); - Py_DECREF(wf.str); - } - return res; + return wf.str; } /* And an interface for Python programs... */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 2 19:18:37 2012 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 02 Mar 2012 19:18:37 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Delete_rule_forbidding_functio?= =?utf8?q?n_type_annotations_in_the_stdlib=2E?= Message-ID: http://hg.python.org/peps/rev/1461451f5efd changeset: 4103:1461451f5efd user: Guido van Rossum date: Fri Mar 02 10:18:31 2012 -0800 summary: Delete rule forbidding function type annotations in the stdlib. files: pep-0008.txt | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -840,12 +840,6 @@ Worse: if greeting is True: -Rules that apply only to the standard library - - - Do not use function type annotations in the standard library. - These are reserved for users and third-party modules. See - PEP 3107 and the bug 10899 for details. - References -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Mar 2 22:54:43 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 02 Mar 2012 22:54:43 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2313964=3A_signal=2E?= =?utf8?q?sigtimedwait=28=29_timeout_is_now_a_float_instead_of_a_tuple?= Message-ID: http://hg.python.org/cpython/rev/67d9595a833c changeset: 75372:67d9595a833c user: Victor Stinner date: Fri Mar 02 22:54:03 2012 +0100 summary: Issue #13964: signal.sigtimedwait() timeout is now a float instead of a tuple Add a private API to convert an int or float to a C timespec structure. files: Doc/library/signal.rst | 9 ++--- Include/pytime.h | 11 ++++++ Lib/test/test_signal.py | 10 ++--- Lib/test/test_time.py | 21 ++++++++++++- Modules/_testcapimodule.c | 19 +++++++++++ Modules/signalmodule.c | 11 +---- Python/pytime.c | 45 +++++++++++++++++++++++++++ 7 files changed, 106 insertions(+), 20 deletions(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -369,12 +369,11 @@ .. versionadded:: 3.3 -.. function:: sigtimedwait(sigset, (timeout_sec, timeout_nsec)) +.. function:: sigtimedwait(sigset, timeout) - Like :func:`sigtimedwait`, but takes a tuple of ``(seconds, nanoseconds)`` - as an additional argument specifying a timeout. If both *timeout_sec* and - *timeout_nsec* are specified as :const:`0`, a poll is performed. Returns - :const:`None` if a timeout occurs. + Like :func:`sigwaitinfo`, but takes an additional *timeout* argument + specifying a timeout. If *timeout* is specified as :const:`0`, a poll is + performed. Returns :const:`None` if a timeout occurs. Availability: Unix (see the man page :manpage:`sigtimedwait(2)` for further information). diff --git a/Include/pytime.h b/Include/pytime.h --- a/Include/pytime.h +++ b/Include/pytime.h @@ -3,6 +3,7 @@ #define Py_PYTIME_H #include "pyconfig.h" /* include for defines */ +#include "object.h" /************************************************************************** Symbols and macros to supply platform-independent interfaces to time related @@ -37,6 +38,16 @@ ((tv_end.tv_sec - tv_start.tv_sec) + \ (tv_end.tv_usec - tv_start.tv_usec) * 0.000001) +#ifndef Py_LIMITED_API +/* Convert a number of seconds, int or float, to a timespec structure. + nsec is always in the range [0; 999999999]. For example, -1.2 is converted + to (-2, 800000000). */ +PyAPI_FUNC(int) _PyTime_ObjectToTimespec( + PyObject *obj, + time_t *sec, + long *nsec); +#endif + /* Dummy to force linking. */ PyAPI_FUNC(void) _PyTime_Init(void); diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -662,7 +662,7 @@ self.wait_helper(signal.SIGALRM, ''' def test(signum): signal.alarm(1) - info = signal.sigtimedwait([signum], (10, 1000)) + info = signal.sigtimedwait([signum], 10.1000) if info.si_signo != signum: raise Exception('info.si_signo != %s' % signum) ''') @@ -675,7 +675,7 @@ def test(signum): import os os.kill(os.getpid(), signum) - info = signal.sigtimedwait([signum], (0, 0)) + info = signal.sigtimedwait([signum], 0) if info.si_signo != signum: raise Exception('info.si_signo != %s' % signum) ''') @@ -685,7 +685,7 @@ def test_sigtimedwait_timeout(self): self.wait_helper(signal.SIGALRM, ''' def test(signum): - received = signal.sigtimedwait([signum], (1, 0)) + received = signal.sigtimedwait([signum], 1.0) if received is not None: raise Exception("received=%r" % (received,)) ''') @@ -694,9 +694,7 @@ 'need signal.sigtimedwait()') def test_sigtimedwait_negative_timeout(self): signum = signal.SIGALRM - self.assertRaises(ValueError, signal.sigtimedwait, [signum], (-1, -1)) - self.assertRaises(ValueError, signal.sigtimedwait, [signum], (0, -1)) - self.assertRaises(ValueError, signal.sigtimedwait, [signum], (-1, 0)) + self.assertRaises(ValueError, signal.sigtimedwait, [signum], -1.0) @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'), 'need signal.sigwaitinfo()') diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -497,12 +497,31 @@ pass +class TestPytime(unittest.TestCase): + def test_timespec(self): + from _testcapi import pytime_object_to_timespec + for obj, timespec in ( + (0, (0, 0)), + (-1, (-1, 0)), + (-1.0, (-1, 0)), + (-1e-9, (-1, 999999999)), + (-1.2, (-2, 800000000)), + (1.123456789, (1, 123456789)), + ): + self.assertEqual(pytime_object_to_timespec(obj), timespec) + + for invalid in (-(2 ** 100), -(2.0 ** 100.0), 2 ** 100, 2.0 ** 100.0): + self.assertRaises(OverflowError, pytime_object_to_timespec, invalid) + + + def test_main(): support.run_unittest( TimeTestCase, TestLocale, TestAsctime4dyear, - TestStrftime4dyear) + TestStrftime4dyear, + TestPytime) if __name__ == "__main__": test_main() diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2323,6 +2323,24 @@ return PyLong_FromLong(r); } +static PyObject * +test_pytime_object_to_timespec(PyObject *self, PyObject *args) +{ + PyObject *obj; + time_t sec; + long nsec; + if (!PyArg_ParseTuple(args, "O:pytime_object_to_timespec", &obj)) + return NULL; + if (_PyTime_ObjectToTimespec(obj, &sec, &nsec) == -1) + return NULL; +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + return Py_BuildValue("Ll", (PY_LONG_LONG)sec, nsec); +#else + assert(sizeof(time_t) <= sizeof(long)); + return Py_BuildValue("ll", (long)sec, nsec); +#endif +} + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, @@ -2412,6 +2430,7 @@ METH_NOARGS}, {"crash_no_current_thread", (PyCFunction)crash_no_current_thread, METH_NOARGS}, {"run_in_subinterp", run_in_subinterp, METH_VARARGS}, + {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -783,16 +783,11 @@ siginfo_t si; int err; - if (!PyArg_ParseTuple(args, "OO:sigtimedwait", &signals, &timeout)) + if (!PyArg_ParseTuple(args, "OO:sigtimedwait", + &signals, &timeout)) return NULL; - if (!PyTuple_Check(timeout) || PyTuple_Size(timeout) != 2) { - PyErr_SetString(PyExc_TypeError, - "sigtimedwait() arg 2 must be a tuple " - "(timeout_sec, timeout_nsec)"); - return NULL; - } else if (!PyArg_ParseTuple(timeout, "ll:sigtimedwait", - &(buf.tv_sec), &(buf.tv_nsec))) + if (_PyTime_ObjectToTimespec(timeout, &buf.tv_sec, &buf.tv_nsec) == -1) return NULL; if (buf.tv_sec < 0 || buf.tv_nsec < 0) { diff --git a/Python/pytime.c b/Python/pytime.c --- a/Python/pytime.c +++ b/Python/pytime.c @@ -70,6 +70,51 @@ #endif /* MS_WINDOWS */ } +int +_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec) +{ + if (PyFloat_Check(obj)) { + double d, intpart, floatpart, err; + + d = PyFloat_AsDouble(obj); + floatpart = modf(d, &intpart); + if (floatpart < 0) { + floatpart = 1.0 + floatpart; + intpart -= 1.0; + } + + *sec = (time_t)intpart; + err = intpart - (double)*sec; + if (err <= -1.0 || err >= 1.0) + goto overflow; + + floatpart *= 1e9; + *nsec = (long)floatpart; + return 0; + } + else { +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + *sec = PyLong_AsLongLong(obj); +#else + assert(sizeof(time_t) <= sizeof(long)); + *sec = PyLong_AsLong(obj); +#endif + if (*sec == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + goto overflow; + else + return -1; + } + *nsec = 0; + return 0; + } + +overflow: + PyErr_SetString(PyExc_OverflowError, + "timestamp out of range for platform time_t"); + return -1; +} + void _PyTime_Init() { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 3 01:35:31 2012 From: python-checkins at python.org (victor.stinner) Date: Sat, 03 Mar 2012 01:35:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_=2313550=3A_Remove_th?= =?utf8?q?e_debug_machinery_from_the_threading_module=3A_remove?= Message-ID: http://hg.python.org/cpython/rev/8ec51b2e57c2 changeset: 75373:8ec51b2e57c2 user: Victor Stinner date: Sat Mar 03 01:32:57 2012 +0100 summary: Close #13550: Remove the debug machinery from the threading module: remove verbose arguments from all threading classes and functions. files: Lib/threading.py | 152 ++++------------------------------ Misc/NEWS | 3 + 2 files changed, 21 insertions(+), 134 deletions(-) diff --git a/Lib/threading.py b/Lib/threading.py --- a/Lib/threading.py +++ b/Lib/threading.py @@ -34,40 +34,6 @@ del _thread -# Debug support (adapted from ihooks.py). - -_VERBOSE = False - -if __debug__: - - class _Verbose(object): - - def __init__(self, verbose=None): - if verbose is None: - verbose = _VERBOSE - self._verbose = verbose - - def _note(self, format, *args): - if self._verbose: - format = format % args - # Issue #4188: calling current_thread() can incur an infinite - # recursion if it has to create a DummyThread on the fly. - ident = get_ident() - try: - name = _active[ident].name - except KeyError: - name = "" % ident - format = "%s: %s\n" % (name, format) - _sys.stderr.write(format) - -else: - # Disable this when using "python -O" - class _Verbose(object): - def __init__(self, verbose=None): - pass - def _note(self, *args): - pass - # Support for profile and trace hooks _profile_hook = None @@ -85,17 +51,14 @@ Lock = _allocate_lock -def RLock(verbose=None, *args, **kwargs): - if verbose is None: - verbose = _VERBOSE - if (__debug__ and verbose) or _CRLock is None: - return _PyRLock(verbose, *args, **kwargs) +def RLock(*args, **kwargs): + if _CRLock is None: + return _PyRLock(*args, **kwargs) return _CRLock(*args, **kwargs) -class _RLock(_Verbose): +class _RLock: - def __init__(self, verbose=None): - _Verbose.__init__(self, verbose) + def __init__(self): self._block = _allocate_lock() self._owner = None self._count = 0 @@ -113,18 +76,11 @@ me = get_ident() if self._owner == me: self._count = self._count + 1 - if __debug__: - self._note("%s.acquire(%s): recursive success", self, blocking) return 1 rc = self._block.acquire(blocking, timeout) if rc: self._owner = me self._count = 1 - if __debug__: - self._note("%s.acquire(%s): initial success", self, blocking) - else: - if __debug__: - self._note("%s.acquire(%s): failure", self, blocking) return rc __enter__ = acquire @@ -136,11 +92,6 @@ if not count: self._owner = None self._block.release() - if __debug__: - self._note("%s.release(): final release", self) - else: - if __debug__: - self._note("%s.release(): non-final release", self) def __exit__(self, t, v, tb): self.release() @@ -150,12 +101,8 @@ def _acquire_restore(self, state): self._block.acquire() self._count, self._owner = state - if __debug__: - self._note("%s._acquire_restore()", self) def _release_save(self): - if __debug__: - self._note("%s._release_save()", self) if self._count == 0: raise RuntimeError("cannot release un-acquired lock") count = self._count @@ -171,10 +118,9 @@ _PyRLock = _RLock -class Condition(_Verbose): +class Condition: - def __init__(self, lock=None, verbose=None): - _Verbose.__init__(self, verbose) + def __init__(self, lock=None): if lock is None: lock = RLock() self._lock = lock @@ -233,23 +179,16 @@ if timeout is None: waiter.acquire() gotit = True - if __debug__: - self._note("%s.wait(): got it", self) else: if timeout > 0: gotit = waiter.acquire(True, timeout) else: gotit = waiter.acquire(False) if not gotit: - if __debug__: - self._note("%s.wait(%s): timed out", self, timeout) try: self._waiters.remove(waiter) except ValueError: pass - else: - if __debug__: - self._note("%s.wait(%s): got it", self, timeout) return gotit finally: self._acquire_restore(saved_state) @@ -265,19 +204,9 @@ else: waittime = endtime - _time() if waittime <= 0: - if __debug__: - self._note("%s.wait_for(%r, %r): Timed out.", - self, predicate, timeout) break - if __debug__: - self._note("%s.wait_for(%r, %r): Waiting with timeout=%s.", - self, predicate, timeout, waittime) self.wait(waittime) result = predicate() - else: - if __debug__: - self._note("%s.wait_for(%r, %r): Success.", - self, predicate, timeout) return result def notify(self, n=1): @@ -286,11 +215,7 @@ __waiters = self._waiters waiters = __waiters[:n] if not waiters: - if __debug__: - self._note("%s.notify(): no waiters", self) return - self._note("%s.notify(): notifying %d waiter%s", self, n, - n!=1 and "s" or "") for waiter in waiters: waiter.release() try: @@ -304,14 +229,13 @@ notifyAll = notify_all -class Semaphore(_Verbose): +class Semaphore: # After Tim Peters' semaphore class, but not quite the same (no maximum) - def __init__(self, value=1, verbose=None): + def __init__(self, value=1): if value < 0: raise ValueError("semaphore initial value must be >= 0") - _Verbose.__init__(self, verbose) self._cond = Condition(Lock()) self._value = value @@ -324,9 +248,6 @@ while self._value == 0: if not blocking: break - if __debug__: - self._note("%s.acquire(%s): blocked waiting, value=%s", - self, blocking, self._value) if timeout is not None: if endtime is None: endtime = _time() + timeout @@ -337,9 +258,6 @@ self._cond.wait(timeout) else: self._value = self._value - 1 - if __debug__: - self._note("%s.acquire: success, value=%s", - self, self._value) rc = True self._cond.release() return rc @@ -349,9 +267,6 @@ def release(self): self._cond.acquire() self._value = self._value + 1 - if __debug__: - self._note("%s.release: success, value=%s", - self, self._value) self._cond.notify() self._cond.release() @@ -361,8 +276,8 @@ class BoundedSemaphore(Semaphore): """Semaphore that checks that # releases is <= # acquires""" - def __init__(self, value=1, verbose=None): - Semaphore.__init__(self, value, verbose) + def __init__(self, value=1): + Semaphore.__init__(self, value) self._initial_value = value def release(self): @@ -371,12 +286,11 @@ return Semaphore.release(self) -class Event(_Verbose): +class Event: # After Tim Peters' event class (without is_posted()) - def __init__(self, verbose=None): - _Verbose.__init__(self, verbose) + def __init__(self): self._cond = Condition(Lock()) self._flag = False @@ -426,13 +340,13 @@ # since the previous cycle. In addition, a 'resetting' state exists which is # similar to 'draining' except that threads leave with a BrokenBarrierError, # and a 'broken' state in which all threads get the exception. -class Barrier(_Verbose): +class Barrier: """ Barrier. Useful for synchronizing a fixed number of threads at known synchronization points. Threads block on 'wait()' and are simultaneously once they have all made that call. """ - def __init__(self, parties, action=None, timeout=None, verbose=None): + def __init__(self, parties, action=None, timeout=None): """ Create a barrier, initialised to 'parties' threads. 'action' is a callable which, when supplied, will be called @@ -441,7 +355,6 @@ If a 'timeout' is provided, it is uses as the default for all subsequent 'wait()' calls. """ - _Verbose.__init__(self, verbose) self._cond = Condition(Lock()) self._action = action self._timeout = timeout @@ -602,7 +515,7 @@ # Main class for threads -class Thread(_Verbose): +class Thread: __initialized = False # Need to store a reference to sys.exc_info for printing @@ -615,9 +528,8 @@ #XXX __exc_clear = _sys.exc_clear def __init__(self, group=None, target=None, name=None, - args=(), kwargs=None, verbose=None, *, daemon=None): + args=(), kwargs=None, *, daemon=None): assert group is None, "group argument must be None for now" - _Verbose.__init__(self, verbose) if kwargs is None: kwargs = {} self._target = target @@ -664,8 +576,6 @@ if self._started.is_set(): raise RuntimeError("threads can only be started once") - if __debug__: - self._note("%s.start(): starting thread", self) with _active_limbo_lock: _limbo[self] = self try: @@ -715,24 +625,17 @@ with _active_limbo_lock: _active[self._ident] = self del _limbo[self] - if __debug__: - self._note("%s._bootstrap(): thread started", self) if _trace_hook: - self._note("%s._bootstrap(): registering trace hook", self) _sys.settrace(_trace_hook) if _profile_hook: - self._note("%s._bootstrap(): registering profile hook", self) _sys.setprofile(_profile_hook) try: self.run() except SystemExit: - if __debug__: - self._note("%s._bootstrap(): raised SystemExit", self) + pass except: - if __debug__: - self._note("%s._bootstrap(): unhandled exception", self) # If sys.stderr is no more (most likely from interpreter # shutdown) use self._stderr. Otherwise still use sys (as in # _sys) in case sys.stderr was redefined since the creation of @@ -763,9 +666,6 @@ # hog; deleting everything else is just for thoroughness finally: del exc_type, exc_value, exc_tb - else: - if __debug__: - self._note("%s._bootstrap(): normal return", self) finally: # Prevent a race in # test_threading.test_no_refcycle_through_target when @@ -832,29 +732,18 @@ if self is current_thread(): raise RuntimeError("cannot join current thread") - if __debug__: - if not self._stopped: - self._note("%s.join(): waiting until thread stops", self) - self._block.acquire() try: if timeout is None: while not self._stopped: self._block.wait() - if __debug__: - self._note("%s.join(): thread stopped", self) else: deadline = _time() + timeout while not self._stopped: delay = deadline - _time() if delay <= 0: - if __debug__: - self._note("%s.join(): timed out", self) break self._block.wait(delay) - else: - if __debug__: - self._note("%s.join(): thread stopped", self) finally: self._block.release() @@ -947,14 +836,9 @@ def _exitfunc(self): self._stop() t = _pickSomeNonDaemonThread() - if t: - if __debug__: - self._note("%s: waiting for other threads", self) while t: t.join() t = _pickSomeNonDaemonThread() - if __debug__: - self._note("%s: exiting", self) self._delete() def _pickSomeNonDaemonThread(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -511,6 +511,9 @@ Library ------- +- Issue #13550: Remove the debug machinery from the threading module: remove + verbose arguments from all threading classes and functions. + - Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, WeakValueDictionary) to return a better approximation when some objects are dead or dying. Moreover, the implementation is now O(1) rather than -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 3 02:44:47 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 03 Mar 2012 02:44:47 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MTc3?= =?utf8?q?=3A_marshal=2Eloads=28=29_now_raises_TypeError_when_given_an_uni?= =?utf8?q?code_string=2E?= Message-ID: http://hg.python.org/cpython/rev/4966907d3661 changeset: 75374:4966907d3661 branch: 3.2 parent: 75369:185a6ae76479 user: Antoine Pitrou date: Sat Mar 03 02:35:32 2012 +0100 summary: Issue #14177: marshal.loads() now raises TypeError when given an unicode string. Patch by Guilherme Gon?alves. files: Lib/test/test_exceptions.py | 2 +- Lib/test/test_marshal.py | 7 ++++++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ Python/marshal.c | 8 ++++---- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -38,7 +38,7 @@ try: try: import marshal - marshal.loads('') + marshal.loads(b'') except EOFError: pass finally: diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -184,7 +184,7 @@ pass def test_loads_recursion(self): - s = 'c' + ('X' * 4*4) + '{' * 2**20 + s = b'c' + (b'X' * 4*4) + b'{' * 2**20 self.assertRaises(ValueError, marshal.loads, s) def test_recursion_limit(self): @@ -257,6 +257,11 @@ finally: support.unlink(support.TESTFN) + def test_loads_reject_unicode_strings(self): + # Issue #14177: marshal.loads() should not accept unicode strings + unicode_string = 'T' + self.assertRaises(TypeError, marshal.loads, unicode_string) + def test_main(): support.run_unittest(IntTestCase, diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -341,6 +341,7 @@ Michael Gilfix Christoph Gohlke Tim Golden +Guilherme Gon?alves Chris Gonnerman David Goodger Hans de Graaff diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -130,6 +130,9 @@ Library ------- +- Issue #14177: marshal.loads() now raises TypeError when given an unicode + string. Patch by Guilherme Gon?alves. + - Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, WeakValueDictionary) to return a better approximation when some objects are dead or dying. Moreover, the implementation is now O(1) rather than diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1383,7 +1383,7 @@ char *s; Py_ssize_t n; PyObject* result; - if (!PyArg_ParseTuple(args, "s*:loads", &p)) + if (!PyArg_ParseTuple(args, "y*:loads", &p)) return NULL; s = p.buf; n = p.len; @@ -1400,10 +1400,10 @@ } PyDoc_STRVAR(loads_doc, -"loads(string)\n\ +"loads(bytes)\n\ \n\ -Convert the string to a value. If no valid value is found, raise\n\ -EOFError, ValueError or TypeError. Extra characters in the string are\n\ +Convert the bytes object to a value. If no valid value is found, raise\n\ +EOFError, ValueError or TypeError. Extra characters in the input are\n\ ignored."); static PyMethodDef marshal_methods[] = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 3 02:44:48 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 03 Mar 2012 02:44:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_-_Issue_=2314177=3A_marshal=2Eloads=28=29_now_raises_TypeErr?= =?utf8?q?or_when_given_an_unicode?= Message-ID: http://hg.python.org/cpython/rev/e67b3a9bd2dc changeset: 75375:e67b3a9bd2dc parent: 75373:8ec51b2e57c2 parent: 75374:4966907d3661 user: Antoine Pitrou date: Sat Mar 03 02:38:37 2012 +0100 summary: - Issue #14177: marshal.loads() now raises TypeError when given an unicode string. Patch by Guilherme Gon?alves. files: Lib/test/test_exceptions.py | 2 +- Lib/test/test_marshal.py | 7 ++++++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ Python/marshal.c | 8 ++++---- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -38,7 +38,7 @@ try: try: import marshal - marshal.loads('') + marshal.loads(b'') except EOFError: pass finally: diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -201,7 +201,7 @@ pass def test_loads_recursion(self): - s = 'c' + ('X' * 4*4) + '{' * 2**20 + s = b'c' + (b'X' * 4*4) + b'{' * 2**20 self.assertRaises(ValueError, marshal.loads, s) def test_recursion_limit(self): @@ -274,6 +274,11 @@ finally: support.unlink(support.TESTFN) + def test_loads_reject_unicode_strings(self): + # Issue #14177: marshal.loads() should not accept unicode strings + unicode_string = 'T' + self.assertRaises(TypeError, marshal.loads, unicode_string) + def test_main(): support.run_unittest(IntTestCase, diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -371,6 +371,7 @@ Michael Goderbauer Christoph Gohlke Tim Golden +Guilherme Gon?alves Tiago Gon?alves Chris Gonnerman David Goodger diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -511,6 +511,9 @@ Library ------- +- Issue #14177: marshal.loads() now raises TypeError when given an unicode + string. Patch by Guilherme Gon?alves. + - Issue #13550: Remove the debug machinery from the threading module: remove verbose arguments from all threading classes and functions. diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1384,7 +1384,7 @@ char *s; Py_ssize_t n; PyObject* result; - if (!PyArg_ParseTuple(args, "s*:loads", &p)) + if (!PyArg_ParseTuple(args, "y*:loads", &p)) return NULL; s = p.buf; n = p.len; @@ -1400,10 +1400,10 @@ } PyDoc_STRVAR(loads_doc, -"loads(string)\n\ +"loads(bytes)\n\ \n\ -Convert the string to a value. If no valid value is found, raise\n\ -EOFError, ValueError or TypeError. Extra characters in the string are\n\ +Convert the bytes object to a value. If no valid value is found, raise\n\ +EOFError, ValueError or TypeError. Extra characters in the input are\n\ ignored."); static PyMethodDef marshal_methods[] = { -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Mar 3 05:37:21 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 03 Mar 2012 05:37:21 +0100 Subject: [Python-checkins] Daily reference leaks (e67b3a9bd2dc): sum=0 Message-ID: results for e67b3a9bd2dc on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogg6WPGk', '-x'] From python-checkins at python.org Sat Mar 3 17:20:43 2012 From: python-checkins at python.org (vinay.sajip) Date: Sat, 03 Mar 2012 17:20:43 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fixed_problem_with_diagnost?= =?utf8?q?ic_output=2E?= Message-ID: http://hg.python.org/cpython/rev/58eef400866e changeset: 75376:58eef400866e user: Vinay Sajip date: Sat Mar 03 16:20:37 2012 +0000 summary: Fixed problem with diagnostic output. files: Lib/test/test_logging.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3682,7 +3682,8 @@ print('The only matching files are: %s' % files, file=sys.stderr) for f in files: print('Contents of %s:' % f) - with open(f, 'r') as tf: + path = os.path.join(dn, f) + with open(path, 'r') as tf: print(tf.read()) self.assertTrue(found, msg=msg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 3 21:22:11 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 03 Mar 2012 21:22:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_link_to_glo?= =?utf8?q?bal_module_index=2E?= Message-ID: http://hg.python.org/cpython/rev/52ecec12c0ed changeset: 75377:52ecec12c0ed branch: 2.7 parent: 75368:ccd16ad37544 user: Georg Brandl date: Sat Mar 03 21:25:42 2012 +0100 summary: Fix link to global module index. files: Doc/tools/sphinxext/indexcontent.html | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tools/sphinxext/indexcontent.html b/Doc/tools/sphinxext/indexcontent.html --- a/Doc/tools/sphinxext/indexcontent.html +++ b/Doc/tools/sphinxext/indexcontent.html @@ -32,7 +32,7 @@

Indices and tables:

- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 3 23:00:25 2012 From: python-checkins at python.org (victor.stinner) Date: Sat, 03 Mar 2012 23:00:25 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_416=3A_add_more_use_cases?= Message-ID: http://hg.python.org/peps/rev/d00a2f16f96a changeset: 4104:d00a2f16f96a user: Victor Stinner date: Sat Mar 03 23:00:19 2012 +0100 summary: PEP 416: add more use cases files: pep-0416.txt | 56 +++++++++++++++++++++++++-------------- 1 files changed, 36 insertions(+), 20 deletions(-) diff --git a/pep-0416.txt b/pep-0416.txt --- a/pep-0416.txt +++ b/pep-0416.txt @@ -24,15 +24,24 @@ mutable (not hashable). A frozendict is hashable and so immutable if and only if all values are hashable (immutable). -Use cases of frozendict: +Use cases: - * frozendict can be used to implement a cache - * hashable frozendict can be used as a key of a mapping or as a member of set - * frozendict helps optimization because the mapping is constant + * frozendict lookup can be done at compile time instead of runtime because the + mapping is read-only. frozendict can be used instead of a preprocessor to + remove conditional code at compilation, like code specific to a debug build. + * hashable frozendict can be used as a key of a mapping or as a member of set. + frozendict can be used to implement a cache. * frozendict avoids the need of a lock when the frozendict is shared - by multiple threads or processes, especially hashable frozendict - * frozendict helps to implement a security sandbox with read-only objects, - e.g. freeze __builtins__ mapping + by multiple threads or processes, especially hashable frozendict. It would + also help to prohibe coroutines (generators + greenlets) to modify the + global state. + * frozendict helps to implement read-only object proxies for security modules. + For example, it would be possible to use frozendict type for __builtins__ + mapping or type.__dict__. This is possible because frozendict is compatible + with the PyDict C API. + * frozendict avoids the need of a read-only proxy in some cases. frozendict is + faster than a proxy because getting an item in a frozendict is a fast lookup + whereas a proxy requires a function call. Constraints @@ -56,24 +65,24 @@ PyDict_DelItem() raise a TypeError -Recipe: immutable dict +Recipe: hashable dict ====================== -An immutable mapping can be implemented using frozendict:: +To ensure that a a frozendict is hashable, values can be checked +before creating the frozendict:: import itertools - class immutabledict(frozendict): - def __new__(cls, *args, **kw): - # ensure that all values are immutable - for key, value in itertools.chain(args, kw.items()): - if not isinstance(value, (int, float, complex, str, bytes)): - hash(value) - # frozendict ensures that all keys are immutable - return frozendict.__new__(cls, *args, **kw) - - def __repr__(self): - return 'immutabledict' + frozendict.__repr__(self)[10:] + def hashabledict(*args, **kw): + # ensure that all values are hashable + for key, value in itertools.chain(args, kw.items()): + if isinstance(value, (int, str, bytes, float, frozenset, complex)): + # avoid the compute the hash (which may be slow) for builtin + # types known to be hashable for any value + continue + hash(value) + # don't check the key: frozendict already checks the key + return frozendict.__new__(cls, *args, **kw) Objections @@ -107,6 +116,13 @@ * `The case for immutable dictionaries; and the central misunderstanding of PEP 351 `_ * `Frozen dictionaries (Python recipe 414283) `_ by Oren Tirosh + * Python security modules implementing read-only object proxies using a C + extension: + + * `pysandbox `_ + * `mxProxy `_ + * `zope.proxy `_ + * `zope.security `_ Copyright -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 00:07:12 2012 From: python-checkins at python.org (victor.stinner) Date: Sun, 04 Mar 2012 00:07:12 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_416=3A_add_the_default_val?= =?utf8?q?ue_of_a_function_argument_use_case?= Message-ID: http://hg.python.org/peps/rev/f519d34d9704 changeset: 4105:f519d34d9704 user: Victor Stinner date: Sun Mar 04 00:07:10 2012 +0100 summary: PEP 416: add the default value of a function argument use case files: pep-0416.txt | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/pep-0416.txt b/pep-0416.txt --- a/pep-0416.txt +++ b/pep-0416.txt @@ -42,6 +42,8 @@ * frozendict avoids the need of a read-only proxy in some cases. frozendict is faster than a proxy because getting an item in a frozendict is a fast lookup whereas a proxy requires a function call. + * use a frozendict as the default value of function argument: avoid the + problem of mutable default argument. Constraints -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 01:38:52 2012 From: python-checkins at python.org (victor.stinner) Date: Sun, 04 Mar 2012 01:38:52 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_=2314085=3A_remove_as?= =?utf8?q?sertions_from_PyUnicode=5FWRITE_macro?= Message-ID: http://hg.python.org/cpython/rev/ba0bd949ddf5 changeset: 75378:ba0bd949ddf5 parent: 75376:58eef400866e user: Victor Stinner date: Sun Mar 04 01:34:37 2012 +0100 summary: Close #14085: remove assertions from PyUnicode_WRITE macro Add checks in PyUnicode_WriteChar() and convert PyUnicode_New() assertion to a test raising a Python exception. files: Include/unicodeobject.h | 3 --- Objects/unicodeobject.c | 11 ++++++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -499,17 +499,14 @@ do { \ switch ((kind)) { \ case PyUnicode_1BYTE_KIND: { \ - assert(value <= 0xff); \ ((Py_UCS1 *)(data))[(index)] = (Py_UCS1)(value); \ break; \ } \ case PyUnicode_2BYTE_KIND: { \ - assert(value <= 0xffff); \ ((Py_UCS2 *)(data))[(index)] = (Py_UCS2)(value); \ break; \ } \ default: { \ - assert(value <= 0x10ffff); \ assert((kind) == PyUnicode_4BYTE_KIND); \ ((Py_UCS4 *)(data))[(index)] = (Py_UCS4)(value); \ } \ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -998,7 +998,11 @@ is_sharing = 1; } else { - assert(maxchar <= MAX_UNICODE); + if (maxchar > MAX_UNICODE) { + PyErr_SetString(PyExc_SystemError, + "invalid maximum character passed to PyUnicode_New"); + return NULL; + } kind_state = PyUnicode_4BYTE_KIND; char_size = 4; if (sizeof(wchar_t) == 4) @@ -3931,6 +3935,7 @@ int PyUnicode_WriteChar(PyObject *unicode, Py_ssize_t index, Py_UCS4 ch) { + Py_UCS4 maxchar; if (!PyUnicode_Check(unicode) || !PyUnicode_IS_COMPACT(unicode)) { PyErr_BadArgument(); return -1; @@ -3942,6 +3947,10 @@ } if (unicode_check_modifiable(unicode)) return -1; + if (ch > PyUnicode_MAX_CHAR_VALUE(unicode)) { + PyErr_SetString(PyExc_ValueError, "character out of range"); + return -1; + } PyUnicode_WRITE(PyUnicode_KIND(unicode), PyUnicode_DATA(unicode), index, ch); return 0; -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Mar 4 05:32:39 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 04 Mar 2012 05:32:39 +0100 Subject: [Python-checkins] Daily reference leaks (ba0bd949ddf5): sum=4 Message-ID: results for ba0bd949ddf5 on branch "default" -------------------------------------------- test_support leaked [4, 0, 0] references, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogk6Eiez', '-x'] From python-checkins at python.org Sun Mar 4 06:15:56 2012 From: python-checkins at python.org (eli.bendersky) Date: Sun, 04 Mar 2012 06:15:56 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314128=3A_Exposing_?= =?utf8?q?Element_as_an_actual_type_from_=5Felementtree=2C_rather_than?= Message-ID: http://hg.python.org/cpython/rev/ce1c26cbe5fb changeset: 75379:ce1c26cbe5fb user: Eli Bendersky date: Sun Mar 04 07:14:03 2012 +0200 summary: Issue #14128: Exposing Element as an actual type from _elementtree, rather than a factory function. This makes the C implementation more aligned with the Python implementation. Also added some tests to ensure that Element is now a type and that it can be subclassed. files: Lib/test/test_xml_etree.py | 39 +++- Lib/test/test_xml_etree_c.py | 22 +- Lib/xml/etree/ElementTree.py | 1 - Modules/_elementtree.c | 235 ++++++++++++++-------- 4 files changed, 202 insertions(+), 95 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1901,16 +1901,51 @@ class TestAcceleratorNotImported(unittest.TestCase): # Test that the C accelerator was not imported for pyET def test_correct_import_pyET(self): - self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') + self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') + + +class TestElementClass(unittest.TestCase): + def test_Element_is_a_type(self): + self.assertIsInstance(ET.Element, type) + + def test_Element_subclass_trivial(self): + class MyElement(ET.Element): + pass + + mye = MyElement('foo') + self.assertIsInstance(mye, ET.Element) + self.assertIsInstance(mye, MyElement) + self.assertEqual(mye.tag, 'foo') + + def test_Element_subclass_constructor(self): + class MyElement(ET.Element): + def __init__(self, tag, attrib={}, **extra): + super(MyElement, self).__init__(tag + '__', attrib, **extra) + + mye = MyElement('foo', {'a': 1, 'b': 2}, c=3, d=4) + self.assertEqual(mye.tag, 'foo__') + self.assertEqual(sorted(mye.items()), + [('a', 1), ('b', 2), ('c', 3), ('d', 4)]) + + def test_Element_subclass_new_method(self): + class MyElement(ET.Element): + def newmethod(self): + return self.tag + + mye = MyElement('joe') + self.assertEqual(mye.newmethod(), 'joe') def test_main(module=pyET): from test import test_xml_etree + # Run the tests specific to the Python implementation + support.run_unittest(TestAcceleratorNotImported) + # The same doctests are used for both the Python and the C implementations test_xml_etree.ET = module - support.run_unittest(TestAcceleratorNotImported) + support.run_unittest(TestElementClass) # XXX the C module should give the same warnings as the Python module with CleanContext(quiet=(module is not pyET)): diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -47,13 +47,21 @@ data = None @unittest.skipUnless(cET, 'requires _elementtree') +class TestAliasWorking(unittest.TestCase): + # Test that the cET alias module is alive + def test_alias_working(self): + e = cET_alias.Element('foo') + self.assertEqual(e.tag, 'foo') + + + at unittest.skipUnless(cET, 'requires _elementtree') class TestAcceleratorImported(unittest.TestCase): # Test that the C accelerator was imported, as expected def test_correct_import_cET(self): - self.assertEqual(cET.Element.__module__, '_elementtree') + self.assertEqual(cET.SubElement.__module__, '_elementtree') def test_correct_import_cET_alias(self): - self.assertEqual(cET_alias.Element.__module__, '_elementtree') + self.assertEqual(cET_alias.SubElement.__module__, '_elementtree') def test_main(): @@ -61,13 +69,15 @@ # Run the tests specific to the C implementation support.run_doctest(test_xml_etree_c, verbosity=True) - - support.run_unittest(MiscTests, TestAcceleratorImported) + support.run_unittest( + MiscTests, + TestAliasWorking, + TestAcceleratorImported + ) # Run the same test suite as the Python module test_xml_etree.test_main(module=cET) - # Exercise the deprecated alias - test_xml_etree.test_main(module=cET_alias) + if __name__ == '__main__': test_main() diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -101,7 +101,6 @@ import re import warnings - class _SimpleElementPath: # emulate pre-1.2 find/findtext/findall behaviour def find(self, element, tag, namespaces=None): diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -191,7 +191,7 @@ } /* -------------------------------------------------------------------- */ -/* the element type */ +/* the Element type */ typedef struct { @@ -236,10 +236,10 @@ #define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type) /* -------------------------------------------------------------------- */ -/* element constructor and destructor */ +/* Element constructors and destructor */ LOCAL(int) -element_new_extra(ElementObject* self, PyObject* attrib) +create_extra(ElementObject* self, PyObject* attrib) { self->extra = PyObject_Malloc(sizeof(ElementObjectExtra)); if (!self->extra) @@ -259,7 +259,7 @@ } LOCAL(void) -element_dealloc_extra(ElementObject* self) +dealloc_extra(ElementObject* self) { int i; @@ -274,8 +274,11 @@ PyObject_Free(self->extra); } +/* Convenience internal function to create new Element objects with the given + * tag and attributes. +*/ LOCAL(PyObject*) -element_new(PyObject* tag, PyObject* attrib) +create_new_element(PyObject* tag, PyObject* attrib) { ElementObject* self; @@ -290,16 +293,10 @@ self->extra = NULL; if (attrib != Py_None) { - - if (element_new_extra(self, attrib) < 0) { + if (create_extra(self, attrib) < 0) { PyObject_Del(self); return NULL; } - - self->extra->length = 0; - self->extra->allocated = STATIC_CHILDREN; - self->extra->children = self->extra->_children; - } Py_INCREF(tag); @@ -316,6 +313,86 @@ return (PyObject*) self; } +static PyObject * +element_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + ElementObject *e = (ElementObject *)type->tp_alloc(type, 0); + if (e != NULL) { + Py_INCREF(Py_None); + e->tag = Py_None; + + Py_INCREF(Py_None); + e->text = Py_None; + + Py_INCREF(Py_None); + e->tail = Py_None; + + e->extra = NULL; + } + return (PyObject *)e; +} + +static int +element_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *tag; + PyObject *tmp; + PyObject *attrib = NULL; + ElementObject *self_elem; + + if (!PyArg_ParseTuple(args, "O|O!:Element", &tag, &PyDict_Type, &attrib)) + return -1; + + if (attrib || kwds) { + attrib = (attrib) ? PyDict_Copy(attrib) : PyDict_New(); + if (!attrib) + return -1; + if (kwds) + PyDict_Update(attrib, kwds); + } else { + Py_INCREF(Py_None); + attrib = Py_None; + } + + self_elem = (ElementObject *)self; + + /* Use None for empty dictionaries */ + if (PyDict_CheckExact(attrib) && PyDict_Size(attrib) == 0) { + Py_INCREF(Py_None); + attrib = Py_None; + } + + if (attrib != Py_None) { + if (create_extra(self_elem, attrib) < 0) { + PyObject_Del(self_elem); + return -1; + } + } + + /* If create_extra needed attrib, it took a reference to it, so we can + * release ours anyway. + */ + Py_DECREF(attrib); + + /* Replace the objects already pointed to by tag, text and tail. */ + tmp = self_elem->tag; + self_elem->tag = tag; + Py_INCREF(tag); + Py_DECREF(tmp); + + tmp = self_elem->text; + self_elem->text = Py_None; + Py_INCREF(Py_None); + Py_DECREF(JOIN_OBJ(tmp)); + + tmp = self_elem->tail; + self_elem->tail = Py_None; + Py_INCREF(Py_None); + Py_DECREF(JOIN_OBJ(tmp)); + + return 0; +} + LOCAL(int) element_resize(ElementObject* self, int extra) { @@ -326,7 +403,7 @@ elements. set an exception and return -1 if allocation failed */ if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); size = self->extra->length + extra; @@ -444,13 +521,15 @@ } static PyObject* -element(PyObject* self, PyObject* args, PyObject* kw) +subelement(PyObject* self, PyObject* args, PyObject* kw) { PyObject* elem; + ElementObject* parent; PyObject* tag; PyObject* attrib = NULL; - if (!PyArg_ParseTuple(args, "O|O!:Element", &tag, + if (!PyArg_ParseTuple(args, "O!O|O!:SubElement", + &Element_Type, &parent, &tag, &PyDict_Type, &attrib)) return NULL; @@ -465,38 +544,7 @@ attrib = Py_None; } - elem = element_new(tag, attrib); - - Py_DECREF(attrib); - - return elem; -} - -static PyObject* -subelement(PyObject* self, PyObject* args, PyObject* kw) -{ - PyObject* elem; - - ElementObject* parent; - PyObject* tag; - PyObject* attrib = NULL; - if (!PyArg_ParseTuple(args, "O!O|O!:SubElement", - &Element_Type, &parent, &tag, - &PyDict_Type, &attrib)) - return NULL; - - if (attrib || kw) { - attrib = (attrib) ? PyDict_Copy(attrib) : PyDict_New(); - if (!attrib) - return NULL; - if (kw) - PyDict_Update(attrib, kw); - } else { - Py_INCREF(Py_None); - attrib = Py_None; - } - - elem = element_new(tag, attrib); + elem = create_new_element(tag, attrib); Py_DECREF(attrib); @@ -512,7 +560,7 @@ element_dealloc(ElementObject* self) { if (self->extra) - element_dealloc_extra(self); + dealloc_extra(self); /* discard attributes */ Py_DECREF(self->tag); @@ -521,7 +569,7 @@ RELEASE(sizeof(ElementObject), "destroy element"); - PyObject_Del(self); + Py_TYPE(self)->tp_free((PyObject *)self); } /* -------------------------------------------------------------------- */ @@ -547,7 +595,7 @@ return NULL; if (self->extra) { - element_dealloc_extra(self); + dealloc_extra(self); self->extra = NULL; } @@ -571,7 +619,7 @@ if (!PyArg_ParseTuple(args, ":__copy__")) return NULL; - element = (ElementObject*) element_new( + element = (ElementObject*) create_new_element( self->tag, (self->extra) ? self->extra->attrib : Py_None ); if (!element) @@ -634,7 +682,7 @@ attrib = Py_None; } - element = (ElementObject*) element_new(tag, attrib); + element = (ElementObject*) create_new_element(tag, attrib); Py_DECREF(tag); Py_DECREF(attrib); @@ -1029,7 +1077,7 @@ return NULL; if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); if (index < 0) { index += self->extra->length; @@ -1100,7 +1148,7 @@ if (!attrib) return NULL; - elem = element_new(tag, attrib); + elem = create_new_element(tag, attrib); Py_DECREF(attrib); @@ -1154,7 +1202,10 @@ static PyObject* element_repr(ElementObject* self) { - return PyUnicode_FromFormat("", self->tag, self); + if (self->tag) + return PyUnicode_FromFormat("", self->tag, self); + else + return PyUnicode_FromFormat("", self); } static PyObject* @@ -1168,7 +1219,7 @@ return NULL; if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); attrib = element_get_attrib(self); if (!attrib) @@ -1284,7 +1335,7 @@ PyObject* seq = NULL; if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); if (PySlice_GetIndicesEx(item, self->extra->length, @@ -1448,7 +1499,7 @@ } else if (strcmp(name, "attrib") == 0) { PyErr_Clear(); if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); res = element_get_attrib(self); } @@ -1484,7 +1535,7 @@ Py_INCREF(self->tail); } else if (strcmp(name, "attrib") == 0) { if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); Py_DECREF(self->extra->attrib); self->extra->attrib = value; Py_INCREF(self->extra->attrib); @@ -1516,31 +1567,41 @@ PyVarObject_HEAD_INIT(NULL, 0) "Element", sizeof(ElementObject), 0, /* methods */ - (destructor)element_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - (setattrfunc)element_setattr, /* tp_setattr */ - 0, /* tp_reserved */ - (reprfunc)element_repr, /* tp_repr */ - 0, /* tp_as_number */ - &element_as_sequence, /* tp_as_sequence */ - &element_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc)element_getattro, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - element_methods, /* tp_methods */ - 0, /* tp_members */ + (destructor)element_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + (setattrfunc)element_setattr, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc)element_repr, /* tp_repr */ + 0, /* tp_as_number */ + &element_as_sequence, /* tp_as_sequence */ + &element_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + (getattrofunc)element_getattro, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + element_methods, /* 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 */ + (initproc)element_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + element_new, /* tp_new */ + 0, /* tp_free */ }; /* ==================================================================== */ @@ -1666,7 +1727,7 @@ self->data = NULL; } - node = element_new(tag, attrib); + node = create_new_element(tag, attrib); if (!node) return NULL; @@ -2801,7 +2862,6 @@ /* python module interface */ static PyMethodDef _functions[] = { - {"Element", (PyCFunction) element, METH_VARARGS|METH_KEYWORDS}, {"SubElement", (PyCFunction) subelement, METH_VARARGS|METH_KEYWORDS}, {"TreeBuilder", (PyCFunction) treebuilder, METH_VARARGS}, #if defined(USE_EXPAT) @@ -2911,5 +2971,8 @@ Py_INCREF(elementtree_parseerror_obj); PyModule_AddObject(m, "ParseError", elementtree_parseerror_obj); + Py_INCREF((PyObject *)&Element_Type); + PyModule_AddObject(m, "Element", (PyObject *)&Element_Type); + return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 06:15:57 2012 From: python-checkins at python.org (eli.bendersky) Date: Sun, 04 Mar 2012 06:15:57 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_trailing_whitespace?= Message-ID: http://hg.python.org/cpython/rev/fbb9847b8f43 changeset: 75380:fbb9847b8f43 user: Eli Bendersky date: Sun Mar 04 07:15:21 2012 +0200 summary: fix trailing whitespace files: Lib/test/test_xml_etree_c.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -52,7 +52,6 @@ def test_alias_working(self): e = cET_alias.Element('foo') self.assertEqual(e.tag, 'foo') - @unittest.skipUnless(cET, 'requires _elementtree') class TestAcceleratorImported(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 08:24:59 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 04 Mar 2012 08:24:59 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Rewrite_PEP_414_to_be_less_pas?= =?utf8?q?sionate_in_its_tone_and_better_address_the_common?= Message-ID: http://hg.python.org/peps/rev/8a6e3b28dbef changeset: 4106:8a6e3b28dbef user: Nick Coghlan date: Sun Mar 04 17:24:43 2012 +1000 summary: Rewrite PEP 414 to be less passionate in its tone and better address the common objections files: pep-0414.txt | 484 ++++++++++++++++++++++++-------------- 1 files changed, 298 insertions(+), 186 deletions(-) diff --git a/pep-0414.txt b/pep-0414.txt --- a/pep-0414.txt +++ b/pep-0414.txt @@ -2,7 +2,8 @@ Title: Explicit Unicode Literal for Python 3.3 Version: $Revision$ Last-Modified: $Date$ -Author: Armin Ronacher +Author: Armin Ronacher , + Nick Coghlan Status: Accepted Type: Standards Track Content-Type: text/x-rst @@ -16,231 +17,339 @@ This document proposes the reintegration of an explicit unicode literal from Python 2.x to the Python 3.x language specification, in order to -enable side-by-side support of libraries for both Python 2 and Python 3 -without the need for an explicit 2to3 run. +reduce the volume of changes needed when porting Unicode-aware +Python 2 applications to Python 3. BDFL Pronouncement ================== -This PEP has been formally accepted for Python 3.3. +This PEP has been formally accepted for Python 3.3: + I'm accepting the PEP. It's about as harmless as they come. Make it so. -Rationale and Goals -=================== -Python 3 is a major new revision of the language, and it was decided very -early on that breaking backwards compatibility was part of the design. The -migration from a Python 2.x to a Python 3 codebase is to be accomplished -with the aid of a separate translation tool that converts the Python 2.x -sourcecode to Python 3 syntax. With more and more libraries supporting -Python 3, however, it has become clear that 2to3 as a tool is -insufficient, and people are now attempting to find ways to make the same -source work in both Python 2.x and Python 3.x, with varying levels of -success. +Proposal +======== -Python 2.6 and Python 2.7 support syntax features from Python 3 which for -the most part make a unified code base possible. Many thought that the -``unicode_literals`` future import might make a common source possible, -but it turns out that it's doing more harm than good. +This PEP proposes that Python 3.3 restore support for Python 2's Unicode +literal syntax, substantially increasing the number of lines of existing +Python 2 code in Unicode aware applications that will run without modification +on Python 3. -With the design of the updated WSGI specification a few new terms for -strings were loosely defined: unicode strings, byte strings and native -strings. In Python 3 the native string type is unicode, in Python 2 the -native string type is a bytestring. These native string types are used in -a couple of places. The native string type can be interned and is -preferably used for identifier names, filenames, source code and a few -other low level interpreter operations such as the return value of a -``__repr__`` or exception messages. +Specifically, the Python 3 definition for string literal prefixes will be +expanded to allow:: -In Python 2.7 these string types can be defined explicitly. Without any -future imports ``b'foo'`` means bytestring, ``u'foo'`` declares a unicode -string and ``'foo'`` a native string which in Python 2.x means bytes. -With the ``unicode_literals`` import the native string type is no longer -available by syntax and has to be incorrectly labeled as bytestring. If -such a codebase is then used in Python 3, the interpreter will start using -byte objects in places where they are no longer accepted (such as -identifiers). This can be solved by a module that detects 2.x and 3.x and -provides wrapper functions that transcode literals at runtime (either by -having a ``u`` function that marks things as unicode without future -imports or the inverse by having a ``n`` function that marks strings as -native). Unfortunately, this has the side effect of slowing down the -runtime performance of Python and makes for less beautiful code. -Considering that Python 2 and Python 3 support for most libraries will -have to continue side by side for several more years to come, this means -that such modules lose one of Python's key properties: easily readable and -understandable code. + "u" | "U" | "ur" | "UR" | "Ur" | "uR" -Additionally, the vast majority of people who maintain Python 2.x -codebases are more familiar with Python 2.x semantics, and a per-file -difference in literal meanings will be very annoying for them in the long -run. A quick poll on Twitter about the use of the division future import -supported my suspicions that people opt out of behaviour-changing future -imports because they are a maintenance burden. Every time you review code -you have to check the top of the file to see if the behaviour was changed. -Obviously that was an unscientific informal poll, but it might be -something worth considering. +in additional to the currently supported:: -Proposed Solution + "r" | "R" + +The following will all denote ordinary Python 3 strings:: + + 'text' + "text" + '''text''' + """text""" + u'text' + u"text" + u'''text''' + u"""text""" + U'text' + U"text" + U'''text''' + U"""text""" + +Combination of the unicode prefix with the raw string prefix will also be +supported, just as it was in Python 2. + +No changes are proposed to Python 3's actual Unicode handling, only to the +acceptable forms for string literals. + + +Author's Note +============= + +This PEP was originally written by Armin Ronacher, and directly reflected his +feelings regarding his personal experiences porting Unicode aware Python +applications to Python 3. Guido's approval was given based on Armin's version +of the PEP. + +The currently published version has been rewritten by Nick Coghlan to address +the concerns of those who felt that Armin's experience did not accurately +reflect the *typical* experience of porting to Python 3, but rather only +related to a specific subset of porting activities that were not well served +by the existing set of porting tools. + +Readers should be aware that many of the arguments in this PEP are *not* +technical ones. Instead, they relate heavily to the *social* and *personal* +aspects of software development. After all, developers are people first, +coders second. + + +Rationale +========= + +With the release of a Python 3 compatible version of the Web Services Gateway +Interface (WSGI) specification (PEP 3333) for Python 3.2, many parts of the +Python web ecosystem have been making a concerted effort to support Python 3 +without adversely affecting their existing developer and user communities. + +One major item of feedback from key developers in those communities, including +Chris McDonough (WebOb, Pyramid), Armin Ronacher (Flask, Werkzeug), Jacob +Kaplan-Moss (Django) and Kenneth Reitz (``requests``) is that the requirement +to change the spelling of *every* Unicode literal in an application +(regardless of how that is accomplished) is a key stumbling block for porting +efforts. + +In particular, unlike many of the other Python 3 changes, it isn't one that +framework and library authors can easily handle on behalf of their users. Most +of those users couldn't care less about the "purity" of the Python language +specification, they just want their websites and applications to work as well +as possible. + +While it is the Python web community that has been most vocal in highlighting +this concern, it is expected that other highly Unicode aware domains (such as +GUI development) may run into similar issues as they (and their communities) +start making concerted efforts to support Python 3. + + +Common Objections ================= -The idea is to support (with Python 3.3) an explicit ``u`` and ``U`` -prefix for native strings in addition to the prefix-less variants. These -would stick around for the entirety of the Python 3 lifetime but might at -some point yield deprecation warnings if deemed appropriate. This could -be something for pyflakes or other similar libraries to support. -Python 3.2 and earlier -====================== +This PEP may harm adoption of Python 3.2 +---------------------------------------- -An argument against this proposal was made on the Python-Dev mailinglist, -mentioning that Ubuntu LTS will ship Python 3.2 and 2.7 for only 5 years. -The counterargument is that Python 2.7 is currently the Python version of -choice for users who want LTS support. As it stands, when chosing between -2.7 and Python 3.2, Python 3 is currently not the best choice for certain -long-term investments, since the ecosystem is not yet properly developed, -and libraries are still fighting with their API decisions for Python 3. +This complaint is interesting, as it carries within it a tacit admission that +this PEP *will* make it easier to port Unicode aware Python 2 applications to +Python 3. -A valid point is that this would encourage people to become dependent on -Python 3.3 for their ports. Fortunately that is not a big problem since -that could be fixed at installation time similar to how many projects are -currently invoking 2to3 as part of their installation process. +There are many existing Python communities that are prepared to put up with +the constraints imposed by the existing suite of porting tools, or to update +their Python 2 code bases sufficiently that the problems are minimised. -For Python 3.1 and Python 3.2 (even 3.0 if necessary) a simple -on-installation hook could be provided that tokenizes all source files and -strips away the otherwise unnecessary ``u`` prefix at installation time. +This PEP is not for those communities. Instead, it is designed specifically to +help people that *don't* want to put up with those difficulties. -Who Benefits? -============= +However, since the proposal is for a comparatively small tweak to the language +syntax with no semantic changes, it may be feasible to support it as a third +party import hook. While such an import hook will impose a small import time +overhead, and will require additional steps from each application that needs it +to get the hook in place, it would allow applications that target Python 3.2 +to use libraries and frameworks that may otherwise only run on Python 3.3+. -There are a couple of places where decisions have to be made for or -against unicode support almost arbitrarily. This is mostly the case for -protocols that do not support unicode all the way down, or hide it behind -transport encodings that might or might not be unicode themselves. HTTP, -Email and WSGI are good examples of that. For certain ambiguous cases it -would be possible to apply the same logic for unicode that Python 3 -applies to the Python 2 versions of the library as well but, if those -details were exposed to the user of the API, it would mean breaking -compatibility for existing users of the Python 2 API which is a no-go for -many situations. The automatic upgrading of binary strings to unicode -strings that would be enabled by this proposal would make it much easier -to port such libraries over. +This approach may prove useful, for example, for applications that wish to +target Python 3 for the Ubuntu LTS release that ships with Python 2.7 and 3.2. -Not only the libraries but also the users of these APIs would benefit from -that. For instance, the urllib module in Python 2 is using byte strings, -and the one in Python 3 is using unicode strings. By leveraging a native -string, users can avoid having to adjust for that. +If such an import hook becomes available, this PEP will be updated to include +a reference to it. -Problems with 2to3 -================== -In practice 2to3 currently suffers from a few problems which make it -unnecessarily difficult and/or unpleasant to use: +Python 3 shouldn't be made worse just to support porting from Python 2 +---------------------------------------------------------------------- -- Bad overall performance. In many cases 2to3 runs 20 times slower than - the testsuite for the library or application it's testing. (This for - instance is the case for the Jinja2 library). -- Slightly different behaviour in 2to3 between different versions of - Python cause different outcomes when paired with custom fixers. -- Line numbers from error messages do not match up with the real source - lines due to added/rewritten imports. -- extending 2to3 with custom fixers is nontrivial without using - distribute. By default 2to3 works acceptably well for upgrading - byte-based APIs to unicode based APIs but it fails to upgrade APIs - which already support unicode to Python 3:: +This is indeed one of the key design principles of Python 3. However, one of +the key design principles of Python as a whole is that "practicality beats +purity". If we're going to impose a significant burden on third party +developers, we should have a solid rationale for doing so. - --- test.py (original) - +++ test.py (refactored) - @@ -1,5 +1,5 @@ - class Foo(object): - def __unicode__(self): - - return u'test' - + return 'test' - def __str__(self): - - return unicode(self).encode('utf-8') - + return str(self).encode('utf-8') +In most cases, the rationale for backwards incompatible Python 3 changes are +either to improve code correctness (for example, stricter separation of binary +and text data and integer division upgrading to floats when necessary), reduce +typical memory usage (for example, increased usage of iterators and views over +concrete lists), or to remove distracting nuisances that make Python code +harder to read without increasing its expressiveness (for example, the comma +based syntax for naming caught exceptions). Changes backed by such reasoning +are *not* going to be reverted, regardless of objections from Python 2 +developers attempting to make the transition to Python 3. +In many cases, Python 2 offered two ways of doing things for historical reasons. +For example, inequality could be tested with both ``!=`` and ``<>`` and integer +literals could be specified with an optional ``L`` suffix. Such redundancies +have been eliminated in Python 3, which reduces the overall size of the +language and improves consistency across developers. -APIs and Concepts Using Native Strings -====================================== +In the original Python 3 design (up to and including Python 3.2), the explicit +prefix syntax for unicode literals was deemed to fall into this category, as it +is completely unnecessary in Python 3. However, the difference between those +other cases and unicode literals is that the unicode literal prefix is *not* +redundant in Python 2 code: it is a programmatically significant distinction +that needs to be preserved in some fashion to avoid losing information. -The following is an incomplete list of APIs and general concepts that use -native strings and need implicit upgrading to unicode in Python 3, and -which would directly benefit from this support: +While porting tools were created to help with the transition (see next section) +it still creates an additional burden on heavy users of unicode strings in +Python 2, solely so that future developers learning Python 3 don't need to be +told "For historical reasons, string literals may have an optional ``u`` or +``U`` prefix. Never use this yourselves, it's just there to help with porting +from an earlier version of the language." -- Python identifiers (dict keys, class names, module names, import - paths) -- URLs for the most part as well as HTTP headers in urllib/http servers -- WSGI environment keys and CGI-inherited values -- Python source code for dynamic compilation and AST hacks -- Exception messages -- ``__repr__`` return value -- preferred filesystem paths -- preferred OS environment +Plenty of students learning Python 2 received similar warnings regarding string +exceptions without being confused or irreparably stunted in their growth as +Python developers. It will be the same with this feature. +This point is further reinforced by the fact that Python 3 *still* allows the +uppercase variants of the ``B`` and ``R`` prefixes for bytes literals and raw +bytes and string literals. If the potential for confusion due to string prefix +variants is that significant, where was the outcry asking that these +redundant prefixes removed along with all the other redundancies that were +eliminated in Python 3? -Modernizing Code -================ +Just as support for string exceptions was eliminated from Python 2 using the +normal deprecation process, support for redundant string prefix characters +(specifically, ``B``, ``R``, ``u``, ``U``) may be eventually eliminated +from Python 3, regardless of the current acceptance of this PEP. -The 2to3 tool can be easily adjusted to generate code that runs on both -Python 2 and Python 3. An experimental extension to 2to3 which only -modernizes Python code to the extent that it runs on Python 2.7 or later -with support for the ``six`` library is available as python-modernize -[1]_. For most cases the runtime impact of ``six`` can be neglected (like -a function that calls ``iteritems()`` on a passed dictionary under 2.x or -``items()`` under 3.x), but to make strings cheap for both 2.x and 3.x it -is nearly impossible. The way it currently works is by abusing the -``unicode-escape`` codec on Python 2.x native strings. This is especially -ugly if such a string literal is used in a tight loop. -This proposal would fix this. The modernize module could easily be -adjusted to simply not translate unicode strings, and the runtime overhead -would disappear. +The WSGI "native strings" concept is an ugly hack, anyway +--------------------------------------------------------- -Possible Downsides -================== +One reason the removal of unicode literals has provoked such concern amongst +the web development community is that the updated WSGI specification had to +make a few compromises to minimise the disruption for existing web servers +that provide a WSGI-compatible interface (this was deemed necessary in order +to make the updated standard a viable target for web application authors and +web framework developers). -The obvious downside for this is that potential Python 3 users would have -to be aware of the fact that ``u`` is an optional prefix for strings. -This is something that Python 3 in general tried to avoid. The second -inequality comparison operator was removed, the ``L`` prefix for long -integers etc. This PEP would propose a slight revert on that practice by -reintroducing redundant syntax. On the other hand, Python already has -multiple literals for strings with mostly the same behavior (single -quoted, double quoted, single triple quoted, double triple quoted). +One of those compromises is the concept of a "native string". WSGI defines +three different kinds of string: -Runtime Overhead of Wrappers -============================ +* text strings: handled as ``unicode`` in Python 2 and ``str`` in Python 3 +* native strings: handled as ``str`` in both Python 2 and Python 3 +* binary data: handled as ``str`` in Python 2 and ``bytes`` in Python 3 -I did some basic timings on the performance of a ``u()`` wrapper function -as used by the ``six`` library. The implementation of ``u()`` is as -follows:: +Native strings are a useful concept because there are some APIs and internal +operations that are designed primarily to work with native strings. They often +don't support ``unicode`` in Python 2 and don't support ``bytes`` in Python 3 +(at least, not without needing additional encoding information and/or imposing +constraints that don't apply to the native string variants). - if sys.version_info >= (3, 0): - def u(value): - return value - else: - def u(value): - return unicode(value, 'unicode-escape') +Some example of such interfaces are: -The intention is that ``u'foo'`` can be turned to ``u('foo')`` and that on -Python 2.x an implicit decoding happens. In this case the wrapper will -have a decoding overhead for Python 2.x. I did some basic timings [2]_ to -see how bad the performance loss would be. The following examples measure -the execution time over 10000 iterations:: +* Python identifiers (dict keys, class names, module names, import paths) +* URLs for the most part as well as HTTP headers in urllib/http servers +* WSGI environment keys and CGI-inherited values +* Python source code for dynamic compilation and AST hacks +* Exception messages +* ``__repr__`` return value +* preferred filesystem paths +* preferred OS environment - u'\N{SNOWMAN}barbaz' 1000 loops, best of 3: 295 usec per loop - u('\N{SNOWMAN}barbaz') 10 loops, best of 3: 18.5 msec per loop - u'foobarbaz_%d' % x 100 loops, best of 3: 8.32 msec per loop - u('foobarbaz_%d') % x 10 loops, best of 3: 25.6 msec per loop - u'f??barbaz' 1000 loops, best of 3: 289 usec per loop - u('f??barbaz') 100 loops, best of 3: 15.1 msec per loop - u'foobarbaz' 1000 loops, best of 3: 294 usec per loop - u('foobarbaz') 100 loops, best of 3: 14.3 msec per loop +In Python 2.6 and 2.7, these distinctions are most naturally expressed as +follows: -The overhead of the wrapper function in Python 3 is the price of a -function call since the function only has to return the argument -unchanged. +* ``u""``: text string +* ``""``: native string +* ``b""``: binary data + +In Python 3, the native strings are not distinguished from any other text +strings: + +* ``""``: text string +* ``""``: native string +* ``b""``: binary data + +If ``from __future__ import unicode_literals`` is used to modify the behaviour +of Python 2, then, along with an appropriate definition of ``n()``, the +distinction can be expressed as: + +* ``""``: text string +* ``n("")``: native string +* ``b""``: binary data + +(While ``n=str`` works for simple cases, it can sometimes have problems +due to non-ASCII source encodings) + +In the common subset of Python 2 and Python 3 (with appropriate +specification of a source encoding and definitions of the ``u()`` and ``b()`` +helper functions), they can be expressed as: + +* ``u("")``: text string +* ``""``: native string +* ``b("")``: binary data + +That last approach is the only variant that supports Python 2.5 and earlier. + +Of all the alternatives, the format currently supported in Python 2.6 and 2.7 +is by far the cleanest. With this PEP, that format will also be supported in +Python 3.3+. If the import hook approach works out as planned, it may even be +supported in Python 3.1 and 3.2. A bit more effort could likely adapt the hook +to allow the use of the ``b`` prefix on Python 2.5 + + +The existing tools should be good enough for everyone +----------------------------------------------------- + +A commonly expressed sentiment from developers that have already sucessfully +ported applications to Python 3 is along the lines of "if you think it's hard, +you're doing it wrong" or "it's not that hard, just try it!". While it is no +doubt unintentional, these responses all have the effect of telling the +people that are pointing out inadequacies in the current porting toolset +"there's nothing wrong with the porting tools, you just suck and don't know +how to use them properly". + +These responses are a case of completely missing the point of what people are +complaining about. The feedback that resulted in this PEP isn't due to people complaining that ports aren't possible. Instead, the feedback is coming from +people that have succesfully *completed* ports and are objecting that they +found the experience thoroughly *unpleasant* for the class of application that +they needed to port (specifically, Unicode aware web frameworks and support +libraries). + +This is a subjective appraisal, and it's the reason why the Python 3 +porting tools ecosystem is a case where the "one obvious way to do it" +philosophy emphatically does *not* apply. While it was originally intended that +"develop in Python 2, convert with ``2to3``, test both" would be the standard +way to develop for both versions in parallel, in practice, the needs of +different projects and developer communities have proven to be sufficiently +diverse that a variety of approaches have been devised, allowing each group +to select an approach that best fits their needs. + +Lennart Regebro has produced an excellent overview of the available migration +strategies [2]_, and a similar review is provided in the official porting +guide [3]_. (Note that the official guidance has softened to "it depends on +your specific situation" since Lennart wrote his overview). + +However, both of those guides are written from the founding assumption that +all of the developers involved are *already* committed to the idea of +supporting Python 3. They make no allowance for the *social* aspects of such a +change when you're interacting with a user base that may not be especially +tolerant of disruptions without a clear benefit, or are trying to persuade +Python 2 focused upstream developers to accept patches that are solely about +improving Python 3 forward compatibility. + +With the current porting toolset, *every* migration strategy will result in +changes to *every* Unicode literal in a project. No exceptions. They will +be converted to either an unprefixed string literal (if the project decides to +adopt the ``unicode_literals`` import) or else to a converter call like +``u("text")``. + +If the ``unicode_literals`` import approach is employed, but is not adopted +across the entire project at the same time, then the meaning of a bare string +literal may become annoyingly ambiguous. This problem can be particularly +pernicious for *aggregated* software, like a Django site - in such a situation, +some files may end up using the unicode literals import and others may not, +creating definite potential for confusion. + +While these problems are clearly solvable at a technical level, they're a +completely unnecessary distraction at the social level. Developer energy should +be reserved for addressing *real* technical difficulties associated with the +Python 3 transition (like distinguishing their 8-bit text strings from their +binary data). They shouldn't be punished with additional code changes (even +automated ones) solely due to the fact that they have *already* explicitly +identified their Unicode strings in Python 2. + +Armin Ronacher has created an experimental extension to 2to3 which only +modernizes Python code to the extent that it runs on Python 2.7 or later with +support from the cross-version compatibility ``six`` library is available as +``python-modernize`` [1]_. Currently, the deltas generated by this tool will +affect every Unicode literal in the converted source. This will create +legitimate concerns amongst upstream developers asked to accept such changes. + +However, by eliminating the noise from changes to the Unicode literal syntax, +many projects could be cleanly and (relatively) non-controversially made +forward compatible with Python 3.3+ just by running ``python-modernize`` and +applying the recommended changes. References @@ -248,9 +357,12 @@ .. [1] Python-Modernize (http://github.com/mitsuhiko/python-modernize) -.. [2] Benchmark - (https://github.com/mitsuhiko/unicode-literals-pep/blob/master/timing.py) +.. [2] Porting to Python 3: Migration Strategies + (http://python3porting.com/strategies.html) + +.. [3] Porting Python 2 Code to Python 3 + (http://docs.python.org/howto/pyporting.html) Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 08:49:04 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 04 Mar 2012 08:49:04 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Make_it_clear_that_the_objecti?= =?utf8?q?on_headings_are_paraphrased_versions_of_the?= Message-ID: http://hg.python.org/peps/rev/dd45be81d861 changeset: 4107:dd45be81d861 user: Nick Coghlan date: Sun Mar 04 17:48:49 2012 +1000 summary: Make it clear that the objection headings are paraphrased versions of the complaints made about the PEP files: pep-0414.txt | 17 +++++++++++------ 1 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pep-0414.txt b/pep-0414.txt --- a/pep-0414.txt +++ b/pep-0414.txt @@ -119,8 +119,8 @@ ================= -This PEP may harm adoption of Python 3.2 ----------------------------------------- +Complaint: This PEP may harm adoption of Python 3.2 +--------------------------------------------------- This complaint is interesting, as it carries within it a tacit admission that this PEP *will* make it easier to port Unicode aware Python 2 applications to @@ -147,8 +147,8 @@ a reference to it. -Python 3 shouldn't be made worse just to support porting from Python 2 ----------------------------------------------------------------------- +Complaint: Python 3 shouldn't be made worse just to support porting from Python 2 +--------------------------------------------------------------------------------- This is indeed one of the key design principles of Python 3. However, one of the key design principles of Python as a whole is that "practicality beats @@ -193,7 +193,7 @@ uppercase variants of the ``B`` and ``R`` prefixes for bytes literals and raw bytes and string literals. If the potential for confusion due to string prefix variants is that significant, where was the outcry asking that these -redundant prefixes removed along with all the other redundancies that were +redundant prefixes be removed along with all the other redundancies that were eliminated in Python 3? Just as support for string exceptions was eliminated from Python 2 using the @@ -202,8 +202,8 @@ from Python 3, regardless of the current acceptance of this PEP. -The WSGI "native strings" concept is an ugly hack, anyway ---------------------------------------------------------- +Complaint: The WSGI "native strings" concept is an ugly hack +------------------------------------------------------------ One reason the removal of unicode literals has provoked such concern amongst the web development community is that the updated WSGI specification had to @@ -272,14 +272,15 @@ That last approach is the only variant that supports Python 2.5 and earlier. Of all the alternatives, the format currently supported in Python 2.6 and 2.7 -is by far the cleanest. With this PEP, that format will also be supported in +is by far the cleanest approach that clearly distinguishes the three desired +kinds of behaviour. With this PEP, that format will also be supported in Python 3.3+. If the import hook approach works out as planned, it may even be supported in Python 3.1 and 3.2. A bit more effort could likely adapt the hook to allow the use of the ``b`` prefix on Python 2.5 -The existing tools should be good enough for everyone ------------------------------------------------------ +Complaint: The existing tools should be good enough for everyone +---------------------------------------------------------------- A commonly expressed sentiment from developers that have already sucessfully ported applications to Python 3 is along the lines of "if you think it's hard, -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 08:56:27 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 04 Mar 2012 08:56:27 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_More_minor_cleanups_to_PEP_414?= Message-ID: http://hg.python.org/peps/rev/2dd168f93bfa changeset: 4108:2dd168f93bfa user: Nick Coghlan date: Sun Mar 04 17:56:12 2012 +1000 summary: More minor cleanups to PEP 414 files: pep-0414.txt | 18 ++++++++++-------- 1 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pep-0414.txt b/pep-0414.txt --- a/pep-0414.txt +++ b/pep-0414.txt @@ -221,8 +221,8 @@ Native strings are a useful concept because there are some APIs and internal operations that are designed primarily to work with native strings. They often -don't support ``unicode`` in Python 2 and don't support ``bytes`` in Python 3 -(at least, not without needing additional encoding information and/or imposing +don't support ``unicode`` in Python 2 or support ``bytes`` in Python 3 (at +least, not without needing additional encoding information and/or imposing constraints that don't apply to the native string variants). Some example of such interfaces are: @@ -329,7 +329,7 @@ across the entire project at the same time, then the meaning of a bare string literal may become annoyingly ambiguous. This problem can be particularly pernicious for *aggregated* software, like a Django site - in such a situation, -some files may end up using the unicode literals import and others may not, +some files may end up using the ``unicode_literals`` import and others may not, creating definite potential for confusion. While these problems are clearly solvable at a technical level, they're a @@ -342,13 +342,15 @@ Armin Ronacher has created an experimental extension to 2to3 which only modernizes Python code to the extent that it runs on Python 2.7 or later with -support from the cross-version compatibility ``six`` library is available as -``python-modernize`` [1]_. Currently, the deltas generated by this tool will -affect every Unicode literal in the converted source. This will create -legitimate concerns amongst upstream developers asked to accept such changes. +support from the cross-version compatibility ``six`` library. This tool is +available as ``python-modernize`` [1]_. Currently, the deltas generated by +this tool will affect every Unicode literal in the converted source. This +will create legitimate concerns amongst upstream developers asked to accept +such changes, and amongst framework *users* being asked to change their +applications. However, by eliminating the noise from changes to the Unicode literal syntax, -many projects could be cleanly and (relatively) non-controversially made +many projects could be cleanly and (comparatively) non-controversially made forward compatible with Python 3.3+ just by running ``python-modernize`` and applying the recommended changes. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 08:58:24 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 04 Mar 2012 08:58:24 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Update_post_history_for_PEP_41?= =?utf8?q?4?= Message-ID: http://hg.python.org/peps/rev/96c76924c6f5 changeset: 4109:96c76924c6f5 user: Nick Coghlan date: Sun Mar 04 17:58:04 2012 +1000 summary: Update post history for PEP 414 files: pep-0414.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0414.txt b/pep-0414.txt --- a/pep-0414.txt +++ b/pep-0414.txt @@ -8,7 +8,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 15-Feb-2012 -Post-History: 28-Feb-2012 +Post-History: 28-Feb-2012, 04-Mar-2012 Resolution: http://mail.python.org/pipermail/python-dev/2012-February/116995.html -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 13:35:01 2012 From: python-checkins at python.org (armin.ronacher) Date: Sun, 04 Mar 2012 13:35:01 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Basic_support_for_PEP_414_w?= =?utf8?q?ithout_docs_or_tests=2E?= Message-ID: http://hg.python.org/cpython/rev/ed9497d6a216 changeset: 75381:ed9497d6a216 user: Armin Ronacher date: Sun Mar 04 12:04:06 2012 +0000 summary: Basic support for PEP 414 without docs or tests. files: Lib/tokenize.py | 30 ++++++++++++++++++++++-------- Parser/tokenizer.c | 10 +++++++--- Python/ast.c | 3 +++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Lib/tokenize.py b/Lib/tokenize.py --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -135,10 +135,10 @@ Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" # Tail end of """ string. Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' -Triple = group("[bB]?[rR]?'''", '[bB]?[rR]?"""') +Triple = group("[bBuU]?[rR]?'''", '[bBuU]?[rR]?"""') # Single-line ' or " string. -String = group(r"[bB]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*'", - r'[bB]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*"') +String = group(r"[bBuU]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*'", + r'[bBuU]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*"') # Because of leftmost-then-longest match semantics, be sure to put the # longest operators first (e.g., if = came before ==, == would get @@ -156,9 +156,9 @@ Token = Ignore + PlainToken # First (or only) line of ' or " string. -ContStr = group(r"[bB]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*" + +ContStr = group(r"[bBuU]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*" + group("'", r'\\\r?\n'), - r'[bB]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*' + + r'[bBuU]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*' + group('"', r'\\\r?\n')) PseudoExtras = group(r'\\\r?\n', Comment, Triple) PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) @@ -176,21 +176,35 @@ "bR'''": Single3, 'bR"""': Double3, "Br'''": Single3, 'Br"""': Double3, "BR'''": Single3, 'BR"""': Double3, - 'r': None, 'R': None, 'b': None, 'B': None} + "u'''": Single3, 'u"""': Double3, + "ur'''": Single3, 'ur"""': Double3, + "R'''": Single3, 'R"""': Double3, + "U'''": Single3, 'U"""': Double3, + "uR'''": Single3, 'uR"""': Double3, + "Ur'''": Single3, 'Ur"""': Double3, + "UR'''": Single3, 'UR"""': Double3, + 'r': None, 'R': None, 'b': None, 'B': None, + 'u': None, 'U': None} triple_quoted = {} for t in ("'''", '"""', "r'''", 'r"""', "R'''", 'R"""', "b'''", 'b"""', "B'''", 'B"""', "br'''", 'br"""', "Br'''", 'Br"""', - "bR'''", 'bR"""', "BR'''", 'BR"""'): + "bR'''", 'bR"""', "BR'''", 'BR"""', + "u'''", 'u"""', "U'''", 'U"""', + "ur'''", 'ur"""', "Ur'''", 'Ur"""', + "uR'''", 'uR"""', "UR'''", 'UR"""'): triple_quoted[t] = t single_quoted = {} for t in ("'", '"', "r'", 'r"', "R'", 'R"', "b'", 'b"', "B'", 'B"', "br'", 'br"', "Br'", 'Br"', - "bR'", 'bR"', "BR'", 'BR"' ): + "bR'", 'bR"', "BR'", 'BR"' , + "u'", 'u"', "U'", 'U"', + "ur'", 'ur"', "Ur'", 'Ur"', + "uR'", 'uR"', "UR'", 'UR"' ): single_quoted[t] = t tabsize = 8 diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1412,11 +1412,15 @@ /* Identifier (most frequent token!) */ nonascii = 0; if (is_potential_identifier_start(c)) { - /* Process b"", r"", br"" and rb"" */ - int saw_b = 0, saw_r = 0; + /* Process b"", r"", u"", br"", rb"" and ur"" */ + int saw_b = 0, saw_r = 0, saw_u = 0; while (1) { - if (!saw_b && (c == 'b' || c == 'B')) + if (!(saw_b || saw_u) && (c == 'b' || c == 'B')) saw_b = 1; + /* Since this is a backwards compatibility support literal we don't + want to support it in arbitrary order like byte literals. */ + else if (!(saw_b || saw_u || saw_r) && (c == 'u' || c == 'U')) + saw_u = 1; else if (!saw_r && (c == 'r' || c == 'R')) saw_r = 1; else diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -3796,6 +3796,9 @@ quote = *++s; *bytesmode = 1; } + else if (quote == 'u' || quote == 'U') { + quote = *++s; + } else if (quote == 'r' || quote == 'R') { quote = *++s; rawmode = 1; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 13:35:11 2012 From: python-checkins at python.org (armin.ronacher) Date: Sun, 04 Mar 2012 13:35:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Basic_documentation_for_PEP?= =?utf8?q?_414?= Message-ID: http://hg.python.org/cpython/rev/042e7481c7b4 changeset: 75382:042e7481c7b4 user: Armin Ronacher date: Sun Mar 04 12:33:51 2012 +0000 summary: Basic documentation for PEP 414 files: Doc/reference/lexical_analysis.rst | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -401,7 +401,7 @@ .. productionlist:: stringliteral: [`stringprefix`](`shortstring` | `longstring`) - stringprefix: "r" | "R" + stringprefix: "r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR" shortstring: "'" `shortstringitem`* "'" | '"' `shortstringitem`* '"' longstring: "'''" `longstringitem`* "'''" | '"""' `longstringitem`* '"""' shortstringitem: `shortstringchar` | `stringescapeseq` @@ -441,6 +441,9 @@ may only contain ASCII characters; bytes with a numeric value of 128 or greater must be expressed with escapes. +As of Python 3.3 it is possible again to prefix unicode strings with a +``u`` prefix to simplify maintenance of dual 2.x and 3.x codebases. + Both string and bytes literals may optionally be prefixed with a letter ``'r'`` or ``'R'``; such strings are called :dfn:`raw strings` and treat backslashes as literal characters. As a result, in string literals, ``'\U'`` and ``'\u'`` @@ -450,6 +453,11 @@ The ``'rb'`` prefix of raw bytes literals has been added as a synonym of ``'br'``. + .. versionadded:: 3.3 + Support for the unicode legacy literal (``u'value'``) and other + versions were reintroduced to simplify the maintenance of dual + Python 2.x and 3.x codebases. See :pep:`414` for more information. + In triple-quoted strings, unescaped newlines and quotes are allowed (and are retained), except that three unescaped quotes in a row terminate the string. (A "quote" is the character used to open the string, i.e. either ``'`` or ``"``.) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 14:08:29 2012 From: python-checkins at python.org (armin.ronacher) Date: Sun, 04 Mar 2012 14:08:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Updated_tokenize_to_support?= =?utf8?q?_the_inverse_byte_literals_new_in_3=2E3?= Message-ID: http://hg.python.org/cpython/rev/2822765e48a7 changeset: 75383:2822765e48a7 user: Armin Ronacher date: Sun Mar 04 13:07:57 2012 +0000 summary: Updated tokenize to support the inverse byte literals new in 3.3 files: Lib/test/test_tokenize.py | 12 ++++++++++++ Lib/tokenize.py | 22 ++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -563,6 +563,18 @@ NAME 'gr?n' (2, 0) (2, 4) OP '=' (2, 5) (2, 6) STRING "'green'" (2, 7) (2, 14) + +Legacy unicode literals: + + >>> dump_tokens("?rter = u'places'\\ngr?n = UR'green'") + ENCODING 'utf-8' (0, 0) (0, 0) + NAME '?rter' (1, 0) (1, 5) + OP '=' (1, 6) (1, 7) + STRING "u'places'" (1, 8) (1, 17) + NEWLINE '\\n' (1, 17) (1, 18) + NAME 'gr?n' (2, 0) (2, 4) + OP '=' (2, 5) (2, 6) + STRING "UR'green'" (2, 7) (2, 16) """ from test import support diff --git a/Lib/tokenize.py b/Lib/tokenize.py --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -127,6 +127,8 @@ Imagnumber = group(r'[0-9]+[jJ]', Floatnumber + r'[jJ]') Number = group(Imagnumber, Floatnumber, Intnumber) +StringPrefix = r'(?:[uU][rR]?|[bB][rR]|[rR][bB]|[rR]|[uU])?' + # Tail end of ' string. Single = r"[^'\\]*(?:\\.[^'\\]*)*'" # Tail end of " string. @@ -135,10 +137,10 @@ Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" # Tail end of """ string. Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' -Triple = group("[bBuU]?[rR]?'''", '[bBuU]?[rR]?"""') +Triple = group(StringPrefix + "'''", StringPrefix + '"""') # Single-line ' or " string. -String = group(r"[bBuU]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*'", - r'[bBuU]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*"') +String = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'", + StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"') # Because of leftmost-then-longest match semantics, be sure to put the # longest operators first (e.g., if = came before ==, == would get @@ -156,9 +158,9 @@ Token = Ignore + PlainToken # First (or only) line of ' or " string. -ContStr = group(r"[bBuU]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*" + +ContStr = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + group("'", r'\\\r?\n'), - r'[bBuU]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*' + + StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + group('"', r'\\\r?\n')) PseudoExtras = group(r'\\\r?\n', Comment, Triple) PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) @@ -170,12 +172,16 @@ "'''": Single3, '"""': Double3, "r'''": Single3, 'r"""': Double3, "b'''": Single3, 'b"""': Double3, - "br'''": Single3, 'br"""': Double3, "R'''": Single3, 'R"""': Double3, "B'''": Single3, 'B"""': Double3, + "br'''": Single3, 'br"""': Double3, "bR'''": Single3, 'bR"""': Double3, "Br'''": Single3, 'Br"""': Double3, "BR'''": Single3, 'BR"""': Double3, + "rb'''": Single3, 'rb"""': Double3, + "Rb'''": Single3, 'Rb"""': Double3, + "rB'''": Single3, 'rB"""': Double3, + "RB'''": Single3, 'RB"""': Double3, "u'''": Single3, 'u"""': Double3, "ur'''": Single3, 'ur"""': Double3, "R'''": Single3, 'R"""': Double3, @@ -192,6 +198,8 @@ "b'''", 'b"""', "B'''", 'B"""', "br'''", 'br"""', "Br'''", 'Br"""', "bR'''", 'bR"""', "BR'''", 'BR"""', + "rb'''", 'rb"""', "rB'''", 'rB"""', + "Rb'''", 'Rb"""', "RB'''", 'RB"""', "u'''", 'u"""', "U'''", 'U"""', "ur'''", 'ur"""', "Ur'''", 'Ur"""', "uR'''", 'uR"""', "UR'''", 'UR"""'): @@ -202,6 +210,8 @@ "b'", 'b"', "B'", 'B"', "br'", 'br"', "Br'", 'Br"', "bR'", 'bR"', "BR'", 'BR"' , + "rb'", 'rb"', "rB'", 'rB"', + "Rb'", 'Rb"', "RB'", 'RB"' , "u'", 'u"', "U'", 'U"', "ur'", 'ur"', "Ur'", 'Ur"', "uR'", 'uR"', "UR'", 'UR"' ): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 14:28:38 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 14:28:38 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_=2314193=3A_Remove_pymigr_refe?= =?utf8?q?rences=2C_it_is_read_only=2E?= Message-ID: http://hg.python.org/peps/rev/636320b98756 changeset: 4110:636320b98756 user: Georg Brandl date: Sun Mar 04 14:32:42 2012 +0100 summary: #14193: Remove pymigr references, it is read only. files: pep-0385.txt | 20 ++++---------------- 1 files changed, 4 insertions(+), 16 deletions(-) diff --git a/pep-0385.txt b/pep-0385.txt --- a/pep-0385.txt +++ b/pep-0385.txt @@ -62,15 +62,6 @@ switch over to the new repository. -Todo list -========= - -The current list of issues to resolve at various steps in the -conversion is kept `in the pymigr repo`_. - -.. _in the pymigr repo: http://hg.python.org/pymigr/file/tip/todo.txt - - Transition plan =============== @@ -158,14 +149,13 @@ In order to provide user names the way they are common in hg (in the 'First Last ' format), we need an author map to map cvs and svn user names to real names and their email addresses. We -have a complete version of such a map in my `migration tools -repository`_. The email addresses in it might be out of date; that's +have a complete version of such a map in the migration tools +repository (not publicly accessible to avoid leaking addresses to +harvesters). The email addresses in it might be out of date; that's bound to happen, although it would be nice to try and have as many people as possible review it for addresses that are out of date. The current version also still seems to contain some encoding problems. -.. _migration tools repository: http://hg.python.org/pymigr/ - Generating .hgignore -------------------- @@ -313,15 +303,13 @@ A more or less stock hgwebdir installation should be set up. We might want to come up with a style to match the Python website. -A `small WSGI application`_ has been written that can look up +A small WSGI application has been written that can look up Subversion revisions and redirect to the appropriate hgweb page for the given changeset, regardless in which repository the converted revision ended up (since one big Subversion repository is converted into several Mercurial repositories). It can also look up Mercurial changesets by their hexadecimal ID. -.. _small WSGI application: http://hg.python.org/pymigr/file/tip/hglookup.py - roundup ------- -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 15:50:21 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 15:50:21 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_=2314914=3A_fix_typo=2E?= Message-ID: http://hg.python.org/peps/rev/e3a0dc8e94df changeset: 4111:e3a0dc8e94df user: Georg Brandl date: Sun Mar 04 15:54:24 2012 +0100 summary: #14914: fix typo. files: pep-0414.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0414.txt b/pep-0414.txt --- a/pep-0414.txt +++ b/pep-0414.txt @@ -42,7 +42,7 @@ "u" | "U" | "ur" | "UR" | "Ur" | "uR" -in additional to the currently supported:: +in addition to the currently supported:: "r" | "R" -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 15:55:42 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 15:55:42 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Update_for_new_versioning_sche?= =?utf8?q?me_=283=2E3=2E0_instead_of_3=2E3=29?= Message-ID: http://hg.python.org/peps/rev/3b2906825d96 changeset: 4112:3b2906825d96 user: Georg Brandl date: Sun Mar 04 15:59:45 2012 +0100 summary: Update for new versioning scheme (3.3.0 instead of 3.3) files: pep-0101.txt | 25 ++++++++++++------------- 1 files changed, 12 insertions(+), 13 deletions(-) diff --git a/pep-0101.txt b/pep-0101.txt --- a/pep-0101.txt +++ b/pep-0101.txt @@ -62,11 +62,10 @@ http://hg.python.org/release/ We use the following conventions in the examples below. Where a release - number is given, it is of the form X.YaZ, e.g. 2.6a3 for Python 2.6 alpha - 3, where "a" == alpha, "b" == beta, "rc" == release candidate. If a micro - release number is used, then we'll say X.Y.MaZ. + number is given, it is of the form X.Y.ZaN, e.g. 3.3.0a3 for Python 3.3.0 + alpha 3, where "a" == alpha, "b" == beta, "rc" == release candidate. - Release tags are named "vX.YaZ". The branch name for minor release + Release tags are named "vX.Y.ZaN". The branch name for minor release maintenance branches is "X.Y". This helps by performing several automatic editing steps, and guides you @@ -156,7 +155,7 @@ ___ Bump version numbers via the release script. - $ .../release/release.py --bump X.YaZ + $ .../release/release.py --bump X.Y.ZaN This automates updating various release numbers, but you will have to modify a few files manually. If your $EDITOR environment variable is @@ -197,9 +196,9 @@ alpha or beta releases. Note that Andrew Kuchling often takes care of this. - ___ Tag the release for X.YaZ. + ___ Tag the release for X.Y.ZaN. - $ .../release/release.py --tag X.YaZ + $ .../release/release.py --tag X.Y.ZaN ___ If this is a final major release, branch the tree for X.Y. @@ -309,10 +308,10 @@ ___ Use the release script to create the source gzip and bz2 tarballs, md5 checksums, documentation tar and zip files, and gpg signature files. - $ .../release/release.py --export X.YaZ + $ .../release/release.py --export X.Y.ZaN This will leave all the relevant files in a subdirectory called - 'X.YaZ/src', and the built docs in 'X.YaZ/docs' (for final releases). + 'X.Y.ZaN/src', and the built docs in 'X.Y.ZaN/docs' (for final releases). ___ scp or rsync all the files to your home directory on dinsdale.python.org. @@ -361,7 +360,7 @@ Python-3.2.tgz, along with a "prev" subdirectory containing Python-3.2a1.msi, Python-3.2a1.tgz, Python-3.2a1.tar.bz2, etc. - ___ On dinsdale, cd /data/ftp.python.org/pub/python/X.Y[.Z] + ___ On dinsdale, cd /data/ftp.python.org/pub/python/X.Y.Z creating it if necessary. Make sure it is owned by group 'webmaster' and group-writable. @@ -383,14 +382,14 @@ ___ md5sum the files and make sure they got uploaded intact. ___ If this is a final release: Move the doc zips and tarballs to - /data/ftp.python.org/pub/python/doc/X.Y[.Z] creating the directory + /data/ftp.python.org/pub/python/doc/X.Y.Z creating the directory if necessary, and adapt the "current" symlink in .../doc to point to that directory. Note though that if you're releasing a maintenance release for an older version, don't change the current link. ___ If this is a final release (even a maintenance release), also unpack the HTML docs to - /data/ftp.python.org/pub/docs.python.org/release/X.Y[.Z]. + /data/ftp.python.org/pub/docs.python.org/release/X.Y.Z. ___ Let the DE check if the docs are built and work all right. @@ -513,7 +512,7 @@ ___ Do the guided post-release steps with the release script. - $ .../release/release.py --done X.YaZ + $ .../release/release.py --done X.Y.ZaN Review and commit these changes. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 16:22:28 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 16:22:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_encoding_handling_of_th?= =?utf8?q?e_pydoc-topics_writer=2E?= Message-ID: http://hg.python.org/cpython/rev/51347d4f080c changeset: 75384:51347d4f080c user: Georg Brandl date: Sun Mar 04 16:12:02 2012 +0100 summary: Fix encoding handling of the pydoc-topics writer. files: Doc/tools/sphinxext/pyspecific.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/tools/sphinxext/pyspecific.py b/Doc/tools/sphinxext/pyspecific.py --- a/Doc/tools/sphinxext/pyspecific.py +++ b/Doc/tools/sphinxext/pyspecific.py @@ -5,7 +5,7 @@ Sphinx extension with Python doc-specific markup. - :copyright: 2008, 2009, 2010 by Georg Brandl. + :copyright: 2008, 2009, 2010, 2011, 2012 by Georg Brandl. :license: Python license. """ @@ -201,11 +201,12 @@ document.append(doctree.ids[labelid]) destination = StringOutput(encoding='utf-8') writer.write(document, destination) - self.topics[label] = str(writer.output) + self.topics[label] = writer.output.encode('utf-8') def finish(self): f = open(path.join(self.outdir, 'topics.py'), 'w') try: + f.write('# -*- coding: utf-8 -*-\n') f.write('# Autogenerated by Sphinx on %s\n' % asctime()) f.write('topics = ' + pformat(self.topics) + '\n') finally: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 16:22:29 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 16:22:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Regenerate_pydoc_topics=2E?= Message-ID: http://hg.python.org/cpython/rev/ee9e99c10f53 changeset: 75385:ee9e99c10f53 user: Georg Brandl date: Sun Mar 04 16:12:09 2012 +0100 summary: Regenerate pydoc topics. files: Lib/pydoc_data/topics.py | 49 ++++++++++++++------------- 1 files changed, 25 insertions(+), 24 deletions(-) diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,30 +1,31 @@ -# Autogenerated by Sphinx on Thu Apr 28 07:53:12 2011 +# -*- coding: utf-8 -*- +# Autogenerated by Sphinx on Sun Mar 4 16:11:27 2012 topics = {'assert': '\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', - 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nWith the exception of bytes literals, these all correspond to\nimmutable data types, and hence the object's identity is less\nimportant than its value. Multiple evaluations of literals with the\nsame value (either the same occurrence in the program text or a\ndifferent occurrence) may obtain the same object or a different object\nwith the same value.\n", - 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', + 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nAll literals correspond to immutable data types, and hence the\nobject's identity is less important than its value. Multiple\nevaluations of literals with the same value (either the same\noccurrence in the program text or a different occurrence) may obtain\nthe same object or a different object with the same value.\n", + 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier (which can\nbe customized by overriding the ``__getattr__()`` method). If this\nattribute is not available, the exception ``AttributeError`` is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe ``*`` (multiplication) operator yields the product of its\narguments. The arguments must either both be numbers, or one argument\nmust be an integer and the other must be a sequence. In the former\ncase, the numbers are converted to a common type and then multiplied\ntogether. In the latter case, sequence repetition is performed; a\nnegative repetition factor yields an empty sequence.\n\nThe ``/`` (division) and ``//`` (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Integer division yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the ``ZeroDivisionError`` exception.\n\nThe ``%`` (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n``ZeroDivisionError`` exception. The arguments may be floating point\nnumbers, e.g., ``3.14%0.7`` equals ``0.34`` (since ``3.14`` equals\n``4*0.7 + 0.34``.) The modulo operator always yields a result with\nthe same sign as its second operand (or zero); the absolute value of\nthe result is strictly smaller than the absolute value of the second\noperand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: ``x == (x//y)*y + (x%y)``. Floor division and modulo are\nalso connected with the built-in function ``divmod()``: ``divmod(x, y)\n== (x//y, x%y)``. [2].\n\nIn addition to performing the modulo operation on numbers, the ``%``\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *Old String Formatting Operations*.\n\nThe floor division operator, the modulo operator, and the ``divmod()``\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the ``abs()`` function if appropriate.\n\nThe ``+`` (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe ``-`` (subtraction) operator yields the difference of its\narguments. The numeric arguments are first converted to a common\ntype.\n', 'bitwise': '\nBinary bitwise operations\n*************************\n\nEach of the three bitwise operations has a different priority level:\n\n and_expr ::= shift_expr | and_expr "&" shift_expr\n xor_expr ::= and_expr | xor_expr "^" and_expr\n or_expr ::= xor_expr | or_expr "|" xor_expr\n\nThe ``&`` operator yields the bitwise AND of its arguments, which must\nbe integers.\n\nThe ``^`` operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be integers.\n\nThe ``|`` operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be integers.\n', 'bltin-code-objects': '\nCode Objects\n************\n\nCode objects are used by the implementation to represent "pseudo-\ncompiled" executable Python code such as a function body. They differ\nfrom function objects because they don\'t contain a reference to their\nglobal execution environment. Code objects are returned by the built-\nin ``compile()`` function and can be extracted from function objects\nthrough their ``__code__`` attribute. See also the ``code`` module.\n\nA code object can be executed or evaluated by passing it (instead of a\nsource string) to the ``exec()`` or ``eval()`` built-in functions.\n\nSee *The standard type hierarchy* for more information.\n', - 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*). It supports\nno special operations. There is exactly one ellipsis object, named\n``Ellipsis`` (a built-in name).\n\nIt is written as ``Ellipsis`` or ``...``.\n', - 'bltin-null-object': "\nThe Null Object\n***************\n\nThis object is returned by functions that don't explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named ``None`` (a built-in name).\n\nIt is written as ``None``.\n", + 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*), but may also\nbe used in other situations where a sentinel value other than ``None``\nis needed. It supports no special operations. There is exactly one\nellipsis object, named ``Ellipsis`` (a built-in name).\n``type(Ellipsis)()`` produces the ``Ellipsis`` singleton.\n\nIt is written as ``Ellipsis`` or ``...``.\n', + 'bltin-null-object': "\nThe Null Object\n***************\n\nThis object is returned by functions that don't explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named ``None`` (a built-in name). ``type(None)()`` produces\nthe same singleton.\n\nIt is written as ``None``.\n", 'bltin-type-objects': "\nType Objects\n************\n\nType objects represent the various object types. An object's type is\naccessed by the built-in function ``type()``. There are no special\noperations on types. The standard module ``types`` defines names for\nall standard built-in types.\n\nTypes are written like this: ````.\n", 'booleans': '\nBoolean operations\n******************\n\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: ``False``, ``None``, numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a ``__bool__()`` method.\n\nThe operator ``not`` yields ``True`` if its argument is false,\n``False`` otherwise.\n\nThe expression ``x and y`` first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression ``x or y`` first evaluates *x*; if *x* is true, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\n(Note that neither ``and`` nor ``or`` restrict the value and type they\nreturn to ``False`` and ``True``, but rather return the last evaluated\nargument. This is sometimes useful, e.g., if ``s`` is a string that\nshould be replaced by a default value if it is empty, the expression\n``s or \'foo\'`` yields the desired value. Because ``not`` has to\ninvent a value anyway, it does not bother to return a value of the\nsame type as its argument, so e.g., ``not \'foo\'`` yields ``False``,\nnot ``\'\'``.)\n', 'break': '\nThe ``break`` statement\n***********************\n\n break_stmt ::= "break"\n\n``break`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition\nwithin that loop.\n\nIt terminates the nearest enclosing loop, skipping the optional\n``else`` clause if the loop has one.\n\nIf a ``for`` loop is terminated by ``break``, the loop control target\nkeeps its current value.\n\nWhen ``break`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the loop.\n', 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n', - 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to a sequence. Elements from this\nsequence are treated as if they were additional positional arguments;\nif there are positional arguments *x1*,..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to an iterable. Elements from this\niterable are treated as if they were additional positional arguments;\nif there are positional arguments *x1*, ..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', + 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is set as the context of the new exception. The exception\ninformation is not available to the program during execution of the\n``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that the same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', 'continue': '\nThe ``continue`` statement\n**************************\n\n continue_stmt ::= "continue"\n\n``continue`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition or\n``finally`` clause within that loop. It continues with the next cycle\nof the nearest enclosing loop.\n\nWhen ``continue`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nstarting the next loop cycle.\n', 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the other\n is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', - 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n', + 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__bytes__(self)\n\n Called by ``bytes()`` to compute a byte-string representation of an\n object. This should return a ``bytes`` object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\n Note: Note by default the ``__hash__()`` values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the order in which keys are\n retrieved from a dict. Note Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also ``PYTHONHASHSEED``.\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n', 'debugger': '\n``pdb`` --- The Python Debugger\n*******************************\n\nThe module ``pdb`` defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n``Pdb``. This is currently undocumented but easily understood by\nreading the source. The extension interface uses the modules ``bdb``\nand ``cmd``.\n\nThe debugger\'s prompt is ``(Pdb)``. Typical usage to run a program\nunder control of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\n``pdb.py`` can also be invoked as a script to debug other scripts.\nFor example:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: ``pdb.py`` now accepts a ``-c`` option that\nexecutes commands as if given in a ``.pdbrc`` file, see *Debugger\nCommands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the ``continue`` command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type ``continue``, or you can\n step through the statement using ``step`` or ``next`` (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module ``__main__`` is used. (See\n the explanation of the built-in ``exec()`` or ``eval()``\n functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When ``runeval()`` returns, it returns the\n value of the expression. Otherwise this function is similar to\n ``run()``.\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When ``runcall()`` returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n ``sys.last_traceback``.\n\nThe ``run*`` functions and ``set_trace()`` are aliases for\ninstantiating the ``Pdb`` class and calling the method of the same\nname. If you want to access further features, you have to do this\nyourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None, nosigint=False)\n\n ``Pdb`` is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying ``cmd.Cmd`` class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n By default, Pdb sets a handler for the SIGINT signal (which is sent\n when the user presses Ctrl-C on the console) when you give a\n ``continue`` command. This allows you to break into the debugger\n again by pressing Ctrl-C. If you want Pdb not to touch the SIGINT\n handler, set *nosigint* tot true.\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n New in version 3.2: The *nosigint* argument. Previously, a SIGINT\n handler was never set by Pdb.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n``h(elp)`` means that either ``h`` or ``help`` can be used to enter\nthe help command (but not ``he`` or ``hel``, nor ``H`` or ``Help`` or\n``HELP``). Arguments to commands must be separated by whitespace\n(spaces or tabs). Optional arguments are enclosed in square brackets\n(``[]``) in the command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n(``|``).\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a ``list`` command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint (``!``). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by\n``;;``. (A single ``;`` is not used as it is the separator for\nmultiple commands in a line that is passed to the Python parser.) No\nintelligence is applied to separating the commands; the input is split\nat the first ``;;`` pair, even if it is in the middle of a quoted\nstring.\n\nIf a file ``.pdbrc`` exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ``.pdbrc`` can now contain commands that\ncontinue debugging, such as ``continue`` or ``next``. Previously,\nthese commands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. ``help pdb``\n displays the full documentation (the docstring of the ``pdb``\n module). Since the *command* argument must be an identifier,\n ``help exec`` must be entered to get help on the ``!`` command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on ``sys.path``. Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for ``break``.\n\ncl(ear) [filename:lineno | bpnumber [bpnumber ...]]\n\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just ``end`` to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) print some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with ``end``; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between ``next`` and\n ``step`` is that ``step`` stops inside a called function, while\n ``next`` executes called functions at (nearly) full speed, only\n stopping at the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a ``for`` loop or out\n of a ``finally`` clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With ``.`` as argument, list 11 lines around the current line.\n With one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by ``->``. If\n an exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ``>>``, if it\n differs from the current line.\n\n New in version 3.2: The ``>>`` marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for ``list``.\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np(rint) expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\npp expression\n\n Like the ``print`` command, except the value of the expression is\n pretty-printed using the ``pprint`` module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\ndisplay [expression]\n\n Display the value of the expression if it changed, each time\n execution stops in the current frame.\n\n Without expression, list all display expressions for the current\n frame.\n\n New in version 3.2.\n\nundisplay [expression]\n\n Do not display the expression any more in the current frame.\n Without expression, clear all display expressions for the current\n frame.\n\n New in version 3.2.\n\ninteract\n\n Start an interative interpreter (using the ``code`` module) whose\n global namespace contains all the (global and local) names found in\n the current scope.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by ``%1``, ``%2``, and so on, while ``%*`` is replaced by\n all the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ``.pdbrc`` file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n ``global`` statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with ``shlex`` and the result is used as the new\n ``sys.argv``. History, breakpoints, actions and debugger options\n are preserved. ``restart`` is an alias for ``run``.\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module is\n determined by the ``__name__`` in the frame globals.\n', - 'del': '\nThe ``del`` statement\n*********************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather that spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a ``global``\nstatement in the same code block. If the name is unbound, a\n``NameError`` exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2.\n', + 'del': '\nThe ``del`` statement\n*********************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather than spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a ``global``\nstatement in the same code block. If the name is unbound, a\n``NameError`` exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2.\n', 'dict': '\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', 'else': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', @@ -33,8 +34,8 @@ 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: ``()``.)\n', 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, ``077e010`` is legal, and denotes the same\nnumber as ``77e10``. The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator ``-`` and the\nliteral ``1``.\n', 'for': '\nThe ``for`` statement\n*********************\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', - 'formatstrings': '\nFormat String Syntax\n********************\n\nThe ``str.format()`` method and the ``Formatter`` class share the same\nsyntax for format strings (although in the case of ``Formatter``,\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n``{}``. Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n``{{`` and ``}}``.\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point ``\'!\'``, and a *format_spec*, which\nis preceded by a colon ``\':\'``. These specify a non-default format\nfor the replacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either\neither a number or a keyword. If it\'s a number, it refers to a\npositional argument, and if it\'s a keyword, it refers to a named\nkeyword argument. If the numerical arg_names in a format string are\n0, 1, 2, ... in sequence, they can all be omitted (not just some) and\nthe numbers 0, 1, 2, ... will be automatically inserted in that order.\nThe *arg_name* can be followed by any number of index or attribute\nexpressions. An expression of the form ``\'.name\'`` selects the named\nattribute using ``getattr()``, while an expression of the form\n``\'[index]\'`` does an index lookup using ``__getitem__()``.\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so ``\'{} {}\'`` is equivalent to ``\'{0} {1}\'``.\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the\n``__format__()`` method of the value itself. However, in some cases\nit is desirable to force a type to be formatted as a string,\noverriding its own definition of formatting. By converting the value\nto a string before calling ``__format__()``, the normal formatting\nlogic is bypassed.\n\nThree conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, ``\'!r\'`` which calls ``repr()`` and ``\'!a\'``\nwhich calls ``ascii()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in ``format()`` function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string (``""``) produces\nthe same result as if you had called ``str()`` on the value. A non-\nempty format string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nThe *fill* character can be any character other than \'{\' or \'}\'. The\npresence of a fill character is signaled by the character following\nit, which must be one of the alignment options. If the second\ncharacter of *format_spec* is not a valid alignment option, then it is\nassumed that both the fill character and the alignment option are\nabsent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective ``\'0b\'``, ``\'0o\'``, or\n``\'0x\'`` to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for ``\'g\'`` and ``\'G\'``\nconversions, trailing zeros are not removed from the result.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 3.1: Added the ``\',\'`` option (see also **PEP\n378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nIf the *width* field is preceded by a zero (``\'0\'``) character, this\nenables zero-padding. This is equivalent to an *alignment* type of\n``\'=\'`` and a *fill* character of ``\'0\'``.\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with ``\'f\'`` and ``\'F\'``, or before and after the decimal\npoint for a floating point value formatted with ``\'g\'`` or ``\'G\'``.\nFor non-number types the field indicates the maximum field size - in\nother words, how many characters will be used from the field content.\nThe *precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'s\'`` | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'s\'``. |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'b\'`` | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | ``\'c\'`` | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | ``\'d\'`` | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | ``\'o\'`` | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | ``\'x\'`` | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'X\'`` | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'d\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'d\'``. |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except\n``\'n\'`` and None). When doing so, ``float()`` is used to convert the\ninteger to a floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'e\'`` | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``, but converts ``nan`` to |\n | | ``NAN`` and ``inf`` to ``INF``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. For a given precision ``p >= 1``, this |\n | | rounds the number to ``p`` significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1`` would have exponent ``exp``. Then if ``-4 <= exp |\n | | < p``, the number is formatted with presentation type |\n | | ``\'f\'`` and precision ``p-1-exp``. Otherwise, the number |\n | | is formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1``. In both cases insignificant trailing zeros are |\n | | removed from the significand, and the decimal point is |\n | | also removed if there are no remaining digits following |\n | | it. Positive and negative infinity, positive and negative |\n | | zero, and nans, are formatted as ``inf``, ``-inf``, ``0``, |\n | | ``-0`` and ``nan`` respectively, regardless of the |\n | | precision. A precision of ``0`` is treated as equivalent |\n | | to a precision of ``1``. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets too large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to ``\'g\'``, except with at least one digit past |\n | | the decimal point and a default precision of 12. This is |\n | | intended to match ``str()``, except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old ``%``-formatting.\n\nIn most of the cases the syntax is similar to the old\n``%``-formatting, with the addition of the ``{}`` and with ``:`` used\ninstead of ``%``. For example, ``\'%03.2f\'`` can be translated to\n``\'{:03.2f}\'``.\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing ``%s`` and ``%r``:\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing ``%x`` and ``%o`` and converting the value to different\nbases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}.\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12):\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', - 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n', + 'formatstrings': '\nFormat String Syntax\n********************\n\nThe ``str.format()`` method and the ``Formatter`` class share the same\nsyntax for format strings (although in the case of ``Formatter``,\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n``{}``. Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n``{{`` and ``}}``.\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point ``\'!\'``, and a *format_spec*, which\nis preceded by a colon ``\':\'``. These specify a non-default format\nfor the replacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either a\nnumber or a keyword. If it\'s a number, it refers to a positional\nargument, and if it\'s a keyword, it refers to a named keyword\nargument. If the numerical arg_names in a format string are 0, 1, 2,\n... in sequence, they can all be omitted (not just some) and the\nnumbers 0, 1, 2, ... will be automatically inserted in that order.\nBecause *arg_name* is not quote-delimited, it is not possible to\nspecify arbitrary dictionary keys (e.g., the strings ``\'10\'`` or\n``\':-]\'``) within a format string. The *arg_name* can be followed by\nany number of index or attribute expressions. An expression of the\nform ``\'.name\'`` selects the named attribute using ``getattr()``,\nwhile an expression of the form ``\'[index]\'`` does an index lookup\nusing ``__getitem__()``.\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so ``\'{} {}\'`` is equivalent to ``\'{0} {1}\'``.\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the\n``__format__()`` method of the value itself. However, in some cases\nit is desirable to force a type to be formatted as a string,\noverriding its own definition of formatting. By converting the value\nto a string before calling ``__format__()``, the normal formatting\nlogic is bypassed.\n\nThree conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, ``\'!r\'`` which calls ``repr()`` and ``\'!a\'``\nwhich calls ``ascii()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in ``format()`` function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string (``""``) produces\nthe same result as if you had called ``str()`` on the value. A non-\nempty format string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nThe *fill* character can be any character other than \'{\' or \'}\'. The\npresence of a fill character is signaled by the character following\nit, which must be one of the alignment options. If the second\ncharacter of *format_spec* is not a valid alignment option, then it is\nassumed that both the fill character and the alignment option are\nabsent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective ``\'0b\'``, ``\'0o\'``, or\n``\'0x\'`` to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for ``\'g\'`` and ``\'G\'``\nconversions, trailing zeros are not removed from the result.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 3.1: Added the ``\',\'`` option (see also **PEP\n378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nIf the *width* field is preceded by a zero (``\'0\'``) character, this\nenables zero-padding. This is equivalent to an *alignment* type of\n``\'=\'`` and a *fill* character of ``\'0\'``.\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with ``\'f\'`` and ``\'F\'``, or before and after the decimal\npoint for a floating point value formatted with ``\'g\'`` or ``\'G\'``.\nFor non-number types the field indicates the maximum field size - in\nother words, how many characters will be used from the field content.\nThe *precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'s\'`` | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'s\'``. |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'b\'`` | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | ``\'c\'`` | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | ``\'d\'`` | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | ``\'o\'`` | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | ``\'x\'`` | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'X\'`` | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'d\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'d\'``. |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except\n``\'n\'`` and None). When doing so, ``float()`` is used to convert the\ninteger to a floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'e\'`` | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``, but converts ``nan`` to |\n | | ``NAN`` and ``inf`` to ``INF``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. For a given precision ``p >= 1``, this |\n | | rounds the number to ``p`` significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1`` would have exponent ``exp``. Then if ``-4 <= exp |\n | | < p``, the number is formatted with presentation type |\n | | ``\'f\'`` and precision ``p-1-exp``. Otherwise, the number |\n | | is formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1``. In both cases insignificant trailing zeros are |\n | | removed from the significand, and the decimal point is |\n | | also removed if there are no remaining digits following |\n | | it. Positive and negative infinity, positive and negative |\n | | zero, and nans, are formatted as ``inf``, ``-inf``, ``0``, |\n | | ``-0`` and ``nan`` respectively, regardless of the |\n | | precision. A precision of ``0`` is treated as equivalent |\n | | to a precision of ``1``. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets too large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to ``\'g\'``, except with at least one digit past |\n | | the decimal point and a default precision of 12. This is |\n | | intended to match ``str()``, except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old ``%``-formatting.\n\nIn most of the cases the syntax is similar to the old\n``%``-formatting, with the addition of the ``{}`` and with ``:`` used\ninstead of ``%``. For example, ``\'%03.2f\'`` can be translated to\n``\'{:03.2f}\'``.\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing ``%s`` and ``%r``:\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing ``%x`` and ``%o`` and converting the value to different\nbases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12):\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', + 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that the same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n', 'global': '\nThe ``global`` statement\n************************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe ``global`` statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without ``global``, although free variables may refer to\nglobals without being declared global.\n\nNames listed in a ``global`` statement must not be used in the same\ncode block textually preceding that ``global`` statement.\n\nNames listed in a ``global`` statement must not be defined as formal\nparameters or in a ``for`` loop control target, ``class`` definition,\nfunction definition, or ``import`` statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the latter two restrictions, but programs should not abuse\nthis freedom, as future implementations may enforce them or silently\nchange the meaning of the program.\n\n**Programmer\'s note:** the ``global`` is a directive to the parser.\nIt applies only to code parsed at the same time as the ``global``\nstatement. In particular, a ``global`` statement contained in a string\nor code object supplied to the built-in ``exec()`` function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by ``global`` statements in\nthe code containing the function call. The same applies to the\n``eval()`` and ``compile()`` functions.\n', 'id-classes': '\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', 'identifiers': '\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters ``A`` through ``Z``, the underscore ``_`` and, except for the\nfirst character, the digits ``0`` through ``9``.\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n``unicodedata`` module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= xid_start xid_continue*\n id_start ::= \n id_continue ::= \n xid_start ::= \n xid_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\n* *Other_ID_Start* - explicit list of characters in PropList.txt to\n support backwards compatibility\n\n* *Other_ID_Continue* - likewise\n\nAll identifiers are converted into the normal form NFKC while parsing;\ncomparison of identifiers is based on NFKC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', @@ -53,26 +54,26 @@ 'operator-summary': '\nSummary\n*******\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| ``lambda`` | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| ``if`` -- ``else`` | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| ``or`` | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| ``and`` | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| ``not`` *x* | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``in``, ``not`` ``in``, ``is``, ``is not``, | Comparisons, including membership |\n| ``<``, ``<=``, ``>``, ``>=``, ``!=``, ``==`` | tests and identity tests, |\n+-------------------------------------------------+---------------------------------------+\n| ``|`` | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| ``^`` | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| ``&`` | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| ``<<``, ``>>`` | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| ``+``, ``-`` | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| ``x[index]``, ``x[index:index]``, | Subscription, slicing, call, |\n| ``x(arguments...)``, ``x.attribute`` | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| ``(expressions...)``, ``[expressions...]``, | Binding or tuple display, list |\n| ``{key:datum...}``, ``{expressions...}`` | display, dictionary display, set |\n| | display |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While ``abs(x%y) < abs(y)`` is true mathematically, for floats it\n may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that ``-1e-100 % 1e100`` have the same\n sign as ``1e100``, the computed result is ``-1e-100 + 1e100``,\n which is numerically exactly equal to ``1e100``. The function\n ``math.fmod()`` returns a result whose sign matches the sign of\n the first argument instead, and so returns ``-1e-100`` in this\n case. Which approach is more appropriate depends on the\n application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for ``x//y`` to be one larger than ``(x-x%y)//y`` due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[3] While comparisons between strings make sense at the byte level,\n they may be counter-intuitive to users. For example, the strings\n ``"\\u00C7"`` and ``"\\u0327\\u0043"`` compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using ``unicodedata.normalize()``.\n\n[4] Due to automatic garbage-collection, free lists, and the dynamic\n nature of descriptors, you may notice seemingly unusual behaviour\n in certain uses of the ``is`` operator, like those involving\n comparisons between instance methods, or constants. Check their\n documentation for more info.\n\n[5] The ``%`` operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator ``**`` binds less tightly than an arithmetic or\n bitwise unary operator on its right, that is, ``2**-1`` is\n ``0.5``.\n', 'pass': '\nThe ``pass`` statement\n**********************\n\n pass_stmt ::= "pass"\n\n``pass`` is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): ``-1**2`` results in ``-1``.\n\nThe power operator has the same semantics as the built-in ``pow()``\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n``10**2`` returns ``100``, but ``10**-2`` returns ``0.01``.\n\nRaising ``0.0`` to a negative power results in a\n``ZeroDivisionError``. Raising a negative number to a fractional power\nresults in a ``complex`` number. (In earlier versions it raised a\n``ValueError``.)\n', - 'raise': '\nThe ``raise`` statement\n***********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, ``raise`` re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a ``TypeError`` exception is raised indicating that\nthis is an error (if running under IDLE, a ``queue.Empty`` exception\nis raised instead).\n\nOtherwise, ``raise`` evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n``BaseException``. If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the ``__traceback__`` attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the ``with_traceback()`` exception method (which\nreturns the same exception instance, with its traceback set to its\nargument), like so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe ``from`` clause is used for exception chaining: if given, the\nsecond *expression* must be another exception class or instance, which\nwill then be attached to the raised exception as the ``__cause__``\nattribute (which is writable). If the raised exception is not\nhandled, both exceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s ``__context__`` attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', - 'return': '\nThe ``return`` statement\n************************\n\n return_stmt ::= "return" [expression_list]\n\n``return`` may only occur syntactically nested in a function\ndefinition, not within a nested class definition.\n\nIf an expression list is present, it is evaluated, else ``None`` is\nsubstituted.\n\n``return`` leaves the current function call with the expression list\n(or ``None``) as return value.\n\nWhen ``return`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the function.\n\nIn a generator function, the ``return`` statement is not allowed to\ninclude an ``expression_list``. In that context, a bare ``return``\nindicates that the generator is done and will cause ``StopIteration``\nto be raised.\n', + 'raise': '\nThe ``raise`` statement\n***********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, ``raise`` re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a ``RuntimeError`` exception is raised indicating\nthat this is an error.\n\nOtherwise, ``raise`` evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n``BaseException``. If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the ``__traceback__`` attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the ``with_traceback()`` exception method (which\nreturns the same exception instance, with its traceback set to its\nargument), like so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe ``from`` clause is used for exception chaining: if given, the\nsecond *expression* must be another exception class or instance, which\nwill then be attached to the raised exception as the ``__cause__``\nattribute (which is writable). If the raised exception is not\nhandled, both exceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s ``__context__`` attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', + 'return': '\nThe ``return`` statement\n************************\n\n return_stmt ::= "return" [expression_list]\n\n``return`` may only occur syntactically nested in a function\ndefinition, not within a nested class definition.\n\nIf an expression list is present, it is evaluated, else ``None`` is\nsubstituted.\n\n``return`` leaves the current function call with the expression list\n(or ``None``) as return value.\n\nWhen ``return`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the function.\n\nIn a generator function, the ``return`` statement indicates that the\ngenerator is done and will cause ``StopIteration`` to be raised. The\nreturned value (if any) is used as an argument to construct\n``StopIteration`` and becomes the ``StopIteration.value`` attribute.\n', 'sequence-types': "\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python's standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping's keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn't define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don't define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n", 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as division by ``pow(2,n)``. A\nleft shift by *n* bits is defined as multiplication with ``pow(2,n)``.\n\nNote: In the current implementation, the right-hand operand is required to\n be at most ``sys.maxsize``. If the right-hand operand is larger\n than ``sys.maxsize`` an ``OverflowError`` exception is raised.\n', 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or ``del`` statements. The syntax for a\nslicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same\n``__getitem__()`` method as normal subscription) with a key that is\nconstructed from the slice list, as follows. If the slice list\ncontains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n``start``, ``stop`` and ``step`` attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting ``None`` for missing expressions.\n', - 'specialattrs': "\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object's\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nThe following attributes are only supported by *new-style class*es.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each new-style class keeps a list of weak references to its\n immediate subclasses. This method returns a list of all those\n references still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can't tell the type of the\n operands.\n\n[4] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n", - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', - 'string-methods': '\nString Methods\n**************\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n', - 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "R"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` or\n``bytesprefix`` and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (4) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (5) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n5. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default). Exactly eight hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', + 'specialattrs': '\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object\'s\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nclass.__qualname__\n\n The *qualified name* of the class or type.\n\n New in version 3.3.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each class keeps a list of weak references to its immediate\n subclasses. This method returns a list of all those references\n still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] Cased characters are those with general category property being\n one of "Lu" (Letter, uppercase), "Ll" (Letter, lowercase), or "Lt"\n (Letter, titlecase).\n\n[5] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n', + 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__bytes__(self)\n\n Called by ``bytes()`` to compute a byte-string representation of an\n object. This should return a ``bytes`` object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\n Note: Note by default the ``__hash__()`` values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the order in which keys are\n retrieved from a dict. Note Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also ``PYTHONHASHSEED``.\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', + 'string-methods': '\nString Methods\n**************\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter ``\'\xc3\x9f\'`` is equivalent to\n ``"ss"``. Since it is already lowercase, ``lower()`` would do\n nothing to ``\'\xc3\x9f\'``; ``casefold()`` converts it to ``"ss"``.\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by zero or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\n Note: The ``find()`` method should be used only if you need to know the\n position of *sub*. To check if *sub* is a substring or not, use\n the ``in`` operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *iterable*, including ``bytes`` objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n ``s.swapcase().swapcase() == s``.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that ``str.upper().isupper()`` might\n be ``False`` if ``s`` contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than or equal to ``len(s)``.\n', + 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` or\n``bytesprefix`` and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nAs of Python 3.3 it is possible again to prefix unicode strings with a\n``u`` prefix to simplify maintenance of dual 2.x and 3.x codebases.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially.\n\n New in version 3.3: The ``\'rb\'`` prefix of raw bytes literals has\n been added as a synonym of ``\'br\'``.\n\n New in version 3.3: Support for the unicode legacy literal\n (``u\'value\'``) and other versions were reintroduced to simplify the\n maintenance of dual Python 2.x and 3.x codebases. See **PEP 414**\n for more information.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | (4) |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (5) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (6) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Changed in version 3.3: Support for name aliases [1] has been\n added.\n\n5. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n6. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default). Exactly eight hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a ``__getitem__()`` method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a ``__getitem__()``\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that ``x[-1]`` selects the last item of\n``x``). The resulting value must be a nonnegative integer less than\nthe number of items in the sequence, and the subscription selects the\nitem whose index is that value (counting from zero). Since the support\nfor negative indices and slicing occurs in the object\'s\n``__getitem__()`` method, subclasses overriding this method will need\nto explicitly add that support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', 'truth': "\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an ``if`` or\n``while`` condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* ``None``\n\n* ``False``\n\n* zero of any numeric type, for example, ``0``, ``0.0``, ``0j``.\n\n* any empty sequence, for example, ``''``, ``()``, ``[]``.\n\n* any empty mapping, for example, ``{}``.\n\n* instances of user-defined classes, if the class defines a\n ``__bool__()`` or ``__len__()`` method, when that method returns the\n integer zero or ``bool`` value ``False``. [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn ``0`` or ``False`` for false and ``1`` or ``True`` for true,\nunless otherwise stated. (Important exception: the Boolean operations\n``or`` and ``and`` always return one of their operands.)\n", - 'try': '\nThe ``try`` statement\n*********************\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n', - 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name ``None``.\n It is used to signify the absence of a value in many situations,\n e.g., it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n ``NotImplemented``. Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal ``...`` or the\n built-in name ``Ellipsis``. Its truth value is true.\n\n``numbers.Number``\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n ``numbers.Integral``\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers (``int``)\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans (``bool``)\n These represent the truth values False and True. The two\n objects representing the values False and True are the only\n Boolean objects. The Boolean type is a subtype of the integer\n type, and Boolean values behave like the values 0 and 1,\n respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ``"False"`` or\n ``"True"`` are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n ``numbers.Real`` (``float``)\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n ``numbers.Complex`` (``complex``)\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n The items of a string object are Unicode code units. A\n Unicode code unit is represented by a string object of one\n item and can hold either a 16-bit or 32-bit value\n representing a Unicode ordinal (the maximum value for the\n ordinal is given in ``sys.maxunicode``, and depends on how\n Python is configured at compile time). Surrogate pairs may\n be present in the Unicode object, and will be reported as two\n separate items. The built-in functions ``chr()`` and\n ``ord()`` convert between code units and nonnegative integers\n representing the Unicode ordinals as defined in the Unicode\n Standard 3.0. Conversion from and to other encodings are\n possible through the string method ``encode()``.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like ``b\'abc\'`` and the built-in function\n ``bytes()`` can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the ``decode()``\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and ``del`` (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in ``bytearray()`` constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module ``array`` provides an additional example of\n a mutable sequence type, as does the ``collections`` module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function ``len()``\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n ``set()`` constructor and can be modified afterwards by several\n methods, such as ``add()``.\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in ``frozenset()`` constructor. As a frozenset is\n immutable and *hashable*, it can be used again as an element of\n another set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation ``a[k]`` selects the item indexed by\n ``k`` from the mapping ``a``; this can be used in expressions and\n as the target of assignments or ``del`` statements. The built-in\n function ``len()`` returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``) then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the ``{...}``\n notation (see section *Dictionary displays*).\n\n The extension modules ``dbm.ndbm`` and ``dbm.gnu`` provide\n additional examples of mapping types, as does the\n ``collections`` module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | ``__doc__`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | ``__module__`` | The name of the module the | Writable |\n | | function was defined in, or | |\n | | ``None`` if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | ``__defaults__`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +---------------------------+---------------------------------+-------------+\n | ``__code__`` | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | ``__dict__`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | | that contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | ``__annotations__`` | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | or ``\'return\'`` for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | ``__kwdefaults__`` | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: ``__self__`` is the class instance\n object, ``__func__`` is the function object; ``__doc__`` is the\n method\'s documentation (same as ``__func__.__doc__``);\n ``__name__`` is the method name (same as ``__func__.__name__``);\n ``__module__`` is the name of the module the method was defined\n in, or ``None`` if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its ``__self__`` attribute is the instance, and the method\n object is said to be bound. The new method\'s ``__func__``\n attribute is the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the ``__func__``\n attribute of the new instance is not the original method object\n but its ``__func__`` attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its ``__self__``\n attribute is the class itself, and its ``__func__`` attribute is\n the function object underlying the class method.\n\n When an instance method object is called, the underlying\n function (``__func__``) is called, inserting the class instance\n (``__self__``) in front of the argument list. For instance,\n when ``C`` is a class which contains a definition for a function\n ``f()``, and ``x`` is an instance of ``C``, calling ``x.f(1)``\n is equivalent to calling ``C.f(x, 1)``.\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in ``__self__`` will\n actually be the class itself, so that calling either ``x.f(1)``\n or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is\n the underlying function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``__next__()`` method will cause the function to\n execute until it provides a value using the ``yield`` statement.\n When the function executes a ``return`` statement or falls off\n the end, a ``StopIteration`` exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override ``__new__()``. The arguments of the\n call are passed to ``__new__()`` and, in the typical case, to\n ``__init__()`` to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a ``__call__()`` method in their class.\n\nModules\n Modules are imported by the ``import`` statement (see section *The\n import statement*). A module object has a namespace implemented by\n a dictionary object (this is the dictionary referenced by the\n __globals__ attribute of functions defined in the module).\n Attribute references are translated to lookups in this dictionary,\n e.g., ``m.x`` is equivalent to ``m.__dict__["x"]``. A module object\n does not contain the code object used to initialize the module\n (since it isn\'t needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute is not present for C modules that are\n statically linked into the interpreter; for extension modules\n loaded dynamically from a shared library, it is the pathname of the\n shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., ``C.x`` is translated to\n ``C.__dict__["x"]`` (although there are a number of hooks which\n allow for other means of locating attributes). When the attribute\n name is not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a class method object, it is transformed into an instance method\n object whose ``__self__`` attributes is ``C``. When it would yield\n a static method object, it is transformed into the object wrapped\n by the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its ``__dict__``.\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: ``__name__`` is the class name; ``__module__``\n is the module name in which the class was defined; ``__dict__`` is\n the dictionary containing the class\'s namespace; ``__bases__`` is a\n tuple (possibly empty or a singleton) containing the base classes,\n in the order of their occurrence in the base class list;\n ``__doc__`` is the class\'s documentation string, or None if\n undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose ``__self__`` attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s\n ``__dict__``. If no class attribute is found, and the object\'s\n class has a ``__getattr__()`` method, that is called to satisfy the\n lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n ``__setattr__()`` or ``__delattr__()`` method, this is called\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the ``open()`` built-in function,\n and also ``os.popen()``, ``os.fdopen()``, and the ``makefile()``\n method of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n ``io.TextIOBase`` abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_lasti`` gives the precise instruction (this is an index into\n the bytecode string of the code object).\n\n Special writable attributes: ``f_trace``, if not ``None``, is a\n function called at the start of each source code line (this is\n used by the debugger); ``f_lineno`` is the current line number\n of the frame --- writing to this from within a trace function\n jumps to the given line (only for the bottom-most frame). A\n debugger can implement a Jump command (aka Set Next Statement)\n by writing to f_lineno.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by ``sys.exc_info()``. When the program contains\n no suitable handler, the stack trace is written (nicely\n formatted) to the standard error stream; if the interpreter is\n interactive, it is also made available to the user as\n ``sys.last_traceback``.\n\n Special read-only attributes: ``tb_next`` is the next level in\n the stack trace (towards the frame where the exception\n occurred), or ``None`` if there is no next level; ``tb_frame``\n points to the execution frame of the current level;\n ``tb_lineno`` gives the line number where the exception\n occurred; ``tb_lasti`` indicates the precise instruction. The\n line number and last instruction in the traceback may differ\n from the line number of its frame object if the exception\n occurred in a ``try`` statement with no matching except clause\n or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for ``__getitem__()``\n methods. They are also created by the built-in ``slice()``\n function.\n\n Special read-only attributes: ``start`` is the lower bound;\n ``stop`` is the upper bound; ``step`` is the step value; each is\n ``None`` if omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n ``staticmethod()`` constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in ``classmethod()`` constructor.\n', + 'try': '\nThe ``try`` statement\n*********************\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is set as the context of the new exception. The exception\ninformation is not available to the program during execution of the\n``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n', + 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name ``None``.\n It is used to signify the absence of a value in many situations,\n e.g., it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n ``NotImplemented``. Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal ``...`` or the\n built-in name ``Ellipsis``. Its truth value is true.\n\n``numbers.Number``\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n ``numbers.Integral``\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers (``int``)\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans (``bool``)\n These represent the truth values False and True. The two\n objects representing the values False and True are the only\n Boolean objects. The Boolean type is a subtype of the integer\n type, and Boolean values behave like the values 0 and 1,\n respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ``"False"`` or\n ``"True"`` are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n ``numbers.Real`` (``float``)\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n ``numbers.Complex`` (``complex``)\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode\n codepoints. All the codepoints in range ``U+0000 - U+10FFFF``\n can be represented in a string. Python doesn\'t have a\n ``chr`` type, and every character in the string is\n represented as a string object with length ``1``. The built-\n in function ``ord()`` converts a character to its codepoint\n (as an integer); ``chr()`` converts an integer in range ``0 -\n 10FFFF`` to the corresponding character. ``str.encode()`` can\n be used to convert a ``str`` to ``bytes`` using the given\n encoding, and ``bytes.decode()`` can be used to achieve the\n opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like ``b\'abc\'`` and the built-in function\n ``bytes()`` can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the ``decode()``\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and ``del`` (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in ``bytearray()`` constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module ``array`` provides an additional example of\n a mutable sequence type, as does the ``collections`` module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function ``len()``\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n ``set()`` constructor and can be modified afterwards by several\n methods, such as ``add()``.\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in ``frozenset()`` constructor. As a frozenset is\n immutable and *hashable*, it can be used again as an element of\n another set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation ``a[k]`` selects the item indexed by\n ``k`` from the mapping ``a``; this can be used in expressions and\n as the target of assignments or ``del`` statements. The built-in\n function ``len()`` returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``) then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the ``{...}``\n notation (see section *Dictionary displays*).\n\n The extension modules ``dbm.ndbm`` and ``dbm.gnu`` provide\n additional examples of mapping types, as does the\n ``collections`` module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | ``__doc__`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | ``__qualname__`` | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | ``__module__`` | The name of the module the | Writable |\n | | function was defined in, or | |\n | | ``None`` if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | ``__defaults__`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +---------------------------+---------------------------------+-------------+\n | ``__code__`` | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | ``__dict__`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | | that contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | ``__annotations__`` | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | or ``\'return\'`` for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | ``__kwdefaults__`` | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: ``__self__`` is the class instance\n object, ``__func__`` is the function object; ``__doc__`` is the\n method\'s documentation (same as ``__func__.__doc__``);\n ``__name__`` is the method name (same as ``__func__.__name__``);\n ``__module__`` is the name of the module the method was defined\n in, or ``None`` if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its ``__self__`` attribute is the instance, and the method\n object is said to be bound. The new method\'s ``__func__``\n attribute is the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the ``__func__``\n attribute of the new instance is not the original method object\n but its ``__func__`` attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its ``__self__``\n attribute is the class itself, and its ``__func__`` attribute is\n the function object underlying the class method.\n\n When an instance method object is called, the underlying\n function (``__func__``) is called, inserting the class instance\n (``__self__``) in front of the argument list. For instance,\n when ``C`` is a class which contains a definition for a function\n ``f()``, and ``x`` is an instance of ``C``, calling ``x.f(1)``\n is equivalent to calling ``C.f(x, 1)``.\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in ``__self__`` will\n actually be the class itself, so that calling either ``x.f(1)``\n or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is\n the underlying function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``__next__()`` method will cause the function to\n execute until it provides a value using the ``yield`` statement.\n When the function executes a ``return`` statement or falls off\n the end, a ``StopIteration`` exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override ``__new__()``. The arguments of the\n call are passed to ``__new__()`` and, in the typical case, to\n ``__init__()`` to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a ``__call__()`` method in their class.\n\nModules\n Modules are imported by the ``import`` statement (see section *The\n import statement*). A module object has a namespace implemented by\n a dictionary object (this is the dictionary referenced by the\n __globals__ attribute of functions defined in the module).\n Attribute references are translated to lookups in this dictionary,\n e.g., ``m.x`` is equivalent to ``m.__dict__["x"]``. A module object\n does not contain the code object used to initialize the module\n (since it isn\'t needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute is not present for C modules that are\n statically linked into the interpreter; for extension modules\n loaded dynamically from a shared library, it is the pathname of the\n shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., ``C.x`` is translated to\n ``C.__dict__["x"]`` (although there are a number of hooks which\n allow for other means of locating attributes). When the attribute\n name is not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a class method object, it is transformed into an instance method\n object whose ``__self__`` attributes is ``C``. When it would yield\n a static method object, it is transformed into the object wrapped\n by the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its ``__dict__``.\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: ``__name__`` is the class name; ``__module__``\n is the module name in which the class was defined; ``__dict__`` is\n the dictionary containing the class\'s namespace; ``__bases__`` is a\n tuple (possibly empty or a singleton) containing the base classes,\n in the order of their occurrence in the base class list;\n ``__doc__`` is the class\'s documentation string, or None if\n undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose ``__self__`` attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s\n ``__dict__``. If no class attribute is found, and the object\'s\n class has a ``__getattr__()`` method, that is called to satisfy the\n lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n ``__setattr__()`` or ``__delattr__()`` method, this is called\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the ``open()`` built-in function,\n and also ``os.popen()``, ``os.fdopen()``, and the ``makefile()``\n method of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n ``io.TextIOBase`` abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_lasti`` gives the precise instruction (this is an index into\n the bytecode string of the code object).\n\n Special writable attributes: ``f_trace``, if not ``None``, is a\n function called at the start of each source code line (this is\n used by the debugger); ``f_lineno`` is the current line number\n of the frame --- writing to this from within a trace function\n jumps to the given line (only for the bottom-most frame). A\n debugger can implement a Jump command (aka Set Next Statement)\n by writing to f_lineno.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by ``sys.exc_info()``. When the program contains\n no suitable handler, the stack trace is written (nicely\n formatted) to the standard error stream; if the interpreter is\n interactive, it is also made available to the user as\n ``sys.last_traceback``.\n\n Special read-only attributes: ``tb_next`` is the next level in\n the stack trace (towards the frame where the exception\n occurred), or ``None`` if there is no next level; ``tb_frame``\n points to the execution frame of the current level;\n ``tb_lineno`` gives the line number where the exception\n occurred; ``tb_lasti`` indicates the precise instruction. The\n line number and last instruction in the traceback may differ\n from the line number of its frame object if the exception\n occurred in a ``try`` statement with no matching except clause\n or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for ``__getitem__()``\n methods. They are also created by the built-in ``slice()``\n function.\n\n Special read-only attributes: ``start`` is the lower bound;\n ``stop`` is the upper bound; ``step`` is the step value; each is\n ``None`` if omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n ``staticmethod()`` constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in ``classmethod()`` constructor.\n', 'typesfunctions': '\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: ``func(argument-list)``.\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', - 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict([arg])\n\n Return a new dictionary initialized from an optional positional\n argument or from a set of keyword arguments. If no arguments are\n given, return a new empty dictionary. If the positional argument\n *arg* is a mapping object, return a dictionary mapping the same\n keys to the same values as does the mapping object. Otherwise the\n positional argument must be a sequence, a container that supports\n iteration, or an iterator object. The elements of the argument\n must each also be of one of those kinds, and each must in turn\n contain exactly two objects. The first is used as a key in the new\n dictionary, and the second as the key\'s value. If a given key is\n seen more than once, the last value associated with it is retained\n in the new dictionary.\n\n If keyword arguments are given, the keywords themselves with their\n associated values are added as items to the dictionary. If a key\n is specified both in the positional argument and as a keyword\n argument, the value associated with the keyword is retained in the\n dictionary. For example, these all return a dictionary equal to\n ``{"one": 1, "two": 2}``:\n\n * ``dict(one=1, two=2)``\n\n * ``dict({\'one\': 1, \'two\': 2})``\n\n * ``dict(zip((\'one\', \'two\'), (1, 2)))``\n\n * ``dict([[\'two\', 2], [\'one\', 1]])``\n\n The first example only works for keys that are valid Python\n identifiers; the others work with any valid keys.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See ``collections.Counter`` for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iter(d.keys())``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See below for documentation of view objects.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: ``d.update(red=1,\n blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that ``(key, value)`` pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class ``collections.Set`` are available (for example, ``==``,\n``<``, or ``^``).\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'eggs\', \'bacon\', \'spam\'}\n', + 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict([arg])\n\n Return a new dictionary initialized from an optional positional\n argument or from a set of keyword arguments. If no arguments are\n given, return a new empty dictionary. If the positional argument\n *arg* is a mapping object, return a dictionary mapping the same\n keys to the same values as does the mapping object. Otherwise the\n positional argument must be a sequence, a container that supports\n iteration, or an iterator object. The elements of the argument\n must each also be of one of those kinds, and each must in turn\n contain exactly two objects. The first is used as a key in the new\n dictionary, and the second as the key\'s value. If a given key is\n seen more than once, the last value associated with it is retained\n in the new dictionary.\n\n If keyword arguments are given, the keywords themselves with their\n associated values are added as items to the dictionary. If a key\n is specified both in the positional argument and as a keyword\n argument, the value associated with the keyword is retained in the\n dictionary. For example, these all return a dictionary equal to\n ``{"one": 1, "two": 2}``:\n\n * ``dict(one=1, two=2)``\n\n * ``dict({\'one\': 1, \'two\': 2})``\n\n * ``dict(zip((\'one\', \'two\'), (1, 2)))``\n\n * ``dict([[\'two\', 2], [\'one\', 1]])``\n\n The first example only works for keys that are valid Python\n identifiers; the others work with any valid keys.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See ``collections.Counter`` for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iter(d.keys())``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See below for documentation of view objects.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: ``d.update(red=1,\n blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that ``(key, value)`` pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class ``collections.Set`` are available (for example, ``==``,\n``<``, or ``^``).\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', 'typesmethods': "\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as ``append()`` on\nlists) and class instance methods. Built-in methods are described\nwith the types that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the\n``self`` argument to the argument list. Bound methods have two\nspecial read-only attributes: ``m.__self__`` is the object on which\nthe method operates, and ``m.__func__`` is the function implementing\nthe method. Calling ``m(arg-1, arg-2, ..., arg-n)`` is completely\nequivalent to calling ``m.__func__(m.__self__, arg-1, arg-2, ...,\narg-n)``.\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object (``meth.__func__``), setting method\nattributes on bound methods is disallowed. Attempting to set a method\nattribute results in a ``TypeError`` being raised. In order to set a\nmethod attribute, you need to explicitly set it on the underlying\nfunction object:\n\n class C:\n def method(self):\n pass\n\n c = C()\n c.method.__func__.whoami = 'my name is c'\n\nSee *The standard type hierarchy* for more information.\n", - 'typesmodules': "\nModules\n*******\n\nThe only special operation on a module is attribute access:\n``m.name``, where *m* is a module and *name* accesses a name defined\nin *m*'s symbol table. Module attributes can be assigned to. (Note\nthat the ``import`` statement is not, strictly speaking, an operation\non a module object; ``import foo`` does not require a module object\nnamed *foo* to exist, rather it requires an (external) *definition*\nfor a module named *foo* somewhere.)\n\nA special member of every module is ``__dict__``. This is the\ndictionary containing the module's symbol table. Modifying this\ndictionary will actually change the module's symbol table, but direct\nassignment to the ``__dict__`` attribute is not possible (you can\nwrite ``m.__dict__['a'] = 1``, which defines ``m.a`` to be ``1``, but\nyou can't write ``m.__dict__ = {}``). Modifying ``__dict__`` directly\nis not recommended.\n\nModules built into the interpreter are written like this: ````. If loaded from a file, they are written as\n````.\n", - 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWhile string objects are sequences of characters (represented by\nstrings of length 1), bytes and bytearray objects are sequences of\n*integers* (between 0 and 255), representing the ASCII value of single\nbytes. That means that for a bytes or bytearray object *b*, ``b[0]``\nwill be an integer, while ``b[0:1]`` will be a bytes or bytearray\nobject of length 1. The representation of bytes objects uses the\nliteral format (``b\'...\'``) since it is generally more useful than\ne.g. ``bytes([50, 19, 100])``. You can always convert a bytes object\ninto a list of integers using ``list(b)``.\n\nAlso, while in previous Python versions, byte strings and Unicode\nstrings could be exchanged for each other rather freely (barring\nencoding issues), strings and bytes are now completely separate\nconcepts. There\'s no implicit en-/decoding if you pass an object of\nthe wrong type. A string always compares unequal to a bytes or\nbytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support concatenation or repetition, and using ``min()`` or\n``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i*, *j* and *k* are\nintegers.\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*\'th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.index(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. **CPython implementation detail:** If *s* and *t* are both strings,\n some Python implementations such as CPython can usually perform an\n in-place optimization for assignments of the form ``s = s + t`` or\n ``s += t``. When applicable, this optimization makes quadratic\n run-time much less likely. This optimization is both version and\n implementation dependent. For performance sensitive code, it is\n preferable to use the ``str.join()`` method which assures\n consistent linear concatenation performance across versions and\n implementations.\n\n\nString Methods\n==============\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are obsolete and may go\n away in future versions of Python. Use the new *String Formatting*\n in new code.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [4] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(number)03d quote types.\' %\n... {\'language\': "Python", "number": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The precision determines the maximal number of characters used.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents.\n\nRange objects have relatively little behavior: they support indexing,\ncontains, iteration, the ``len()`` function, and the following\nmethods:\n\nrange.count(x)\n\n Return the number of *i*\'s for which ``s[i] == x``.\n\n New in version 3.2.\n\nrange.index(x)\n\n Return the smallest *i* such that ``s[i] == x``. Raises\n ``ValueError`` when *x* is not in the range.\n\n New in version 3.2.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | remove all items from ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | return a shallow copy of ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode(encoding="utf-8", errors="strict")\nbytearray.decode(encoding="utf-8", errors="strict")\n\n Return a string decoded from the given bytes. Default encoding is\n ``\'utf-8\'``. *errors* may be given to set a different error\n handling scheme. The default for *errors* is ``\'strict\'``, meaning\n that encoding errors raise a ``UnicodeError``. Other possible\n values are ``\'ignore\'``, ``\'replace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Added support for keyword arguments.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', + 'typesmodules': "\nModules\n*******\n\nThe only special operation on a module is attribute access:\n``m.name``, where *m* is a module and *name* accesses a name defined\nin *m*'s symbol table. Module attributes can be assigned to. (Note\nthat the ``import`` statement is not, strictly speaking, an operation\non a module object; ``import foo`` does not require a module object\nnamed *foo* to exist, rather it requires an (external) *definition*\nfor a module named *foo* somewhere.)\n\nA special attribute of every module is ``__dict__``. This is the\ndictionary containing the module's symbol table. Modifying this\ndictionary will actually change the module's symbol table, but direct\nassignment to the ``__dict__`` attribute is not possible (you can\nwrite ``m.__dict__['a'] = 1``, which defines ``m.a`` to be ``1``, but\nyou can't write ``m.__dict__ = {}``). Modifying ``__dict__`` directly\nis not recommended.\n\nModules built into the interpreter are written like this: ````. If loaded from a file, they are written as\n````.\n", + 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWhile string objects are sequences of characters (represented by\nstrings of length 1), bytes and bytearray objects are sequences of\n*integers* (between 0 and 255), representing the ASCII value of single\nbytes. That means that for a bytes or bytearray object *b*, ``b[0]``\nwill be an integer, while ``b[0:1]`` will be a bytes or bytearray\nobject of length 1. The representation of bytes objects uses the\nliteral format (``b\'...\'``) since it is generally more useful than\ne.g. ``bytes([50, 19, 100])``. You can always convert a bytes object\ninto a list of integers using ``list(b)``.\n\nAlso, while in previous Python versions, byte strings and Unicode\nstrings could be exchanged for each other rather freely (barring\nencoding issues), strings and bytes are now completely separate\nconcepts. There\'s no implicit en-/decoding if you pass an object of\nthe wrong type. A string always compares unequal to a bytes or\nbytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support concatenation or repetition, and using ``min()`` or\n``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i*, *j* and *k* are\nintegers.\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.index(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. Concatenating immutable strings always results in a new object.\n This means that building up a string by repeated concatenation will\n have a quadratic runtime cost in the total string length. To get a\n linear runtime cost, you must switch to one of the alternatives\n below:\n\n * if concatenating ``str`` objects, you can build a list and use\n ``str.join()`` at the end;\n\n * if concatenating ``bytes`` objects, you can similarly use\n ``bytes.join()``, or you can do in-place concatenation with a\n ``bytearray`` object. ``bytearray`` objects are mutable and have\n an efficient overallocation mechanism.\n\n\nString Methods\n==============\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter ``\'\xc3\x9f\'`` is equivalent to\n ``"ss"``. Since it is already lowercase, ``lower()`` would do\n nothing to ``\'\xc3\x9f\'``; ``casefold()`` converts it to ``"ss"``.\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by zero or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\n Note: The ``find()`` method should be used only if you need to know the\n position of *sub*. To check if *sub* is a substring or not, use\n the ``in`` operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *iterable*, including ``bytes`` objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n ``s.swapcase().swapcase() == s``.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that ``str.upper().isupper()`` might\n be ``False`` if ``s`` contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than or equal to ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are modelled on C\'s\n printf() syntax. They only support formatting of certain builtin\n types. The use of a binary operator means that care may be needed\n in order to format tuples and dictionaries correctly. As the new\n *String Formatting* syntax is more flexible and handles tuples and\n dictionaries naturally, it is recommended for new code. However,\n there are no current plans to deprecate printf-style formatting.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [5] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual\n precision is read from the next element of the tuple in *values*,\n and the value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(number)03d quote types.\' %\n... {\'language\': "Python", "number": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'a\'`` | String (converts any Python object using | (5) |\n| | ``ascii()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. If precision is ``N``, the output is truncated to ``N`` characters.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents.\n\nRange objects have relatively little behavior: they support indexing,\ncontains, iteration, the ``len()`` function, and the following\nmethods:\n\nrange.count(x)\n\n Return the number of *i*\'s for which ``s[i] == x``.\n\n New in version 3.2.\n\nrange.index(x)\n\n Return the smallest *i* such that ``s[i] == x``. Raises\n ``ValueError`` when *x* is not in the range.\n\n New in version 3.2.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | remove all items from ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | return a shallow copy of ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNew in version 3.3: The functions ``count()``, ``find()``,\n``index()``, ``rfind()`` and ``rindex()`` have additional semantics\ncompared to the corresponding string functions: They also accept an\ninteger in range 0 to 255 (a byte) as their first argument.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode(encoding="utf-8", errors="strict")\nbytearray.decode(encoding="utf-8", errors="strict")\n\n Return a string decoded from the given bytes. Default encoding is\n ``\'utf-8\'``. *errors* may be given to set a different error\n handling scheme. The default for *errors* is ``\'strict\'``, meaning\n that encoding errors raise a ``UnicodeError``. Other possible\n values are ``\'ignore\'``, ``\'replace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Added support for keyword arguments.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | remove all items from ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | return a shallow copy of ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n', 'unary': '\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary ``-`` (minus) operator yields the negation of its numeric\nargument.\n\nThe unary ``+`` (plus) operator yields its numeric argument unchanged.\n\nThe unary ``~`` (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of ``x`` is defined as\n``-(x+1)``. It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n``TypeError`` exception is raised.\n', 'while': '\nThe ``while`` statement\n***********************\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n', 'with': '\nThe ``with`` statement\n**********************\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', - 'yield': '\nThe ``yield`` statement\n***********************\n\n yield_stmt ::= yield_expression\n\nThe ``yield`` statement is only used when defining a generator\nfunction, and is only used in the body of the generator function.\nUsing a ``yield`` statement in a function definition is sufficient to\ncause that definition to create a generator function instead of a\nnormal function. When a generator function is called, it returns an\niterator known as a generator iterator, or more commonly, a generator.\nThe body of the generator function is executed by calling the\n``next()`` function on the generator repeatedly until it raises an\nexception.\n\nWhen a ``yield`` statement is executed, the state of the generator is\nfrozen and the value of ``expression_list`` is returned to\n``next()``\'s caller. By "frozen" we mean that all local state is\nretained, including the current bindings of local variables, the\ninstruction pointer, and the internal evaluation stack: enough\ninformation is saved so that the next time ``next()`` is invoked, the\nfunction can proceed exactly as if the ``yield`` statement were just\nanother external call.\n\nThe ``yield`` statement is allowed in the ``try`` clause of a ``try``\n... ``finally`` construct. If the generator is not resumed before it\nis finalized (by reaching a zero reference count or by being garbage\ncollected), the generator-iterator\'s ``close()`` method will be\ncalled, allowing any pending ``finally`` clauses to execute.\n\nSee also:\n\n **PEP 0255** - Simple Generators\n The proposal for adding generators and the ``yield`` statement\n to Python.\n\n **PEP 0342** - Coroutines via Enhanced Generators\n The proposal that, among other generator enhancements, proposed\n allowing ``yield`` to appear inside a ``try`` ... ``finally``\n block.\n'} + 'yield': '\nThe ``yield`` statement\n***********************\n\n yield_stmt ::= yield_expression\n\nThe ``yield`` statement is only used when defining a generator\nfunction, and is only used in the body of the generator function.\nUsing a ``yield`` statement in a function definition is sufficient to\ncause that definition to create a generator function instead of a\nnormal function.\n\nWhen a generator function is called, it returns an iterator known as a\ngenerator iterator, or more commonly, a generator. The body of the\ngenerator function is executed by calling the ``next()`` function on\nthe generator repeatedly until it raises an exception.\n\nWhen a ``yield`` statement is executed, the state of the generator is\nfrozen and the value of ``expression_list`` is returned to\n``next()``\'s caller. By "frozen" we mean that all local state is\nretained, including the current bindings of local variables, the\ninstruction pointer, and the internal evaluation stack: enough\ninformation is saved so that the next time ``next()`` is invoked, the\nfunction can proceed exactly as if the ``yield`` statement were just\nanother external call.\n\nThe ``yield`` statement is allowed in the ``try`` clause of a ``try``\n... ``finally`` construct. If the generator is not resumed before it\nis finalized (by reaching a zero reference count or by being garbage\ncollected), the generator-iterator\'s ``close()`` method will be\ncalled, allowing any pending ``finally`` clauses to execute.\n\nWhen ``yield from `` is used, it treats the supplied expression\nas a subiterator, producing values from it until the underlying\niterator is exhausted.\n\n Changed in version 3.3: Added ``yield from `` to delegate\n control flow to a subiterator\n\nFor full details of ``yield`` semantics, refer to the *Yield\nexpressions* section.\n\nSee also:\n\n **PEP 0255** - Simple Generators\n The proposal for adding generators and the ``yield`` statement\n to Python.\n\n **PEP 0342** - Coroutines via Enhanced Generators\n The proposal to enhance the API and syntax of generators, making\n them usable as simple coroutines.\n\n **PEP 0380** - Syntax for Delegating to a Subgenerator\n The proposal to introduce the ``yield_from`` syntax, making\n delegation to sub-generators easy.\n'} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 16:22:30 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 16:22:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_invalid_markup_and_upda?= =?utf8?q?te_suspicious_ignores=2E?= Message-ID: http://hg.python.org/cpython/rev/b10427df3ab4 changeset: 75386:b10427df3ab4 user: Georg Brandl date: Sun Mar 04 16:17:05 2012 +0100 summary: Fix invalid markup and update suspicious ignores. files: Doc/library/socket.rst | 4 +- Doc/library/sys.rst | 2 +- Doc/tools/sphinxext/susp-ignored.csv | 24 +++++++++++---- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1311,7 +1311,7 @@ import struct - # CAN frame packing/unpacking (see `struct can_frame` in ) + # CAN frame packing/unpacking (see 'struct can_frame' in ) can_frame_fmt = "=IB3x8s" can_frame_size = struct.calcsize(can_frame_fmt) @@ -1326,7 +1326,7 @@ return (can_id, can_dlc, data[:can_dlc]) - # create a raw socket and bind it to the `vcan0` interface + # create a raw socket and bind it to the 'vcan0' interface s = socket.socket(socket.AF_CAN, socket.SOCK_RAW, socket.CAN_RAW) s.bind(('vcan0',)) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -770,7 +770,7 @@ independent Python files are installed; by default, this is the string ``'/usr/local'``. This can be set at build time with the ``--prefix`` argument to the :program:`configure` script. The main collection of Python - library modules is installed in the directory :file:`{prefix}/lib/python{X.Y}`` + library modules is installed in the directory :file:`{prefix}/lib/python{X.Y}` while the platform independent header files (all except :file:`pyconfig.h`) are stored in :file:`{prefix}/include/python{X.Y}`, where *X.Y* is the version number of Python, for example ``3.2``. diff --git a/Doc/tools/sphinxext/susp-ignored.csv b/Doc/tools/sphinxext/susp-ignored.csv --- a/Doc/tools/sphinxext/susp-ignored.csv +++ b/Doc/tools/sphinxext/susp-ignored.csv @@ -112,9 +112,6 @@ library/urllib,,:port,:port library/urllib2,,:password,"""joe:password at python.org""" library/uuid,,:uuid,urn:uuid:12345678-1234-5678-1234-567812345678 -library/xmlrpclib,,:pass,http://user:pass at host:port/path -library/xmlrpclib,,:pass,user:pass -library/xmlrpclib,,:port,http://user:pass at host:port/path license,,`,THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND license,,:zooko,mailto:zooko at zooko.com license,,`,THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND @@ -185,14 +182,13 @@ library/urllib.request,,:close,Connection:close library/urllib.request,,:password,"""joe:password at python.org""" library/urllib.request,,:lang,"xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en"" lang=""en"">\n\n\n" -library/xmlrpc.client,103,:pass,http://user:pass at host:port/path -library/xmlrpc.client,103,:port,http://user:pass at host:port/path -library/xmlrpc.client,103,:pass,user:pass +library/xmlrpc.client,,:pass,http://user:pass at host:port/path +library/xmlrpc.client,,:port,http://user:pass at host:port/path +library/xmlrpc.client,,:pass,user:pass license,,`,* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY license,,`,* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND license,,`,"``Software''), to deal in the Software without restriction, including" license,,`,"THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND," -reference/lexical_analysis,704,`,$ ? ` whatsnew/2.7,735,:Sunday,'2009:4:Sunday' whatsnew/2.7,862,::,"export PYTHONWARNINGS=all,error:::Cookie:0" whatsnew/2.7,862,:Cookie,"export PYTHONWARNINGS=all,error:::Cookie:0" @@ -295,3 +291,17 @@ packaging/tutorial,,::,Type the number of the license you wish to use or ? to try again:: 1 packaging/tutorial,,::,classifier = Development Status :: 3 - Alpha packaging/tutorial,,::,License :: OSI Approved :: GNU General Public License (GPL) +c-api/unicode,,:start,unicode[start:start+length] +library/smtplib,,:port,method must support that as well as a regular host:port +library/socket,,:len,fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) +library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" +library/sqlite3,,:who,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" +library/sqlite3,,:age,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" +library/stdtypes,,::,>>> a[::2].tolist() +library/stdtypes,,::,>>> a[::-1].tolist() +library/stdtypes,,::,>>> hash(v[::-2]) == hash(b'abcefg'[::-2]) +library/stdtypes,,::,>>> y = m[::2] +reference/lexical_analysis,,`,$ ? ` +library/tarfile,,:xz,'r:xz' +library/tarfile,,:xz,'w:xz' +library/tarfile,,:xz,'a:xz' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 16:22:30 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 16:22:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Sort_and_clean_up_suspiciou?= =?utf8?q?s_ignore_file=2E?= Message-ID: http://hg.python.org/cpython/rev/b87cbc1661b5 changeset: 75387:b87cbc1661b5 user: Georg Brandl date: Sun Mar 04 16:22:05 2012 +0100 summary: Sort and clean up suspicious ignore file. files: Doc/tools/sphinxext/susp-ignored.csv | 348 +++++++------- 1 files changed, 170 insertions(+), 178 deletions(-) diff --git a/Doc/tools/sphinxext/susp-ignored.csv b/Doc/tools/sphinxext/susp-ignored.csv --- a/Doc/tools/sphinxext/susp-ignored.csv +++ b/Doc/tools/sphinxext/susp-ignored.csv @@ -1,16 +1,24 @@ c-api/arg,,:ref,"PyArg_ParseTuple(args, ""O|O:ref"", &object, &callback)" c-api/list,,:high,list[low:high] c-api/list,,:high,list[low:high] = itemlist +c-api/sequence,,:i2,del o[i1:i2] c-api/sequence,,:i2,o[i1:i2] c-api/sequence,,:i2,o[i1:i2] = v -c-api/sequence,,:i2,del o[i1:i2] c-api/unicode,,:end,str[start:end] +c-api/unicode,,:start,unicode[start:start+length] +distutils/examples,267,`,This is the description of the ``foobar`` package. distutils/setupscript,,::, extending/embedding,,:numargs,"if(!PyArg_ParseTuple(args, "":numargs""))" +extending/extending,,:myfunction,"PyArg_ParseTuple(args, ""D:myfunction"", &c);" extending/extending,,:set,"if (PyArg_ParseTuple(args, ""O:set_callback"", &temp)) {" -extending/extending,,:myfunction,"PyArg_ParseTuple(args, ""D:myfunction"", &c);" extending/newtypes,,:call,"if (!PyArg_ParseTuple(args, ""sss:call"", &arg1, &arg2, &arg3)) {" extending/windows,,:initspam,/export:initspam +faq/programming,,:chr,">=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(" +faq/programming,,::,for x in sequence[::-1]: +faq/programming,,:reduce,"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y," +faq/programming,,:reduce,"Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro," +faq/windows,229,:EOF, at setlocal enableextensions & python -x %~f0 %* & goto :EOF +faq/windows,393,:REG,.py :REG_SZ: c:\\python.exe -u %s %s howto/cporting,,:add,"if (!PyArg_ParseTuple(args, ""ii:add_ints"", &one, &two))" howto/cporting,,:encode,"if (!PyArg_ParseTuple(args, ""O:encode_object"", &myobj))" howto/cporting,,:say,"if (!PyArg_ParseTuple(args, ""U:say_hello"", &name))" @@ -22,19 +30,53 @@ howto/curses,,:red,"They are: 0:black, 1:red, 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and" howto/curses,,:white,"7:white." howto/curses,,:yellow,"They are: 0:black, 1:red, 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and" +howto/logging,,:And,"WARNING:And this, too" +howto/logging,,:And,"WARNING:root:And this, too" +howto/logging,,:Doing,INFO:root:Doing something +howto/logging,,:Finished,INFO:root:Finished +howto/logging,,:logger,severity:logger name:message +howto/logging,,:Look,WARNING:root:Look before you leap! +howto/logging,,:message,severity:logger name:message +howto/logging,,:root,DEBUG:root:This message should go to the log file +howto/logging,,:root,INFO:root:Doing something +howto/logging,,:root,INFO:root:Finished +howto/logging,,:root,INFO:root:So should this +howto/logging,,:root,INFO:root:Started +howto/logging,,:root,"WARNING:root:And this, too" +howto/logging,,:root,WARNING:root:Look before you leap! +howto/logging,,:root,WARNING:root:Watch out! +howto/logging,,:So,INFO:root:So should this +howto/logging,,:So,INFO:So should this +howto/logging,,:Started,INFO:root:Started +howto/logging,,:This,DEBUG:root:This message should go to the log file +howto/logging,,:This,DEBUG:This message should appear on the console +howto/logging,,:Watch,WARNING:root:Watch out! +howto/pyporting,75,::,# make sure to use :: Python *and* :: Python :: 3 so +howto/pyporting,75,::,"'Programming Language :: Python'," +howto/pyporting,75,::,'Programming Language :: Python :: 3' howto/regex,,::, howto/regex,,:foo,(?:foo) howto/urllib2,,:example,"for example ""joe at password:example.com""" howto/webservers,,.. image:,.. image:: http.png library/audioop,,:ipos,"# factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)]," +library/bisect,32,:hi,all(val >= x for val in a[i:hi]) +library/bisect,42,:hi,all(val > x for val in a[i:hi]) +library/configparser,,:home,my_dir: ${Common:home_dir}/twosheds +library/configparser,,:option,${section:option} +library/configparser,,:path,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} +library/configparser,,:Python,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} +library/configparser,,`,# Set the optional `raw` argument of get() to True if you wish to disable +library/configparser,,:system,path: ${Common:system_dir}/Library/Frameworks/ +library/configparser,,`,# The optional `fallback` argument can be used to provide a fallback value +library/configparser,,`,# The optional `vars` argument is a dict with members that will take library/datetime,,:MM, library/datetime,,:SS, library/decimal,,:optional,"trailneg:optional trailing minus indicator" library/difflib,,:ahi,a[alo:ahi] library/difflib,,:bhi,b[blo:bhi] +library/difflib,,:i1, library/difflib,,:i2, library/difflib,,:j2, -library/difflib,,:i1, library/dis,,:TOS, library/dis,,`,TOS = `TOS` library/doctest,,`,``factorial`` from the ``example`` module: @@ -44,93 +86,164 @@ library/functions,,:stop,"a[start:stop, i]" library/functions,,:stop,a[start:stop:step] library/hotshot,,:lineno,"ncalls tottime percall cumtime percall filename:lineno(function)" +library/http.client,52,:port,host:port library/httplib,,:port,host:port library/imaplib,,:MM,"""DD-Mmm-YYYY HH:MM:SS" library/imaplib,,:SS,"""DD-Mmm-YYYY HH:MM:SS" +library/itertools,,:step,elements from seq[start:stop:step] library/itertools,,:stop,elements from seq[start:stop:step] -library/itertools,,:step,elements from seq[start:stop:step] library/linecache,,:sys,"sys:x:3:3:sys:/dev:/bin/sh" library/logging,,:And, +library/logging,,:Doing,INFO:root:Doing something +library/logging,,:Finished,INFO:root:Finished +library/logging,,:logger,severity:logger name:message +library/logging,,:Look,WARNING:root:Look before you leap! +library/logging,,:message,severity:logger name:message library/logging,,:package1, library/logging,,:package2, +library/logging,,:port,host:port library/logging,,:root, +library/logging,,:So,INFO:root:So should this +library/logging,,:So,INFO:So should this +library/logging,,:Started,INFO:root:Started library/logging,,:This, -library/logging,,:port,host:port +library/logging,,:Watch,WARNING:root:Watch out! +library/logging.handlers,,:port,host:port library/mmap,,:i2,obj[i1:i2] -library/multiprocessing,,:queue,">>> QueueManager.register('get_queue', callable=lambda:queue)" +library/multiprocessing,,`,# Add more tasks using `put()` +library/multiprocessing,,`,# A test file for the `multiprocessing` package +library/multiprocessing,,`,# A test of `multiprocessing.Pool` class +library/multiprocessing,,`,# `BaseManager`. +library/multiprocessing,,`,`Cluster` is a subclass of `SyncManager` so it allows creation of +library/multiprocessing,,`,# create server for a `HostManager` object +library/multiprocessing,,`,# Depends on `multiprocessing` package -- tested with `processing-0.60` +library/multiprocessing,,`,`hostname` gives the name of the host. If hostname is not +library/multiprocessing,,`,# in the original order then consider using `Pool.map()` or library/multiprocessing,,`,">>> l._callmethod('__getitem__', (20,)) # equiv to `l[20]`" library/multiprocessing,,`,">>> l._callmethod('__getslice__', (2, 7)) # equiv to `l[2:7]`" -library/multiprocessing,,`,# `BaseManager`. -library/multiprocessing,,`,# `Pool.imap()` (which will save on the amount of code needed anyway). -library/multiprocessing,,`,# A test file for the `multiprocessing` package -library/multiprocessing,,`,# A test of `multiprocessing.Pool` class -library/multiprocessing,,`,# Add more tasks using `put()` -library/multiprocessing,,`,# create server for a `HostManager` object -library/multiprocessing,,`,# Depends on `multiprocessing` package -- tested with `processing-0.60` -library/multiprocessing,,`,# in the original order then consider using `Pool.map()` or library/multiprocessing,,`,# Not sure if we should synchronize access to `socket.accept()` method by library/multiprocessing,,`,# object. (We import `multiprocessing.reduction` to enable this pickling.) +library/multiprocessing,,`,# `Pool.imap()` (which will save on the amount of code needed anyway). +library/multiprocessing,,:queue,">>> QueueManager.register('get_queue', callable=lambda:queue)" library/multiprocessing,,`,# register the Foo class; make `f()` and `g()` accessible via proxy library/multiprocessing,,`,# register the Foo class; make `g()` and `_h()` accessible via proxy library/multiprocessing,,`,# register the generator function baz; use `GeneratorProxy` to make proxies -library/multiprocessing,,`,`Cluster` is a subclass of `SyncManager` so it allows creation of -library/multiprocessing,,`,`hostname` gives the name of the host. If hostname is not library/multiprocessing,,`,`slots` is used to specify the number of slots for processes on +library/nntplib,,:bytes,:bytes +library/nntplib,,:bytes,"['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']" +library/nntplib,,:lines,:lines +library/nntplib,,:lines,"['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']" library/optparse,,:len,"del parser.rargs[:len(value)]" library/os.path,,:foo,c:foo library/parser,,`,"""Make a function that raises an argument to the exponent `exp`.""" +library/pdb,,:lineno,filename:lineno +library/pdb,,:lineno,[filename:lineno | bpnumber [bpnumber ...]] +library/pickle,,:memory,"conn = sqlite3.connect("":memory:"")" library/posix,,`,"CFLAGS=""`getconf LFS_CFLAGS`"" OPT=""-g -O2 $CFLAGS""" +library/pprint,209,::,"'classifiers': ['Development Status :: 4 - Beta'," +library/pprint,209,::,"'Intended Audience :: Developers'," +library/pprint,209,::,"'License :: OSI Approved :: MIT License'," +library/pprint,209,::,"'Natural Language :: English'," +library/pprint,209,::,"'Operating System :: OS Independent'," +library/pprint,209,::,"'Programming Language :: Python'," +library/pprint,209,::,"'Programming Language :: Python :: 2'," +library/pprint,209,::,"'Programming Language :: Python :: 2.6'," +library/pprint,209,::,"'Programming Language :: Python :: 2.7'," +library/pprint,209,::,"'Topic :: Software Development :: Libraries'," +library/pprint,209,::,"'Topic :: Software Development :: Libraries :: Python Modules']," +library/profile,,:lineno,filename:lineno(function) library/profile,,:lineno,ncalls tottime percall cumtime percall filename:lineno(function) -library/profile,,:lineno,filename:lineno(function) +library/profile,,:lineno,"(sort by filename:lineno)," library/pyexpat,,:elem1, library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">" library/repr,,`,"return `obj`" library/smtplib,,:port,"as well as a regular host:port server." +library/smtplib,,:port,method must support that as well as a regular host:port +library/socket,,::,"(10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0))]" library/socket,,::,'5aef:2b::8' +library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" +library/socket,,:len,fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) +library/sqlite3,,:age,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" +library/sqlite3,,:age,"select name_last, age from people where name_last=:who and age=:age" library/sqlite3,,:memory, -library/sqlite3,,:age,"select name_last, age from people where name_last=:who and age=:age" -library/sqlite3,,:who,"select name_last, age from people where name_last=:who and age=:age" +library/sqlite3,,:who,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" +library/ssl,,:My,"Organizational Unit Name (eg, section) []:My Group" library/ssl,,:My,"Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc." -library/ssl,,:My,"Organizational Unit Name (eg, section) []:My Group" library/ssl,,:myserver,"Common Name (eg, YOUR name) []:myserver.mygroup.myorganization.com" library/ssl,,:MyState,State or Province Name (full name) [Some-State]:MyState library/ssl,,:ops,Email Address []:ops at myserver.mygroup.myorganization.com library/ssl,,:Some,"Locality Name (eg, city) []:Some City" library/ssl,,:US,Country Name (2 letter code) [AU]:US +library/stdtypes,,::,>>> a[::-1].tolist() +library/stdtypes,,::,>>> a[::2].tolist() +library/stdtypes,,:end,s[start:end] +library/stdtypes,,::,>>> hash(v[::-2]) == hash(b'abcefg'[::-2]) library/stdtypes,,:len,s[len(s):len(s)] -library/stdtypes,,:len,s[len(s):len(s)] +library/stdtypes,,::,>>> y = m[::2] library/string,,:end,s[start:end] -library/string,,:end,s[start:end] +library/subprocess,,`,"output=`dmesg | grep hda`" library/subprocess,,`,"output=`mycmd myarg`" -library/subprocess,,`,"output=`dmesg | grep hda`" +library/tarfile,,:bz2, library/tarfile,,:compression,filemode[:compression] library/tarfile,,:gz, -library/tarfile,,:bz2, +library/tarfile,,:xz,'a:xz' +library/tarfile,,:xz,'r:xz' +library/tarfile,,:xz,'w:xz' library/time,,:mm, library/time,,:ss, library/turtle,,::,Example:: +library/urllib2,,:password,"""joe:password at python.org""" library/urllib,,:port,:port -library/urllib2,,:password,"""joe:password at python.org""" +library/urllib.request,,:close,Connection:close +library/urllib.request,,:lang,"xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en"" lang=""en"">\n\n\n" +library/urllib.request,,:password,"""joe:password at python.org""" library/uuid,,:uuid,urn:uuid:12345678-1234-5678-1234-567812345678 +library/xmlrpc.client,,:pass,http://user:pass at host:port/path +library/xmlrpc.client,,:pass,user:pass +library/xmlrpc.client,,:port,http://user:pass at host:port/path +license,,`,"``Software''), to deal in the Software without restriction, including" +license,,`,"THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND," +license,,`,* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND +license,,`,THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +license,,`,* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY license,,`,THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND license,,:zooko,mailto:zooko at zooko.com -license,,`,THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +packaging/examples,,`,This is the description of the ``foobar`` project. +packaging/setupcfg,,::,Development Status :: 3 - Alpha +packaging/setupcfg,,::,License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1) +packaging/setupscript,,::,"'Development Status :: 4 - Beta'," +packaging/setupscript,,::,"'Environment :: Console'," +packaging/setupscript,,::,"'Environment :: Web Environment'," +packaging/setupscript,,::,"'Intended Audience :: Developers'," +packaging/setupscript,,::,"'Intended Audience :: End Users/Desktop'," +packaging/setupscript,,::,"'Intended Audience :: System Administrators'," +packaging/setupscript,,::,"'License :: OSI Approved :: Python Software Foundation License'," +packaging/setupscript,,::,"'Operating System :: MacOS :: MacOS X'," +packaging/setupscript,,::,"'Operating System :: Microsoft :: Windows'," +packaging/setupscript,,::,"'Operating System :: POSIX'," +packaging/setupscript,,::,"'Programming Language :: Python'," +packaging/setupscript,,::,"'Topic :: Communications :: Email'," +packaging/setupscript,,::,"'Topic :: Office/Business'," +packaging/setupscript,,::,"'Topic :: Software Development :: Bug Tracking'," +packaging/tutorial,,::,1) License :: OSI Approved :: GNU General Public License (GPL) +packaging/tutorial,,::,2) License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +packaging/tutorial,,::,classifier = Development Status :: 3 - Alpha +packaging/tutorial,,::,License :: OSI Approved :: GNU General Public License (GPL) +packaging/tutorial,,::,Type the number of the license you wish to use or ? to try again:: 1 +reference/datamodel,,:max, reference/datamodel,,:step,a[i:j:step] -reference/datamodel,,:max, -reference/expressions,,:index,x[index:index] reference/expressions,,:datum,{key:datum...} reference/expressions,,`,`expressions...` +reference/expressions,,:index,x[index:index] reference/grammar,,:output,#diagram:output reference/grammar,,:rules,#diagram:rules +reference/grammar,,`,'`' testlist1 '`' reference/grammar,,:token,#diagram:token -reference/grammar,,`,'`' testlist1 '`' +reference/lexical_analysis,,`,", : . ` = ;" +reference/lexical_analysis,,`,$ ? ` reference/lexical_analysis,,:fileencoding,# vim:fileencoding= -reference/lexical_analysis,,`,", : . ` = ;" +tutorial/datastructures,,:value,It is also possible to delete a key:value tutorial/datastructures,,:value,key:value pairs within the braces adds initial key:value pairs -tutorial/datastructures,,:value,It is also possible to delete a key:value -tutorial/stdlib2,,:start,"fields = struct.unpack('=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(" -faq/programming,,::,for x in sequence[::-1]: -faq/windows,229,:EOF, at setlocal enableextensions & python -x %~f0 %* & goto :EOF -faq/windows,393,:REG,.py :REG_SZ: c:\\python.exe -u %s %s -library/bisect,32,:hi,all(val >= x for val in a[i:hi]) -library/bisect,42,:hi,all(val > x for val in a[i:hi]) -library/http.client,52,:port,host:port -library/nntplib,,:bytes,:bytes -library/nntplib,,:lines,:lines -library/nntplib,,:lines,"['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']" -library/nntplib,,:bytes,"['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']" -library/pickle,,:memory,"conn = sqlite3.connect("":memory:"")" -library/profile,,:lineno,"(sort by filename:lineno)," -library/socket,,::,"(10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0))]" -library/stdtypes,,:end,s[start:end] -library/stdtypes,,:end,s[start:end] -library/urllib.request,,:close,Connection:close -library/urllib.request,,:password,"""joe:password at python.org""" -library/urllib.request,,:lang,"xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en"" lang=""en"">\n\n\n" -library/xmlrpc.client,,:pass,http://user:pass at host:port/path -library/xmlrpc.client,,:port,http://user:pass at host:port/path -library/xmlrpc.client,,:pass,user:pass -license,,`,* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY -license,,`,* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND -license,,`,"``Software''), to deal in the Software without restriction, including" -license,,`,"THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND," +whatsnew/2.7,1619,::,"ParseResult(scheme='http', netloc='[1080::8:800:200C:417A]'," +whatsnew/2.7,1619,::,>>> urlparse.urlparse('http://[1080::8:800:200C:417A]/foo') whatsnew/2.7,735,:Sunday,'2009:4:Sunday' +whatsnew/2.7,862,:Cookie,"export PYTHONWARNINGS=all,error:::Cookie:0" whatsnew/2.7,862,::,"export PYTHONWARNINGS=all,error:::Cookie:0" -whatsnew/2.7,862,:Cookie,"export PYTHONWARNINGS=all,error:::Cookie:0" -whatsnew/2.7,1619,::,>>> urlparse.urlparse('http://[1080::8:800:200C:417A]/foo') -whatsnew/2.7,1619,::,"ParseResult(scheme='http', netloc='[1080::8:800:200C:417A]'," -library/configparser,,`,# Set the optional `raw` argument of get() to True if you wish to disable -library/configparser,,`,# The optional `vars` argument is a dict with members that will take -library/configparser,,`,# The optional `fallback` argument can be used to provide a fallback value -library/configparser,,:option,${section:option} -library/configparser,,:system,path: ${Common:system_dir}/Library/Frameworks/ -library/configparser,,:home,my_dir: ${Common:home_dir}/twosheds -library/configparser,,:path,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} -library/configparser,,:Python,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} -library/pdb,,:lineno,[filename:lineno | bpnumber [bpnumber ...]] -library/pdb,,:lineno,filename:lineno -library/logging,,:Watch,WARNING:root:Watch out! -library/logging,,:So,INFO:root:So should this -library/logging,,:Started,INFO:root:Started -library/logging,,:Doing,INFO:root:Doing something -library/logging,,:Finished,INFO:root:Finished -library/logging,,:Look,WARNING:root:Look before you leap! -library/logging,,:So,INFO:So should this -library/logging,,:logger,severity:logger name:message -library/logging,,:message,severity:logger name:message +whatsnew/3.2,,:affe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:affe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,,:beef,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:beef,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,,:cafe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:cafe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,,:deaf,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:deaf,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') whatsnew/3.2,,:directory,... ${buildout:directory}/downloads/dist +whatsnew/3.2,,:directory,${buildout:directory}/downloads/dist +whatsnew/3.2,,::,"$ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'" +whatsnew/3.2,,:feed,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:feed,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,,:gz,">>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:" whatsnew/3.2,,:location,... zope9-location = ${zope9:location} +whatsnew/3.2,,:location,zope9-location = ${zope9:location} whatsnew/3.2,,:prefix,... zope-conf = ${custom:prefix}/etc/zope.conf -howto/logging,,:root,WARNING:root:Watch out! -howto/logging,,:Watch,WARNING:root:Watch out! -howto/logging,,:root,DEBUG:root:This message should go to the log file -howto/logging,,:This,DEBUG:root:This message should go to the log file -howto/logging,,:root,INFO:root:So should this -howto/logging,,:So,INFO:root:So should this -howto/logging,,:root,"WARNING:root:And this, too" -howto/logging,,:And,"WARNING:root:And this, too" -howto/logging,,:root,INFO:root:Started -howto/logging,,:Started,INFO:root:Started -howto/logging,,:root,INFO:root:Doing something -howto/logging,,:Doing,INFO:root:Doing something -howto/logging,,:root,INFO:root:Finished -howto/logging,,:Finished,INFO:root:Finished -howto/logging,,:root,WARNING:root:Look before you leap! -howto/logging,,:Look,WARNING:root:Look before you leap! -howto/logging,,:This,DEBUG:This message should appear on the console -howto/logging,,:So,INFO:So should this -howto/logging,,:And,"WARNING:And this, too" -howto/logging,,:logger,severity:logger name:message -howto/logging,,:message,severity:logger name:message -library/logging.handlers,,:port,host:port -library/imaplib,116,:MM,"""DD-Mmm-YYYY HH:MM:SS" -library/imaplib,116,:SS,"""DD-Mmm-YYYY HH:MM:SS" -whatsnew/3.2,,::,"$ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'" -howto/pyporting,75,::,# make sure to use :: Python *and* :: Python :: 3 so -howto/pyporting,75,::,"'Programming Language :: Python'," -howto/pyporting,75,::,'Programming Language :: Python :: 3' -whatsnew/3.2,,:gz,">>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:" -whatsnew/3.2,,:directory,${buildout:directory}/downloads/dist -whatsnew/3.2,,:location,zope9-location = ${zope9:location} whatsnew/3.2,,:prefix,zope-conf = ${custom:prefix}/etc/zope.conf -whatsnew/3.2,,:beef,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:cafe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:affe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:deaf,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:feed,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:beef,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:cafe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:affe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:deaf,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:feed,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -library/pprint,209,::,"'classifiers': ['Development Status :: 4 - Beta'," -library/pprint,209,::,"'Intended Audience :: Developers'," -library/pprint,209,::,"'License :: OSI Approved :: MIT License'," -library/pprint,209,::,"'Natural Language :: English'," -library/pprint,209,::,"'Operating System :: OS Independent'," -library/pprint,209,::,"'Programming Language :: Python'," -library/pprint,209,::,"'Programming Language :: Python :: 2'," -library/pprint,209,::,"'Programming Language :: Python :: 2.6'," -library/pprint,209,::,"'Programming Language :: Python :: 2.7'," -library/pprint,209,::,"'Topic :: Software Development :: Libraries'," -library/pprint,209,::,"'Topic :: Software Development :: Libraries :: Python Modules']," -packaging/examples,,`,This is the description of the ``foobar`` project. -packaging/setupcfg,,::,Development Status :: 3 - Alpha -packaging/setupcfg,,::,License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1) -packaging/setupscript,,::,"'Development Status :: 4 - Beta'," -packaging/setupscript,,::,"'Environment :: Console'," -packaging/setupscript,,::,"'Environment :: Web Environment'," -packaging/setupscript,,::,"'Intended Audience :: End Users/Desktop'," -packaging/setupscript,,::,"'Intended Audience :: Developers'," -packaging/setupscript,,::,"'Intended Audience :: System Administrators'," -packaging/setupscript,,::,"'License :: OSI Approved :: Python Software Foundation License'," -packaging/setupscript,,::,"'Operating System :: MacOS :: MacOS X'," -packaging/setupscript,,::,"'Operating System :: Microsoft :: Windows'," -packaging/setupscript,,::,"'Operating System :: POSIX'," -packaging/setupscript,,::,"'Programming Language :: Python'," -packaging/setupscript,,::,"'Topic :: Communications :: Email'," -packaging/setupscript,,::,"'Topic :: Office/Business'," -packaging/setupscript,,::,"'Topic :: Software Development :: Bug Tracking'," -packaging/tutorial,,::,1) License :: OSI Approved :: GNU General Public License (GPL) -packaging/tutorial,,::,2) License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) -packaging/tutorial,,::,Type the number of the license you wish to use or ? to try again:: 1 -packaging/tutorial,,::,classifier = Development Status :: 3 - Alpha -packaging/tutorial,,::,License :: OSI Approved :: GNU General Public License (GPL) -c-api/unicode,,:start,unicode[start:start+length] -library/smtplib,,:port,method must support that as well as a regular host:port -library/socket,,:len,fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) -library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" -library/sqlite3,,:who,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" -library/sqlite3,,:age,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" -library/stdtypes,,::,>>> a[::2].tolist() -library/stdtypes,,::,>>> a[::-1].tolist() -library/stdtypes,,::,>>> hash(v[::-2]) == hash(b'abcefg'[::-2]) -library/stdtypes,,::,>>> y = m[::2] -reference/lexical_analysis,,`,$ ? ` -library/tarfile,,:xz,'r:xz' -library/tarfile,,:xz,'w:xz' -library/tarfile,,:xz,'a:xz' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 16:22:31 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 16:22:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Bump_to_3=2E3=2E0a1=2E?= Message-ID: http://hg.python.org/cpython/rev/eb86a9785d29 changeset: 75388:eb86a9785d29 user: Georg Brandl date: Sun Mar 04 16:23:53 2012 +0100 summary: Bump to 3.3.0a1. files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 8 ++++---- Misc/RPM/python-3.3.spec | 2 +- README | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 3 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 0 +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.3.0a0" +#define PY_VERSION "3.3.0a1" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.3a0" +__version__ = "3.3.0a1" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.3a0" +IDLE_VERSION = "3.3.0a1" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,10 +2,10 @@ Python News +++++++++++ -What's New in Python 3.3 Alpha 1? -================================= - -*Release date: XX-XXX-20XX* +What's New in Python 3.3.0 Alpha 1? +=================================== + +*Release date: 05-Mar-2012* Core and Builtins ----------------- diff --git a/Misc/RPM/python-3.3.spec b/Misc/RPM/python-3.3.spec --- a/Misc/RPM/python-3.3.spec +++ b/Misc/RPM/python-3.3.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.3a0 +%define version 3.3.0a1 %define libvers 3.3 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Python version 3.3 alpha 0 -================================== +This is Python version 3.3.0 alpha 1 +==================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Python Software Foundation. All rights reserved. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 16:22:32 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 16:22:32 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Update_copyright_years_and_?= =?utf8?q?version_name=2E?= Message-ID: http://hg.python.org/cpython/rev/f1a9a6505731 changeset: 75389:f1a9a6505731 user: Georg Brandl date: Sun Mar 04 16:26:19 2012 +0100 summary: Update copyright years and version name. files: Doc/license.rst | 2 +- LICENSE | 2 +- PC/python_nt.rc | 2 +- Python/getcopyright.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/license.rst b/Doc/license.rst --- a/Doc/license.rst +++ b/Doc/license.rst @@ -118,7 +118,7 @@ +----------------+--------------+------------+------------+-----------------+ | 3.2.2 | 3.2.1 | 2011 | PSF | yes | +----------------+--------------+------------+------------+-----------------+ -| 3.3 | 3.2 | 2012 | PSF | yes | +| 3.3.0 | 3.2 | 2012 | PSF | yes | +----------------+--------------+------------+------------+-----------------+ .. note:: diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -73,7 +73,7 @@ 3.2 3.1 2011 PSF yes 3.2.1 3.2 2011 PSF yes 3.2.2 3.2.1 2011 PSF yes - 3.3 3.2 2012 PSF yes + 3.3.0 3.2 2012 PSF yes Footnotes: diff --git a/PC/python_nt.rc b/PC/python_nt.rc --- a/PC/python_nt.rc +++ b/PC/python_nt.rc @@ -12,7 +12,7 @@ # include "pythonnt_rc.h" #endif -/* e.g., 2.1a2 +/* e.g., 3.3.0a1 * PY_VERSION comes from patchevel.h */ #define PYTHON_VERSION PY_VERSION "\0" diff --git a/Python/getcopyright.c b/Python/getcopyright.c --- a/Python/getcopyright.c +++ b/Python/getcopyright.c @@ -19,5 +19,5 @@ const char * Py_GetCopyright(void) { - return cprt; + return cprt; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 16:22:48 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 16:22:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Added_tag_v3=2E3=2E0a1_for_?= =?utf8?q?changeset_f1a9a6505731?= Message-ID: http://hg.python.org/cpython/rev/7531b5b00fe8 changeset: 75390:7531b5b00fe8 user: Georg Brandl date: Sun Mar 04 16:26:49 2012 +0100 summary: Added tag v3.3.0a1 for changeset f1a9a6505731 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -95,3 +95,4 @@ c860feaa348d663e598986894ee4680480577e15 v3.2.2rc1 137e45f15c0bd262c9ad4c032d97425bc0589456 v3.2.2 7085403daf439adb3f9e70ef13f6bedb1c447376 v3.2.3rc1 +f1a9a6505731714f0e157453ff850e3b71615c45 v3.3.0a1 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 16:37:30 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 16:37:30 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_status_update=2E?= Message-ID: http://hg.python.org/peps/rev/0cedf6955177 changeset: 4113:0cedf6955177 user: Georg Brandl date: Sun Mar 04 16:41:28 2012 +0100 summary: PEP status update. files: pep-0398.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -62,6 +62,8 @@ * PEP 380: Syntax for Delegating to a Subgenerator * PEP 393: Flexible String Representation * PEP 399: Pure Python/C Accelerator Module Compatibility Requirements +* PEP 409: Suppressing exception context +* PEP 414: Explicit Unicode Literal for Python 3.3 * PEP 3151: Reworking the OS and IO exception hierarchy * PEP 3155: Qualified name for classes and functions @@ -77,7 +79,6 @@ * PEP 382: Namespace Packages * PEP 395: Module Aliasing * PEP 397: Python launcher for Windows -* PEP 409: Suppressing exception context * PEP 3143: Standard daemon process library (Note that these are not accepted yet and even if they are, they might -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Mar 4 18:35:49 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 04 Mar 2012 18:35:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314166=3A_Pickler_o?= =?utf8?q?bjects_now_have_an_optional_=60dispatch=5Ftable=60_attribute?= Message-ID: http://hg.python.org/cpython/rev/f7a9a10ae0c0 changeset: 75391:f7a9a10ae0c0 user: Antoine Pitrou date: Sun Mar 04 18:31:48 2012 +0100 summary: Issue #14166: Pickler objects now have an optional `dispatch_table` attribute which allows to set custom per-pickler reduction functions. Patch by sbt. files: Doc/library/copyreg.rst | 8 +- Doc/library/pickle.rst | 61 +++++++++++++++++ Lib/pickle.py | 4 +- Lib/test/pickletester.py | 99 ++++++++++++++++++++++++++++ Lib/test/test_pickle.py | 28 +++++++- Misc/NEWS | 4 + Modules/_pickle.c | 39 ++++++++-- 7 files changed, 228 insertions(+), 15 deletions(-) diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -32,6 +32,8 @@ returned by *function* at pickling time. :exc:`TypeError` will be raised if *object* is a class or *constructor* is not callable. - See the :mod:`pickle` module for more details on the interface expected of - *function* and *constructor*. - + See the :mod:`pickle` module for more details on the interface + expected of *function* and *constructor*. Note that the + :attr:`~pickle.Pickler.dispatch_table` attribute of a pickler + object or subclass of :class:`pickle.Pickler` can also be used for + declaring reduction functions. diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -285,6 +285,29 @@ See :ref:`pickle-persistent` for details and examples of uses. + .. attribute:: dispatch_table + + A pickler object's dispatch table is a registry of *reduction + functions* of the kind which can be declared using + :func:`copyreg.pickle`. It is a mapping whose keys are classes + and whose values are reduction functions. A reduction function + takes a single argument of the associated class and should + conform to the same interface as a :meth:`~object.__reduce__` + method. + + By default, a pickler object will not have a + :attr:`dispatch_table` attribute, and it will instead use the + global dispatch table managed by the :mod:`copyreg` module. + However, to customize the pickling for a specific pickler object + one can set the :attr:`dispatch_table` attribute to a dict-like + object. Alternatively, if a subclass of :class:`Pickler` has a + :attr:`dispatch_table` attribute then this will be used as the + default dispatch table for instances of that class. + + See :ref:`pickle-dispatch` for usage examples. + + .. versionadded:: 3.3 + .. attribute:: fast Deprecated. Enable fast mode if set to a true value. The fast mode @@ -575,6 +598,44 @@ .. literalinclude:: ../includes/dbpickle.py +.. _pickle-dispatch: + +Dispatch Tables +^^^^^^^^^^^^^^^ + +If one wants to customize pickling of some classes without disturbing +any other code which depends on pickling, then one can create a +pickler with a private dispatch table. + +The global dispatch table managed by the :mod:`copyreg` module is +available as :data:`copyreg.dispatch_table`. Therefore, one may +choose to use a modified copy of :data:`copyreg.dispatch_table` as a +private dispatch table. + +For example :: + + f = io.BytesIO() + p = pickle.Pickler(f) + p.dispatch_table = copyreg.dispatch_table.copy() + p.dispatch_table[SomeClass] = reduce_SomeClass + +creates an instance of :class:`pickle.Pickler` with a private dispatch +table which handles the ``SomeClass`` class specially. Alternatively, +the code :: + + class MyPickler(pickle.Pickler): + dispatch_table = copyreg.dispatch_table.copy() + dispatch_table[SomeClass] = reduce_SomeClass + f = io.BytesIO() + p = MyPickler(f) + +does the same, but all instances of ``MyPickler`` will by default +share the same dispatch table. The equivalent code using the +:mod:`copyreg` module is :: + + copyreg.pickle(SomeClass, reduce_SomeClass) + f = io.BytesIO() + p = pickle.Pickler(f) .. _pickle-state: diff --git a/Lib/pickle.py b/Lib/pickle.py --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -297,8 +297,8 @@ f(self, obj) # Call unbound method with explicit self return - # Check copyreg.dispatch_table - reduce = dispatch_table.get(t) + # Check private dispatch table if any, or else copyreg.dispatch_table + reduce = getattr(self, 'dispatch_table', dispatch_table).get(t) if reduce: rv = reduce(obj) else: diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1605,6 +1605,105 @@ self.assertEqual(unpickler.load(), data) +# Tests for dispatch_table attribute + +REDUCE_A = 'reduce_A' + +class AAA(object): + def __reduce__(self): + return str, (REDUCE_A,) + +class BBB(object): + pass + +class AbstractDispatchTableTests(unittest.TestCase): + + def test_default_dispatch_table(self): + # No dispatch_table attribute by default + f = io.BytesIO() + p = self.pickler_class(f, 0) + with self.assertRaises(AttributeError): + p.dispatch_table + self.assertFalse(hasattr(p, 'dispatch_table')) + + def test_class_dispatch_table(self): + # A dispatch_table attribute can be specified class-wide + dt = self.get_dispatch_table() + + class MyPickler(self.pickler_class): + dispatch_table = dt + + def dumps(obj, protocol=None): + f = io.BytesIO() + p = MyPickler(f, protocol) + self.assertEqual(p.dispatch_table, dt) + p.dump(obj) + return f.getvalue() + + self._test_dispatch_table(dumps, dt) + + def test_instance_dispatch_table(self): + # A dispatch_table attribute can also be specified instance-wide + dt = self.get_dispatch_table() + + def dumps(obj, protocol=None): + f = io.BytesIO() + p = self.pickler_class(f, protocol) + p.dispatch_table = dt + self.assertEqual(p.dispatch_table, dt) + p.dump(obj) + return f.getvalue() + + self._test_dispatch_table(dumps, dt) + + def _test_dispatch_table(self, dumps, dispatch_table): + def custom_load_dump(obj): + return pickle.loads(dumps(obj, 0)) + + def default_load_dump(obj): + return pickle.loads(pickle.dumps(obj, 0)) + + # pickling complex numbers using protocol 0 relies on copyreg + # so check pickling a complex number still works + z = 1 + 2j + self.assertEqual(custom_load_dump(z), z) + self.assertEqual(default_load_dump(z), z) + + # modify pickling of complex + REDUCE_1 = 'reduce_1' + def reduce_1(obj): + return str, (REDUCE_1,) + dispatch_table[complex] = reduce_1 + self.assertEqual(custom_load_dump(z), REDUCE_1) + self.assertEqual(default_load_dump(z), z) + + # check picklability of AAA and BBB + a = AAA() + b = BBB() + self.assertEqual(custom_load_dump(a), REDUCE_A) + self.assertIsInstance(custom_load_dump(b), BBB) + self.assertEqual(default_load_dump(a), REDUCE_A) + self.assertIsInstance(default_load_dump(b), BBB) + + # modify pickling of BBB + dispatch_table[BBB] = reduce_1 + self.assertEqual(custom_load_dump(a), REDUCE_A) + self.assertEqual(custom_load_dump(b), REDUCE_1) + self.assertEqual(default_load_dump(a), REDUCE_A) + self.assertIsInstance(default_load_dump(b), BBB) + + # revert pickling of BBB and modify pickling of AAA + REDUCE_2 = 'reduce_2' + def reduce_2(obj): + return str, (REDUCE_2,) + dispatch_table[AAA] = reduce_2 + del dispatch_table[BBB] + self.assertEqual(custom_load_dump(a), REDUCE_2) + self.assertIsInstance(custom_load_dump(b), BBB) + self.assertEqual(default_load_dump(a), REDUCE_A) + self.assertIsInstance(default_load_dump(b), BBB) + + if __name__ == "__main__": # Print some stuff that can be used to rewrite DATA{0,1,2} from pickletools import dis diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -1,5 +1,6 @@ import pickle import io +import collections from test import support @@ -7,6 +8,7 @@ from test.pickletester import AbstractPickleModuleTests from test.pickletester import AbstractPersistentPicklerTests from test.pickletester import AbstractPicklerUnpicklerObjectTests +from test.pickletester import AbstractDispatchTableTests from test.pickletester import BigmemPickleTests try: @@ -80,6 +82,18 @@ unpickler_class = pickle._Unpickler +class PyDispatchTableTests(AbstractDispatchTableTests): + pickler_class = pickle._Pickler + def get_dispatch_table(self): + return pickle.dispatch_table.copy() + + +class PyChainDispatchTableTests(AbstractDispatchTableTests): + pickler_class = pickle._Pickler + def get_dispatch_table(self): + return collections.ChainMap({}, pickle.dispatch_table) + + if has_c_implementation: class CPicklerTests(PyPicklerTests): pickler = _pickle.Pickler @@ -101,14 +115,26 @@ pickler_class = _pickle.Pickler unpickler_class = _pickle.Unpickler + class CDispatchTableTests(AbstractDispatchTableTests): + pickler_class = pickle.Pickler + def get_dispatch_table(self): + return pickle.dispatch_table.copy() + + class CChainDispatchTableTests(AbstractDispatchTableTests): + pickler_class = pickle.Pickler + def get_dispatch_table(self): + return collections.ChainMap({}, pickle.dispatch_table) + def test_main(): - tests = [PickleTests, PyPicklerTests, PyPersPicklerTests] + tests = [PickleTests, PyPicklerTests, PyPersPicklerTests, + PyDispatchTableTests, PyChainDispatchTableTests] if has_c_implementation: tests.extend([CPicklerTests, CPersPicklerTests, CDumpPickle_LoadPickle, DumpPickle_CLoadPickle, PyPicklerUnpicklerObjectTests, CPicklerUnpicklerObjectTests, + CDispatchTableTests, CChainDispatchTableTests, InMemoryPickleTests]) support.run_unittest(*tests) support.run_doctest(pickle) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -511,6 +511,10 @@ Library ------- +- Issue #14166: Pickler objects now have an optional ``dispatch_table`` + attribute which allows to set custom per-pickler reduction functions. + Patch by sbt. + - Issue #14177: marshal.loads() now raises TypeError when given an unicode string. Patch by Guilherme Gon?alves. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -319,6 +319,7 @@ objects to support self-referential objects pickling. */ PyObject *pers_func; /* persistent_id() method, can be NULL */ + PyObject *dispatch_table; /* private dispatch_table, can be NULL */ PyObject *arg; PyObject *write; /* write() method of the output stream. */ @@ -764,6 +765,7 @@ return NULL; self->pers_func = NULL; + self->dispatch_table = NULL; self->arg = NULL; self->write = NULL; self->proto = 0; @@ -3176,17 +3178,24 @@ /* XXX: This part needs some unit tests. */ /* Get a reduction callable, and call it. This may come from - * copyreg.dispatch_table, the object's __reduce_ex__ method, - * or the object's __reduce__ method. + * self.dispatch_table, copyreg.dispatch_table, the object's + * __reduce_ex__ method, or the object's __reduce__ method. */ - reduce_func = PyDict_GetItem(dispatch_table, (PyObject *)type); + if (self->dispatch_table == NULL) { + reduce_func = PyDict_GetItem(dispatch_table, (PyObject *)type); + /* PyDict_GetItem() unlike PyObject_GetItem() and + PyObject_GetAttr() returns a borrowed ref */ + Py_XINCREF(reduce_func); + } else { + reduce_func = PyObject_GetItem(self->dispatch_table, (PyObject *)type); + if (reduce_func == NULL) { + if (PyErr_ExceptionMatches(PyExc_KeyError)) + PyErr_Clear(); + else + goto error; + } + } if (reduce_func != NULL) { - /* Here, the reference count of the reduce_func object returned by - PyDict_GetItem needs to be increased to be consistent with the one - returned by PyObject_GetAttr. This is allow us to blindly DECREF - reduce_func at the end of the save() routine. - */ - Py_INCREF(reduce_func); Py_INCREF(obj); reduce_value = _Pickler_FastCall(self, reduce_func, obj); } @@ -3359,6 +3368,7 @@ Py_XDECREF(self->output_buffer); Py_XDECREF(self->write); Py_XDECREF(self->pers_func); + Py_XDECREF(self->dispatch_table); Py_XDECREF(self->arg); Py_XDECREF(self->fast_memo); @@ -3372,6 +3382,7 @@ { Py_VISIT(self->write); Py_VISIT(self->pers_func); + Py_VISIT(self->dispatch_table); Py_VISIT(self->arg); Py_VISIT(self->fast_memo); return 0; @@ -3383,6 +3394,7 @@ Py_CLEAR(self->output_buffer); Py_CLEAR(self->write); Py_CLEAR(self->pers_func); + Py_CLEAR(self->dispatch_table); Py_CLEAR(self->arg); Py_CLEAR(self->fast_memo); @@ -3427,6 +3439,7 @@ PyObject *proto_obj = NULL; PyObject *fix_imports = Py_True; _Py_IDENTIFIER(persistent_id); + _Py_IDENTIFIER(dispatch_table); if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO:Pickler", kwlist, &file, &proto_obj, &fix_imports)) @@ -3468,6 +3481,13 @@ if (self->pers_func == NULL) return -1; } + self->dispatch_table = NULL; + if (_PyObject_HasAttrId((PyObject *)self, &PyId_dispatch_table)) { + self->dispatch_table = _PyObject_GetAttrId((PyObject *)self, + &PyId_dispatch_table); + if (self->dispatch_table == NULL) + return -1; + } return 0; } @@ -3749,6 +3769,7 @@ static PyMemberDef Pickler_members[] = { {"bin", T_INT, offsetof(PicklerObject, bin)}, {"fast", T_INT, offsetof(PicklerObject, fast)}, + {"dispatch_table", T_OBJECT_EX, offsetof(PicklerObject, dispatch_table)}, {NULL} }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 19:10:31 2012 From: python-checkins at python.org (alex.gaynor) Date: Sun, 04 Mar 2012 19:10:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Add_a_crasher_f?= =?utf8?q?or_the_documented_issue_of_calling_=22Py=5FDECREF=28self-=3Exxx?= =?utf8?b?KSI7?= Message-ID: http://hg.python.org/cpython/rev/e04e1f253ed8 changeset: 75392:e04e1f253ed8 branch: 2.7 parent: 75377:52ecec12c0ed user: Armin Rigo date: Sun Mar 04 18:56:23 2012 +0100 summary: Add a crasher for the documented issue of calling "Py_DECREF(self->xxx)"; files: Lib/test/crashers/decref_before_assignment.py | 44 ++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-) diff --git a/Lib/test/crashers/decref_before_assignment.py b/Lib/test/crashers/decref_before_assignment.py new file mode 100644 --- /dev/null +++ b/Lib/test/crashers/decref_before_assignment.py @@ -0,0 +1,44 @@ +""" +General example for an attack against code like this: + + Py_DECREF(obj->attr); obj->attr = ...; + +here in Module/_json.c:scanner_init(). + +Explanation: if the first Py_DECREF() calls either a __del__ or a +weakref callback, it will run while the 'obj' appears to have in +'obj->attr' still the old reference to the object, but not holding +the reference count any more. + +Status: progress has been made replacing these cases, but there is an +infinite number of such cases. +""" + +import _json, weakref + +class Ctx1(object): + encoding = "utf8" + strict = None + object_hook = None + object_pairs_hook = None + parse_float = None + parse_int = None + parse_constant = None + +class Foo(unicode): + pass + +def delete_me(*args): + print scanner.encoding.__dict__ + +class Ctx2(Ctx1): + @property + def encoding(self): + global wref + f = Foo("utf8") + f.abc = globals() + wref = weakref.ref(f, delete_me) + return f + +scanner = _json.make_scanner(Ctx1()) +scanner.__init__(Ctx2()) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 20:13:00 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 04 Mar 2012 20:13:00 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Generate_product_code_UUID_?= =?utf8?q?from_download_URL=2E?= Message-ID: http://hg.python.org/cpython/rev/8d5796c8325e changeset: 75393:8d5796c8325e parent: 75391:f7a9a10ae0c0 user: Martin v. L?wis date: Sun Mar 04 19:48:25 2012 +0100 summary: Generate product code UUID from download URL. files: Tools/msi/msi.py | 19 +++++++++++-------- 1 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -6,7 +6,6 @@ import uisample from win32com.client import constants from distutils.spawn import find_executable -from uuids import product_codes import tempfile # Settings can be overridden in config.py below @@ -77,9 +76,6 @@ if snapshot: current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24)) - product_code = msilib.gen_uuid() -else: - product_code = product_codes[current_version] if full_current_version is None: full_current_version = current_version @@ -187,12 +183,19 @@ msilib.set_arch_from_file(dll_path) if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"): raise SystemError("msisupport.dll for incorrect architecture") + if msilib.Win64: upgrade_code = upgrade_code_64 - # Bump the last digit of the code by one, so that 32-bit and 64-bit - # releases get separate product codes - digit = hex((int(product_code[-2],16)+1)%16)[-1] - product_code = product_code[:-2] + digit + '}' + +if snapshot: + product_code = msilib.gen_uuid() +else: + # official release: generate UUID from the download link that the file will have + import uuid + product_code = uuid.uuid3(uuid.NAMESPACE_URL, + 'http://www.python.org/ftp/python/%s.%s.%s/python-%s%s.msi' % + (major, minor, micro, full_current_version, msilib.arch_ext)) + product_code = '{%s}' % product_code if testpackage: ext = 'px' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 20:15:59 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 04 Mar 2012 20:15:59 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Enable_PGI/PGO_builds_for_x?= =?utf8?q?64_python3=2Edll?= Message-ID: http://hg.python.org/cpython/rev/6629347abe72 changeset: 75394:6629347abe72 user: Martin v. L?wis date: Sun Mar 04 20:15:39 2012 +0100 summary: Enable PGI/PGO builds for x64 python3.dll files: PCbuild/pcbuild.sln | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -584,16 +584,16 @@ {6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.ActiveCfg = Release|x64 {6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.Build.0 = Release|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|Win32.ActiveCfg = PGInstrument|Win32 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = Debug|x64 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = Debug|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = PGUpdate|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = PGUpdate|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = Release|x64 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = PGInstrument|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = Release|x64 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = PGUpdate|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.ActiveCfg = Release|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.Build.0 = Release|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.ActiveCfg = Release|x64 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 20:24:33 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 04 Mar 2012 20:24:33 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_sporadic_fa?= =?utf8?q?ilure_in_test=5Fweakset?= Message-ID: http://hg.python.org/cpython/rev/5f79d68ba087 changeset: 75395:5f79d68ba087 branch: 2.7 parent: 75392:e04e1f253ed8 user: Antoine Pitrou date: Sun Mar 04 20:20:34 2012 +0100 summary: Fix sporadic failure in test_weakset files: Lib/_weakrefset.py | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -116,11 +116,8 @@ def update(self, other): if self._pending_removals: self._commit_removals() - if isinstance(other, self.__class__): - self.data.update(other.data) - else: - for element in other: - self.add(element) + for element in other: + self.add(element) def __ior__(self, other): self.update(other) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 20:32:26 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 04 Mar 2012 20:32:26 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_spelling=2E?= Message-ID: http://hg.python.org/cpython/rev/575a2affd214 changeset: 75396:575a2affd214 parent: 75394:6629347abe72 user: Georg Brandl date: Sun Mar 04 20:36:28 2012 +0100 summary: Fix spelling. files: Lib/test/crashers/loosing_mro_ref.py | 0 1 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Lib/test/crashers/loosing_mro_ref.py b/Lib/test/crashers/losing_mro_ref.py rename from Lib/test/crashers/loosing_mro_ref.py rename to Lib/test/crashers/losing_mro_ref.py -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 20:51:07 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 04 Mar 2012 20:51:07 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_some_set_al?= =?utf8?q?gebra_methods_of_WeakSet_objects=2E?= Message-ID: http://hg.python.org/cpython/rev/428bfb58e3b3 changeset: 75397:428bfb58e3b3 branch: 2.7 parent: 75395:5f79d68ba087 user: Antoine Pitrou date: Sun Mar 04 20:47:05 2012 +0100 summary: Fix some set algebra methods of WeakSet objects. files: Lib/_weakrefset.py | 41 ++++++++------------------- Lib/test/test_weakset.py | 22 ++++++++++++-- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -123,26 +123,14 @@ self.update(other) return self - # Helper functions for simple delegating methods. - def _apply(self, other, method): - if not isinstance(other, self.__class__): - other = self.__class__(other) - newdata = method(other.data) - newset = self.__class__() - newset.data = newdata + def difference(self, other): + newset = self.copy() + newset.difference_update(other) return newset - - def difference(self, other): - return self._apply(other, self.data.difference) __sub__ = difference def difference_update(self, other): - if self._pending_removals: - self._commit_removals() - if self is other: - self.data.clear() - else: - self.data.difference_update(ref(item) for item in other) + self.__isub__(other) def __isub__(self, other): if self._pending_removals: self._commit_removals() @@ -153,13 +141,11 @@ return self def intersection(self, other): - return self._apply(other, self.data.intersection) + return self.__class__(item for item in other if item in self) __and__ = intersection def intersection_update(self, other): - if self._pending_removals: - self._commit_removals() - self.data.intersection_update(ref(item) for item in other) + self.__iand__(other) def __iand__(self, other): if self._pending_removals: self._commit_removals() @@ -186,27 +172,24 @@ return self.data == set(ref(item) for item in other) def symmetric_difference(self, other): - return self._apply(other, self.data.symmetric_difference) + newset = self.copy() + newset.symmetric_difference_update(other) + return newset __xor__ = symmetric_difference def symmetric_difference_update(self, other): - if self._pending_removals: - self._commit_removals() - if self is other: - self.data.clear() - else: - self.data.symmetric_difference_update(ref(item) for item in other) + self.__ixor__(other) def __ixor__(self, other): if self._pending_removals: self._commit_removals() if self is other: self.data.clear() else: - self.data.symmetric_difference_update(ref(item) for item in other) + self.data.symmetric_difference_update(ref(item, self._remove) for item in other) return self def union(self, other): - return self._apply(other, self.data.union) + return self.__class__(e for s in (self, other) for e in s) __or__ = union def isdisjoint(self, other): diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -83,6 +83,11 @@ x = WeakSet(self.items + self.items2) c = C(self.items2) self.assertEqual(self.s.union(c), x) + del c + self.assertEqual(len(u), len(self.items) + len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(u), len(self.items) + len(self.items2)) def test_or(self): i = self.s.union(self.items2) @@ -90,14 +95,19 @@ self.assertEqual(self.s | frozenset(self.items2), i) def test_intersection(self): - i = self.s.intersection(self.items2) + s = WeakSet(self.letters) + i = s.intersection(self.items2) for c in self.letters: - self.assertEqual(c in i, c in self.d and c in self.items2) - self.assertEqual(self.s, WeakSet(self.items)) + self.assertEqual(c in i, c in self.items2 and c in self.letters) + self.assertEqual(s, WeakSet(self.letters)) self.assertEqual(type(i), WeakSet) for C in set, frozenset, dict.fromkeys, list, tuple: x = WeakSet([]) - self.assertEqual(self.s.intersection(C(self.items2)), x) + self.assertEqual(i.intersection(C(self.items)), x) + self.assertEqual(len(i), len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(i), len(self.items2)) def test_isdisjoint(self): self.assertTrue(self.s.isdisjoint(WeakSet(self.items2))) @@ -128,6 +138,10 @@ self.assertEqual(self.s, WeakSet(self.items)) self.assertEqual(type(i), WeakSet) self.assertRaises(TypeError, self.s.symmetric_difference, [[]]) + self.assertEqual(len(i), len(self.items) + len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(i), len(self.items) + len(self.items2)) def test_xor(self): i = self.s.symmetric_difference(self.items2) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 21:04:08 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 04 Mar 2012 21:04:08 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Port_2=2E7_fix_?= =?utf8?q?for_sporadic_failure_in_test=5Fweakset=2E?= Message-ID: http://hg.python.org/cpython/rev/5a2bc0d574f6 changeset: 75398:5a2bc0d574f6 branch: 3.2 parent: 75374:4966907d3661 user: Antoine Pitrou date: Sun Mar 04 20:20:34 2012 +0100 summary: Port 2.7 fix for sporadic failure in test_weakset. files: Lib/_weakrefset.py | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -114,11 +114,8 @@ def update(self, other): if self._pending_removals: self._commit_removals() - if isinstance(other, self.__class__): - self.data.update(other.data) - else: - for element in other: - self.add(element) + for element in other: + self.add(element) def __ior__(self, other): self.update(other) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 21:04:09 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 04 Mar 2012 21:04:09 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Port_2=2E7_fix_for_sporadic_failure_in_test=5Fweakset=2E?= Message-ID: http://hg.python.org/cpython/rev/2843f32a3a34 changeset: 75399:2843f32a3a34 parent: 75391:f7a9a10ae0c0 parent: 75398:5a2bc0d574f6 user: Antoine Pitrou date: Sun Mar 04 20:55:35 2012 +0100 summary: Port 2.7 fix for sporadic failure in test_weakset. files: Lib/_weakrefset.py | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -114,11 +114,8 @@ def update(self, other): if self._pending_removals: self._commit_removals() - if isinstance(other, self.__class__): - self.data.update(other.data) - else: - for element in other: - self.add(element) + for element in other: + self.add(element) def __ior__(self, other): self.update(other) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 21:04:10 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 04 Mar 2012 21:04:10 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merge?= Message-ID: http://hg.python.org/cpython/rev/72d1b21ee10f changeset: 75400:72d1b21ee10f parent: 75399:2843f32a3a34 parent: 75396:575a2affd214 user: Antoine Pitrou date: Sun Mar 04 20:59:01 2012 +0100 summary: Merge files: Lib/test/crashers/loosing_mro_ref.py | 0 PCbuild/pcbuild.sln | 12 +++++----- Tools/msi/msi.py | 19 +++++++++------ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Lib/test/crashers/loosing_mro_ref.py b/Lib/test/crashers/losing_mro_ref.py rename from Lib/test/crashers/loosing_mro_ref.py rename to Lib/test/crashers/losing_mro_ref.py diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -584,16 +584,16 @@ {6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.ActiveCfg = Release|x64 {6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.Build.0 = Release|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|Win32.ActiveCfg = PGInstrument|Win32 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = Debug|x64 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = Debug|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = PGUpdate|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = PGUpdate|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = Release|x64 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = PGInstrument|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = Release|x64 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = PGUpdate|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.ActiveCfg = Release|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.Build.0 = Release|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.ActiveCfg = Release|x64 diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -6,7 +6,6 @@ import uisample from win32com.client import constants from distutils.spawn import find_executable -from uuids import product_codes import tempfile # Settings can be overridden in config.py below @@ -77,9 +76,6 @@ if snapshot: current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24)) - product_code = msilib.gen_uuid() -else: - product_code = product_codes[current_version] if full_current_version is None: full_current_version = current_version @@ -187,12 +183,19 @@ msilib.set_arch_from_file(dll_path) if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"): raise SystemError("msisupport.dll for incorrect architecture") + if msilib.Win64: upgrade_code = upgrade_code_64 - # Bump the last digit of the code by one, so that 32-bit and 64-bit - # releases get separate product codes - digit = hex((int(product_code[-2],16)+1)%16)[-1] - product_code = product_code[:-2] + digit + '}' + +if snapshot: + product_code = msilib.gen_uuid() +else: + # official release: generate UUID from the download link that the file will have + import uuid + product_code = uuid.uuid3(uuid.NAMESPACE_URL, + 'http://www.python.org/ftp/python/%s.%s.%s/python-%s%s.msi' % + (major, minor, micro, full_current_version, msilib.arch_ext)) + product_code = '{%s}' % product_code if testpackage: ext = 'px' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 21:16:46 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 04 Mar 2012 21:16:46 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314171=3A_Add_valgr?= =?utf8?q?ind_suppressions_for_OpenSSL_issue=2E?= Message-ID: http://hg.python.org/cpython/rev/9a69b47f194e changeset: 75401:9a69b47f194e user: Martin v. L?wis date: Sun Mar 04 21:16:39 2012 +0100 summary: Issue #14171: Add valgrind suppressions for OpenSSL issue. Patch by Zooko O'Whielacronx. files: Misc/valgrind-python.supp | 32 +++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) diff --git a/Misc/valgrind-python.supp b/Misc/valgrind-python.supp --- a/Misc/valgrind-python.supp +++ b/Misc/valgrind-python.supp @@ -310,6 +310,38 @@ ### fun:MD5_Update ###} +# Fedora's package "openssl-1.0.1-0.1.beta2.fc17.x86_64" on x86_64 +# See http://bugs.python.org/issue14171 +{ + openssl 1.0.1 prng 1 + Memcheck:Cond + fun:bcmp + fun:fips_get_entropy + fun:FIPS_drbg_instantiate + fun:RAND_init_fips + fun:OPENSSL_init_library + fun:SSL_library_init + fun:init_hashlib +} + +{ + openssl 1.0.1 prng 2 + Memcheck:Cond + fun:fips_get_entropy + fun:FIPS_drbg_instantiate + fun:RAND_init_fips + fun:OPENSSL_init_library + fun:SSL_library_init + fun:init_hashlib +} + +{ + openssl 1.0.1 prng 3 + Memcheck:Value8 + fun:_x86_64_AES_encrypt_compact + fun:AES_encrypt +} + # # All of these problems come from using test_socket_ssl # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 21:30:34 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 04 Mar 2012 21:30:34 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_some_set_al?= =?utf8?q?gebra_methods_of_WeakSet_objects=2E?= Message-ID: http://hg.python.org/cpython/rev/d19d9ecbe42b changeset: 75402:d19d9ecbe42b branch: 3.2 parent: 75398:5a2bc0d574f6 user: Antoine Pitrou date: Sun Mar 04 20:47:05 2012 +0100 summary: Fix some set algebra methods of WeakSet objects. files: Lib/_weakrefset.py | 41 ++++++++------------------- Lib/test/test_weakset.py | 22 ++++++++++++-- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -121,26 +121,14 @@ self.update(other) return self - # Helper functions for simple delegating methods. - def _apply(self, other, method): - if not isinstance(other, self.__class__): - other = self.__class__(other) - newdata = method(other.data) - newset = self.__class__() - newset.data = newdata + def difference(self, other): + newset = self.copy() + newset.difference_update(other) return newset - - def difference(self, other): - return self._apply(other, self.data.difference) __sub__ = difference def difference_update(self, other): - if self._pending_removals: - self._commit_removals() - if self is other: - self.data.clear() - else: - self.data.difference_update(ref(item) for item in other) + self.__isub__(other) def __isub__(self, other): if self._pending_removals: self._commit_removals() @@ -151,13 +139,11 @@ return self def intersection(self, other): - return self._apply(other, self.data.intersection) + return self.__class__(item for item in other if item in self) __and__ = intersection def intersection_update(self, other): - if self._pending_removals: - self._commit_removals() - self.data.intersection_update(ref(item) for item in other) + self.__iand__(other) def __iand__(self, other): if self._pending_removals: self._commit_removals() @@ -184,27 +170,24 @@ return self.data == set(ref(item) for item in other) def symmetric_difference(self, other): - return self._apply(other, self.data.symmetric_difference) + newset = self.copy() + newset.symmetric_difference_update(other) + return newset __xor__ = symmetric_difference def symmetric_difference_update(self, other): - if self._pending_removals: - self._commit_removals() - if self is other: - self.data.clear() - else: - self.data.symmetric_difference_update(ref(item) for item in other) + self.__ixor__(other) def __ixor__(self, other): if self._pending_removals: self._commit_removals() if self is other: self.data.clear() else: - self.data.symmetric_difference_update(ref(item) for item in other) + self.data.symmetric_difference_update(ref(item, self._remove) for item in other) return self def union(self, other): - return self._apply(other, self.data.union) + return self.__class__(e for s in (self, other) for e in s) __or__ = union def isdisjoint(self, other): diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -71,6 +71,11 @@ x = WeakSet(self.items + self.items2) c = C(self.items2) self.assertEqual(self.s.union(c), x) + del c + self.assertEqual(len(u), len(self.items) + len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(u), len(self.items) + len(self.items2)) def test_or(self): i = self.s.union(self.items2) @@ -78,14 +83,19 @@ self.assertEqual(self.s | frozenset(self.items2), i) def test_intersection(self): - i = self.s.intersection(self.items2) + s = WeakSet(self.letters) + i = s.intersection(self.items2) for c in self.letters: - self.assertEqual(c in i, c in self.d and c in self.items2) - self.assertEqual(self.s, WeakSet(self.items)) + self.assertEqual(c in i, c in self.items2 and c in self.letters) + self.assertEqual(s, WeakSet(self.letters)) self.assertEqual(type(i), WeakSet) for C in set, frozenset, dict.fromkeys, list, tuple: x = WeakSet([]) - self.assertEqual(self.s.intersection(C(self.items2)), x) + self.assertEqual(i.intersection(C(self.items)), x) + self.assertEqual(len(i), len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(i), len(self.items2)) def test_isdisjoint(self): self.assertTrue(self.s.isdisjoint(WeakSet(self.items2))) @@ -116,6 +126,10 @@ self.assertEqual(self.s, WeakSet(self.items)) self.assertEqual(type(i), WeakSet) self.assertRaises(TypeError, self.s.symmetric_difference, [[]]) + self.assertEqual(len(i), len(self.items) + len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(i), len(self.items) + len(self.items2)) def test_xor(self): i = self.s.symmetric_difference(self.items2) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 4 21:30:35 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 04 Mar 2012 21:30:35 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Fix_some_set_algebra_methods_of_WeakSet_objects=2E?= Message-ID: http://hg.python.org/cpython/rev/edda4b33a75a changeset: 75403:edda4b33a75a parent: 75401:9a69b47f194e parent: 75402:d19d9ecbe42b user: Antoine Pitrou date: Sun Mar 04 21:16:52 2012 +0100 summary: Fix some set algebra methods of WeakSet objects. files: Lib/_weakrefset.py | 41 ++++++++------------------- Lib/test/test_weakset.py | 22 ++++++++++++-- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -121,26 +121,14 @@ self.update(other) return self - # Helper functions for simple delegating methods. - def _apply(self, other, method): - if not isinstance(other, self.__class__): - other = self.__class__(other) - newdata = method(other.data) - newset = self.__class__() - newset.data = newdata + def difference(self, other): + newset = self.copy() + newset.difference_update(other) return newset - - def difference(self, other): - return self._apply(other, self.data.difference) __sub__ = difference def difference_update(self, other): - if self._pending_removals: - self._commit_removals() - if self is other: - self.data.clear() - else: - self.data.difference_update(ref(item) for item in other) + self.__isub__(other) def __isub__(self, other): if self._pending_removals: self._commit_removals() @@ -151,13 +139,11 @@ return self def intersection(self, other): - return self._apply(other, self.data.intersection) + return self.__class__(item for item in other if item in self) __and__ = intersection def intersection_update(self, other): - if self._pending_removals: - self._commit_removals() - self.data.intersection_update(ref(item) for item in other) + self.__iand__(other) def __iand__(self, other): if self._pending_removals: self._commit_removals() @@ -184,27 +170,24 @@ return self.data == set(ref(item) for item in other) def symmetric_difference(self, other): - return self._apply(other, self.data.symmetric_difference) + newset = self.copy() + newset.symmetric_difference_update(other) + return newset __xor__ = symmetric_difference def symmetric_difference_update(self, other): - if self._pending_removals: - self._commit_removals() - if self is other: - self.data.clear() - else: - self.data.symmetric_difference_update(ref(item) for item in other) + self.__ixor__(other) def __ixor__(self, other): if self._pending_removals: self._commit_removals() if self is other: self.data.clear() else: - self.data.symmetric_difference_update(ref(item) for item in other) + self.data.symmetric_difference_update(ref(item, self._remove) for item in other) return self def union(self, other): - return self._apply(other, self.data.union) + return self.__class__(e for s in (self, other) for e in s) __or__ = union def isdisjoint(self, other): diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -71,6 +71,11 @@ x = WeakSet(self.items + self.items2) c = C(self.items2) self.assertEqual(self.s.union(c), x) + del c + self.assertEqual(len(u), len(self.items) + len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(u), len(self.items) + len(self.items2)) def test_or(self): i = self.s.union(self.items2) @@ -78,14 +83,19 @@ self.assertEqual(self.s | frozenset(self.items2), i) def test_intersection(self): - i = self.s.intersection(self.items2) + s = WeakSet(self.letters) + i = s.intersection(self.items2) for c in self.letters: - self.assertEqual(c in i, c in self.d and c in self.items2) - self.assertEqual(self.s, WeakSet(self.items)) + self.assertEqual(c in i, c in self.items2 and c in self.letters) + self.assertEqual(s, WeakSet(self.letters)) self.assertEqual(type(i), WeakSet) for C in set, frozenset, dict.fromkeys, list, tuple: x = WeakSet([]) - self.assertEqual(self.s.intersection(C(self.items2)), x) + self.assertEqual(i.intersection(C(self.items)), x) + self.assertEqual(len(i), len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(i), len(self.items2)) def test_isdisjoint(self): self.assertTrue(self.s.isdisjoint(WeakSet(self.items2))) @@ -116,6 +126,10 @@ self.assertEqual(self.s, WeakSet(self.items)) self.assertEqual(type(i), WeakSet) self.assertRaises(TypeError, self.s.symmetric_difference, [[]]) + self.assertEqual(len(i), len(self.items) + len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(i), len(self.items) + len(self.items2)) def test_xor(self): i = self.s.symmetric_difference(self.items2) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Mar 5 05:32:58 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 05 Mar 2012 05:32:58 +0100 Subject: [Python-checkins] Daily reference leaks (edda4b33a75a): sum=0 Message-ID: results for edda4b33a75a on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogURr4WQ', '-x'] From python-checkins at python.org Mon Mar 5 05:43:33 2012 From: python-checkins at python.org (meador.inge) Date: Mon, 05 Mar 2012 05:43:33 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0MTk1?= =?utf8?b?OiBNYWtlIFdlYWtTZXQuX19sdF9fIGFuZCBXZWFrU2V0Ll9fZ3RfXyBpcnJlZmxl?= =?utf8?q?xive=2E?= Message-ID: http://hg.python.org/cpython/rev/4b3f1decb1af changeset: 75404:4b3f1decb1af branch: 2.7 parent: 75397:428bfb58e3b3 user: Meador Inge date: Sun Mar 04 22:02:17 2012 -0600 summary: Issue #14195: Make WeakSet.__lt__ and WeakSet.__gt__ irreflexive. files: Lib/_weakrefset.py | 12 ++++---- Lib/test/test_weakset.py | 34 ++++++++++++++++++--------- Misc/NEWS | 4 +++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -154,17 +154,17 @@ def issubset(self, other): return self.data.issubset(ref(item) for item in other) - __lt__ = issubset + __le__ = issubset - def __le__(self, other): - return self.data <= set(ref(item) for item in other) + def __lt__(self, other): + return self.data < set(ref(item) for item in other) def issuperset(self, other): return self.data.issuperset(ref(item) for item in other) - __gt__ = issuperset + __ge__ = issuperset - def __ge__(self, other): - return self.data >= set(ref(item) for item in other) + def __gt__(self, other): + return self.data > set(ref(item) for item in other) def __eq__(self, other): if not isinstance(other, self.__class__): diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -41,6 +41,12 @@ self.items = [SomeClass(c) for c in ('a', 'b', 'c')] self.items2 = [SomeClass(c) for c in ('x', 'y', 'z')] self.letters = [SomeClass(c) for c in string.ascii_letters] + self.ab_items = [SomeClass(c) for c in 'ab'] + self.abcde_items = [SomeClass(c) for c in 'abcde'] + self.def_items = [SomeClass(c) for c in 'def'] + self.ab_weakset = WeakSet(self.ab_items) + self.abcde_weakset = WeakSet(self.abcde_items) + self.def_weakset = WeakSet(self.def_items) self.s = WeakSet(self.items) self.d = dict.fromkeys(self.items) self.obj = SomeClass('F') @@ -149,22 +155,28 @@ self.assertEqual(self.s ^ frozenset(self.items2), i) def test_sub_and_super(self): - pl, ql, rl = map(lambda s: [SomeClass(c) for c in s], ['ab', 'abcde', 'def']) - p, q, r = map(WeakSet, (pl, ql, rl)) - self.assertTrue(p < q) - self.assertTrue(p <= q) - self.assertTrue(q <= q) - self.assertTrue(q > p) - self.assertTrue(q >= p) - self.assertFalse(q < r) - self.assertFalse(q <= r) - self.assertFalse(q > r) - self.assertFalse(q >= r) + self.assertTrue(self.ab_weakset <= self.abcde_weakset) + self.assertTrue(self.abcde_weakset <= self.abcde_weakset) + self.assertTrue(self.abcde_weakset >= self.ab_weakset) + self.assertFalse(self.abcde_weakset <= self.def_weakset) + self.assertFalse(self.abcde_weakset >= self.def_weakset) self.assertTrue(set('a').issubset('abc')) self.assertTrue(set('abc').issuperset('a')) self.assertFalse(set('a').issubset('cbs')) self.assertFalse(set('cbs').issuperset('a')) + def test_lt(self): + self.assertTrue(self.ab_weakset < self.abcde_weakset) + self.assertFalse(self.abcde_weakset < self.def_weakset) + self.assertFalse(self.ab_weakset < self.ab_weakset) + self.assertFalse(WeakSet() < WeakSet()) + + def test_gt(self): + self.assertTrue(self.abcde_weakset > self.ab_weakset) + self.assertFalse(self.abcde_weakset > self.def_weakset) + self.assertFalse(self.ab_weakset > self.ab_weakset) + self.assertFalse(WeakSet() > WeakSet()) + def test_gc(self): # Create a nest of cycles to exercise overall ref count check s = WeakSet(Foo() for i in range(1000)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -101,6 +101,10 @@ Library ------- +- Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly + return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been + fixed. + - Issue #14159: Fix the len() of weak sets to return a better approximation when some objects are dead or dying. Moreover, the implementation is now O(1) rather than O(n). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 05:43:34 2012 From: python-checkins at python.org (meador.inge) Date: Mon, 05 Mar 2012 05:43:34 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MTk1?= =?utf8?b?OiBNYWtlIFdlYWtTZXQuX19sdF9fIGFuZCBXZWFrU2V0Ll9fZ3RfXyBpcnJlZmxl?= =?utf8?q?xive=2E?= Message-ID: http://hg.python.org/cpython/rev/5b88475aae96 changeset: 75405:5b88475aae96 branch: 3.2 parent: 75402:d19d9ecbe42b user: Meador Inge date: Sun Mar 04 22:15:38 2012 -0600 summary: Issue #14195: Make WeakSet.__lt__ and WeakSet.__gt__ irreflexive. files: Lib/_weakrefset.py | 12 ++++---- Lib/test/test_weakset.py | 34 ++++++++++++++++++--------- Misc/NEWS | 4 +++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -152,17 +152,17 @@ def issubset(self, other): return self.data.issubset(ref(item) for item in other) - __lt__ = issubset + __le__ = issubset - def __le__(self, other): - return self.data <= set(ref(item) for item in other) + def __lt__(self, other): + return self.data < set(ref(item) for item in other) def issuperset(self, other): return self.data.issuperset(ref(item) for item in other) - __gt__ = issuperset + __ge__ = issuperset - def __ge__(self, other): - return self.data >= set(ref(item) for item in other) + def __gt__(self, other): + return self.data > set(ref(item) for item in other) def __eq__(self, other): if not isinstance(other, self.__class__): diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -28,6 +28,12 @@ # need to keep references to them self.items = [ustr(c) for c in ('a', 'b', 'c')] self.items2 = [ustr(c) for c in ('x', 'y', 'z')] + self.ab_items = [ustr(c) for c in 'ab'] + self.abcde_items = [ustr(c) for c in 'abcde'] + self.def_items = [ustr(c) for c in 'def'] + self.ab_weakset = WeakSet(self.ab_items) + self.abcde_weakset = WeakSet(self.abcde_items) + self.def_weakset = WeakSet(self.def_items) self.letters = [ustr(c) for c in string.ascii_letters] self.s = WeakSet(self.items) self.d = dict.fromkeys(self.items) @@ -137,22 +143,28 @@ self.assertEqual(self.s ^ frozenset(self.items2), i) def test_sub_and_super(self): - pl, ql, rl = map(lambda s: [ustr(c) for c in s], ['ab', 'abcde', 'def']) - p, q, r = map(WeakSet, (pl, ql, rl)) - self.assertTrue(p < q) - self.assertTrue(p <= q) - self.assertTrue(q <= q) - self.assertTrue(q > p) - self.assertTrue(q >= p) - self.assertFalse(q < r) - self.assertFalse(q <= r) - self.assertFalse(q > r) - self.assertFalse(q >= r) + self.assertTrue(self.ab_weakset <= self.abcde_weakset) + self.assertTrue(self.abcde_weakset <= self.abcde_weakset) + self.assertTrue(self.abcde_weakset >= self.ab_weakset) + self.assertFalse(self.abcde_weakset <= self.def_weakset) + self.assertFalse(self.abcde_weakset >= self.def_weakset) self.assertTrue(set('a').issubset('abc')) self.assertTrue(set('abc').issuperset('a')) self.assertFalse(set('a').issubset('cbs')) self.assertFalse(set('cbs').issuperset('a')) + def test_lt(self): + self.assertTrue(self.ab_weakset < self.abcde_weakset) + self.assertFalse(self.abcde_weakset < self.def_weakset) + self.assertFalse(self.ab_weakset < self.ab_weakset) + self.assertFalse(WeakSet() < WeakSet()) + + def test_gt(self): + self.assertTrue(self.abcde_weakset > self.ab_weakset) + self.assertFalse(self.abcde_weakset > self.def_weakset) + self.assertFalse(self.ab_weakset > self.ab_weakset) + self.assertFalse(WeakSet() > WeakSet()) + def test_gc(self): # Create a nest of cycles to exercise overall ref count check s = WeakSet(Foo() for i in range(1000)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -130,6 +130,10 @@ Library ------- +- Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly + return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been + fixed. + - Issue #14177: marshal.loads() now raises TypeError when given an unicode string. Patch by Guilherme Gon?alves. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 05:43:35 2012 From: python-checkins at python.org (meador.inge) Date: Mon, 05 Mar 2012 05:43:35 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiBJc3N1ZSAjMTQxOTU6IE1ha2UgV2Vha1NldC5fX2x0X18gYW5kIFdlYWtTZXQu?= =?utf8?b?X19ndF9fIGlycmVmbGV4aXZlLg==?= Message-ID: http://hg.python.org/cpython/rev/31dc8fe15b02 changeset: 75406:31dc8fe15b02 parent: 75403:edda4b33a75a parent: 75405:5b88475aae96 user: Meador Inge date: Sun Mar 04 22:40:15 2012 -0600 summary: Issue #14195: Make WeakSet.__lt__ and WeakSet.__gt__ irreflexive. files: Lib/_weakrefset.py | 12 ++++---- Lib/test/test_weakset.py | 34 ++++++++++++++++++--------- Misc/NEWS | 4 +++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -152,17 +152,17 @@ def issubset(self, other): return self.data.issubset(ref(item) for item in other) - __lt__ = issubset + __le__ = issubset - def __le__(self, other): - return self.data <= set(ref(item) for item in other) + def __lt__(self, other): + return self.data < set(ref(item) for item in other) def issuperset(self, other): return self.data.issuperset(ref(item) for item in other) - __gt__ = issuperset + __ge__ = issuperset - def __ge__(self, other): - return self.data >= set(ref(item) for item in other) + def __gt__(self, other): + return self.data > set(ref(item) for item in other) def __eq__(self, other): if not isinstance(other, self.__class__): diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -28,6 +28,12 @@ # need to keep references to them self.items = [ustr(c) for c in ('a', 'b', 'c')] self.items2 = [ustr(c) for c in ('x', 'y', 'z')] + self.ab_items = [ustr(c) for c in 'ab'] + self.abcde_items = [ustr(c) for c in 'abcde'] + self.def_items = [ustr(c) for c in 'def'] + self.ab_weakset = WeakSet(self.ab_items) + self.abcde_weakset = WeakSet(self.abcde_items) + self.def_weakset = WeakSet(self.def_items) self.letters = [ustr(c) for c in string.ascii_letters] self.s = WeakSet(self.items) self.d = dict.fromkeys(self.items) @@ -137,22 +143,28 @@ self.assertEqual(self.s ^ frozenset(self.items2), i) def test_sub_and_super(self): - pl, ql, rl = map(lambda s: [ustr(c) for c in s], ['ab', 'abcde', 'def']) - p, q, r = map(WeakSet, (pl, ql, rl)) - self.assertTrue(p < q) - self.assertTrue(p <= q) - self.assertTrue(q <= q) - self.assertTrue(q > p) - self.assertTrue(q >= p) - self.assertFalse(q < r) - self.assertFalse(q <= r) - self.assertFalse(q > r) - self.assertFalse(q >= r) + self.assertTrue(self.ab_weakset <= self.abcde_weakset) + self.assertTrue(self.abcde_weakset <= self.abcde_weakset) + self.assertTrue(self.abcde_weakset >= self.ab_weakset) + self.assertFalse(self.abcde_weakset <= self.def_weakset) + self.assertFalse(self.abcde_weakset >= self.def_weakset) self.assertTrue(set('a').issubset('abc')) self.assertTrue(set('abc').issuperset('a')) self.assertFalse(set('a').issubset('cbs')) self.assertFalse(set('cbs').issuperset('a')) + def test_lt(self): + self.assertTrue(self.ab_weakset < self.abcde_weakset) + self.assertFalse(self.abcde_weakset < self.def_weakset) + self.assertFalse(self.ab_weakset < self.ab_weakset) + self.assertFalse(WeakSet() < WeakSet()) + + def test_gt(self): + self.assertTrue(self.abcde_weakset > self.ab_weakset) + self.assertFalse(self.abcde_weakset > self.def_weakset) + self.assertFalse(self.ab_weakset > self.ab_weakset) + self.assertFalse(WeakSet() > WeakSet()) + def test_gc(self): # Create a nest of cycles to exercise overall ref count check s = WeakSet(Foo() for i in range(1000)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -511,6 +511,10 @@ Library ------- +- Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly + return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been + fixed. + - Issue #14166: Pickler objects now have an optional ``dispatch_table`` attribute which allows to set custom per-pickler reduction functions. Patch by sbt. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 07:01:57 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 05 Mar 2012 07:01:57 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314168=3A_Check_for?= =?utf8?q?_presence_of_=5Fattrs_before_accessing_it=2E?= Message-ID: http://hg.python.org/cpython/rev/73c76466cf44 changeset: 75407:73c76466cf44 user: Martin v. L?wis date: Mon Mar 05 07:01:49 2012 +0100 summary: Issue #14168: Check for presence of _attrs before accessing it. files: Lib/test/test_minidom.py | 15 ++++++++++++--- Lib/xml/dom/minidom.py | 4 ++++ Misc/NEWS | 2 ++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -362,11 +362,17 @@ def testGetAttrList(self): pass - def testGetAttrValues(self): pass + def testGetAttrValues(self): + pass - def testGetAttrLength(self): pass + def testGetAttrLength(self): + pass - def testGetAttribute(self): pass + def testGetAttribute(self): + dom = Document() + child = dom.appendChild( + dom.createElementNS("http://www.python.org", "python:abc")) + self.assertEqual(child.getAttribute('missing'), '') def testGetAttributeNS(self): dom = Document() @@ -378,6 +384,9 @@ 'http://www.python.org') self.assertEqual(child.getAttributeNS("http://www.w3.org", "other"), '') + child2 = child.appendChild(dom.createElement('abc')) + self.assertEqual(child2.getAttributeNS("http://www.python.org", "missing"), + '') def testGetAttributeNode(self): pass diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -723,12 +723,16 @@ Node.unlink(self) def getAttribute(self, attname): + if self._attrs is None: + return "" try: return self._attrs[attname].value except KeyError: return "" def getAttributeNS(self, namespaceURI, localName): + if self._attrsNS is None: + return "" try: return self._attrsNS[(namespaceURI, localName)].value except KeyError: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -511,6 +511,8 @@ Library ------- +- Issue #14168: Check for presence of _attrs before accessing it. + - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been fixed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 07:58:33 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 05 Mar 2012 07:58:33 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Incorporate_measurement_result?= =?utf8?q?s=2E?= Message-ID: http://hg.python.org/peps/rev/eaaccc02c636 changeset: 4114:eaaccc02c636 user: Martin v. L?wis date: Mon Mar 05 07:58:30 2012 +0100 summary: Incorporate measurement results. files: pep-0393.txt | 21 +++++++++++++++++++++ 1 files changed, 21 insertions(+), 0 deletions(-) diff --git a/pep-0393.txt b/pep-0393.txt --- a/pep-0393.txt +++ b/pep-0393.txt @@ -372,6 +372,25 @@ slowdowns of 1% to 30%; for specific benchmarks, speedups may happen as may happen significantly larger slowdowns. +In actual measurements of a Django application ([2]_), significant +reductions of memory usage could be found. For example, the storage +for Unicode objects reduced to 2216807 bytes, down from 6378540 bytes +for a wide Unicode build, and down from 3694694 bytes for a narrow +Unicode build (all on a 32-bit system). This reduction came from the +prevalence of ASCII strings in this application; out of 36,000 strings +(with 1,310,000 chars), 35713 where ASCII strings (with 1,300,000 +chars). The sources for these strings where not further analysed; +many of them likely originate from identifiers in the library, and +string constants in Django's source code. + +In comparison to Python 2, both Unicode and byte strings need to be +accounted. In the test application, Unicode and byte strings combined +had a length of 2,046,000 units (bytes/chars) in 2.x, and 2,200,000 +units in 3.x. On a 32-bit system, where the 2.x build used 32-bit +wchar_t/Py_UNICODE, the 2.x test used 3,620,000 bytes, and the 3.x +build 3,340,000 bytes. This reduction in 3.x using the PEP compared +to 2.x only occurs when comparing with a wide unicode build. + Porting Guidelines ================== @@ -435,6 +454,8 @@ .. [1] PEP 393 branch https://bitbucket.org/t0rsten/pep-393 +.. [2] Django measurement results + http://www.dcl.hpi.uni-potsdam.de/home/loewis/djmemprof/ Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Mar 5 08:50:45 2012 From: python-checkins at python.org (georg.brandl) Date: Mon, 05 Mar 2012 08:50:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_3=2E3=2E0a1_is_done=2E?= Message-ID: http://hg.python.org/cpython/rev/84d09c1d2b6b changeset: 75408:84d09c1d2b6b user: Georg Brandl date: Mon Mar 05 08:54:46 2012 +0100 summary: 3.3.0a1 is done. files: Include/patchlevel.h | 2 +- Misc/NEWS | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.3.0a1" +#define PY_VERSION "3.3.0a1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,18 @@ Python News +++++++++++ +What's New in Python 3.3.0 Alpha 2? +=================================== + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.3.0 Alpha 1? =================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 09:37:27 2012 From: python-checkins at python.org (stefan.krah) Date: Mon, 05 Mar 2012 09:37:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314181=3A_Allow_mem?= =?utf8?q?oryview_construction_from_an_object_that_uses_the?= Message-ID: http://hg.python.org/cpython/rev/f1441971b621 changeset: 75409:f1441971b621 user: Stefan Krah date: Mon Mar 05 09:30:47 2012 +0100 summary: Issue #14181: Allow memoryview construction from an object that uses the getbuffer redirection scheme. files: Lib/test/test_buffer.py | 90 +++++++++++++++++++++++++++++ Modules/_testbuffer.c | 25 ++++--- Objects/memoryobject.c | 3 - 3 files changed, 105 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -3373,6 +3373,15 @@ del nd m.release() + a = bytearray([1,2,3]) + m = memoryview(a) + nd1 = ndarray(m, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + nd2 = ndarray(nd1, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + self.assertIs(nd2.obj, m) + self.assertRaises(BufferError, m.release) + del nd1, nd2 + m.release() + # chained views a = bytearray([1,2,3]) m1 = memoryview(a) @@ -3383,6 +3392,17 @@ del nd m2.release() + a = bytearray([1,2,3]) + m1 = memoryview(a) + m2 = memoryview(m1) + nd1 = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + nd2 = ndarray(nd1, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + self.assertIs(nd2.obj, m2) + m1.release() + self.assertRaises(BufferError, m2.release) + del nd1, nd2 + m2.release() + # Allow changing layout while buffers are exported. nd = ndarray([1,2,3], shape=[3], flags=ND_VAREXPORT) m1 = memoryview(nd) @@ -3418,12 +3438,82 @@ catch22(m1) self.assertEqual(m1[0], ord(b'1')) + x = ndarray(list(range(12)), shape=[2,2,3], format='l') + y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + self.assertIs(z.obj, x) + with memoryview(z) as m: + catch22(m) + self.assertEqual(m[0:1].tolist(), [[[0, 1, 2], [3, 4, 5]]]) + + # Test garbage collection. + for flags in (0, ND_REDIRECT): + x = bytearray(b'123') + with memoryview(x) as m1: + del x + y = ndarray(m1, getbuf=PyBUF_FULL_RO, flags=flags) + with memoryview(y) as m2: + del y + z = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=flags) + with memoryview(z) as m3: + del z + catch22(m3) + catch22(m2) + catch22(m1) + self.assertEqual(m1[0], ord(b'1')) + self.assertEqual(m2[1], ord(b'2')) + self.assertEqual(m3[2], ord(b'3')) + del m3 + del m2 + del m1 + + x = bytearray(b'123') + with memoryview(x) as m1: + del x + y = ndarray(m1, getbuf=PyBUF_FULL_RO, flags=flags) + with memoryview(y) as m2: + del y + z = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=flags) + with memoryview(z) as m3: + del z + catch22(m1) + catch22(m2) + catch22(m3) + self.assertEqual(m1[0], ord(b'1')) + self.assertEqual(m2[1], ord(b'2')) + self.assertEqual(m3[2], ord(b'3')) + del m1, m2, m3 + # XXX If m1 has exports, raise BufferError. # x = bytearray(b'123') # with memoryview(x) as m1: # ex = ndarray(m1) # m1[0] == ord(b'1') + def test_memoryview_redirect(self): + + nd = ndarray([1.0 * x for x in range(12)], shape=[12], format='d') + a = array.array('d', [1.0 * x for x in range(12)]) + + for x in (nd, a): + y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + m = memoryview(z) + + self.assertIs(y.obj, x) + self.assertIs(z.obj, x) + self.assertIs(m.obj, x) + + self.assertEqual(m, x) + self.assertEqual(m, y) + self.assertEqual(m, z) + + self.assertEqual(m[1:3], x[1:3]) + self.assertEqual(m[1:3], y[1:3]) + self.assertEqual(m[1:3], z[1:3]) + del y, z + self.assertEqual(m[1:3], x[1:3]) + def test_issue_7385(self): x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL) self.assertRaises(BufferError, memoryview, x) diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -53,14 +53,14 @@ #define ND_SCALAR 0x008 /* scalar: ndim = 0 */ #define ND_PIL 0x010 /* convert to PIL-style array (suboffsets) */ #define ND_GETBUF_FAIL 0x020 /* test issue 7385 */ +#define ND_REDIRECT 0x040 /* redirect buffer requests */ /* Default: NumPy style (strides), read-only, no var-export, C-style layout */ #define ND_DEFAULT 0x0 /* Internal flags for the base buffer */ -#define ND_C 0x040 /* C contiguous layout (default) */ -#define ND_OWN_ARRAYS 0x080 /* consumer owns arrays */ -#define ND_UNUSED 0x100 /* initializer */ +#define ND_C 0x080 /* C contiguous layout (default) */ +#define ND_OWN_ARRAYS 0x100 /* consumer owns arrays */ /* ndarray properties */ #define ND_IS_CONSUMER(nd) \ @@ -1290,7 +1290,7 @@ PyObject *strides = NULL; /* number of bytes to the next elt in each dim */ Py_ssize_t offset = 0; /* buffer offset */ PyObject *format = simple_format; /* struct module specifier: "B" */ - int flags = ND_UNUSED; /* base buffer and ndarray flags */ + int flags = ND_DEFAULT; /* base buffer and ndarray flags */ int getbuf = PyBUF_UNUSED; /* re-exporter: getbuffer request flags */ @@ -1302,10 +1302,10 @@ /* NDArrayObject is re-exporter */ if (PyObject_CheckBuffer(v) && shape == NULL) { if (strides || offset || format != simple_format || - flags != ND_UNUSED) { + !(flags == ND_DEFAULT || flags == ND_REDIRECT)) { PyErr_SetString(PyExc_TypeError, - "construction from exporter object only takes a single " - "additional getbuf argument"); + "construction from exporter object only takes 'obj', 'getbuf' " + "and 'flags' arguments"); return -1; } @@ -1315,6 +1315,7 @@ return -1; init_flags(nd->head); + nd->head->flags |= flags; return 0; } @@ -1333,8 +1334,6 @@ return -1; } - if (flags == ND_UNUSED) - flags = ND_DEFAULT; if (flags & ND_VAREXPORT) { nd->flags |= ND_VAREXPORT; flags &= ~ND_VAREXPORT; @@ -1357,7 +1356,7 @@ PyObject *strides = NULL; /* number of bytes to the next elt in each dim */ PyObject *format = simple_format; /* struct module specifier: "B" */ Py_ssize_t offset = 0; /* buffer offset */ - int flags = ND_UNUSED; /* base buffer flags */ + int flags = ND_DEFAULT; /* base buffer flags */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OnOi", kwlist, &items, &shape, &strides, &offset, &format, &flags)) @@ -1423,6 +1422,11 @@ Py_buffer *base = &ndbuf->base; int baseflags = ndbuf->flags; + /* redirect mode */ + if (base->obj != NULL && (baseflags&ND_REDIRECT)) { + return PyObject_GetBuffer(base->obj, view, flags); + } + /* start with complete information */ *view = *base; view->obj = NULL; @@ -2654,6 +2658,7 @@ PyModule_AddIntConstant(m, "ND_SCALAR", ND_SCALAR); PyModule_AddIntConstant(m, "ND_PIL", ND_PIL); PyModule_AddIntConstant(m, "ND_GETBUF_FAIL", ND_GETBUF_FAIL); + PyModule_AddIntConstant(m, "ND_REDIRECT", ND_REDIRECT); PyModule_AddIntConstant(m, "PyBUF_SIMPLE", PyBUF_SIMPLE); PyModule_AddIntConstant(m, "PyBUF_WRITABLE", PyBUF_WRITABLE); diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -91,9 +91,6 @@ return NULL; } - /* Assume that master.obj is a new reference to base. */ - assert(mbuf->master.obj == base); - return (PyObject *)mbuf; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 10:43:02 2012 From: python-checkins at python.org (florent.xicluna) Date: Mon, 05 Mar 2012 10:43:02 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314007=3A_drop_unus?= =?utf8?b?ZWQgVHJlZUJ1aWxkZXIoKS54bWwu?= Message-ID: http://hg.python.org/cpython/rev/39cc025968f1 changeset: 75410:39cc025968f1 user: Florent Xicluna date: Mon Mar 05 10:28:42 2012 +0100 summary: Issue #14007: drop unused TreeBuilder().xml. files: Modules/_elementtree.c | 23 ----------------------- 1 files changed, 0 insertions(+), 23 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1699,13 +1699,6 @@ /* handlers */ LOCAL(PyObject*) -treebuilder_handle_xml(TreeBuilderObject* self, PyObject* encoding, - PyObject* standalone) -{ - Py_RETURN_NONE; -} - -LOCAL(PyObject*) treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag, PyObject* attrib) { @@ -1976,22 +1969,10 @@ return treebuilder_handle_start(self, tag, attrib); } -static PyObject* -treebuilder_xml(TreeBuilderObject* self, PyObject* args) -{ - PyObject* encoding; - PyObject* standalone; - if (!PyArg_ParseTuple(args, "OO:xml", &encoding, &standalone)) - return NULL; - - return treebuilder_handle_xml(self, encoding, standalone); -} - static PyMethodDef treebuilder_methods[] = { {"data", (PyCFunction) treebuilder_data, METH_VARARGS}, {"start", (PyCFunction) treebuilder_start, METH_VARARGS}, {"end", (PyCFunction) treebuilder_end, METH_VARARGS}, - {"xml", (PyCFunction) treebuilder_xml, METH_VARARGS}, {"close", (PyCFunction) treebuilder_close, METH_VARARGS}, {NULL, NULL} }; @@ -2052,8 +2033,6 @@ PyObject* names; - PyObject* handle_xml; - PyObject* handle_start; PyObject* handle_data; PyObject* handle_end; @@ -2506,7 +2485,6 @@ Py_INCREF(target); self->target = target; - self->handle_xml = PyObject_GetAttrString(target, "xml"); self->handle_start = PyObject_GetAttrString(target, "start"); self->handle_data = PyObject_GetAttrString(target, "data"); self->handle_end = PyObject_GetAttrString(target, "end"); @@ -2562,7 +2540,6 @@ Py_XDECREF(self->handle_end); Py_XDECREF(self->handle_data); Py_XDECREF(self->handle_start); - Py_XDECREF(self->handle_xml); Py_DECREF(self->target); Py_DECREF(self->entity); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 10:43:03 2012 From: python-checkins at python.org (florent.xicluna) Date: Mon, 05 Mar 2012 10:43:03 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314007=3A_accept_in?= =?utf8?q?complete_TreeBuilder_objects_=28missing?= Message-ID: http://hg.python.org/cpython/rev/47016103185f changeset: 75411:47016103185f user: Florent Xicluna date: Mon Mar 05 10:42:19 2012 +0100 summary: Issue #14007: accept incomplete TreeBuilder objects (missing start/end/data/close) for the Python implementation as well. Add disabled tests for the doctype() method. files: Lib/test/test_xml_etree.py | 165 +++++++++++++++------- Lib/xml/etree/ElementTree.py | 81 +++++----- Misc/NEWS | 4 + 3 files changed, 155 insertions(+), 95 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1855,58 +1855,16 @@ # -------------------------------------------------------------------- -class CleanContext(object): - """Provide default namespace mapping and path cache.""" - checkwarnings = None +class ElementTreeTest(unittest.TestCase): - def __init__(self, quiet=False): - if sys.flags.optimize >= 2: - # under -OO, doctests cannot be run and therefore not all warnings - # will be emitted - quiet = True - deprecations = ( - # Search behaviour is broken if search path starts with "/". - ("This search is broken in 1.3 and earlier, and will be fixed " - "in a future version. If you rely on the current behaviour, " - "change it to '.+'", FutureWarning), - # Element.getchildren() and Element.getiterator() are deprecated. - ("This method will be removed in future versions. " - "Use .+ instead.", DeprecationWarning), - ("This method will be removed in future versions. " - "Use .+ instead.", PendingDeprecationWarning), - # XMLParser.doctype() is deprecated. - ("This method of XMLParser is deprecated. Define doctype.. " - "method on the TreeBuilder target.", DeprecationWarning)) - self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet) - - def __enter__(self): - from xml.etree import ElementPath - self._nsmap = ET.register_namespace._namespace_map - # Copy the default namespace mapping - self._nsmap_copy = self._nsmap.copy() - # Copy the path cache (should be empty) - self._path_cache = ElementPath._cache - ElementPath._cache = self._path_cache.copy() - self.checkwarnings.__enter__() - - def __exit__(self, *args): - from xml.etree import ElementPath - # Restore mapping and path cache - self._nsmap.clear() - self._nsmap.update(self._nsmap_copy) - ElementPath._cache = self._path_cache - self.checkwarnings.__exit__(*args) - - -class TestAcceleratorNotImported(unittest.TestCase): - # Test that the C accelerator was not imported for pyET - def test_correct_import_pyET(self): - self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') - - -class TestElementClass(unittest.TestCase): - def test_Element_is_a_type(self): + def test_istype(self): + self.assertIsInstance(ET.ParseError, type) + self.assertIsInstance(ET.QName, type) + self.assertIsInstance(ET.ElementTree, type) self.assertIsInstance(ET.Element, type) + # XXX issue 14128 with C ElementTree + # self.assertIsInstance(ET.TreeBuilder, type) + # self.assertIsInstance(ET.XMLParser, type) def test_Element_subclass_trivial(self): class MyElement(ET.Element): @@ -1936,16 +1894,115 @@ self.assertEqual(mye.newmethod(), 'joe') +class TreeBuilderTest(unittest.TestCase): + + sample1 = ('' + 'text') + + def test_dummy_builder(self): + class BaseDummyBuilder: + def close(self): + return 42 + + class DummyBuilder(BaseDummyBuilder): + data = start = end = lambda *a: None + + parser = ET.XMLParser(target=DummyBuilder()) + parser.feed(self.sample1) + self.assertEqual(parser.close(), 42) + + parser = ET.XMLParser(target=BaseDummyBuilder()) + parser.feed(self.sample1) + self.assertEqual(parser.close(), 42) + + parser = ET.XMLParser(target=object()) + parser.feed(self.sample1) + self.assertIsNone(parser.close()) + + + @unittest.expectedFailure # XXX issue 14007 with C ElementTree + def test_doctype(self): + class DoctypeParser: + _doctype = None + + def doctype(self, name, pubid, system): + self._doctype = (name, pubid, system) + + def close(self): + return self._doctype + + parser = ET.XMLParser(target=DoctypeParser()) + parser.feed(self.sample1) + + self.assertEqual(parser.close(), + ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')) + + +class NoAcceleratorTest(unittest.TestCase): + + # Test that the C accelerator was not imported for pyET + def test_correct_import_pyET(self): + self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') + self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') + +# -------------------------------------------------------------------- + + +class CleanContext(object): + """Provide default namespace mapping and path cache.""" + checkwarnings = None + + def __init__(self, quiet=False): + if sys.flags.optimize >= 2: + # under -OO, doctests cannot be run and therefore not all warnings + # will be emitted + quiet = True + deprecations = ( + # Search behaviour is broken if search path starts with "/". + ("This search is broken in 1.3 and earlier, and will be fixed " + "in a future version. If you rely on the current behaviour, " + "change it to '.+'", FutureWarning), + # Element.getchildren() and Element.getiterator() are deprecated. + ("This method will be removed in future versions. " + "Use .+ instead.", DeprecationWarning), + ("This method will be removed in future versions. " + "Use .+ instead.", PendingDeprecationWarning)) + self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet) + + def __enter__(self): + from xml.etree import ElementPath + self._nsmap = ET.register_namespace._namespace_map + # Copy the default namespace mapping + self._nsmap_copy = self._nsmap.copy() + # Copy the path cache (should be empty) + self._path_cache = ElementPath._cache + ElementPath._cache = self._path_cache.copy() + self.checkwarnings.__enter__() + + def __exit__(self, *args): + from xml.etree import ElementPath + # Restore mapping and path cache + self._nsmap.clear() + self._nsmap.update(self._nsmap_copy) + ElementPath._cache = self._path_cache + self.checkwarnings.__exit__(*args) + + def test_main(module=pyET): from test import test_xml_etree - # Run the tests specific to the Python implementation - support.run_unittest(TestAcceleratorNotImported) - # The same doctests are used for both the Python and the C implementations test_xml_etree.ET = module - support.run_unittest(TestElementClass) + test_classes = [ElementTreeTest, TreeBuilderTest] + if module is pyET: + # Run the tests specific to the Python implementation + test_classes += [NoAcceleratorTest] + + support.run_unittest(*test_classes) # XXX the C module should give the same warnings as the Python module with CleanContext(quiet=(module is not pyET)): diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1511,24 +1511,30 @@ self.target = self._target = target self._error = expat.error self._names = {} # name memo cache - # callbacks + # main callbacks parser.DefaultHandlerExpand = self._default - parser.StartElementHandler = self._start - parser.EndElementHandler = self._end - parser.CharacterDataHandler = self._data - # optional callbacks - parser.CommentHandler = self._comment - parser.ProcessingInstructionHandler = self._pi + if hasattr(target, 'start'): + parser.StartElementHandler = self._start + if hasattr(target, 'end'): + parser.EndElementHandler = self._end + if hasattr(target, 'data'): + parser.CharacterDataHandler = target.data + # miscellaneous callbacks + if hasattr(target, 'comment'): + parser.CommentHandler = target.comment + if hasattr(target, 'pi'): + parser.ProcessingInstructionHandler = target.pi # let expat do the buffering, if supported try: - self._parser.buffer_text = 1 + parser.buffer_text = 1 except AttributeError: pass # use new-style attribute handling, if supported try: - self._parser.ordered_attributes = 1 - self._parser.specified_attributes = 1 - parser.StartElementHandler = self._start_list + parser.ordered_attributes = 1 + parser.specified_attributes = 1 + if hasattr(target, 'start'): + parser.StartElementHandler = self._start_list except AttributeError: pass self._doctype = None @@ -1572,44 +1578,29 @@ attrib[fixname(attrib_in[i])] = attrib_in[i+1] return self.target.start(tag, attrib) - def _data(self, text): - return self.target.data(text) - def _end(self, tag): return self.target.end(self._fixname(tag)) - def _comment(self, data): - try: - comment = self.target.comment - except AttributeError: - pass - else: - return comment(data) - - def _pi(self, target, data): - try: - pi = self.target.pi - except AttributeError: - pass - else: - return pi(target, data) - def _default(self, text): prefix = text[:1] if prefix == "&": # deal with undefined entities try: - self.target.data(self.entity[text[1:-1]]) + data_handler = self.target.data + except AttributeError: + return + try: + data_handler(self.entity[text[1:-1]]) except KeyError: from xml.parsers import expat err = expat.error( "undefined entity %s: line %d, column %d" % - (text, self._parser.ErrorLineNumber, - self._parser.ErrorColumnNumber) + (text, self.parser.ErrorLineNumber, + self.parser.ErrorColumnNumber) ) err.code = 11 # XML_ERROR_UNDEFINED_ENTITY - err.lineno = self._parser.ErrorLineNumber - err.offset = self._parser.ErrorColumnNumber + err.lineno = self.parser.ErrorLineNumber + err.offset = self.parser.ErrorColumnNumber raise err elif prefix == "<" and text[:9] == " http://hg.python.org/cpython/rev/0457fb8bf39c changeset: 75412:0457fb8bf39c parent: 75409:f1441971b621 user: Vinay Sajip date: Mon Mar 05 09:43:47 2012 +0000 summary: Added more diagnostics for diagnosing #12151. files: Lib/test/test_logging.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3651,6 +3651,8 @@ def test_rollover(self): fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S', backupCount=1) + fmt = logging.Formatter('%(asctime)s %(message)s') + fh.setFormatter(fmt) r = logging.makeLogRecord({'msg': 'testing'}) fh.emit(r) self.assertLogFile(self.fn) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 10:44:33 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 05 Mar 2012 10:44:33 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merged_upstream_changes=2E?= Message-ID: http://hg.python.org/cpython/rev/cf7b360f9971 changeset: 75413:cf7b360f9971 parent: 75412:0457fb8bf39c parent: 75411:47016103185f user: Vinay Sajip date: Mon Mar 05 09:44:25 2012 +0000 summary: Merged upstream changes. files: Lib/test/test_xml_etree.py | 165 +++++++++++++++------- Lib/xml/etree/ElementTree.py | 81 +++++----- Misc/NEWS | 4 + Modules/_elementtree.c | 23 --- 4 files changed, 155 insertions(+), 118 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1855,58 +1855,16 @@ # -------------------------------------------------------------------- -class CleanContext(object): - """Provide default namespace mapping and path cache.""" - checkwarnings = None +class ElementTreeTest(unittest.TestCase): - def __init__(self, quiet=False): - if sys.flags.optimize >= 2: - # under -OO, doctests cannot be run and therefore not all warnings - # will be emitted - quiet = True - deprecations = ( - # Search behaviour is broken if search path starts with "/". - ("This search is broken in 1.3 and earlier, and will be fixed " - "in a future version. If you rely on the current behaviour, " - "change it to '.+'", FutureWarning), - # Element.getchildren() and Element.getiterator() are deprecated. - ("This method will be removed in future versions. " - "Use .+ instead.", DeprecationWarning), - ("This method will be removed in future versions. " - "Use .+ instead.", PendingDeprecationWarning), - # XMLParser.doctype() is deprecated. - ("This method of XMLParser is deprecated. Define doctype.. " - "method on the TreeBuilder target.", DeprecationWarning)) - self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet) - - def __enter__(self): - from xml.etree import ElementPath - self._nsmap = ET.register_namespace._namespace_map - # Copy the default namespace mapping - self._nsmap_copy = self._nsmap.copy() - # Copy the path cache (should be empty) - self._path_cache = ElementPath._cache - ElementPath._cache = self._path_cache.copy() - self.checkwarnings.__enter__() - - def __exit__(self, *args): - from xml.etree import ElementPath - # Restore mapping and path cache - self._nsmap.clear() - self._nsmap.update(self._nsmap_copy) - ElementPath._cache = self._path_cache - self.checkwarnings.__exit__(*args) - - -class TestAcceleratorNotImported(unittest.TestCase): - # Test that the C accelerator was not imported for pyET - def test_correct_import_pyET(self): - self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') - - -class TestElementClass(unittest.TestCase): - def test_Element_is_a_type(self): + def test_istype(self): + self.assertIsInstance(ET.ParseError, type) + self.assertIsInstance(ET.QName, type) + self.assertIsInstance(ET.ElementTree, type) self.assertIsInstance(ET.Element, type) + # XXX issue 14128 with C ElementTree + # self.assertIsInstance(ET.TreeBuilder, type) + # self.assertIsInstance(ET.XMLParser, type) def test_Element_subclass_trivial(self): class MyElement(ET.Element): @@ -1936,16 +1894,115 @@ self.assertEqual(mye.newmethod(), 'joe') +class TreeBuilderTest(unittest.TestCase): + + sample1 = ('' + 'text') + + def test_dummy_builder(self): + class BaseDummyBuilder: + def close(self): + return 42 + + class DummyBuilder(BaseDummyBuilder): + data = start = end = lambda *a: None + + parser = ET.XMLParser(target=DummyBuilder()) + parser.feed(self.sample1) + self.assertEqual(parser.close(), 42) + + parser = ET.XMLParser(target=BaseDummyBuilder()) + parser.feed(self.sample1) + self.assertEqual(parser.close(), 42) + + parser = ET.XMLParser(target=object()) + parser.feed(self.sample1) + self.assertIsNone(parser.close()) + + + @unittest.expectedFailure # XXX issue 14007 with C ElementTree + def test_doctype(self): + class DoctypeParser: + _doctype = None + + def doctype(self, name, pubid, system): + self._doctype = (name, pubid, system) + + def close(self): + return self._doctype + + parser = ET.XMLParser(target=DoctypeParser()) + parser.feed(self.sample1) + + self.assertEqual(parser.close(), + ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')) + + +class NoAcceleratorTest(unittest.TestCase): + + # Test that the C accelerator was not imported for pyET + def test_correct_import_pyET(self): + self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') + self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') + +# -------------------------------------------------------------------- + + +class CleanContext(object): + """Provide default namespace mapping and path cache.""" + checkwarnings = None + + def __init__(self, quiet=False): + if sys.flags.optimize >= 2: + # under -OO, doctests cannot be run and therefore not all warnings + # will be emitted + quiet = True + deprecations = ( + # Search behaviour is broken if search path starts with "/". + ("This search is broken in 1.3 and earlier, and will be fixed " + "in a future version. If you rely on the current behaviour, " + "change it to '.+'", FutureWarning), + # Element.getchildren() and Element.getiterator() are deprecated. + ("This method will be removed in future versions. " + "Use .+ instead.", DeprecationWarning), + ("This method will be removed in future versions. " + "Use .+ instead.", PendingDeprecationWarning)) + self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet) + + def __enter__(self): + from xml.etree import ElementPath + self._nsmap = ET.register_namespace._namespace_map + # Copy the default namespace mapping + self._nsmap_copy = self._nsmap.copy() + # Copy the path cache (should be empty) + self._path_cache = ElementPath._cache + ElementPath._cache = self._path_cache.copy() + self.checkwarnings.__enter__() + + def __exit__(self, *args): + from xml.etree import ElementPath + # Restore mapping and path cache + self._nsmap.clear() + self._nsmap.update(self._nsmap_copy) + ElementPath._cache = self._path_cache + self.checkwarnings.__exit__(*args) + + def test_main(module=pyET): from test import test_xml_etree - # Run the tests specific to the Python implementation - support.run_unittest(TestAcceleratorNotImported) - # The same doctests are used for both the Python and the C implementations test_xml_etree.ET = module - support.run_unittest(TestElementClass) + test_classes = [ElementTreeTest, TreeBuilderTest] + if module is pyET: + # Run the tests specific to the Python implementation + test_classes += [NoAcceleratorTest] + + support.run_unittest(*test_classes) # XXX the C module should give the same warnings as the Python module with CleanContext(quiet=(module is not pyET)): diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1511,24 +1511,30 @@ self.target = self._target = target self._error = expat.error self._names = {} # name memo cache - # callbacks + # main callbacks parser.DefaultHandlerExpand = self._default - parser.StartElementHandler = self._start - parser.EndElementHandler = self._end - parser.CharacterDataHandler = self._data - # optional callbacks - parser.CommentHandler = self._comment - parser.ProcessingInstructionHandler = self._pi + if hasattr(target, 'start'): + parser.StartElementHandler = self._start + if hasattr(target, 'end'): + parser.EndElementHandler = self._end + if hasattr(target, 'data'): + parser.CharacterDataHandler = target.data + # miscellaneous callbacks + if hasattr(target, 'comment'): + parser.CommentHandler = target.comment + if hasattr(target, 'pi'): + parser.ProcessingInstructionHandler = target.pi # let expat do the buffering, if supported try: - self._parser.buffer_text = 1 + parser.buffer_text = 1 except AttributeError: pass # use new-style attribute handling, if supported try: - self._parser.ordered_attributes = 1 - self._parser.specified_attributes = 1 - parser.StartElementHandler = self._start_list + parser.ordered_attributes = 1 + parser.specified_attributes = 1 + if hasattr(target, 'start'): + parser.StartElementHandler = self._start_list except AttributeError: pass self._doctype = None @@ -1572,44 +1578,29 @@ attrib[fixname(attrib_in[i])] = attrib_in[i+1] return self.target.start(tag, attrib) - def _data(self, text): - return self.target.data(text) - def _end(self, tag): return self.target.end(self._fixname(tag)) - def _comment(self, data): - try: - comment = self.target.comment - except AttributeError: - pass - else: - return comment(data) - - def _pi(self, target, data): - try: - pi = self.target.pi - except AttributeError: - pass - else: - return pi(target, data) - def _default(self, text): prefix = text[:1] if prefix == "&": # deal with undefined entities try: - self.target.data(self.entity[text[1:-1]]) + data_handler = self.target.data + except AttributeError: + return + try: + data_handler(self.entity[text[1:-1]]) except KeyError: from xml.parsers import expat err = expat.error( "undefined entity %s: line %d, column %d" % - (text, self._parser.ErrorLineNumber, - self._parser.ErrorColumnNumber) + (text, self.parser.ErrorLineNumber, + self.parser.ErrorColumnNumber) ) err.code = 11 # XML_ERROR_UNDEFINED_ENTITY - err.lineno = self._parser.ErrorLineNumber - err.offset = self._parser.ErrorColumnNumber + err.lineno = self.parser.ErrorLineNumber + err.offset = self.parser.ErrorColumnNumber raise err elif prefix == "<" and text[:9] == "target = target; - self->handle_xml = PyObject_GetAttrString(target, "xml"); self->handle_start = PyObject_GetAttrString(target, "start"); self->handle_data = PyObject_GetAttrString(target, "data"); self->handle_end = PyObject_GetAttrString(target, "end"); @@ -2562,7 +2540,6 @@ Py_XDECREF(self->handle_end); Py_XDECREF(self->handle_data); Py_XDECREF(self->handle_start); - Py_XDECREF(self->handle_xml); Py_DECREF(self->target); Py_DECREF(self->entity); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 10:51:05 2012 From: python-checkins at python.org (stefan.krah) Date: Mon, 05 Mar 2012 10:51:05 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2310181=3A_The_decis?= =?utf8?q?ion_was_to_raise_a_buffer_error_in_memory=5Fexit=28=29?= Message-ID: http://hg.python.org/cpython/rev/373f6cdc6d08 changeset: 75414:373f6cdc6d08 parent: 75409:f1441971b621 user: Stefan Krah date: Mon Mar 05 10:45:31 2012 +0100 summary: Issue #10181: The decision was to raise a buffer error in memory_exit() if the view has exported buffers. Make this official by uncommenting a test case. files: Lib/test/test_buffer.py | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -3484,11 +3484,12 @@ self.assertEqual(m3[2], ord(b'3')) del m1, m2, m3 - # XXX If m1 has exports, raise BufferError. - # x = bytearray(b'123') - # with memoryview(x) as m1: - # ex = ndarray(m1) - # m1[0] == ord(b'1') + # memoryview.release() fails if the view has exported buffers. + x = bytearray(b'123') + with self.assertRaises(BufferError): + with memoryview(x) as m: + ex = ndarray(m) + m[0] == ord(b'1') def test_memoryview_redirect(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 10:51:05 2012 From: python-checkins at python.org (stefan.krah) Date: Mon, 05 Mar 2012 10:51:05 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?b?KTogTWVyZ2Uu?= Message-ID: http://hg.python.org/cpython/rev/93996b0e07f2 changeset: 75415:93996b0e07f2 parent: 75414:373f6cdc6d08 parent: 75413:cf7b360f9971 user: Stefan Krah date: Mon Mar 05 10:50:11 2012 +0100 summary: Merge. files: Lib/test/test_logging.py | 2 + Lib/test/test_xml_etree.py | 165 +++++++++++++++------- Lib/xml/etree/ElementTree.py | 81 +++++----- Misc/NEWS | 4 + Modules/_elementtree.c | 23 --- 5 files changed, 157 insertions(+), 118 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3651,6 +3651,8 @@ def test_rollover(self): fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S', backupCount=1) + fmt = logging.Formatter('%(asctime)s %(message)s') + fh.setFormatter(fmt) r = logging.makeLogRecord({'msg': 'testing'}) fh.emit(r) self.assertLogFile(self.fn) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1855,58 +1855,16 @@ # -------------------------------------------------------------------- -class CleanContext(object): - """Provide default namespace mapping and path cache.""" - checkwarnings = None +class ElementTreeTest(unittest.TestCase): - def __init__(self, quiet=False): - if sys.flags.optimize >= 2: - # under -OO, doctests cannot be run and therefore not all warnings - # will be emitted - quiet = True - deprecations = ( - # Search behaviour is broken if search path starts with "/". - ("This search is broken in 1.3 and earlier, and will be fixed " - "in a future version. If you rely on the current behaviour, " - "change it to '.+'", FutureWarning), - # Element.getchildren() and Element.getiterator() are deprecated. - ("This method will be removed in future versions. " - "Use .+ instead.", DeprecationWarning), - ("This method will be removed in future versions. " - "Use .+ instead.", PendingDeprecationWarning), - # XMLParser.doctype() is deprecated. - ("This method of XMLParser is deprecated. Define doctype.. " - "method on the TreeBuilder target.", DeprecationWarning)) - self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet) - - def __enter__(self): - from xml.etree import ElementPath - self._nsmap = ET.register_namespace._namespace_map - # Copy the default namespace mapping - self._nsmap_copy = self._nsmap.copy() - # Copy the path cache (should be empty) - self._path_cache = ElementPath._cache - ElementPath._cache = self._path_cache.copy() - self.checkwarnings.__enter__() - - def __exit__(self, *args): - from xml.etree import ElementPath - # Restore mapping and path cache - self._nsmap.clear() - self._nsmap.update(self._nsmap_copy) - ElementPath._cache = self._path_cache - self.checkwarnings.__exit__(*args) - - -class TestAcceleratorNotImported(unittest.TestCase): - # Test that the C accelerator was not imported for pyET - def test_correct_import_pyET(self): - self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') - - -class TestElementClass(unittest.TestCase): - def test_Element_is_a_type(self): + def test_istype(self): + self.assertIsInstance(ET.ParseError, type) + self.assertIsInstance(ET.QName, type) + self.assertIsInstance(ET.ElementTree, type) self.assertIsInstance(ET.Element, type) + # XXX issue 14128 with C ElementTree + # self.assertIsInstance(ET.TreeBuilder, type) + # self.assertIsInstance(ET.XMLParser, type) def test_Element_subclass_trivial(self): class MyElement(ET.Element): @@ -1936,16 +1894,115 @@ self.assertEqual(mye.newmethod(), 'joe') +class TreeBuilderTest(unittest.TestCase): + + sample1 = ('' + 'text') + + def test_dummy_builder(self): + class BaseDummyBuilder: + def close(self): + return 42 + + class DummyBuilder(BaseDummyBuilder): + data = start = end = lambda *a: None + + parser = ET.XMLParser(target=DummyBuilder()) + parser.feed(self.sample1) + self.assertEqual(parser.close(), 42) + + parser = ET.XMLParser(target=BaseDummyBuilder()) + parser.feed(self.sample1) + self.assertEqual(parser.close(), 42) + + parser = ET.XMLParser(target=object()) + parser.feed(self.sample1) + self.assertIsNone(parser.close()) + + + @unittest.expectedFailure # XXX issue 14007 with C ElementTree + def test_doctype(self): + class DoctypeParser: + _doctype = None + + def doctype(self, name, pubid, system): + self._doctype = (name, pubid, system) + + def close(self): + return self._doctype + + parser = ET.XMLParser(target=DoctypeParser()) + parser.feed(self.sample1) + + self.assertEqual(parser.close(), + ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')) + + +class NoAcceleratorTest(unittest.TestCase): + + # Test that the C accelerator was not imported for pyET + def test_correct_import_pyET(self): + self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') + self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') + +# -------------------------------------------------------------------- + + +class CleanContext(object): + """Provide default namespace mapping and path cache.""" + checkwarnings = None + + def __init__(self, quiet=False): + if sys.flags.optimize >= 2: + # under -OO, doctests cannot be run and therefore not all warnings + # will be emitted + quiet = True + deprecations = ( + # Search behaviour is broken if search path starts with "/". + ("This search is broken in 1.3 and earlier, and will be fixed " + "in a future version. If you rely on the current behaviour, " + "change it to '.+'", FutureWarning), + # Element.getchildren() and Element.getiterator() are deprecated. + ("This method will be removed in future versions. " + "Use .+ instead.", DeprecationWarning), + ("This method will be removed in future versions. " + "Use .+ instead.", PendingDeprecationWarning)) + self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet) + + def __enter__(self): + from xml.etree import ElementPath + self._nsmap = ET.register_namespace._namespace_map + # Copy the default namespace mapping + self._nsmap_copy = self._nsmap.copy() + # Copy the path cache (should be empty) + self._path_cache = ElementPath._cache + ElementPath._cache = self._path_cache.copy() + self.checkwarnings.__enter__() + + def __exit__(self, *args): + from xml.etree import ElementPath + # Restore mapping and path cache + self._nsmap.clear() + self._nsmap.update(self._nsmap_copy) + ElementPath._cache = self._path_cache + self.checkwarnings.__exit__(*args) + + def test_main(module=pyET): from test import test_xml_etree - # Run the tests specific to the Python implementation - support.run_unittest(TestAcceleratorNotImported) - # The same doctests are used for both the Python and the C implementations test_xml_etree.ET = module - support.run_unittest(TestElementClass) + test_classes = [ElementTreeTest, TreeBuilderTest] + if module is pyET: + # Run the tests specific to the Python implementation + test_classes += [NoAcceleratorTest] + + support.run_unittest(*test_classes) # XXX the C module should give the same warnings as the Python module with CleanContext(quiet=(module is not pyET)): diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1511,24 +1511,30 @@ self.target = self._target = target self._error = expat.error self._names = {} # name memo cache - # callbacks + # main callbacks parser.DefaultHandlerExpand = self._default - parser.StartElementHandler = self._start - parser.EndElementHandler = self._end - parser.CharacterDataHandler = self._data - # optional callbacks - parser.CommentHandler = self._comment - parser.ProcessingInstructionHandler = self._pi + if hasattr(target, 'start'): + parser.StartElementHandler = self._start + if hasattr(target, 'end'): + parser.EndElementHandler = self._end + if hasattr(target, 'data'): + parser.CharacterDataHandler = target.data + # miscellaneous callbacks + if hasattr(target, 'comment'): + parser.CommentHandler = target.comment + if hasattr(target, 'pi'): + parser.ProcessingInstructionHandler = target.pi # let expat do the buffering, if supported try: - self._parser.buffer_text = 1 + parser.buffer_text = 1 except AttributeError: pass # use new-style attribute handling, if supported try: - self._parser.ordered_attributes = 1 - self._parser.specified_attributes = 1 - parser.StartElementHandler = self._start_list + parser.ordered_attributes = 1 + parser.specified_attributes = 1 + if hasattr(target, 'start'): + parser.StartElementHandler = self._start_list except AttributeError: pass self._doctype = None @@ -1572,44 +1578,29 @@ attrib[fixname(attrib_in[i])] = attrib_in[i+1] return self.target.start(tag, attrib) - def _data(self, text): - return self.target.data(text) - def _end(self, tag): return self.target.end(self._fixname(tag)) - def _comment(self, data): - try: - comment = self.target.comment - except AttributeError: - pass - else: - return comment(data) - - def _pi(self, target, data): - try: - pi = self.target.pi - except AttributeError: - pass - else: - return pi(target, data) - def _default(self, text): prefix = text[:1] if prefix == "&": # deal with undefined entities try: - self.target.data(self.entity[text[1:-1]]) + data_handler = self.target.data + except AttributeError: + return + try: + data_handler(self.entity[text[1:-1]]) except KeyError: from xml.parsers import expat err = expat.error( "undefined entity %s: line %d, column %d" % - (text, self._parser.ErrorLineNumber, - self._parser.ErrorColumnNumber) + (text, self.parser.ErrorLineNumber, + self.parser.ErrorColumnNumber) ) err.code = 11 # XML_ERROR_UNDEFINED_ENTITY - err.lineno = self._parser.ErrorLineNumber - err.offset = self._parser.ErrorColumnNumber + err.lineno = self.parser.ErrorLineNumber + err.offset = self.parser.ErrorColumnNumber raise err elif prefix == "<" and text[:9] == "target = target; - self->handle_xml = PyObject_GetAttrString(target, "xml"); self->handle_start = PyObject_GetAttrString(target, "start"); self->handle_data = PyObject_GetAttrString(target, "data"); self->handle_end = PyObject_GetAttrString(target, "end"); @@ -2562,7 +2540,6 @@ Py_XDECREF(self->handle_end); Py_XDECREF(self->handle_data); Py_XDECREF(self->handle_start); - Py_XDECREF(self->handle_xml); Py_DECREF(self->target); Py_DECREF(self->entity); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 11:43:01 2012 From: python-checkins at python.org (florent.xicluna) Date: Mon, 05 Mar 2012 11:43:01 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Flatten_nested_try_=2E=2E?= =?utf8?b?LiBmaW5hbGx5LCB0cnkgLi4uIGV4Y2VwdC4=?= Message-ID: http://hg.python.org/cpython/rev/09b19d06590e changeset: 75416:09b19d06590e user: Florent Xicluna date: Mon Mar 05 11:42:49 2012 +0100 summary: Flatten nested try ... finally, try ... except. files: Lib/xml/etree/ElementTree.py | 11 +++++------ 1 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1674,12 +1674,11 @@ except self._error as v: self._raiseerror(v) try: - try: - close_handler = self.target.close - except AttributeError: - pass - else: - return close_handler() + close_handler = self.target.close + except AttributeError: + pass + else: + return close_handler() finally: # get rid of circular references del self.parser, self._parser -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 12:35:49 2012 From: python-checkins at python.org (florent.xicluna) Date: Mon, 05 Mar 2012 12:35:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_xml=2Edom=3A_fix_typo=2C_dr?= =?utf8?q?op_unused_imports=2E?= Message-ID: http://hg.python.org/cpython/rev/e5c5c0b5d16c changeset: 75417:e5c5c0b5d16c user: Florent Xicluna date: Mon Mar 05 12:35:15 2012 +0100 summary: xml.dom: fix typo, drop unused imports. files: Lib/xml/dom/domreg.py | 2 -- Lib/xml/dom/expatbuilder.py | 4 +--- 2 files changed, 1 insertions(+), 5 deletions(-) diff --git a/Lib/xml/dom/domreg.py b/Lib/xml/dom/domreg.py --- a/Lib/xml/dom/domreg.py +++ b/Lib/xml/dom/domreg.py @@ -2,8 +2,6 @@ directly. Instead, the functions getDOMImplementation and registerDOMImplementation should be imported from xml.dom.""" -from xml.dom.minicompat import * # isinstance, StringTypes - # This is a list of well-known implementations. Well-known names # should be published by posting to xml-sig at python.org, and are # subsequently recorded in this file. diff --git a/Lib/xml/dom/expatbuilder.py b/Lib/xml/dom/expatbuilder.py --- a/Lib/xml/dom/expatbuilder.py +++ b/Lib/xml/dom/expatbuilder.py @@ -33,8 +33,6 @@ from xml.dom.minidom import _append_child, _set_attribute_node from xml.dom.NodeFilter import NodeFilter -from xml.dom.minicompat import * - TEXT_NODE = Node.TEXT_NODE CDATA_SECTION_NODE = Node.CDATA_SECTION_NODE DOCUMENT_NODE = Node.DOCUMENT_NODE @@ -755,7 +753,7 @@ a = minidom.Attr("xmlns", XMLNS_NAMESPACE, "xmlns", EMPTY_PREFIX) a.value = uri - a.ownerDocuemnt = self.document + a.ownerDocument = self.document _set_attribute_node(node, a) del self._ns_ordered_prefixes[:] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 12:37:38 2012 From: python-checkins at python.org (florent.xicluna) Date: Mon, 05 Mar 2012 12:37:38 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_xml=2Edom=2Eminidom=3A_add_?= =?utf8?q?more_=5F=5Fslots=5F=5F_to_limit_resource_usage=2E?= Message-ID: http://hg.python.org/cpython/rev/49c5511b234a changeset: 75418:49c5511b234a user: Florent Xicluna date: Mon Mar 05 12:37:02 2012 +0100 summary: xml.dom.minidom: add more __slots__ to limit resource usage. files: Lib/xml/dom/__init__.py | 1 + Lib/xml/dom/minidom.py | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Lib/xml/dom/__init__.py b/Lib/xml/dom/__init__.py --- a/Lib/xml/dom/__init__.py +++ b/Lib/xml/dom/__init__.py @@ -17,6 +17,7 @@ class Node: """Class giving the NodeType constants.""" + __slots__ = () # DOM implementations may use this as a base class for their own # Node implementations. If they don't, the constants defined here diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -62,10 +62,7 @@ return writer.stream.getvalue() def hasChildNodes(self): - if self.childNodes: - return True - else: - return False + return bool(self.childNodes) def _get_childNodes(self): return self.childNodes @@ -930,6 +927,7 @@ """Mixin that makes childless-ness easy to implement and avoids the complexity of the Node methods that deal with children. """ + __slots__ = () attributes = None childNodes = EmptyNodeList() @@ -1067,6 +1065,8 @@ class Text(CharacterData): + __slots__ = () + nodeType = Node.TEXT_NODE nodeName = "#text" attributes = None @@ -1188,6 +1188,8 @@ class CDATASection(Text): + __slots__ = () + nodeType = Node.CDATA_SECTION_NODE nodeName = "#cdata-section" @@ -1266,8 +1268,7 @@ class Identified: """Mix-in class that supports the publicId and systemId attributes.""" - # XXX this does not work, this is an old-style class - # __slots__ = 'publicId', 'systemId' + __slots__ = 'publicId', 'systemId' def _identified_mixin_init(self, publicId, systemId): self.publicId = publicId -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 13:48:53 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 05 Mar 2012 13:48:53 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312151=3A_Added_mor?= =?utf8?q?e_info_to_diagnostics=2E?= Message-ID: http://hg.python.org/cpython/rev/a495c41c1e13 changeset: 75419:a495c41c1e13 user: Vinay Sajip date: Mon Mar 05 12:45:51 2012 +0000 summary: Issue #12151: Added more info to diagnostics. files: Lib/test/test_logging.py | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3653,11 +3653,12 @@ backupCount=1) fmt = logging.Formatter('%(asctime)s %(message)s') fh.setFormatter(fmt) - r = logging.makeLogRecord({'msg': 'testing'}) - fh.emit(r) + r1 = logging.makeLogRecord({'msg': 'testing - initial'}) + r2 = logging.makeLogRecord({'msg': 'testing - after delay'}) + fh.emit(r1) self.assertLogFile(self.fn) - time.sleep(1.01) # just a little over a second ... - fh.emit(r) + time.sleep(1.1) # a little over a second ... + fh.emit(r2) fh.close() # At this point, we should have a recent rotated file which we # can test for the existence of. However, in practice, on some -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 13:58:10 2012 From: python-checkins at python.org (nick.coghlan) Date: Mon, 05 Mar 2012 13:58:10 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Add_link_to_Vinay=27s_import_h?= =?utf8?q?ook_project?= Message-ID: http://hg.python.org/peps/rev/44abb43f6e54 changeset: 4115:44abb43f6e54 user: Nick Coghlan date: Sun Mar 04 23:02:40 2012 +1000 summary: Add link to Vinay's import hook project files: pep-0414.txt | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pep-0414.txt b/pep-0414.txt --- a/pep-0414.txt +++ b/pep-0414.txt @@ -143,8 +143,7 @@ This approach may prove useful, for example, for applications that wish to target Python 3 for the Ubuntu LTS release that ships with Python 2.7 and 3.2. -If such an import hook becomes available, this PEP will be updated to include -a reference to it. +One such import hook project is Vinay Sajip's ``uprefix`` [4]_. Complaint: Python 3 shouldn't be made worse just to support porting from Python 2 @@ -367,6 +366,10 @@ .. [3] Porting Python 2 Code to Python 3 (http://docs.python.org/howto/pyporting.html) +.. [4] uprefix import hook project + (https://bitbucket.org/vinay.sajip/uprefix) + + Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Mar 5 13:58:11 2012 From: python-checkins at python.org (nick.coghlan) Date: Mon, 05 Mar 2012 13:58:11 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Mark_PEP_414_as_Final_and_inco?= =?utf8?q?rporate_feedback_=28both_public_and_private=29?= Message-ID: http://hg.python.org/peps/rev/72f097c38b12 changeset: 4116:72f097c38b12 user: Nick Coghlan date: Mon Mar 05 22:56:18 2012 +1000 summary: Mark PEP 414 as Final and incorporate feedback (both public and private) files: pep-0414.txt | 122 +++++++++++++++++++++++--------------- 1 files changed, 75 insertions(+), 47 deletions(-) diff --git a/pep-0414.txt b/pep-0414.txt --- a/pep-0414.txt +++ b/pep-0414.txt @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Armin Ronacher , Nick Coghlan -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 15-Feb-2012 @@ -71,21 +71,17 @@ Author's Note ============= -This PEP was originally written by Armin Ronacher, and directly reflected his -feelings regarding his personal experiences porting Unicode aware Python -applications to Python 3. Guido's approval was given based on Armin's version -of the PEP. +This PEP was originally written by Armin Ronacher, and Guido's approval was +given based on that version. -The currently published version has been rewritten by Nick Coghlan to address -the concerns of those who felt that Armin's experience did not accurately -reflect the *typical* experience of porting to Python 3, but rather only -related to a specific subset of porting activities that were not well served -by the existing set of porting tools. +The currently published version has been rewritten by Nick Coghlan to +include additional historical details and rationale that were taken into +account when Guido made his decision, but were not explicitly documented in +Armin's version of the PEP. Readers should be aware that many of the arguments in this PEP are *not* technical ones. Instead, they relate heavily to the *social* and *personal* -aspects of software development. After all, developers are people first, -coders second. +aspects of software development. Rationale @@ -134,17 +130,28 @@ help people that *don't* want to put up with those difficulties. However, since the proposal is for a comparatively small tweak to the language -syntax with no semantic changes, it may be feasible to support it as a third -party import hook. While such an import hook will impose a small import time -overhead, and will require additional steps from each application that needs it -to get the hook in place, it would allow applications that target Python 3.2 -to use libraries and frameworks that may otherwise only run on Python 3.3+. - -This approach may prove useful, for example, for applications that wish to -target Python 3 for the Ubuntu LTS release that ships with Python 2.7 and 3.2. +syntax with no semantic changes, it is feasible to support it as a third +party import hook. While such an import hook imposes some import time +overhead, and requires additional steps from each application that needs it +to get the hook in place, it allows applications that target Python 3.2 +to use libraries and frameworks that would otherwise only run on Python 3.3+ +due to their use of unicode literal prefixes. One such import hook project is Vinay Sajip's ``uprefix`` [4]_. +For those that prefer to translate their code in advance rather than +converting on the fly at import time, Armin Ronacher is working on a hook +that runs at install time rather than during import [5]_. + +Combining the two approaches is of course also possible. For example, the +import hook could be used for rapid edit-test cycles during local +development, but the install hook for continuous integration tasks and +deployment on Python 3.2. + +The approaches described in this section may prove useful, for example, for +applications that wish to target Python 3 on the Ubuntu 12.04 LTS release, +which will ship with Python 2.7 and 3.2 as officially supported Python +versions. Complaint: Python 3 shouldn't be made worse just to support porting from Python 2 --------------------------------------------------------------------------------- @@ -155,14 +162,15 @@ developers, we should have a solid rationale for doing so. In most cases, the rationale for backwards incompatible Python 3 changes are -either to improve code correctness (for example, stricter separation of binary -and text data and integer division upgrading to floats when necessary), reduce -typical memory usage (for example, increased usage of iterators and views over -concrete lists), or to remove distracting nuisances that make Python code -harder to read without increasing its expressiveness (for example, the comma -based syntax for naming caught exceptions). Changes backed by such reasoning -are *not* going to be reverted, regardless of objections from Python 2 -developers attempting to make the transition to Python 3. +either to improve code correctness (for example, stricter default separation +of binary and text data and integer division upgrading to floats when +necessary), reduce typical memory usage (for example, increased usage of +iterators and views over concrete lists), or to remove distracting nuisances +that make Python code harder to read without increasing its expressiveness +(for example, the comma based syntax for naming caught exceptions). Changes +backed by such reasoning are *not* going to be reverted, regardless of +objections from Python 2 developers attempting to make the transition to +Python 3. In many cases, Python 2 offered two ways of doing things for historical reasons. For example, inequality could be tested with both ``!=`` and ``<>`` and integer @@ -197,8 +205,11 @@ Just as support for string exceptions was eliminated from Python 2 using the normal deprecation process, support for redundant string prefix characters -(specifically, ``B``, ``R``, ``u``, ``U``) may be eventually eliminated -from Python 3, regardless of the current acceptance of this PEP. +(specifically, ``B``, ``R``, ``u``, ``U``) may eventually be eliminated +from Python 3, regardless of the current acceptance of this PEP. However, +such a change will likely only occur once third party libraries supporting +Python 2.7 is about as common as libraries supporting Python 2.2 or 2.3 is +today. Complaint: The WSGI "native strings" concept is an ugly hack @@ -218,13 +229,27 @@ * native strings: handled as ``str`` in both Python 2 and Python 3 * binary data: handled as ``str`` in Python 2 and ``bytes`` in Python 3 -Native strings are a useful concept because there are some APIs and internal -operations that are designed primarily to work with native strings. They often -don't support ``unicode`` in Python 2 or support ``bytes`` in Python 3 (at -least, not without needing additional encoding information and/or imposing -constraints that don't apply to the native string variants). +Some developers consider WSGI's "native strings" to be an ugly hack, as they +are *explicitly* documented as being used solely for ``latin-1`` decoded +"text", regardless of the actual encoding of the underlying data. Using this +approach bypasses many of the updates to Python 3's data model that are +designed to encourage correct handling of text encodings. However, it +generally works due to the specific details of the problem domain - web server +and web framework developers are some of the individuals *most* aware of how +blurry the line can get between binary data and text when working with HTTP +and related protocols, and how important it is to understand the implications +of the encodings in use when manipulating encoded text data. At the +*application* level most of these details are hidden from the developer by +the web frameworks and support libraries (both in Python 2 *and* in Python 3). -Some example of such interfaces are: +In practice, native strings are a useful concept because there are some APIs +(both in the standard library and in third party frameworks and packages) and +some internal interpreter details that are designed primarily to work with +native strings. These components often don't support ``unicode`` in Python 2 +or ``bytes`` in Python 3, or, if they do, require additional encoding details +and/or impose constraints that don't apply to the native string variants. + +Some example of interfaces that are best handled as native strings are: * Python identifiers (dict keys, class names, module names, import paths) * URLs for the most part as well as HTTP headers in urllib/http servers @@ -238,16 +263,16 @@ In Python 2.6 and 2.7, these distinctions are most naturally expressed as follows: -* ``u""``: text string -* ``""``: native string -* ``b""``: binary data +* ``u""``: text string (``unicode``) +* ``""``: native string (``str``) +* ``b""``: binary data (``str``, also aliased as ``bytes``) -In Python 3, the native strings are not distinguished from any other text -strings: +In Python 3, the ``latin-1`` decoded native strings are not distinguished +from any other text strings: -* ``""``: text string -* ``""``: native string -* ``b""``: binary data +* ``""``: text string (``str``) +* ``""``: native string (``str``) +* ``b""``: binary data (``bytes``) If ``from __future__ import unicode_literals`` is used to modify the behaviour of Python 2, then, along with an appropriate definition of ``n()``, the @@ -273,9 +298,10 @@ Of all the alternatives, the format currently supported in Python 2.6 and 2.7 is by far the cleanest approach that clearly distinguishes the three desired kinds of behaviour. With this PEP, that format will also be supported in -Python 3.3+. If the import hook approach works out as planned, it may even be -supported in Python 3.1 and 3.2. A bit more effort could likely adapt the hook -to allow the use of the ``b`` prefix on Python 2.5 +Python 3.3+. It will also be supported in Python 3.1 and 3.2 through the use +of import and install hooks. While it is significantly less likely, it is +also conceivable that the hooks could be adapted to allow the use of the +``b`` prefix on Python 2.5. Complaint: The existing tools should be good enough for everyone @@ -369,6 +395,8 @@ .. [4] uprefix import hook project (https://bitbucket.org/vinay.sajip/uprefix) +.. [5] install hook to remove unicode string prefix characters + (https://github.com/mitsuhiko/unicode-literals-pep/tree/master/install-hook) Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Mar 5 14:12:53 2012 From: python-checkins at python.org (nick.coghlan) Date: Mon, 05 Mar 2012 14:12:53 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Additional_clarifications_in_t?= =?utf8?q?he_WSGI_section?= Message-ID: http://hg.python.org/peps/rev/15ff6bd4e78c changeset: 4117:15ff6bd4e78c user: Nick Coghlan date: Mon Mar 05 23:12:42 2012 +1000 summary: Additional clarifications in the WSGI section files: pep-0414.txt | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pep-0414.txt b/pep-0414.txt --- a/pep-0414.txt +++ b/pep-0414.txt @@ -245,13 +245,15 @@ In practice, native strings are a useful concept because there are some APIs (both in the standard library and in third party frameworks and packages) and some internal interpreter details that are designed primarily to work with -native strings. These components often don't support ``unicode`` in Python 2 +``str``. These components often don't support ``unicode`` in Python 2 or ``bytes`` in Python 3, or, if they do, require additional encoding details -and/or impose constraints that don't apply to the native string variants. +and/or impose constraints that don't apply to the ``str`` variants. -Some example of interfaces that are best handled as native strings are: +Some example of interfaces that are best handled by using actual ``str`` +instances are: -* Python identifiers (dict keys, class names, module names, import paths) +* Python identifiers (as attributes, dict keys, class names, module names, + import references, etc) * URLs for the most part as well as HTTP headers in urllib/http servers * WSGI environment keys and CGI-inherited values * Python source code for dynamic compilation and AST hacks -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Mar 5 14:40:14 2012 From: python-checkins at python.org (stefan.krah) Date: Mon, 05 Mar 2012 14:40:14 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314181=3A_Test_crea?= =?utf8?q?ting_memoryviews_from_a_static_exporter_with_both?= Message-ID: http://hg.python.org/cpython/rev/3a1f7c9f0b25 changeset: 75420:3a1f7c9f0b25 user: Stefan Krah date: Mon Mar 05 14:37:34 2012 +0100 summary: Issue #14181: Test creating memoryviews from a static exporter with both view.obj==NULL and view.obj==base. files: Lib/test/test_buffer.py | 94 ++++++++++++++++++++ Modules/_testbuffer.c | 126 +++++++++++++++++++++++++++- 2 files changed, 219 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -3515,6 +3515,100 @@ del y, z self.assertEqual(m[1:3], x[1:3]) + def test_memoryview_from_static_exporter(self): + + fmt = 'B' + lst = [0,1,2,3,4,5,6,7,8,9,10,11] + + # exceptions + self.assertRaises(TypeError, staticarray, 1, 2, 3) + + # view.obj==x + x = staticarray() + y = memoryview(x) + self.verify(y, obj=x, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + for i in range(12): + self.assertEqual(y[i], i) + del x + del y + + x = staticarray() + y = memoryview(x) + del y + del x + + x = staticarray() + y = ndarray(x, getbuf=PyBUF_FULL_RO) + z = ndarray(y, getbuf=PyBUF_FULL_RO) + m = memoryview(z) + self.assertIs(y.obj, x) + self.assertIs(m.obj, z) + self.verify(m, obj=z, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + del x, y, z, m + + x = staticarray() + y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + m = memoryview(z) + self.assertIs(y.obj, x) + self.assertIs(z.obj, x) + self.assertIs(m.obj, x) + self.verify(m, obj=x, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + del x, y, z, m + + # view.obj==NULL + x = staticarray(legacy_mode=True) + y = memoryview(x) + self.verify(y, obj=None, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + for i in range(12): + self.assertEqual(y[i], i) + del x + del y + + x = staticarray(legacy_mode=True) + y = memoryview(x) + del y + del x + + x = staticarray(legacy_mode=True) + y = ndarray(x, getbuf=PyBUF_FULL_RO) + z = ndarray(y, getbuf=PyBUF_FULL_RO) + m = memoryview(z) + self.assertIs(y.obj, None) + self.assertIs(m.obj, z) + self.verify(m, obj=z, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + del x, y, z, m + + x = staticarray(legacy_mode=True) + y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + m = memoryview(z) + # Clearly setting view.obj==NULL is inferior, since it + # messes up the redirection chain: + self.assertIs(y.obj, None) + self.assertIs(z.obj, y) + self.assertIs(m.obj, y) + self.verify(m, obj=y, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + del x, y, z, m + def test_issue_7385(self): x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL) self.assertRaises(BufferError, memoryview, x) diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -2602,6 +2602,126 @@ ndarray_new, /* tp_new */ }; +/**************************************************************************/ +/* StaticArray Object */ +/**************************************************************************/ + +static PyTypeObject StaticArray_Type; + +typedef struct { + PyObject_HEAD + int legacy_mode; /* if true, use the view.obj==NULL hack */ +} StaticArrayObject; + +static char static_mem[12] = {0,1,2,3,4,5,6,7,8,9,10,11}; +static Py_ssize_t static_shape[1] = {12}; +static Py_ssize_t static_strides[1] = {1}; +static Py_buffer static_buffer = { + static_mem, /* buf */ + NULL, /* obj */ + 12, /* len */ + 1, /* itemsize */ + 1, /* readonly */ + 1, /* ndim */ + "B", /* format */ + static_shape, /* shape */ + static_strides, /* strides */ + NULL, /* suboffsets */ + NULL /* internal */ +}; + +static PyObject * +staticarray_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return (PyObject *)PyObject_New(StaticArrayObject, &StaticArray_Type); +} + +static int +staticarray_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + StaticArrayObject *a = (StaticArrayObject *)self; + static char *kwlist[] = { + "legacy_mode", NULL + }; + PyObject *legacy_mode = Py_False; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &legacy_mode)) + return -1; + + a->legacy_mode = (legacy_mode != Py_False); + return 0; +} + +static void +staticarray_dealloc(StaticArrayObject *self) +{ + PyObject_Del(self); +} + +/* Return a buffer for a PyBUF_FULL_RO request. Flags are not checked, + which makes this object a non-compliant exporter! */ +static int +staticarray_getbuf(StaticArrayObject *self, Py_buffer *view, int flags) +{ + *view = static_buffer; + + if (self->legacy_mode) { + view->obj = NULL; /* Don't use this in new code. */ + } + else { + view->obj = (PyObject *)self; + Py_INCREF(view->obj); + } + + return 0; +} + +static PyBufferProcs staticarray_as_buffer = { + (getbufferproc)staticarray_getbuf, /* bf_getbuffer */ + NULL, /* bf_releasebuffer */ +}; + +static PyTypeObject StaticArray_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "staticarray", /* Name of this type */ + sizeof(StaticArrayObject), /* Basic object size */ + 0, /* Item size for varobject */ + (destructor)staticarray_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 */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &staticarray_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* 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 */ + staticarray_init, /* tp_init */ + 0, /* tp_alloc */ + staticarray_new, /* tp_new */ +}; + static struct PyMethodDef _testbuffer_functions[] = { {"slice_indices", slice_indices, METH_VARARGS, NULL}, @@ -2634,10 +2754,14 @@ if (m == NULL) return NULL; - Py_TYPE(&NDArray_Type)=&PyType_Type; + Py_TYPE(&NDArray_Type) = &PyType_Type; Py_INCREF(&NDArray_Type); PyModule_AddObject(m, "ndarray", (PyObject *)&NDArray_Type); + Py_TYPE(&StaticArray_Type) = &PyType_Type; + Py_INCREF(&StaticArray_Type); + PyModule_AddObject(m, "staticarray", (PyObject *)&StaticArray_Type); + structmodule = PyImport_ImportModule("struct"); if (structmodule == NULL) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:04:06 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 05 Mar 2012 16:04:06 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_remove_f=5Fyieldfrom_access?= =?utf8?q?_from_Python_=28closes_=2313970=29?= Message-ID: http://hg.python.org/cpython/rev/84620bca0e35 changeset: 75421:84620bca0e35 user: Benjamin Peterson date: Mon Mar 05 09:03:51 2012 -0600 summary: remove f_yieldfrom access from Python (closes #13970) files: Objects/frameobject.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -20,7 +20,6 @@ {"f_builtins", T_OBJECT, OFF(f_builtins), READONLY}, {"f_globals", T_OBJECT, OFF(f_globals), READONLY}, {"f_lasti", T_INT, OFF(f_lasti), READONLY}, - {"f_yieldfrom", T_OBJECT, OFF(f_yieldfrom), READONLY}, {NULL} /* Sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:26:02 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:26:02 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Use_raw_string_?= =?utf8?q?for_a_docstring_that_uses_a_backslash?= Message-ID: http://hg.python.org/cpython/rev/8ce8006dfc42 changeset: 75422:8ce8006dfc42 branch: 3.2 parent: 75405:5b88475aae96 user: ?ric Araujo date: Mon Mar 05 15:45:08 2012 +0100 summary: Use raw string for a docstring that uses a backslash files: Lib/xmlrpc/server.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -1,4 +1,4 @@ -"""XML-RPC Servers. +r"""XML-RPC Servers. This module can be used to create simple XML-RPC servers by creating a server and either installing functions, a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:26:03 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:26:03 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Remove_mention_?= =?utf8?q?of_defunct_file=2E?= Message-ID: http://hg.python.org/cpython/rev/8934bbbed2ae changeset: 75423:8934bbbed2ae branch: 3.2 user: ?ric Araujo date: Mon Mar 05 15:47:32 2012 +0100 summary: Remove mention of defunct file. Misc/COPYRIGHT was renamed twelve years ago to LICENSE and later copied to the main docs, to which there is already a link. files: Doc/howto/advocacy.rst | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst --- a/Doc/howto/advocacy.rst +++ b/Doc/howto/advocacy.rst @@ -264,8 +264,7 @@ **What are the restrictions on Python's use?** -They're practically nonexistent. Consult the :file:`Misc/COPYRIGHT` file in the -source distribution, or the section :ref:`history-and-license` for the full +They're practically nonexistent. Consult :ref:`history-and-license` for the full language, but it boils down to three conditions: * You have to leave the copyright notice on the software; if you don't include -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:26:10 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:26:10 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Use_source_reST?= =?utf8?q?_role_instead_of_file_where_it_makes_sense=2E?= Message-ID: http://hg.python.org/cpython/rev/7894257ef861 changeset: 75424:7894257ef861 branch: 3.2 user: ?ric Araujo date: Mon Mar 05 15:50:37 2012 +0100 summary: Use source reST role instead of file where it makes sense. source generates a nifty link to the Mercurial web viewer. files: Doc/howto/cporting.rst | 4 ++-- Doc/howto/regex.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst --- a/Doc/howto/cporting.rst +++ b/Doc/howto/cporting.rst @@ -261,8 +261,8 @@ copy as you see fit.) You can find :file:`capsulethunk.h` in the Python source distribution -in the :file:`Doc/includes` directory. We also include it here for -your reference; here is :file:`capsulethunk.h`: +as :source:`Doc/includes/capsulethunk.h`. We also include it here for +your convenience: .. literalinclude:: ../includes/capsulethunk.h diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -360,7 +360,7 @@ You can learn about this by interactively experimenting with the :mod:`re` module. If you have :mod:`tkinter` available, you may also want to look at -:file:`Tools/demo/redemo.py`, a demonstration program included with the +:source:`Tools/demo/redemo.py`, a demonstration program included with the Python distribution. It allows you to enter REs and strings, and displays whether the RE matches or fails. :file:`redemo.py` can be quite useful when trying to debug a complicated RE. Phil Schwartz's `Kodos @@ -495,7 +495,7 @@ the same ones in several locations, then it might be worthwhile to collect all the definitions in one place, in a section of code that compiles all the REs ahead of time. To take an example from the standard library, here's an extract -from the now deprecated :file:`xmllib.py`:: +from the now-defunct Python 2 standard :mod:`xmllib` module:: ref = re.compile( ... ) entityref = re.compile( ... ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:26:11 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:26:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Move_xml=2Eetre?= =?utf8?q?e_higher_and_xml=2Eparsers=2Eexpat_lower_in_the_markup_ToC=2E?= Message-ID: http://hg.python.org/cpython/rev/d99c0a4b66f3 changeset: 75425:d99c0a4b66f3 branch: 3.2 user: ?ric Araujo date: Mon Mar 05 16:01:41 2012 +0100 summary: Move xml.etree higher and xml.parsers.expat lower in the markup ToC. I assume that most users looking at this page are looking for a library to process XML, not a low-level parser. First proposed in #11379. files: Doc/library/markup.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/markup.rst b/Doc/library/markup.rst --- a/Doc/library/markup.rst +++ b/Doc/library/markup.rst @@ -23,7 +23,7 @@ html.rst html.parser.rst html.entities.rst - pyexpat.rst + xml.etree.elementtree.rst xml.dom.rst xml.dom.minidom.rst xml.dom.pulldom.rst @@ -31,4 +31,4 @@ xml.sax.handler.rst xml.sax.utils.rst xml.sax.reader.rst - xml.etree.elementtree.rst + pyexpat.rst -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:26:17 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:26:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Make_distutils?= =?utf8?q?=E2=80=99_upload_command_work_with_bdist=5Fmsi_products_=28=2313?= =?utf8?b?NzE5KS4=?= Message-ID: http://hg.python.org/cpython/rev/3d1362fa07c3 changeset: 75426:3d1362fa07c3 branch: 3.2 user: ?ric Araujo date: Mon Mar 05 16:09:29 2012 +0100 summary: Make distutils? upload command work with bdist_msi products (#13719). Patch by Ralf Schmitt. files: Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/tests/test_bdist_msi.py | 18 ++++++++++---- Misc/NEWS | 2 + 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -260,7 +260,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', fullname + tup = 'bdist_msi', self.target_version or 'any', installer_name self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,12 +1,11 @@ """Tests for distutils.command.bdist_msi.""" +import sys import unittest -import sys - from test.support import run_unittest - from distutils.tests import support - at unittest.skipUnless(sys.platform=="win32", "These tests are only for win32") + + at unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows') class BDistMSITestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): @@ -14,9 +13,18 @@ def test_minimal(self): # minimal test XXX need more tests from distutils.command.bdist_msi import bdist_msi - pkg_pth, dist = self.create_dist() + project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() + cmd.run() + + bdists = os.listdir(os.path.join(project_dir, 'dist')) + self.assertEqual(bdists, ['foo-0.1.msi']) + + # bug #13719: upload ignores bdist_msi files + self.assertEqual(dist.dist_files, + [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) + def test_suite(): return unittest.makeSuite(BDistMSITestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -130,6 +130,8 @@ Library ------- +- Issue #13719: Make the distutils upload command aware of bdist_msi products. + - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been fixed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:26:18 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:26:18 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Backport_minido?= =?utf8?q?m_attribute_tests_from_default_=2873c76466cf44=29=2E?= Message-ID: http://hg.python.org/cpython/rev/0860e8a24858 changeset: 75427:0860e8a24858 branch: 3.2 user: ?ric Araujo date: Mon Mar 05 16:11:41 2012 +0100 summary: Backport minidom attribute tests from default (73c76466cf44). Some minidom code changed between 3.2 and 3.3, so to be sure to avoid differenced in behavior I?m backporting these tests added by MvL. files: Lib/test/test_minidom.py | 26 ++++++++++++++++++++++---- 1 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -350,13 +350,31 @@ def testGetAttrList(self): pass - def testGetAttrValues(self): pass + def testGetAttrValues(self): + pass - def testGetAttrLength(self): pass + def testGetAttrLength(self): + pass - def testGetAttribute(self): pass + def testGetAttribute(self): + dom = Document() + child = dom.appendChild( + dom.createElementNS("http://www.python.org", "python:abc")) + self.assertEqual(child.getAttribute('missing'), '') - def testGetAttributeNS(self): pass + def testGetAttributeNS(self): + dom = Document() + child = dom.appendChild( + dom.createElementNS("http://www.python.org", "python:abc")) + child.setAttributeNS("http://www.w3.org", "xmlns:python", + "http://www.python.org") + self.assertEqual(child.getAttributeNS("http://www.w3.org", "python"), + 'http://www.python.org') + self.assertEqual(child.getAttributeNS("http://www.w3.org", "other"), + '') + child2 = child.appendChild(dom.createElement('abc')) + self.assertEqual(child2.getAttributeNS("http://www.python.org", "missing"), + '') def testGetAttributeNode(self): pass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:26:19 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:26:19 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Improve_packaging=2Edatabas?= =?utf8?q?e_documentation?= Message-ID: http://hg.python.org/cpython/rev/9fbe549df5ba changeset: 75428:9fbe549df5ba parent: 75420:3a1f7c9f0b25 user: ?ric Araujo date: Mon Mar 05 16:16:37 2012 +0100 summary: Improve packaging.database documentation files: Doc/library/packaging.database.rst | 45 +++++++++++++---- Lib/packaging/database.py | 1 + 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/Doc/library/packaging.database.rst b/Doc/library/packaging.database.rst --- a/Doc/library/packaging.database.rst +++ b/Doc/library/packaging.database.rst @@ -15,6 +15,11 @@ Most functions also provide an extra argument ``use_egg_info`` to take legacy distributions into account. +For the purpose of this module, "installed" means that the distribution's +:file:`.dist-info`, :file:`.egg-info` or :file:`egg` directory or file is found +on :data:`sys.path`. For example, if the parent directory of a +:file:`dist-info` directory is added to :envvar:`PYTHONPATH`, then it will be +available in the database. Classes representing installed distributions -------------------------------------------- @@ -128,7 +133,7 @@ for the first installed distribution matching *name*. Egg distributions are considered only if *use_egg_info* is true; if both a dist-info and an egg file are found, the dist-info prevails. The directories to be searched are - given in *paths*, which defaults to :data:`sys.path`. Return ``None`` if no + given in *paths*, which defaults to :data:`sys.path`. Returns ``None`` if no matching distribution is found. .. FIXME param should be named use_egg @@ -200,20 +205,23 @@ Examples -------- -Print all information about a distribution -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Printing all information about a distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Given a path to a ``.dist-info`` distribution, we shall print out all +Given the name of an installed distribution, we shall print out all information that can be obtained using functions provided in this module:: import sys import packaging.database - path = input() + try: + name = sys.argv[1] + except ValueError: + sys.exit('Not enough arguments') + # first create the Distribution instance - try: - dist = packaging.database.Distribution(path) - except FileNotFoundError: + dist = packaging.database.Distribution(path) + if dist is None: sys.exit('No such distribution') print('Information about %r' % dist.name) @@ -244,7 +252,7 @@ .. code-block:: sh - $ echo /tmp/choxie/choxie-2.0.0.9.dist-info | python3 print_info.py + python print_info.py choxie we get the following output: @@ -299,10 +307,23 @@ * It was installed as a dependency -Find out obsoleted distributions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Getting metadata about a distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Now, we take tackle a different problem, we are interested in finding out +Sometimes you're not interested about the packaging information contained in a +full :class:`Distribution` object but just want to do something with its +:attr:`~Distribution.metadata`:: + + >>> from packaging.database import get_distribution + >>> info = get_distribution('chocolate').metadata + >>> info['Keywords'] + ['cooking', 'happiness'] + + +Finding out obsoleted distributions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now, we tackle a different problem, we are interested in finding out which distributions have been obsoleted. This can be easily done as follows:: import packaging.database diff --git a/Lib/packaging/database.py b/Lib/packaging/database.py --- a/Lib/packaging/database.py +++ b/Lib/packaging/database.py @@ -19,6 +19,7 @@ 'get_distributions', 'get_distribution', 'get_file_users', 'provides_distribution', 'obsoletes_distribution', 'enable_cache', 'disable_cache', 'clear_cache', + # XXX these functions' names look like get_file_users but are not related 'get_file_path', 'get_file'] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:26:20 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:26:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/561532103d74 changeset: 75429:561532103d74 parent: 75428:9fbe549df5ba parent: 75427:0860e8a24858 user: ?ric Araujo date: Mon Mar 05 16:24:07 2012 +0100 summary: Merge 3.2 files: Doc/howto/advocacy.rst | 3 +- Doc/howto/cporting.rst | 4 +- Doc/howto/regex.rst | 4 +- Doc/library/markup.rst | 4 +- Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/tests/test_bdist_msi.py | 18 ++++++++++---- Lib/xmlrpc/server.py | 2 +- Misc/NEWS | 2 + 8 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst --- a/Doc/howto/advocacy.rst +++ b/Doc/howto/advocacy.rst @@ -264,8 +264,7 @@ **What are the restrictions on Python's use?** -They're practically nonexistent. Consult the :file:`Misc/COPYRIGHT` file in the -source distribution, or the section :ref:`history-and-license` for the full +They're practically nonexistent. Consult :ref:`history-and-license` for the full language, but it boils down to three conditions: * You have to leave the copyright notice on the software; if you don't include diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst --- a/Doc/howto/cporting.rst +++ b/Doc/howto/cporting.rst @@ -261,8 +261,8 @@ copy as you see fit.) You can find :file:`capsulethunk.h` in the Python source distribution -in the :file:`Doc/includes` directory. We also include it here for -your reference; here is :file:`capsulethunk.h`: +as :source:`Doc/includes/capsulethunk.h`. We also include it here for +your convenience: .. literalinclude:: ../includes/capsulethunk.h diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -360,7 +360,7 @@ You can learn about this by interactively experimenting with the :mod:`re` module. If you have :mod:`tkinter` available, you may also want to look at -:file:`Tools/demo/redemo.py`, a demonstration program included with the +:source:`Tools/demo/redemo.py`, a demonstration program included with the Python distribution. It allows you to enter REs and strings, and displays whether the RE matches or fails. :file:`redemo.py` can be quite useful when trying to debug a complicated RE. Phil Schwartz's `Kodos @@ -495,7 +495,7 @@ the same ones in several locations, then it might be worthwhile to collect all the definitions in one place, in a section of code that compiles all the REs ahead of time. To take an example from the standard library, here's an extract -from the now deprecated :file:`xmllib.py`:: +from the now-defunct Python 2 standard :mod:`xmllib` module:: ref = re.compile( ... ) entityref = re.compile( ... ) diff --git a/Doc/library/markup.rst b/Doc/library/markup.rst --- a/Doc/library/markup.rst +++ b/Doc/library/markup.rst @@ -23,7 +23,7 @@ html.rst html.parser.rst html.entities.rst - pyexpat.rst + xml.etree.elementtree.rst xml.dom.rst xml.dom.minidom.rst xml.dom.pulldom.rst @@ -31,4 +31,4 @@ xml.sax.handler.rst xml.sax.utils.rst xml.sax.reader.rst - xml.etree.elementtree.rst + pyexpat.rst diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -260,7 +260,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', fullname + tup = 'bdist_msi', self.target_version or 'any', installer_name self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,12 +1,11 @@ """Tests for distutils.command.bdist_msi.""" +import sys import unittest -import sys - from test.support import run_unittest - from distutils.tests import support - at unittest.skipUnless(sys.platform=="win32", "These tests are only for win32") + + at unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows') class BDistMSITestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): @@ -14,9 +13,18 @@ def test_minimal(self): # minimal test XXX need more tests from distutils.command.bdist_msi import bdist_msi - pkg_pth, dist = self.create_dist() + project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() + cmd.run() + + bdists = os.listdir(os.path.join(project_dir, 'dist')) + self.assertEqual(bdists, ['foo-0.1.msi']) + + # bug #13719: upload ignores bdist_msi files + self.assertEqual(dist.dist_files, + [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) + def test_suite(): return unittest.makeSuite(BDistMSITestCase) diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -1,4 +1,4 @@ -"""XML-RPC Servers. +r"""XML-RPC Servers. This module can be used to create simple XML-RPC servers by creating a server and either installing functions, a diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #13719: Make the distutils upload command aware of bdist_msi products. + - Issue #14007: Accept incomplete TreeBuilder objects (missing start, end, data or close method) for the Python implementation as well. Drop the no-op TreeBuilder().xml() method from the C implementation. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:26:21 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:26:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Branch_merge?= Message-ID: http://hg.python.org/cpython/rev/e12a65da2358 changeset: 75430:e12a65da2358 parent: 75429:561532103d74 parent: 75421:84620bca0e35 user: ?ric Araujo date: Mon Mar 05 16:25:40 2012 +0100 summary: Branch merge files: Objects/frameobject.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -20,7 +20,6 @@ {"f_builtins", T_OBJECT, OFF(f_builtins), READONLY}, {"f_globals", T_OBJECT, OFF(f_globals), READONLY}, {"f_lasti", T_INT, OFF(f_lasti), READONLY}, - {"f_yieldfrom", T_OBJECT, OFF(f_yieldfrom), READONLY}, {NULL} /* Sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:48:28 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:48:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Use_raw_string_?= =?utf8?q?for_a_docstring_that_uses_a_backslash?= Message-ID: http://hg.python.org/cpython/rev/e3fcc1ce09ef changeset: 75431:e3fcc1ce09ef branch: 2.7 parent: 75404:4b3f1decb1af user: ?ric Araujo date: Mon Mar 05 16:29:30 2012 +0100 summary: Use raw string for a docstring that uses a backslash files: Lib/SimpleXMLRPCServer.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/SimpleXMLRPCServer.py b/Lib/SimpleXMLRPCServer.py --- a/Lib/SimpleXMLRPCServer.py +++ b/Lib/SimpleXMLRPCServer.py @@ -1,4 +1,4 @@ -"""Simple XML-RPC Server. +r"""Simple XML-RPC Server. This module can be used to create simple XML-RPC servers by creating a server and either installing functions, a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:48:28 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:48:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Remove_mention_?= =?utf8?q?of_defunct_file=2E?= Message-ID: http://hg.python.org/cpython/rev/952e056223fc changeset: 75432:952e056223fc branch: 2.7 user: ?ric Araujo date: Mon Mar 05 16:30:46 2012 +0100 summary: Remove mention of defunct file. Misc/COPYRIGHT was renamed twelve years ago to LICENSE and later copied to the main docs, to which there is already a link. files: Doc/howto/advocacy.rst | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst --- a/Doc/howto/advocacy.rst +++ b/Doc/howto/advocacy.rst @@ -264,8 +264,7 @@ **What are the restrictions on Python's use?** -They're practically nonexistent. Consult the :file:`Misc/COPYRIGHT` file in the -source distribution, or the section :ref:`history-and-license` for the full +They're practically nonexistent. Consult :ref:`history-and-license` for the full language, but it boils down to three conditions: * You have to leave the copyright notice on the software; if you don't include -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:48:30 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:48:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Use_source_reST?= =?utf8?q?_role_instead_of_file_where_it_makes_sense=2E?= Message-ID: http://hg.python.org/cpython/rev/3993b6c8cd0a changeset: 75433:3993b6c8cd0a branch: 2.7 user: ?ric Araujo date: Mon Mar 05 16:43:41 2012 +0100 summary: Use source reST role instead of file where it makes sense. source generates a nifty link to the Mercurial web viewer. files: Doc/howto/cporting.rst | 4 ++-- Doc/howto/regex.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst --- a/Doc/howto/cporting.rst +++ b/Doc/howto/cporting.rst @@ -261,8 +261,8 @@ copy as you see fit.) You can find :file:`capsulethunk.h` in the Python source distribution -in the :file:`Doc/includes` directory. We also include it here for -your reference; here is :file:`capsulethunk.h`: +as :source:`Doc/includes/capsulethunk.h`. We also include it here for +your convenience: .. literalinclude:: ../includes/capsulethunk.h diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -365,7 +365,7 @@ You can learn about this by interactively experimenting with the :mod:`re` module. If you have Tkinter available, you may also want to look at -:file:`Tools/scripts/redemo.py`, a demonstration program included with the +:source:`Tools/scripts/redemo.py`, a demonstration program included with the Python distribution. It allows you to enter REs and strings, and displays whether the RE matches or fails. :file:`redemo.py` can be quite useful when trying to debug a complicated RE. Phil Schwartz's `Kodos @@ -501,7 +501,7 @@ the same ones in several locations, then it might be worthwhile to collect all the definitions in one place, in a section of code that compiles all the REs ahead of time. To take an example from the standard library, here's an extract -from :file:`xmllib.py`:: +from the deprecated :mod:`xmllib` module:: ref = re.compile( ... ) entityref = re.compile( ... ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:48:31 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:48:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Move_xml=2Eetre?= =?utf8?q?e_higher_and_xml=2Eparsers=2Eexpat_lower_in_the_markup_ToC=2E?= Message-ID: http://hg.python.org/cpython/rev/fc32753feb0a changeset: 75434:fc32753feb0a branch: 2.7 user: ?ric Araujo date: Mon Mar 05 16:44:49 2012 +0100 summary: Move xml.etree higher and xml.parsers.expat lower in the markup ToC. I assume that most users looking at this page are looking for a library to process XML, not a low-level parser. First proposed in #11379. files: Doc/library/markup.rst | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/library/markup.rst b/Doc/library/markup.rst --- a/Doc/library/markup.rst +++ b/Doc/library/markup.rst @@ -1,4 +1,3 @@ - .. _markup: ********************************** @@ -26,7 +25,7 @@ htmlparser.rst sgmllib.rst htmllib.rst - pyexpat.rst + xml.etree.elementtree.rst xml.dom.rst xml.dom.minidom.rst xml.dom.pulldom.rst @@ -34,4 +33,4 @@ xml.sax.handler.rst xml.sax.utils.rst xml.sax.reader.rst - xml.etree.elementtree.rst + pyexpat.rst -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 16:48:33 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 16:48:33 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Make_distutils?= =?utf8?q?=E2=80=99_upload_command_work_with_bdist=5Fmsi_products_=28=2313?= =?utf8?b?NzE5KS4=?= Message-ID: http://hg.python.org/cpython/rev/7671932c98d3 changeset: 75435:7671932c98d3 branch: 2.7 user: ?ric Araujo date: Mon Mar 05 16:47:33 2012 +0100 summary: Make distutils? upload command work with bdist_msi products (#13719). Patch by Ralf Schmitt. files: Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/tests/test_bdist_msi.py | 18 ++++++++++---- Misc/NEWS | 2 + 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -262,7 +262,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', fullname + tup = 'bdist_msi', self.target_version or 'any', installer_name self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,12 +1,11 @@ """Tests for distutils.command.bdist_msi.""" +import sys import unittest -import sys - from test.test_support import run_unittest - from distutils.tests import support - at unittest.skipUnless(sys.platform=="win32", "These tests are only for win32") + + at unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows') class BDistMSITestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): @@ -14,9 +13,18 @@ def test_minimal(self): # minimal test XXX need more tests from distutils.command.bdist_msi import bdist_msi - pkg_pth, dist = self.create_dist() + project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() + cmd.run() + + bdists = os.listdir(os.path.join(project_dir, 'dist')) + self.assertEqual(bdists, ['foo-0.1.msi']) + + # bug #13719: upload ignores bdist_msi files + self.assertEqual(dist.dist_files, + [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) + def test_suite(): return unittest.makeSuite(BDistMSITestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -101,6 +101,8 @@ Library ------- +- Issue #13719: Make the distutils upload command aware of bdist_msi products. + - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been fixed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 17:01:15 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 17:01:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_NameError?= Message-ID: http://hg.python.org/cpython/rev/cec6bb749616 changeset: 75436:cec6bb749616 branch: 2.7 user: ?ric Araujo date: Mon Mar 05 17:00:49 2012 +0100 summary: Fix NameError files: Lib/distutils/tests/test_bdist_msi.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,4 +1,5 @@ """Tests for distutils.command.bdist_msi.""" +import os import sys import unittest from test.test_support import run_unittest -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 17:04:48 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 17:04:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_NameError_f?= =?utf8?q?rom_=2313719_fix?= Message-ID: http://hg.python.org/cpython/rev/4cfcda9e80cb changeset: 75437:4cfcda9e80cb branch: 3.2 parent: 75427:0860e8a24858 user: ?ric Araujo date: Mon Mar 05 17:02:31 2012 +0100 summary: Fix NameError from #13719 fix files: Lib/distutils/tests/test_bdist_msi.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,4 +1,5 @@ """Tests for distutils.command.bdist_msi.""" +import os import sys import unittest from test.support import run_unittest -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 17:04:49 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 17:04:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Make_packaging=E2=80=99_upl?= =?utf8?q?oad_command_work_with_bdist=5Fmsi_products_=28=2313719=29?= Message-ID: http://hg.python.org/cpython/rev/449c9fc2fc2d changeset: 75438:449c9fc2fc2d parent: 75430:e12a65da2358 user: ?ric Araujo date: Mon Mar 05 17:04:07 2012 +0100 summary: Make packaging? upload command work with bdist_msi products (#13719) files: Lib/packaging/command/bdist_msi.py | 2 +- Lib/packaging/tests/test_command_bdist_msi.py | 13 ++++++++- Misc/NEWS | 3 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Lib/packaging/command/bdist_msi.py b/Lib/packaging/command/bdist_msi.py --- a/Lib/packaging/command/bdist_msi.py +++ b/Lib/packaging/command/bdist_msi.py @@ -261,7 +261,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', fullname + tup = 'bdist_msi', self.target_version or 'any', installer_name self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/packaging/tests/test_command_bdist_msi.py b/Lib/packaging/tests/test_command_bdist_msi.py --- a/Lib/packaging/tests/test_command_bdist_msi.py +++ b/Lib/packaging/tests/test_command_bdist_msi.py @@ -1,20 +1,29 @@ """Tests for distutils.command.bdist_msi.""" +import os import sys from packaging.tests import unittest, support + at unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows') class BDistMSITestCase(support.TempdirManager, support.LoggingCatcher, unittest.TestCase): - @unittest.skipUnless(sys.platform == "win32", "runs only on win32") def test_minimal(self): # minimal test XXX need more tests from packaging.command.bdist_msi import bdist_msi - pkg_pth, dist = self.create_dist() + project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() + cmd.run() + + bdists = os.listdir(os.path.join(project_dir, 'dist')) + self.assertEqual(bdists, ['foo-0.1.msi']) + + # bug #13719: upload ignores bdist_msi files + self.assertEqual(dist.dist_files, + [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) def test_suite(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,7 +13,8 @@ Library ------- -- Issue #13719: Make the distutils upload command aware of bdist_msi products. +- Issue #13719: Make the distutils and packaging upload commands aware of + bdist_msi products. - Issue #14007: Accept incomplete TreeBuilder objects (missing start, end, data or close method) for the Python implementation as well. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 17:04:50 2012 From: python-checkins at python.org (eric.araujo) Date: Mon, 05 Mar 2012 17:04:50 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/f282d9041ac7 changeset: 75439:f282d9041ac7 parent: 75438:449c9fc2fc2d parent: 75437:4cfcda9e80cb user: ?ric Araujo date: Mon Mar 05 17:04:20 2012 +0100 summary: Merge 3.2 files: Lib/distutils/tests/test_bdist_msi.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,4 +1,5 @@ """Tests for distutils.command.bdist_msi.""" +import os import sys import unittest from test.support import run_unittest -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 17:51:46 2012 From: python-checkins at python.org (stefan.krah) Date: Mon, 05 Mar 2012 17:51:46 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314181=3A_Preserve_?= =?utf8?q?backwards_compatibility_for_getbufferprocs_that_a=29_do?= Message-ID: http://hg.python.org/cpython/rev/9f7d06a9eabe changeset: 75440:9f7d06a9eabe parent: 75420:3a1f7c9f0b25 user: Stefan Krah date: Mon Mar 05 17:45:17 2012 +0100 summary: Issue #14181: Preserve backwards compatibility for getbufferprocs that a) do not adhere to the new documentation and b) manage to clobber view->obj before returning failure. files: Lib/test/test_buffer.py | 6 ++++++ Modules/_testbuffer.c | 29 +++++++++++++++-------------- Objects/memoryobject.c | 2 +- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -3609,6 +3609,12 @@ lst=lst) del x, y, z, m + def test_memoryview_getbuffer_undefined(self): + + # getbufferproc does not adhere to the new documentation + nd = ndarray([1,2,3], [3], flags=ND_GETBUF_FAIL|ND_GETBUF_UNDEFINED) + self.assertRaises(BufferError, memoryview, nd) + def test_issue_7385(self): x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL) self.assertRaises(BufferError, memoryview, x) diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -44,23 +44,21 @@ #define ADJUST_PTR(ptr, suboffsets) \ (HAVE_PTR(suboffsets) ? *((char**)ptr) + suboffsets[0] : ptr) +/* Default: NumPy style (strides), read-only, no var-export, C-style layout */ +#define ND_DEFAULT 0x000 /* User configurable flags for the ndarray */ -#define ND_VAREXPORT 0x001 /* change layout while buffers are exported */ - +#define ND_VAREXPORT 0x001 /* change layout while buffers are exported */ /* User configurable flags for each base buffer */ -#define ND_WRITABLE 0x002 /* mark base buffer as writable */ -#define ND_FORTRAN 0x004 /* Fortran contiguous layout */ -#define ND_SCALAR 0x008 /* scalar: ndim = 0 */ -#define ND_PIL 0x010 /* convert to PIL-style array (suboffsets) */ -#define ND_GETBUF_FAIL 0x020 /* test issue 7385 */ -#define ND_REDIRECT 0x040 /* redirect buffer requests */ - -/* Default: NumPy style (strides), read-only, no var-export, C-style layout */ -#define ND_DEFAULT 0x0 - +#define ND_WRITABLE 0x002 /* mark base buffer as writable */ +#define ND_FORTRAN 0x004 /* Fortran contiguous layout */ +#define ND_SCALAR 0x008 /* scalar: ndim = 0 */ +#define ND_PIL 0x010 /* convert to PIL-style array (suboffsets) */ +#define ND_REDIRECT 0x020 /* redirect buffer requests */ +#define ND_GETBUF_FAIL 0x040 /* trigger getbuffer failure */ +#define ND_GETBUF_UNDEFINED 0x080 /* undefined view.obj */ /* Internal flags for the base buffer */ -#define ND_C 0x080 /* C contiguous layout (default) */ -#define ND_OWN_ARRAYS 0x100 /* consumer owns arrays */ +#define ND_C 0x100 /* C contiguous layout (default) */ +#define ND_OWN_ARRAYS 0x200 /* consumer owns arrays */ /* ndarray properties */ #define ND_IS_CONSUMER(nd) \ @@ -1449,6 +1447,8 @@ if (baseflags & ND_GETBUF_FAIL) { PyErr_SetString(PyExc_BufferError, "ND_GETBUF_FAIL: forced test exception"); + if (baseflags & ND_GETBUF_UNDEFINED) + view->obj = (PyObject *)0x1; /* wrong but permitted in <= 3.2 */ return -1; } @@ -2782,6 +2782,7 @@ PyModule_AddIntConstant(m, "ND_SCALAR", ND_SCALAR); PyModule_AddIntConstant(m, "ND_PIL", ND_PIL); PyModule_AddIntConstant(m, "ND_GETBUF_FAIL", ND_GETBUF_FAIL); + PyModule_AddIntConstant(m, "ND_GETBUF_UNDEFINED", ND_GETBUF_UNDEFINED); PyModule_AddIntConstant(m, "ND_REDIRECT", ND_REDIRECT); PyModule_AddIntConstant(m, "PyBUF_SIMPLE", PyBUF_SIMPLE); diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -86,7 +86,7 @@ return NULL; if (PyObject_GetBuffer(base, &mbuf->master, PyBUF_FULL_RO) < 0) { - /* mbuf->master.obj must be NULL. */ + mbuf->master.obj = NULL; Py_DECREF(mbuf); return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 17:51:47 2012 From: python-checkins at python.org (stefan.krah) Date: Mon, 05 Mar 2012 17:51:47 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?b?KTogTWVyZ2Uu?= Message-ID: http://hg.python.org/cpython/rev/d85f419eda77 changeset: 75441:d85f419eda77 parent: 75440:9f7d06a9eabe parent: 75439:f282d9041ac7 user: Stefan Krah date: Mon Mar 05 17:48:21 2012 +0100 summary: Merge. files: Doc/howto/advocacy.rst | 3 +- Doc/howto/cporting.rst | 4 +- Doc/howto/regex.rst | 4 +- Doc/library/markup.rst | 4 +- Doc/library/packaging.database.rst | 45 +++++++-- Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/tests/test_bdist_msi.py | 19 +++- Lib/packaging/command/bdist_msi.py | 2 +- Lib/packaging/database.py | 1 + Lib/packaging/tests/test_command_bdist_msi.py | 13 ++- Lib/xmlrpc/server.py | 2 +- Misc/NEWS | 3 + Objects/frameobject.c | 1 - 13 files changed, 72 insertions(+), 31 deletions(-) diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst --- a/Doc/howto/advocacy.rst +++ b/Doc/howto/advocacy.rst @@ -264,8 +264,7 @@ **What are the restrictions on Python's use?** -They're practically nonexistent. Consult the :file:`Misc/COPYRIGHT` file in the -source distribution, or the section :ref:`history-and-license` for the full +They're practically nonexistent. Consult :ref:`history-and-license` for the full language, but it boils down to three conditions: * You have to leave the copyright notice on the software; if you don't include diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst --- a/Doc/howto/cporting.rst +++ b/Doc/howto/cporting.rst @@ -261,8 +261,8 @@ copy as you see fit.) You can find :file:`capsulethunk.h` in the Python source distribution -in the :file:`Doc/includes` directory. We also include it here for -your reference; here is :file:`capsulethunk.h`: +as :source:`Doc/includes/capsulethunk.h`. We also include it here for +your convenience: .. literalinclude:: ../includes/capsulethunk.h diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -360,7 +360,7 @@ You can learn about this by interactively experimenting with the :mod:`re` module. If you have :mod:`tkinter` available, you may also want to look at -:file:`Tools/demo/redemo.py`, a demonstration program included with the +:source:`Tools/demo/redemo.py`, a demonstration program included with the Python distribution. It allows you to enter REs and strings, and displays whether the RE matches or fails. :file:`redemo.py` can be quite useful when trying to debug a complicated RE. Phil Schwartz's `Kodos @@ -495,7 +495,7 @@ the same ones in several locations, then it might be worthwhile to collect all the definitions in one place, in a section of code that compiles all the REs ahead of time. To take an example from the standard library, here's an extract -from the now deprecated :file:`xmllib.py`:: +from the now-defunct Python 2 standard :mod:`xmllib` module:: ref = re.compile( ... ) entityref = re.compile( ... ) diff --git a/Doc/library/markup.rst b/Doc/library/markup.rst --- a/Doc/library/markup.rst +++ b/Doc/library/markup.rst @@ -23,7 +23,7 @@ html.rst html.parser.rst html.entities.rst - pyexpat.rst + xml.etree.elementtree.rst xml.dom.rst xml.dom.minidom.rst xml.dom.pulldom.rst @@ -31,4 +31,4 @@ xml.sax.handler.rst xml.sax.utils.rst xml.sax.reader.rst - xml.etree.elementtree.rst + pyexpat.rst diff --git a/Doc/library/packaging.database.rst b/Doc/library/packaging.database.rst --- a/Doc/library/packaging.database.rst +++ b/Doc/library/packaging.database.rst @@ -15,6 +15,11 @@ Most functions also provide an extra argument ``use_egg_info`` to take legacy distributions into account. +For the purpose of this module, "installed" means that the distribution's +:file:`.dist-info`, :file:`.egg-info` or :file:`egg` directory or file is found +on :data:`sys.path`. For example, if the parent directory of a +:file:`dist-info` directory is added to :envvar:`PYTHONPATH`, then it will be +available in the database. Classes representing installed distributions -------------------------------------------- @@ -128,7 +133,7 @@ for the first installed distribution matching *name*. Egg distributions are considered only if *use_egg_info* is true; if both a dist-info and an egg file are found, the dist-info prevails. The directories to be searched are - given in *paths*, which defaults to :data:`sys.path`. Return ``None`` if no + given in *paths*, which defaults to :data:`sys.path`. Returns ``None`` if no matching distribution is found. .. FIXME param should be named use_egg @@ -200,20 +205,23 @@ Examples -------- -Print all information about a distribution -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Printing all information about a distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Given a path to a ``.dist-info`` distribution, we shall print out all +Given the name of an installed distribution, we shall print out all information that can be obtained using functions provided in this module:: import sys import packaging.database - path = input() + try: + name = sys.argv[1] + except ValueError: + sys.exit('Not enough arguments') + # first create the Distribution instance - try: - dist = packaging.database.Distribution(path) - except FileNotFoundError: + dist = packaging.database.Distribution(path) + if dist is None: sys.exit('No such distribution') print('Information about %r' % dist.name) @@ -244,7 +252,7 @@ .. code-block:: sh - $ echo /tmp/choxie/choxie-2.0.0.9.dist-info | python3 print_info.py + python print_info.py choxie we get the following output: @@ -299,10 +307,23 @@ * It was installed as a dependency -Find out obsoleted distributions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Getting metadata about a distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Now, we take tackle a different problem, we are interested in finding out +Sometimes you're not interested about the packaging information contained in a +full :class:`Distribution` object but just want to do something with its +:attr:`~Distribution.metadata`:: + + >>> from packaging.database import get_distribution + >>> info = get_distribution('chocolate').metadata + >>> info['Keywords'] + ['cooking', 'happiness'] + + +Finding out obsoleted distributions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now, we tackle a different problem, we are interested in finding out which distributions have been obsoleted. This can be easily done as follows:: import packaging.database diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -260,7 +260,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', fullname + tup = 'bdist_msi', self.target_version or 'any', installer_name self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,12 +1,12 @@ """Tests for distutils.command.bdist_msi.""" +import os +import sys import unittest -import sys - from test.support import run_unittest - from distutils.tests import support - at unittest.skipUnless(sys.platform=="win32", "These tests are only for win32") + + at unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows') class BDistMSITestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): @@ -14,9 +14,18 @@ def test_minimal(self): # minimal test XXX need more tests from distutils.command.bdist_msi import bdist_msi - pkg_pth, dist = self.create_dist() + project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() + cmd.run() + + bdists = os.listdir(os.path.join(project_dir, 'dist')) + self.assertEqual(bdists, ['foo-0.1.msi']) + + # bug #13719: upload ignores bdist_msi files + self.assertEqual(dist.dist_files, + [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) + def test_suite(): return unittest.makeSuite(BDistMSITestCase) diff --git a/Lib/packaging/command/bdist_msi.py b/Lib/packaging/command/bdist_msi.py --- a/Lib/packaging/command/bdist_msi.py +++ b/Lib/packaging/command/bdist_msi.py @@ -261,7 +261,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', fullname + tup = 'bdist_msi', self.target_version or 'any', installer_name self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/packaging/database.py b/Lib/packaging/database.py --- a/Lib/packaging/database.py +++ b/Lib/packaging/database.py @@ -19,6 +19,7 @@ 'get_distributions', 'get_distribution', 'get_file_users', 'provides_distribution', 'obsoletes_distribution', 'enable_cache', 'disable_cache', 'clear_cache', + # XXX these functions' names look like get_file_users but are not related 'get_file_path', 'get_file'] diff --git a/Lib/packaging/tests/test_command_bdist_msi.py b/Lib/packaging/tests/test_command_bdist_msi.py --- a/Lib/packaging/tests/test_command_bdist_msi.py +++ b/Lib/packaging/tests/test_command_bdist_msi.py @@ -1,20 +1,29 @@ """Tests for distutils.command.bdist_msi.""" +import os import sys from packaging.tests import unittest, support + at unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows') class BDistMSITestCase(support.TempdirManager, support.LoggingCatcher, unittest.TestCase): - @unittest.skipUnless(sys.platform == "win32", "runs only on win32") def test_minimal(self): # minimal test XXX need more tests from packaging.command.bdist_msi import bdist_msi - pkg_pth, dist = self.create_dist() + project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() + cmd.run() + + bdists = os.listdir(os.path.join(project_dir, 'dist')) + self.assertEqual(bdists, ['foo-0.1.msi']) + + # bug #13719: upload ignores bdist_msi files + self.assertEqual(dist.dist_files, + [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) def test_suite(): diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -1,4 +1,4 @@ -"""XML-RPC Servers. +r"""XML-RPC Servers. This module can be used to create simple XML-RPC servers by creating a server and either installing functions, a diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #13719: Make the distutils and packaging upload commands aware of + bdist_msi products. + - Issue #14007: Accept incomplete TreeBuilder objects (missing start, end, data or close method) for the Python implementation as well. Drop the no-op TreeBuilder().xml() method from the C implementation. diff --git a/Objects/frameobject.c b/Objects/frameobject.c --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -20,7 +20,6 @@ {"f_builtins", T_OBJECT, OFF(f_builtins), READONLY}, {"f_globals", T_OBJECT, OFF(f_globals), READONLY}, {"f_lasti", T_INT, OFF(f_lasti), READONLY}, - {"f_yieldfrom", T_OBJECT, OFF(f_yieldfrom), READONLY}, {NULL} /* Sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 19:32:42 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 05 Mar 2012 19:32:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2312328=3A_Fix_multi?= =?utf8?q?processing=27s_use_of_overlapped_I/O_on_Windows=2E?= Message-ID: http://hg.python.org/cpython/rev/75c27daa592e changeset: 75442:75c27daa592e user: Antoine Pitrou date: Mon Mar 05 19:28:37 2012 +0100 summary: Issue #12328: Fix multiprocessing's use of overlapped I/O on Windows. Also, add a multiprocessing.connection.wait(rlist, timeout=None) function for polling multiple objects at once. Patch by sbt. Complete changelist from sbt's patch: * Adds a wait(rlist, timeout=None) function for polling multiple objects at once. On Unix this is just a wrapper for select(rlist, [], [], timeout=None). * Removes use of the SentinelReady exception and the sentinels argument to certain methods. concurrent.futures.process has been changed to use wait() instead of SentinelReady. * Fixes bugs concerning PipeConnection.poll() and messages of zero length. * Fixes PipeListener.accept() to call ConnectNamedPipe() with overlapped=True. * Fixes Queue.empty() and SimpleQueue.empty() so that they are threadsafe on Windows. * Now PipeConnection.poll() and wait() will not modify the pipe except possibly by consuming a zero length message. (Previously poll() could consume a partial message.) * All of multiprocesing's pipe related blocking functions/methods are now interruptible by SIGINT on Windows. files: Doc/library/multiprocessing.rst | 82 ++- Lib/concurrent/futures/process.py | 12 +- Lib/multiprocessing/connection.py | 332 ++++++--- Lib/multiprocessing/queues.py | 9 +- Lib/test/test_multiprocessing.py | 235 +++++++- Misc/NEWS | 4 + Modules/_multiprocessing/win32_functions.c | 69 +- 7 files changed, 586 insertions(+), 157 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -415,13 +415,14 @@ A numeric handle of a system object which will become "ready" when the process ends. + You can use this value if you want to wait on several events at + once using :func:`multiprocessing.connection.wait`. Otherwise + calling :meth:`join()` is simpler. + On Windows, this is an OS handle usable with the ``WaitForSingleObject`` and ``WaitForMultipleObjects`` family of API calls. On Unix, this is a file descriptor usable with primitives from the :mod:`select` module. - You can use this value if you want to wait on several events at once. - Otherwise calling :meth:`join()` is simpler. - .. versionadded:: 3.3 .. method:: terminate() @@ -785,6 +786,9 @@ *timeout* is a number then this specifies the maximum time in seconds to block. If *timeout* is ``None`` then an infinite timeout is used. + Note that multiple connection objects may be polled at once by + using :func:`multiprocessing.connection.wait`. + .. method:: send_bytes(buffer[, offset[, size]]) Send byte data from an object supporting the buffer interface as a @@ -1779,8 +1783,9 @@ However, the :mod:`multiprocessing.connection` module allows some extra flexibility. It basically gives a high level message oriented API for dealing -with sockets or Windows named pipes, and also has support for *digest -authentication* using the :mod:`hmac` module. +with sockets or Windows named pipes. It also has support for *digest +authentication* using the :mod:`hmac` module, and for polling +multiple connections at the same time. .. function:: deliver_challenge(connection, authkey) @@ -1878,6 +1883,38 @@ The address from which the last accepted connection came. If this is unavailable then it is ``None``. +.. function:: wait(object_list, timeout=None) + + Wait till an object in *object_list* is ready. Returns the list of + those objects in *object_list* which are ready. If *timeout* is a + float then the call blocks for at most that many seconds. If + *timeout* is ``None`` then it will block for an unlimited period. + + For both Unix and Windows, an object can appear in *object_list* if + it is + + * a readable :class:`~multiprocessing.Connection` object; + * a connected and readable :class:`socket.socket` object; or + * the :attr:`~multiprocessing.Process.sentinel` attribute of a + :class:`~multiprocessing.Process` object. + + A connection or socket object is ready when there is data available + to be read from it, or the other end has been closed. + + **Unix**: ``wait(object_list, timeout)`` almost equivalent + ``select.select(object_list, [], [], timeout)``. The difference is + that, if :func:`select.select` is interrupted by a signal, it can + raise :exc:`OSError` with an error number of ``EINTR``, whereas + :func:`wait` will not. + + **Windows**: An item in *object_list* must either be an integer + handle which is waitable (according to the definition used by the + documentation of the Win32 function ``WaitForMultipleObjects()``) + or it can be an object with a :meth:`fileno` method which returns a + socket handle or pipe handle. (Note that pipe handles and socket + handles are **not** waitable handles.) + + .. versionadded:: 3.3 The module defines two exceptions: @@ -1929,6 +1966,41 @@ conn.close() +The following code uses :func:`~multiprocessing.connection.wait` to +wait for messages from multiple processes at once:: + + import time, random + from multiprocessing import Process, Pipe, current_process + from multiprocessing.connection import wait + + def foo(w): + for i in range(10): + w.send((i, current_process().name)) + w.close() + + if __name__ == '__main__': + readers = [] + + for i in range(4): + r, w = Pipe(duplex=False) + readers.append(r) + p = Process(target=foo, args=(w,)) + p.start() + # We close the writable end of the pipe now to be sure that + # p is the only process which owns a handle for it. This + # ensures that when p closes its handle for the writable end, + # wait() will promptly report the readable end as being ready. + w.close() + + while readers: + for r in wait(readers): + try: + msg = r.recv() + except EOFError: + readers.remove(r) + else: + print(msg) + .. _multiprocessing-address-formats: diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -50,7 +50,8 @@ from concurrent.futures import _base import queue import multiprocessing -from multiprocessing.queues import SimpleQueue, SentinelReady, Full +from multiprocessing.queues import SimpleQueue, Full +from multiprocessing.connection import wait import threading import weakref @@ -212,6 +213,8 @@ for p in processes.values(): p.join() + reader = result_queue._reader + while True: _add_call_item_to_queue(pending_work_items, work_ids_queue, @@ -219,9 +222,10 @@ sentinels = [p.sentinel for p in processes.values()] assert sentinels - try: - result_item = result_queue.get(sentinels=sentinels) - except SentinelReady: + ready = wait([reader] + sentinels) + if reader in ready: + result_item = reader.recv() + else: # Mark the process pool broken so that submits fail right now. executor = executor_reference() if executor is not None: diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -32,7 +32,7 @@ # SUCH DAMAGE. # -__all__ = [ 'Client', 'Listener', 'Pipe' ] +__all__ = [ 'Client', 'Listener', 'Pipe', 'wait' ] import io import os @@ -58,8 +58,6 @@ raise win32 = None -_select = _eintr_retry(select.select) - # # # @@ -122,15 +120,6 @@ else: raise ValueError('address type of %r unrecognized' % address) - -class SentinelReady(Exception): - """ - Raised when a sentinel is ready when polling. - """ - def __init__(self, *args): - Exception.__init__(self, *args) - self.sentinels = args[0] - # # Connection classes # @@ -268,11 +257,11 @@ (offset + size) // itemsize]) return size - def recv(self, sentinels=None): + def recv(self): """Receive a (picklable) object""" self._check_closed() self._check_readable() - buf = self._recv_bytes(sentinels=sentinels) + buf = self._recv_bytes() return pickle.loads(buf.getbuffer()) def poll(self, timeout=0.0): @@ -290,85 +279,80 @@ Overlapped I/O is used, so the handles must have been created with FILE_FLAG_OVERLAPPED. """ - _buffered = b'' + _got_empty_message = False def _close(self, _CloseHandle=win32.CloseHandle): _CloseHandle(self._handle) def _send_bytes(self, buf): - overlapped = win32.WriteFile(self._handle, buf, overlapped=True) - nwritten, complete = overlapped.GetOverlappedResult(True) - assert complete + ov, err = win32.WriteFile(self._handle, buf, overlapped=True) + try: + if err == win32.ERROR_IO_PENDING: + waitres = win32.WaitForMultipleObjects( + [ov.event], False, INFINITE) + assert waitres == WAIT_OBJECT_0 + except: + ov.cancel() + raise + finally: + nwritten, err = ov.GetOverlappedResult(True) + assert err == 0 assert nwritten == len(buf) - def _recv_bytes(self, maxsize=None, sentinels=()): - if sentinels: - self._poll(-1.0, sentinels) - buf = io.BytesIO() - firstchunk = self._buffered - if firstchunk: - lenfirstchunk = len(firstchunk) - buf.write(firstchunk) - self._buffered = b'' + def _recv_bytes(self, maxsize=None): + if self._got_empty_message: + self._got_empty_message = False + return io.BytesIO() else: - # A reasonable size for the first chunk transfer - bufsize = 128 - if maxsize is not None and maxsize < bufsize: - bufsize = maxsize + bsize = 128 if maxsize is None else min(maxsize, 128) try: - overlapped = win32.ReadFile(self._handle, bufsize, overlapped=True) - lenfirstchunk, complete = overlapped.GetOverlappedResult(True) - firstchunk = overlapped.getbuffer() - assert lenfirstchunk == len(firstchunk) + ov, err = win32.ReadFile(self._handle, bsize, + overlapped=True) + try: + if err == win32.ERROR_IO_PENDING: + waitres = win32.WaitForMultipleObjects( + [ov.event], False, INFINITE) + assert waitres == WAIT_OBJECT_0 + except: + ov.cancel() + raise + finally: + nread, err = ov.GetOverlappedResult(True) + if err == 0: + f = io.BytesIO() + f.write(ov.getbuffer()) + return f + elif err == win32.ERROR_MORE_DATA: + return self._get_more_data(ov, maxsize) except IOError as e: if e.winerror == win32.ERROR_BROKEN_PIPE: raise EOFError - raise - buf.write(firstchunk) - if complete: - return buf - navail, nleft = win32.PeekNamedPipe(self._handle) - if maxsize is not None and lenfirstchunk + nleft > maxsize: - return None - if nleft > 0: - overlapped = win32.ReadFile(self._handle, nleft, overlapped=True) - res, complete = overlapped.GetOverlappedResult(True) - assert res == nleft - assert complete - buf.write(overlapped.getbuffer()) - return buf + else: + raise + raise RuntimeError("shouldn't get here; expected KeyboardInterrupt") - def _poll(self, timeout, sentinels=()): - # Fast non-blocking path - navail, nleft = win32.PeekNamedPipe(self._handle) - if navail > 0: + def _poll(self, timeout): + if (self._got_empty_message or + win32.PeekNamedPipe(self._handle)[0] != 0): return True - elif timeout == 0.0: - return False - # Blocking: use overlapped I/O - if timeout < 0.0: - timeout = INFINITE - else: - timeout = int(timeout * 1000 + 0.5) - overlapped = win32.ReadFile(self._handle, 1, overlapped=True) - try: - handles = [overlapped.event] - handles += sentinels - res = win32.WaitForMultipleObjects(handles, False, timeout) - finally: - # Always cancel overlapped I/O in the same thread - # (because CancelIoEx() appears only in Vista) - overlapped.cancel() - if res == WAIT_TIMEOUT: - return False - idx = res - WAIT_OBJECT_0 - if idx == 0: - # I/O was successful, store received data - overlapped.GetOverlappedResult(True) - self._buffered += overlapped.getbuffer() - return True - assert 0 < idx < len(handles) - raise SentinelReady([handles[idx]]) + if timeout < 0: + timeout = None + return bool(wait([self], timeout)) + + def _get_more_data(self, ov, maxsize): + buf = ov.getbuffer() + f = io.BytesIO() + f.write(buf) + left = win32.PeekNamedPipe(self._handle)[1] + assert left > 0 + if maxsize is not None and len(buf) + left > maxsize: + self._bad_message_length() + ov, err = win32.ReadFile(self._handle, left, overlapped=True) + rbytes, err = ov.GetOverlappedResult(True) + assert err == 0 + assert rbytes == left + f.write(ov.getbuffer()) + return f class Connection(_ConnectionBase): @@ -397,17 +381,11 @@ break buf = buf[n:] - def _recv(self, size, sentinels=(), read=_read): + def _recv(self, size, read=_read): buf = io.BytesIO() handle = self._handle - if sentinels: - handles = [handle] + sentinels remaining = size while remaining > 0: - if sentinels: - r = _select(handles, [], [])[0] - if handle not in r: - raise SentinelReady(r) chunk = read(handle, remaining) n = len(chunk) if n == 0: @@ -428,17 +406,17 @@ if n > 0: self._send(buf) - def _recv_bytes(self, maxsize=None, sentinels=()): - buf = self._recv(4, sentinels) + def _recv_bytes(self, maxsize=None): + buf = self._recv(4) size, = struct.unpack("!i", buf.getvalue()) if maxsize is not None and size > maxsize: return None - return self._recv(size, sentinels) + return self._recv(size) def _poll(self, timeout): if timeout < 0.0: timeout = None - r = _select([self._handle], [], [], timeout)[0] + r = wait([self._handle], timeout) return bool(r) @@ -559,7 +537,8 @@ ) overlapped = win32.ConnectNamedPipe(h1, overlapped=True) - overlapped.GetOverlappedResult(True) + _, err = overlapped.GetOverlappedResult(True) + assert err == 0 c1 = PipeConnection(h1, writable=duplex) c2 = PipeConnection(h2, readable=duplex) @@ -633,39 +612,40 @@ ''' def __init__(self, address, backlog=None): self._address = address - handle = win32.CreateNamedPipe( - address, win32.PIPE_ACCESS_DUPLEX | - win32.FILE_FLAG_FIRST_PIPE_INSTANCE, + self._handle_queue = [self._new_handle(first=True)] + + self._last_accepted = None + sub_debug('listener created with address=%r', self._address) + self.close = Finalize( + self, PipeListener._finalize_pipe_listener, + args=(self._handle_queue, self._address), exitpriority=0 + ) + + def _new_handle(self, first=False): + flags = win32.PIPE_ACCESS_DUPLEX | win32.FILE_FLAG_OVERLAPPED + if first: + flags |= win32.FILE_FLAG_FIRST_PIPE_INSTANCE + return win32.CreateNamedPipe( + self._address, flags, win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE | win32.PIPE_WAIT, win32.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, win32.NMPWAIT_WAIT_FOREVER, win32.NULL ) - self._handle_queue = [handle] - self._last_accepted = None - - sub_debug('listener created with address=%r', self._address) - - self.close = Finalize( - self, PipeListener._finalize_pipe_listener, - args=(self._handle_queue, self._address), exitpriority=0 - ) def accept(self): - newhandle = win32.CreateNamedPipe( - self._address, win32.PIPE_ACCESS_DUPLEX, - win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE | - win32.PIPE_WAIT, - win32.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, - win32.NMPWAIT_WAIT_FOREVER, win32.NULL - ) - self._handle_queue.append(newhandle) + self._handle_queue.append(self._new_handle()) handle = self._handle_queue.pop(0) + ov = win32.ConnectNamedPipe(handle, overlapped=True) try: - win32.ConnectNamedPipe(handle, win32.NULL) - except WindowsError as e: - if e.winerror != win32.ERROR_PIPE_CONNECTED: - raise + res = win32.WaitForMultipleObjects([ov.event], False, INFINITE) + except: + ov.cancel() + win32.CloseHandle(handle) + raise + finally: + _, err = ov.GetOverlappedResult(True) + assert err == 0 return PipeConnection(handle) @staticmethod @@ -684,7 +664,8 @@ win32.WaitNamedPipe(address, 1000) h = win32.CreateFile( address, win32.GENERIC_READ | win32.GENERIC_WRITE, - 0, win32.NULL, win32.OPEN_EXISTING, 0, win32.NULL + 0, win32.NULL, win32.OPEN_EXISTING, + win32.FILE_FLAG_OVERLAPPED, win32.NULL ) except WindowsError as e: if e.winerror not in (win32.ERROR_SEM_TIMEOUT, @@ -773,6 +754,125 @@ import xmlrpc.client as xmlrpclib return ConnectionWrapper(Client(*args, **kwds), _xml_dumps, _xml_loads) +# +# Wait +# + +if sys.platform == 'win32': + + def _exhaustive_wait(handles, timeout): + # Return ALL handles which are currently signalled. (Only + # returning the first signalled might create starvation issues.) + L = list(handles) + ready = [] + while L: + res = win32.WaitForMultipleObjects(L, False, timeout) + if res == WAIT_TIMEOUT: + break + elif WAIT_OBJECT_0 <= res < WAIT_OBJECT_0 + len(L): + res -= WAIT_OBJECT_0 + elif WAIT_ABANDONED_0 <= res < WAIT_ABANDONED_0 + len(L): + res -= WAIT_ABANDONED_0 + else: + raise RuntimeError('Should not get here') + ready.append(L[res]) + L = L[res+1:] + timeout = 0 + return ready + + _ready_errors = {win32.ERROR_BROKEN_PIPE, win32.ERROR_NETNAME_DELETED} + + def wait(object_list, timeout=None): + ''' + Wait till an object in object_list is ready/readable. + + Returns list of those objects in object_list which are ready/readable. + ''' + if timeout is None: + timeout = INFINITE + elif timeout < 0: + timeout = 0 + else: + timeout = int(timeout * 1000 + 0.5) + + object_list = list(object_list) + waithandle_to_obj = {} + ov_list = [] + ready_objects = set() + ready_handles = set() + + try: + for o in object_list: + try: + fileno = getattr(o, 'fileno') + except AttributeError: + waithandle_to_obj[o.__index__()] = o + else: + # start an overlapped read of length zero + try: + ov, err = win32.ReadFile(fileno(), 0, True) + except OSError as e: + err = e.winerror + if err not in _ready_errors: + raise + if err == win32.ERROR_IO_PENDING: + ov_list.append(ov) + waithandle_to_obj[ov.event] = o + else: + # If o.fileno() is an overlapped pipe handle and + # err == 0 then there is a zero length message + # in the pipe, but it HAS NOT been consumed. + ready_objects.add(o) + timeout = 0 + + ready_handles = _exhaustive_wait(waithandle_to_obj.keys(), timeout) + finally: + # request that overlapped reads stop + for ov in ov_list: + ov.cancel() + + # wait for all overlapped reads to stop + for ov in ov_list: + try: + _, err = ov.GetOverlappedResult(True) + except OSError as e: + err = e.winerror + if err not in _ready_errors: + raise + if err != win32.ERROR_OPERATION_ABORTED: + o = waithandle_to_obj[ov.event] + ready_objects.add(o) + if err == 0: + # If o.fileno() is an overlapped pipe handle then + # a zero length message HAS been consumed. + if hasattr(o, '_got_empty_message'): + o._got_empty_message = True + + ready_objects.update(waithandle_to_obj[h] for h in ready_handles) + return [o for o in object_list if o in ready_objects] + +else: + + def wait(object_list, timeout=None): + ''' + Wait till an object in object_list is ready/readable. + + Returns list of those objects in object_list which are ready/readable. + ''' + if timeout is not None: + if timeout <= 0: + return select.select(object_list, [], [], 0)[0] + else: + deadline = time.time() + timeout + while True: + try: + return select.select(object_list, [], [], timeout)[0] + except OSError as e: + if e.errno != errno.EINTR: + raise + if timeout is not None: + timeout = deadline - time.time() + # Late import because of circular import from multiprocessing.forking import duplicate, close diff --git a/Lib/multiprocessing/queues.py b/Lib/multiprocessing/queues.py --- a/Lib/multiprocessing/queues.py +++ b/Lib/multiprocessing/queues.py @@ -44,7 +44,7 @@ from queue import Empty, Full import _multiprocessing -from multiprocessing.connection import Pipe, SentinelReady +from multiprocessing.connection import Pipe from multiprocessing.synchronize import Lock, BoundedSemaphore, Semaphore, Condition from multiprocessing.util import debug, info, Finalize, register_after_fork from multiprocessing.forking import assert_spawning @@ -360,6 +360,7 @@ def __init__(self): self._reader, self._writer = Pipe(duplex=False) self._rlock = Lock() + self._poll = self._reader.poll if sys.platform == 'win32': self._wlock = None else: @@ -367,7 +368,7 @@ self._make_methods() def empty(self): - return not self._reader.poll() + return not self._poll() def __getstate__(self): assert_spawning(self) @@ -380,10 +381,10 @@ def _make_methods(self): recv = self._reader.recv racquire, rrelease = self._rlock.acquire, self._rlock.release - def get(*, sentinels=None): + def get(): racquire() try: - return recv(sentinels) + return recv() finally: rrelease() self.get = get diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -1811,6 +1811,84 @@ p.join() l.close() +class _TestPoll(unittest.TestCase): + + ALLOWED_TYPES = ('processes', 'threads') + + def test_empty_string(self): + a, b = self.Pipe() + self.assertEqual(a.poll(), False) + b.send_bytes(b'') + self.assertEqual(a.poll(), True) + self.assertEqual(a.poll(), True) + + @classmethod + def _child_strings(cls, conn, strings): + for s in strings: + time.sleep(0.1) + conn.send_bytes(s) + conn.close() + + def test_strings(self): + strings = (b'hello', b'', b'a', b'b', b'', b'bye', b'', b'lop') + a, b = self.Pipe() + p = self.Process(target=self._child_strings, args=(b, strings)) + p.start() + + for s in strings: + for i in range(200): + if a.poll(0.01): + break + x = a.recv_bytes() + self.assertEqual(s, x) + + p.join() + + @classmethod + def _child_boundaries(cls, r): + # Polling may "pull" a message in to the child process, but we + # don't want it to pull only part of a message, as that would + # corrupt the pipe for any other processes which might later + # read from it. + r.poll(5) + + def test_boundaries(self): + r, w = self.Pipe(False) + p = self.Process(target=self._child_boundaries, args=(r,)) + p.start() + time.sleep(2) + L = [b"first", b"second"] + for obj in L: + w.send_bytes(obj) + w.close() + p.join() + self.assertIn(r.recv_bytes(), L) + + @classmethod + def _child_dont_merge(cls, b): + b.send_bytes(b'a') + b.send_bytes(b'b') + b.send_bytes(b'cd') + + def test_dont_merge(self): + a, b = self.Pipe() + self.assertEqual(a.poll(0.0), False) + self.assertEqual(a.poll(0.1), False) + + p = self.Process(target=self._child_dont_merge, args=(b,)) + p.start() + + self.assertEqual(a.recv_bytes(), b'a') + self.assertEqual(a.poll(1.0), True) + self.assertEqual(a.poll(1.0), True) + self.assertEqual(a.recv_bytes(), b'b') + self.assertEqual(a.poll(1.0), True) + self.assertEqual(a.poll(1.0), True) + self.assertEqual(a.poll(0.0), True) + self.assertEqual(a.recv_bytes(), b'cd') + + p.join() + # # Test of sending connection and socket objects between processes # @@ -2404,8 +2482,163 @@ flike.flush() assert sio.getvalue() == 'foo' + +class TestWait(unittest.TestCase): + + @classmethod + def _child_test_wait(cls, w, slow): + for i in range(10): + if slow: + time.sleep(random.random()*0.1) + w.send((i, os.getpid())) + w.close() + + def test_wait(self, slow=False): + from multiprocessing import Pipe, Process + from multiprocessing.connection import wait + readers = [] + procs = [] + messages = [] + + for i in range(4): + r, w = Pipe(duplex=False) + p = Process(target=self._child_test_wait, args=(w, slow)) + p.daemon = True + p.start() + w.close() + readers.append(r) + procs.append(p) + + while readers: + for r in wait(readers): + try: + msg = r.recv() + except EOFError: + readers.remove(r) + r.close() + else: + messages.append(msg) + + messages.sort() + expected = sorted((i, p.pid) for i in range(10) for p in procs) + self.assertEqual(messages, expected) + + @classmethod + def _child_test_wait_socket(cls, address, slow): + s = socket.socket() + s.connect(address) + for i in range(10): + if slow: + time.sleep(random.random()*0.1) + s.sendall(('%s\n' % i).encode('ascii')) + s.close() + + def test_wait_socket(self, slow=False): + from multiprocessing import Process + from multiprocessing.connection import wait + l = socket.socket() + l.bind(('', 0)) + l.listen(4) + addr = ('localhost', l.getsockname()[1]) + readers = [] + procs = [] + dic = {} + + for i in range(4): + p = Process(target=self._child_test_wait_socket, args=(addr, slow)) + p.daemon = True + p.start() + procs.append(p) + + for i in range(4): + r, _ = l.accept() + readers.append(r) + dic[r] = [] + l.close() + + while readers: + for r in wait(readers): + msg = r.recv(32) + if not msg: + readers.remove(r) + r.close() + else: + dic[r].append(msg) + + expected = ''.join('%s\n' % i for i in range(10)).encode('ascii') + for v in dic.values(): + self.assertEqual(b''.join(v), expected) + + def test_wait_slow(self): + self.test_wait(True) + + def test_wait_socket_slow(self): + self.test_wait(True) + + def test_wait_timeout(self): + from multiprocessing.connection import wait + + expected = 1 + a, b = multiprocessing.Pipe() + + start = time.time() + res = wait([a, b], 1) + delta = time.time() - start + + self.assertEqual(res, []) + self.assertLess(delta, expected + 0.2) + self.assertGreater(delta, expected - 0.2) + + b.send(None) + + start = time.time() + res = wait([a, b], 1) + delta = time.time() - start + + self.assertEqual(res, [a]) + self.assertLess(delta, 0.2) + + def test_wait_integer(self): + from multiprocessing.connection import wait + + expected = 5 + a, b = multiprocessing.Pipe() + p = multiprocessing.Process(target=time.sleep, args=(expected,)) + + p.start() + self.assertIsInstance(p.sentinel, int) + + start = time.time() + res = wait([a, p.sentinel, b], expected + 20) + delta = time.time() - start + + self.assertEqual(res, [p.sentinel]) + self.assertLess(delta, expected + 1) + self.assertGreater(delta, expected - 1) + + a.send(None) + + start = time.time() + res = wait([a, p.sentinel, b], 20) + delta = time.time() - start + + self.assertEqual(res, [p.sentinel, b]) + self.assertLess(delta, 0.2) + + b.send(None) + + start = time.time() + res = wait([a, p.sentinel, b], 20) + delta = time.time() - start + + self.assertEqual(res, [a, p.sentinel, b]) + self.assertLess(delta, 0.2) + + p.join() + + testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, - TestStdinBadfiledescriptor] + TestStdinBadfiledescriptor, TestWait] # # diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,10 @@ Library ------- +- Issue #12328: Fix multiprocessing's use of overlapped I/O on Windows. + Also, add a multiprocessing.connection.wait(rlist, timeout=None) function + for polling multiple objects at once. Patch by sbt. + - Issue #13719: Make the distutils and packaging upload commands aware of bdist_msi products. diff --git a/Modules/_multiprocessing/win32_functions.c b/Modules/_multiprocessing/win32_functions.c --- a/Modules/_multiprocessing/win32_functions.c +++ b/Modules/_multiprocessing/win32_functions.c @@ -60,16 +60,18 @@ static void overlapped_dealloc(OverlappedObject *self) { + DWORD bytes; int err = GetLastError(); if (self->pending) { - if (check_CancelIoEx()) - Py_CancelIoEx(self->handle, &self->overlapped); - else { - PyErr_SetString(PyExc_RuntimeError, - "I/O operations still in flight while destroying " - "Overlapped object, the process may crash"); - PyErr_WriteUnraisable(NULL); - } + /* make it a programming error to deallocate while operation + is pending, even if we can safely cancel it */ + if (check_CancelIoEx() && + Py_CancelIoEx(self->handle, &self->overlapped)) + GetOverlappedResult(self->handle, &self->overlapped, &bytes, TRUE); + PyErr_SetString(PyExc_RuntimeError, + "I/O operations still in flight while destroying " + "Overlapped object, the process may crash"); + PyErr_WriteUnraisable(NULL); } CloseHandle(self->overlapped.hEvent); SetLastError(err); @@ -85,6 +87,7 @@ int wait; BOOL res; DWORD transferred = 0; + DWORD err; wait = PyObject_IsTrue(waitobj); if (wait < 0) @@ -94,23 +97,27 @@ wait != 0); Py_END_ALLOW_THREADS - if (!res) { - int err = GetLastError(); - if (err == ERROR_IO_INCOMPLETE) - Py_RETURN_NONE; - if (err != ERROR_MORE_DATA) { + err = res ? ERROR_SUCCESS : GetLastError(); + switch (err) { + case ERROR_SUCCESS: + case ERROR_MORE_DATA: + case ERROR_OPERATION_ABORTED: + self->completed = 1; + self->pending = 0; + break; + case ERROR_IO_INCOMPLETE: + break; + default: self->pending = 0; return PyErr_SetExcFromWindowsErr(PyExc_IOError, err); - } } - self->pending = 0; - self->completed = 1; - if (self->read_buffer) { + if (self->completed && self->read_buffer != NULL) { assert(PyBytes_CheckExact(self->read_buffer)); - if (_PyBytes_Resize(&self->read_buffer, transferred)) + if (transferred != PyBytes_GET_SIZE(self->read_buffer) && + _PyBytes_Resize(&self->read_buffer, transferred)) return NULL; } - return Py_BuildValue("lN", (long) transferred, PyBool_FromLong(res)); + return Py_BuildValue("II", (unsigned) transferred, (unsigned) err); } static PyObject * @@ -522,9 +529,10 @@ HANDLE handle; Py_buffer _buf, *buf; PyObject *bufobj; - int written; + DWORD written; BOOL ret; int use_overlapped = 0; + DWORD err; OverlappedObject *overlapped = NULL; static char *kwlist[] = {"handle", "buffer", "overlapped", NULL}; @@ -553,8 +561,9 @@ overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS + err = ret ? 0 : GetLastError(); + if (overlapped) { - int err = GetLastError(); if (!ret) { if (err == ERROR_IO_PENDING) overlapped->pending = 1; @@ -563,13 +572,13 @@ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } } - return (PyObject *) overlapped; + return Py_BuildValue("NI", (PyObject *) overlapped, err); } PyBuffer_Release(buf); if (!ret) return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - return PyLong_FromLong(written); + return Py_BuildValue("II", written, err); } static PyObject * @@ -581,6 +590,7 @@ PyObject *buf; BOOL ret; int use_overlapped = 0; + DWORD err; OverlappedObject *overlapped = NULL; static char *kwlist[] = {"handle", "size", "overlapped", NULL}; @@ -607,8 +617,9 @@ overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS + err = ret ? 0 : GetLastError(); + if (overlapped) { - int err = GetLastError(); if (!ret) { if (err == ERROR_IO_PENDING) overlapped->pending = 1; @@ -617,16 +628,16 @@ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } } - return (PyObject *) overlapped; + return Py_BuildValue("NI", (PyObject *) overlapped, err); } - if (!ret && GetLastError() != ERROR_MORE_DATA) { + if (!ret && err != ERROR_MORE_DATA) { Py_DECREF(buf); return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } if (_PyBytes_Resize(&buf, nread)) return NULL; - return Py_BuildValue("NN", buf, PyBool_FromLong(ret)); + return Py_BuildValue("NI", buf, err); } static PyObject * @@ -783,7 +794,11 @@ WIN32_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS); WIN32_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE); + WIN32_CONSTANT(F_DWORD, ERROR_IO_PENDING); + WIN32_CONSTANT(F_DWORD, ERROR_MORE_DATA); + WIN32_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); WIN32_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); + WIN32_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED); WIN32_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); WIN32_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); WIN32_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 21:03:01 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 05 Mar 2012 21:03:01 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Added_delay_before_record_c?= =?utf8?q?reation=2E?= Message-ID: http://hg.python.org/cpython/rev/09f19e575724 changeset: 75443:09f19e575724 user: Vinay Sajip date: Mon Mar 05 20:02:53 2012 +0000 summary: Added delay before record creation. files: Lib/test/test_logging.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3654,10 +3654,10 @@ fmt = logging.Formatter('%(asctime)s %(message)s') fh.setFormatter(fmt) r1 = logging.makeLogRecord({'msg': 'testing - initial'}) - r2 = logging.makeLogRecord({'msg': 'testing - after delay'}) fh.emit(r1) self.assertLogFile(self.fn) time.sleep(1.1) # a little over a second ... + r2 = logging.makeLogRecord({'msg': 'testing - after delay'}) fh.emit(r2) fh.close() # At this point, we should have a recent rotated file which we -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 22:02:40 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 05 Mar 2012 22:02:40 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Move_entry_to_right_section?= =?utf8?q?=2E_Mention_minidom=2E?= Message-ID: http://hg.python.org/cpython/rev/39c18162137b changeset: 75444:39c18162137b user: Martin v. L?wis date: Mon Mar 05 22:02:28 2012 +0100 summary: Move entry to right section. Mention minidom. files: Misc/NEWS | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #14168: Check for presence of Element._attrs in minidom before + accessing it. + - Issue #12328: Fix multiprocessing's use of overlapped I/O on Windows. Also, add a multiprocessing.connection.wait(rlist, timeout=None) function for polling multiple objects at once. Patch by sbt. @@ -534,8 +537,6 @@ Library ------- -- Issue #14168: Check for presence of _attrs before accessing it. - - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been fixed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 5 22:43:45 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 05 Mar 2012 22:43:45 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_implicitly_set_=5F=5Fsuppress?= =?utf8?b?X2NvbnRleHRfXyB3aGVuIF9fY2F1c2VfXyBpcyBzZXQ=?= Message-ID: http://hg.python.org/peps/rev/0a7019500350 changeset: 4118:0a7019500350 user: Benjamin Peterson date: Mon Mar 05 15:43:34 2012 -0600 summary: implicitly set __suppress_context__ when __cause__ is set files: pep-0415.txt | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pep-0415.txt b/pep-0415.txt --- a/pep-0415.txt +++ b/pep-0415.txt @@ -42,11 +42,12 @@ ======== A new attribute on ``BaseException``, ``__suppress_context__``, will -be introduced. The ``raise exc from cause`` syntax will set -``exc.__suppress_context__`` to ``True``. Exception printing code will -check for that attribute to determine whether context and cause will -be printed. ``__cause__`` will return to its original purpose and -values. +be introduced. Whenever ``__cause__`` is set, ``__suppress_context__`` +will be set to ``True``. In particular, ``raise exc from cause`` +syntax will set ``exc.__suppress_context__`` to ``True``. Exception +printing code will check for that attribute to determine whether +context and cause will be printed. ``__cause__`` will return to its +original purpose and values. There is precedence for ``__suppress_context__`` with the ``print_line_and_file`` exception attribute. @@ -54,9 +55,11 @@ To summarize, ``raise exc from cause`` will be equivalent to:: exc.__cause__ = cause - exc.__suppress_context__ = True raise exc +where ``exc.__cause__ = cause`` implicitly sets +``exc.__suppress_context__``. + Patches ======= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 6 01:13:02 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 06 Mar 2012 01:13:02 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_=2314205=3A_dict_look?= =?utf8?q?up_raises_a_RuntimeError_if_the_dict_is_modified_during?= Message-ID: http://hg.python.org/cpython/rev/934aaf2191d0 changeset: 75445:934aaf2191d0 user: Victor Stinner date: Tue Mar 06 01:03:13 2012 +0100 summary: Close #14205: dict lookup raises a RuntimeError if the dict is modified during a lookup. "if you want to make a sandbox on top of CPython, you have to fix segfaults" so let's fix segfaults! files: Lib/test/crashers/nasty_eq_vs_dict.py | 47 -- Lib/test/test_dict.py | 22 +- Lib/test/test_mutants.py | 291 -------------- Misc/NEWS | 5 +- Objects/dictobject.c | 18 +- 5 files changed, 31 insertions(+), 352 deletions(-) diff --git a/Lib/test/crashers/nasty_eq_vs_dict.py b/Lib/test/crashers/nasty_eq_vs_dict.py deleted file mode 100644 --- a/Lib/test/crashers/nasty_eq_vs_dict.py +++ /dev/null @@ -1,47 +0,0 @@ -# from http://mail.python.org/pipermail/python-dev/2001-June/015239.html - -# if you keep changing a dictionary while looking up a key, you can -# provoke an infinite recursion in C - -# At the time neither Tim nor Michael could be bothered to think of a -# way to fix it. - -class Yuck: - def __init__(self): - self.i = 0 - - def make_dangerous(self): - self.i = 1 - - def __hash__(self): - # direct to slot 4 in table of size 8; slot 12 when size 16 - return 4 + 8 - - def __eq__(self, other): - if self.i == 0: - # leave dict alone - pass - elif self.i == 1: - # fiddle to 16 slots - self.__fill_dict(6) - self.i = 2 - else: - # fiddle to 8 slots - self.__fill_dict(4) - self.i = 1 - - return 1 - - def __fill_dict(self, n): - self.i = 0 - dict.clear() - for i in range(n): - dict[i] = i - dict[self] = "OK!" - -y = Yuck() -dict = {y: "OK!"} - -z = Yuck() -y.make_dangerous() -print(dict[z]) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -379,7 +379,7 @@ x.fail = True self.assertRaises(Exc, d.pop, x) - def test_mutatingiteration(self): + def test_mutating_iteration(self): # changing dict size during iteration d = {} d[1] = 1 @@ -387,6 +387,26 @@ for i in d: d[i+1] = 1 + def test_mutating_lookup(self): + # changing dict during a lookup + class NastyKey: + mutate_dict = None + + def __hash__(self): + # hash collision! + return 1 + + def __eq__(self, other): + if self.mutate_dict: + self.mutate_dict[self] = 1 + return self == other + + d = {} + d[NastyKey()] = 0 + NastyKey.mutate_dict = d + with self.assertRaises(RuntimeError): + d[NastyKey()] = None + def test_repr(self): d = {} self.assertEqual(repr(d), '{}') diff --git a/Lib/test/test_mutants.py b/Lib/test/test_mutants.py deleted file mode 100644 --- a/Lib/test/test_mutants.py +++ /dev/null @@ -1,291 +0,0 @@ -from test.support import verbose, TESTFN -import random -import os - -# From SF bug #422121: Insecurities in dict comparison. - -# Safety of code doing comparisons has been an historical Python weak spot. -# The problem is that comparison of structures written in C *naturally* -# wants to hold on to things like the size of the container, or "the -# biggest" containee so far, across a traversal of the container; but -# code to do containee comparisons can call back into Python and mutate -# the container in arbitrary ways while the C loop is in midstream. If the -# C code isn't extremely paranoid about digging things out of memory on -# each trip, and artificially boosting refcounts for the duration, anything -# from infinite loops to OS crashes can result (yes, I use Windows ). -# -# The other problem is that code designed to provoke a weakness is usually -# white-box code, and so catches only the particular vulnerabilities the -# author knew to protect against. For example, Python's list.sort() code -# went thru many iterations as one "new" vulnerability after another was -# discovered. -# -# So the dict comparison test here uses a black-box approach instead, -# generating dicts of various sizes at random, and performing random -# mutations on them at random times. This proved very effective, -# triggering at least six distinct failure modes the first 20 times I -# ran it. Indeed, at the start, the driver never got beyond 6 iterations -# before the test died. - -# The dicts are global to make it easy to mutate tham from within functions. -dict1 = {} -dict2 = {} - -# The current set of keys in dict1 and dict2. These are materialized as -# lists to make it easy to pick a dict key at random. -dict1keys = [] -dict2keys = [] - -# Global flag telling maybe_mutate() whether to *consider* mutating. -mutate = 0 - -# If global mutate is true, consider mutating a dict. May or may not -# mutate a dict even if mutate is true. If it does decide to mutate a -# dict, it picks one of {dict1, dict2} at random, and deletes a random -# entry from it; or, more rarely, adds a random element. - -def maybe_mutate(): - global mutate - if not mutate: - return - if random.random() < 0.5: - return - - if random.random() < 0.5: - target, keys = dict1, dict1keys - else: - target, keys = dict2, dict2keys - - if random.random() < 0.2: - # Insert a new key. - mutate = 0 # disable mutation until key inserted - while 1: - newkey = Horrid(random.randrange(100)) - if newkey not in target: - break - target[newkey] = Horrid(random.randrange(100)) - keys.append(newkey) - mutate = 1 - - elif keys: - # Delete a key at random. - mutate = 0 # disable mutation until key deleted - i = random.randrange(len(keys)) - key = keys[i] - del target[key] - del keys[i] - mutate = 1 - -# A horrid class that triggers random mutations of dict1 and dict2 when -# instances are compared. - -class Horrid: - def __init__(self, i): - # Comparison outcomes are determined by the value of i. - self.i = i - - # An artificial hashcode is selected at random so that we don't - # have any systematic relationship between comparison outcomes - # (based on self.i and other.i) and relative position within the - # hash vector (based on hashcode). - # XXX This is no longer effective. - ##self.hashcode = random.randrange(1000000000) - - def __hash__(self): - return 42 - return self.hashcode - - def __eq__(self, other): - maybe_mutate() # The point of the test. - return self.i == other.i - - def __ne__(self, other): - raise RuntimeError("I didn't expect some kind of Spanish inquisition!") - - __lt__ = __le__ = __gt__ = __ge__ = __ne__ - - def __repr__(self): - return "Horrid(%d)" % self.i - -# Fill dict d with numentries (Horrid(i), Horrid(j)) key-value pairs, -# where i and j are selected at random from the candidates list. -# Return d.keys() after filling. - -def fill_dict(d, candidates, numentries): - d.clear() - for i in range(numentries): - d[Horrid(random.choice(candidates))] = \ - Horrid(random.choice(candidates)) - return list(d.keys()) - -# Test one pair of randomly generated dicts, each with n entries. -# Note that dict comparison is trivial if they don't have the same number -# of entires (then the "shorter" dict is instantly considered to be the -# smaller one, without even looking at the entries). - -def test_one(n): - global mutate, dict1, dict2, dict1keys, dict2keys - - # Fill the dicts without mutating them. - mutate = 0 - dict1keys = fill_dict(dict1, range(n), n) - dict2keys = fill_dict(dict2, range(n), n) - - # Enable mutation, then compare the dicts so long as they have the - # same size. - mutate = 1 - if verbose: - print("trying w/ lengths", len(dict1), len(dict2), end=' ') - while dict1 and len(dict1) == len(dict2): - if verbose: - print(".", end=' ') - c = dict1 == dict2 - if verbose: - print() - -# Run test_one n times. At the start (before the bugs were fixed), 20 -# consecutive runs of this test each blew up on or before the sixth time -# test_one was run. So n doesn't have to be large to get an interesting -# test. -# OTOH, calling with large n is also interesting, to ensure that the fixed -# code doesn't hold on to refcounts *too* long (in which case memory would -# leak). - -def test(n): - for i in range(n): - test_one(random.randrange(1, 100)) - -# See last comment block for clues about good values for n. -test(100) - -########################################################################## -# Another segfault bug, distilled by Michael Hudson from a c.l.py post. - -class Child: - def __init__(self, parent): - self.__dict__['parent'] = parent - def __getattr__(self, attr): - self.parent.a = 1 - self.parent.b = 1 - self.parent.c = 1 - self.parent.d = 1 - self.parent.e = 1 - self.parent.f = 1 - self.parent.g = 1 - self.parent.h = 1 - self.parent.i = 1 - return getattr(self.parent, attr) - -class Parent: - def __init__(self): - self.a = Child(self) - -# Hard to say what this will print! May vary from time to time. But -# we're specifically trying to test the tp_print slot here, and this is -# the clearest way to do it. We print the result to a temp file so that -# the expected-output file doesn't need to change. - -f = open(TESTFN, "w") -print(Parent().__dict__, file=f) -f.close() -os.unlink(TESTFN) - -########################################################################## -# And another core-dumper from Michael Hudson. - -dict = {} - -# Force dict to malloc its table. -for i in range(1, 10): - dict[i] = i - -f = open(TESTFN, "w") - -class Machiavelli: - def __repr__(self): - dict.clear() - - # Michael sez: "doesn't crash without this. don't know why." - # Tim sez: "luck of the draw; crashes with or without for me." - print(file=f) - - return repr("machiavelli") - - def __hash__(self): - return 0 - -dict[Machiavelli()] = Machiavelli() - -print(str(dict), file=f) -f.close() -os.unlink(TESTFN) -del f, dict - - -########################################################################## -# And another core-dumper from Michael Hudson. - -dict = {} - -# let's force dict to malloc its table -for i in range(1, 10): - dict[i] = i - -class Machiavelli2: - def __eq__(self, other): - dict.clear() - return 1 - - def __hash__(self): - return 0 - -dict[Machiavelli2()] = Machiavelli2() - -try: - dict[Machiavelli2()] -except KeyError: - pass - -del dict - -########################################################################## -# And another core-dumper from Michael Hudson. - -dict = {} - -# let's force dict to malloc its table -for i in range(1, 10): - dict[i] = i - -class Machiavelli3: - def __init__(self, id): - self.id = id - - def __eq__(self, other): - if self.id == other.id: - dict.clear() - return 1 - else: - return 0 - - def __repr__(self): - return "%s(%s)"%(self.__class__.__name__, self.id) - - def __hash__(self): - return 0 - -dict[Machiavelli3(1)] = Machiavelli3(0) -dict[Machiavelli3(2)] = Machiavelli3(0) - -f = open(TESTFN, "w") -try: - try: - print(dict[Machiavelli3(2)], file=f) - except KeyError: - pass -finally: - f.close() - os.unlink(TESTFN) - -del dict -del dict1, dict2, dict1keys, dict2keys diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,10 +10,13 @@ Core and Builtins ----------------- +- Issue #14205: dict lookup raises a RuntimeError if the dict is modified + during a lookup. + Library ------- -- Issue #14168: Check for presence of Element._attrs in minidom before +- Issue #14168: Check for presence of Element._attrs in minidom before accessing it. - Issue #12328: Fix multiprocessing's use of overlapped I/O on Windows. diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -347,12 +347,9 @@ return ep; } else { - /* The compare did major nasty stuff to the - * dict: start over. - * XXX A clever adversary could prevent this - * XXX from terminating. - */ - return lookdict(mp, key, hash); + PyErr_SetString(PyExc_RuntimeError, + "dictionary changed size during lookup"); + return NULL; } } freeslot = NULL; @@ -379,12 +376,9 @@ return ep; } else { - /* The compare did major nasty stuff to the - * dict: start over. - * XXX A clever adversary could prevent this - * XXX from terminating. - */ - return lookdict(mp, key, hash); + PyErr_SetString(PyExc_RuntimeError, + "dictionary changed size during lookup"); + return NULL; } } else if (ep->me_key == dummy && freeslot == NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 02:05:21 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 06 Mar 2012 02:05:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_test=5Fpty=3A_fix_ResourceW?= =?utf8?q?arning_warnings?= Message-ID: http://hg.python.org/cpython/rev/815f7c25740b changeset: 75446:815f7c25740b user: Victor Stinner date: Tue Mar 06 02:04:58 2012 +0100 summary: test_pty: fix ResourceWarning warnings files: Lib/test/test_pty.py | 19 ++++++++++++++----- 1 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -205,6 +205,7 @@ self.orig_stdout_fileno = pty.STDOUT_FILENO self.orig_pty_select = pty.select self.fds = [] # A list of file descriptors to close. + self.files = [] self.select_rfds_lengths = [] self.select_rfds_results = [] @@ -212,10 +213,15 @@ pty.STDIN_FILENO = self.orig_stdin_fileno pty.STDOUT_FILENO = self.orig_stdout_fileno pty.select = self.orig_pty_select + for file in self.files: + try: + file.close() + except OSError: + pass for fd in self.fds: try: os.close(fd) - except: + except OSError: pass def _pipe(self): @@ -223,6 +229,11 @@ self.fds.extend(pipe_fds) return pipe_fds + def _socketpair(self): + socketpair = socket.socketpair() + self.files.extend(socketpair) + return socketpair + def _mock_select(self, rfds, wfds, xfds): # This will raise IndexError when no more expected calls exist. self.assertEqual(self.select_rfds_lengths.pop(0), len(rfds)) @@ -234,9 +245,8 @@ pty.STDOUT_FILENO = mock_stdout_fd mock_stdin_fd, write_to_stdin_fd = self._pipe() pty.STDIN_FILENO = mock_stdin_fd - socketpair = socket.socketpair() + socketpair = self._socketpair() masters = [s.fileno() for s in socketpair] - self.fds.extend(masters) # Feed data. Smaller than PIPEBUF. These writes will not block. os.write(masters[1], b'from master') @@ -263,9 +273,8 @@ pty.STDOUT_FILENO = mock_stdout_fd mock_stdin_fd, write_to_stdin_fd = self._pipe() pty.STDIN_FILENO = mock_stdin_fd - socketpair = socket.socketpair() + socketpair = self._socketpair() masters = [s.fileno() for s in socketpair] - self.fds.extend(masters) os.close(masters[1]) socketpair[1].close() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 02:06:29 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 06 Mar 2012 02:06:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_an_unused_variable?= Message-ID: http://hg.python.org/cpython/rev/9aa51342cb73 changeset: 75447:9aa51342cb73 user: Victor Stinner date: Tue Mar 06 02:06:01 2012 +0100 summary: Remove an unused variable files: Objects/unicodeobject.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3935,7 +3935,6 @@ int PyUnicode_WriteChar(PyObject *unicode, Py_ssize_t index, Py_UCS4 ch) { - Py_UCS4 maxchar; if (!PyUnicode_Check(unicode) || !PyUnicode_IS_COMPACT(unicode)) { PyErr_BadArgument(); return -1; -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Mar 6 05:35:16 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 06 Mar 2012 05:35:16 +0100 Subject: [Python-checkins] Daily reference leaks (9aa51342cb73): sum=0 Message-ID: results for 9aa51342cb73 on branch "default" -------------------------------------------- test_multiprocessing leaked [0, 118, -118] references, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog_mUtg6', '-x'] From python-checkins at python.org Tue Mar 6 07:59:20 2012 From: python-checkins at python.org (larry.hastings) Date: Tue, 06 Mar 2012 07:59:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_a_comment=3A_PySequence?= =?utf8?q?=5FFast=28=29_creates_a_list=2C_not_a_tuple=2E?= Message-ID: http://hg.python.org/cpython/rev/d8f68195210e changeset: 75448:d8f68195210e user: Larry Hastings date: Mon Mar 05 22:59:13 2012 -0800 summary: Fix a comment: PySequence_Fast() creates a list, not a tuple. files: Include/abstract.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Include/abstract.h b/Include/abstract.h --- a/Include/abstract.h +++ b/Include/abstract.h @@ -1026,7 +1026,7 @@ PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); /* - Returns the sequence, o, as a tuple, unless it's already a + Returns the sequence, o, as a list, unless it's already a tuple or list. Use PySequence_Fast_GET_ITEM to access the members of this list, and PySequence_Fast_GET_SIZE to get its length. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 08:42:23 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 06 Mar 2012 08:42:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314200=3A_Add_bench?= =?utf8?q?mark_results_to_text_flow=2E?= Message-ID: http://hg.python.org/cpython/rev/d916145b20c3 changeset: 75449:d916145b20c3 user: Martin v. L?wis date: Tue Mar 06 08:42:17 2012 +0100 summary: Issue #14200: Add benchmark results to text flow. files: Doc/whatsnew/3.3.rst | 23 ++++++++++------------- 1 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -167,19 +167,16 @@ * non-BMP strings (``U+10000-U+10FFFF``) use 4 bytes per codepoint. -The net effect is that for most applications, memory usage of string storage -should decrease significantly - especially compared to former wide unicode -builds - as, in many cases, strings will be pure ASCII even in international -contexts (because many strings store non-human language data, such as XML -fragments, HTTP headers, JSON-encoded data, etc.). We also hope that it -will, for the same reasons, increase CPU cache efficiency on non-trivial -applications. - -.. The memory usage of Python 3.3 is two to three times smaller than Python 3.2, - and a little bit better than Python 2.7, on a `Django benchmark - `_. - XXX The result should be moved in the PEP and a link to the PEP should - be added here. +The net effect is that for most applications, memory usage of string +storage should decrease significantly - especially compared to former +wide unicode builds - as, in many cases, strings will be pure ASCII +even in international contexts (because many strings store non-human +language data, such as XML fragments, HTTP headers, JSON-encoded data, +etc.). We also hope that it will, for the same reasons, increase CPU +cache efficiency on non-trivial applications. The memory usage of +Python 3.3 is two to three times smaller than Python 3.2, and a little +bit better than Python 2.7, on a Django benchmark (see the PEP for +details). PEP 3151: Reworking the OS and IO exception hierarchy -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 11:49:26 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 06 Mar 2012 11:49:26 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Minor_changes_made_by_Carl_Mey?= =?utf8?b?ZXIu?= Message-ID: http://hg.python.org/peps/rev/860dc43def41 changeset: 4119:860dc43def41 user: Vinay Sajip date: Tue Mar 06 10:49:22 2012 +0000 summary: Minor changes made by Carl Meyer. files: pep-0405.txt | 264 +++++++++++--------------------------- 1 files changed, 77 insertions(+), 187 deletions(-) diff --git a/pep-0405.txt b/pep-0405.txt --- a/pep-0405.txt +++ b/pep-0405.txt @@ -42,9 +42,9 @@ Python's ``site`` module and manually symlink/copy an ever-changing set of standard-library modules into the virtual environment in order to perform a delicate boot-strapping dance at every startup. -(Virtualenv copies the binary because symlinking it does not provide -isolation, as Python dereferences a symlinked executable before -searching for ``sys.prefix``.) +(Virtualenv must copy the binary in order to provide isolation, as +Python dereferences a symlinked executable before searching for +``sys.prefix``.) The ``PYTHONHOME`` environment variable, Python's only existing built-in solution for virtual environments, requires @@ -85,22 +85,22 @@ create this virtual environment. In this case, prefix-finding continues as normal using the value of -the ``home`` key as the effective Python binary location, which -results in ``sys.prefix`` being set to the system installation prefix, -while ``sys.site_prefix`` is set to the directory containing +the ``home`` key as the effective Python binary location, which finds +the prefix of the base installation. ``sys.base_prefix`` is set to +this value, while ``sys.prefix`` is set to the directory containing ``pyvenv.cfg``. (If ``pyvenv.cfg`` is not found or does not contain the ``home`` key, -prefix-finding continues normally, and ``sys.site_prefix`` will be -equal to ``sys.prefix``.) +prefix-finding continues normally, and ``sys.prefix`` will be equal to +``sys.base_prefix``.) The ``site`` and ``sysconfig`` standard-library modules are modified -such that site-package directories ("purelib" and "platlib", in -``sysconfig`` terms) are found relative to ``sys.site_prefix``, while -other directories (the standard library, include files) are still -found relative to ``sys.prefix``. +such that the standard library and header files are are found relative +to ``sys.base_prefix``, while site-package directories ("purelib" and +"platlib", in ``sysconfig`` terms) are still found relative to +``sys.prefix``. -(Also, ``sys.site_exec_prefix`` is added, and handled similarly with +(Also, ``sys.base_exec_prefix`` is added, and handled similarly with regard to ``sys.exec_prefix``.) Thus, a Python virtual environment in its simplest form would consist @@ -166,7 +166,13 @@ virtualenv will be created, according to the given options, at each provided path. -The ``venv`` module also adds a ``pysetup3`` script into each venv. +The ``venv`` module also provides "shell activation scripts" for POSIX +and Windows systems which simply add the virtual environment's ``bin`` +(or ``Scripts``) directory to the front of the user's shell PATH. +This is not strictly necessary for use of a virtual environment (as an +explicit path to the venv's python binary or scripts can just as well +be used), but it is convenient. + In order to allow ``pysetup`` and other Python package managers to install packages into the virtual environment the same way they would install into a normal Python installation, and avoid special-casing @@ -179,6 +185,7 @@ bin/python3 bin/python bin/pysetup3 + include/ lib/python3.3/site-packages/ While on a Windows system:: @@ -188,12 +195,13 @@ Scripts/python3.dll Scripts/pysetup3.exe Scripts/pysetup3-script.py - ... other DLLs and pyds... + ... other DLLs and pyds... + Include/ Lib/site-packages/ Third-party packages installed into the virtual environment will have their Python modules placed in the ``site-packages`` directory, and -their executables placed in ``bin/`` or ``Scripts\``. +their executables placed in ``bin/`` or ``Scripts``. .. note:: @@ -266,22 +274,18 @@ target directory instead of raising an exception. Defaults to ``False``. -* ``use_symlinks`` - A Boolean value indicating whether to attempt to +* ``symlinks`` - A Boolean value indicating whether to attempt to symlink the Python binary (and any necessary DLLs or other binaries, e.g. ``pythonw.exe``), rather than copying. Defaults to ``False``. -The returned env-builder is an object with a ``create`` method, which -takes as required argument the path (absolute or relative to the -current directory) of the target directory which is to contain the -virtual environment. The ``create`` method either creates the -environment in the specified directory, or raises an appropriate -exception. +The instantiated env-builder has a ``create`` method, which takes as +required argument the path (absolute or relative to the current +directory) of the target directory which is to contain the virtual +environment. The ``create`` method either creates the environment in +the specified directory, or raises an appropriate exception. -Creators of third-party virtual environment tools are free to use the -provided ``EnvBuilder`` class as a base class. - -The ``venv`` module also provides a module-level function as a -convenience:: +The ``venv`` module also provides a module-level ``create`` function +as a convenience:: def create(env_dir, system_site_packages=False, clear=False, use_symlinks=False): @@ -291,6 +295,9 @@ use_symlinks=use_symlinks) builder.create(env_dir) +Creators of third-party virtual environment tools are free to use the +provided ``EnvBuilder`` class as a base class. + The ``create`` method of the ``EnvBuilder`` class illustrates the hooks available for customization:: @@ -322,18 +329,18 @@ under Windows, DLLs) in the environment. * ``post_setup`` - A (no-op by default) hook method which can be - overridden in third party implementations to pre-install packages or + overridden in third party subclasses to pre-install packages or install scripts in the virtual environment. In addition, ``EnvBuilder`` provides a utility method that can be called from ``post_setup`` in subclasses to assist in installing -scripts into the virtual environment. The method ``install_scripts`` -accepts as arguments the ``context`` object (see above) and a -bytestring. The bytestring should be a base64-encoded zip file -containing directories "common", "posix", "nt", each containing -scripts destined for the bin directory in the environment. The -contents of "common" and the directory corresponding to ``os.name`` -are copied after doing some text replacement of placeholders: +custom scripts into the virtual environment. The method +``install_scripts`` accepts as arguments the ``context`` object (see +above) and a path to a directory. The directory should contain +subdirectories "common", "posix", "nt", each containing scripts +destined for the bin directory in the environment. The contents of +"common" and the directory corresponding to ``os.name`` are copied +after doing some text replacement of placeholders: * ``__VENV_DIR__`` is replaced with absolute path of the environment directory. @@ -349,27 +356,10 @@ The ``DistributeEnvBuilder`` subclass in the reference implementation illustrates how the customization hook can be used in practice to -pre-install Distribute and shell activation scripts into the virtual -environment. It's not envisaged that ``DistributeEnvBuilder`` will be -actually added to Python core, but it makes the reference -implementation more immediately useful for testing and exploratory -purposes. - -The "shell activation scripts" provided by ``DistributeEnvBuilder`` -simply add the virtual environment's ``bin/`` (or ``Scripts\``) -directory to the front of the user's shell PATH. This is not strictly -necessary for use of a virtual environment (as an explicit path to the -venv's python binary or scripts can just as well be used), but it is -convenient. - -This PEP does not propose that the ``venv`` module in core Python will -add such activation scripts by default, as they are shell-specific. -Adding activation scripts for the wide variety of possible shells is -an added maintenance burden, and is left to third-party extension -tools. - -No doubt the process of PEP review will show up any customization -requirements which have not yet been considered. +pre-install Distribute into the virtual environment. It's not +envisaged that ``DistributeEnvBuilder`` will be actually added to +Python core, but it makes the reference implementation more +immediately useful for testing and exploratory purposes. Backwards Compatibility @@ -405,33 +395,40 @@ __ http://docs.python.org/dev/library/sys.html#sys.prefix -This PEP currently proposes to leave ``sys.prefix`` pointing to the -base system installation (which is where the standard library and -header files are found), and introduce a new value in ``sys`` -(``sys.site_prefix``) to point to the prefix for ``site-packages``. -This maintains the documented semantics of ``sys.prefix``, but risks -breaking isolation if third-party code uses ``sys.prefix`` rather than -``sys.site_prefix`` or the appropriate ``site`` API to find +Maintaining this documented definition would mean leaving +``sys.prefix`` pointing to the base system installation (which is +where the standard library and header files are found), and +introducing a new value in ``sys`` (something like +``sys.site_prefix``) to point to the prefix for ``site-packages``. +This would maintain the documented semantics of ``sys.prefix``, but +risk breaking isolation if third-party code uses ``sys.prefix`` rather +than ``sys.site_prefix`` or the appropriate ``site`` API to find site-packages directories. The most notable case is probably `setuptools`_ and its fork -`distribute`_, which mostly use ``distutils``/``sysconfig`` APIs, but -do use ``sys.prefix`` directly to build up a list of site directories -for pre-flight checking where ``pth`` files can usefully be placed. -It would be trivial to modify these tools (currently only -`distribute`_ is Python 3 compatible) to check ``sys.site_prefix`` and -fall back to ``sys.prefix`` if it doesn't exist (for earlier versions -of Python). If Distribute is modified in this way and released before -Python 3.3 is released with the ``venv`` module, there would be no -likely reason for an older version of Distribute to ever be installed -in a virtual environment. +`distribute`_, which mostly use ``distutils``and ``sysconfig`` APIs, +but do use ``sys.prefix`` directly to build up a list of site +directories for pre-flight checking where ``pth`` files can usefully +be placed. -In terms of other third-party usage, a `Google Code Search`_ turns up -what appears to be a roughly even mix of usage between packages using -``sys.prefix`` to build up a site-packages path and packages using it -to e.g. eliminate the standard-library from code-execution tracing. -Either choice that's made here will require one or the other of these -uses to be updated. +Otherwise, a `Google Code Search`_ turns up what appears to be a +roughly even mix of usage between packages using ``sys.prefix`` to +build up a site-packages path and packages using it to e.g. eliminate +the standard-library from code-execution tracing. + +Although it requires modifying the documented definition of +``sys.prefix``, this PEP prefers to have ``sys.prefix`` point to the +virtual environment (where ``site-packages`` is found), and introduce +``sys.base_prefix`` to point to the standard library and Python header +files. Rationale for this choice: + +* It is preferable to err on the side of greater isolation of the + virtual environment. + +* Virtualenv already modifies ``sys.prefix`` to point at the virtual + environment, and in practice this has not been a problem. + +* No modification is required to setuptools/distribute. .. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools .. _distribute: http://packages.python.org/distribute/ @@ -441,72 +438,6 @@ Open Questions ============== -Naming of the new ``sys`` prefix attributes -------------------------------------------- - -The name ``sys.site_prefix`` was chosen with the following -considerations in mind: - -* Inasmuch as "site" has a meaning in Python, it means a combination - of Python version, standard library, and specific set of - site-packages. This is, fundamentally, what a venv is (although it - shares the standard library with its "base" site). - -* It is the Python ``site`` module which implements adding - site-packages directories to ``sys.path``, so ``sys.site_prefix`` is - a prefix used (and set) primarily by the ``site`` module. - -A concern has been raised that the term ``site`` in Python is already -overloaded and of unclear meaning, and this usage will increase the -overload. - -One proposed alternative is ``sys.venv_prefix``, which has the -advantage of being clearly related to the venv implementation. The -downside of this proposal is that it implies the attribute is only -useful/relevant when in a venv and should be absent or ``None`` when -not in a venv. This imposes an unnecessary extra burden on code using -the attribute: ``sys.venv_prefix if sys.venv_prefix else sys.prefix``. -The prefix attributes are more usable and general if they are always -present and set, and split by meaning (stdlib vs site-packages, -roughly), rather than specifically tied to venv. Also, third-party -code should be encouraged to not know or care whether it is running in -a virtual environment or not; this option seems to work against that -goal. - -Another option would be ``sys.local_prefix``, which has both the -advantage and disadvantage, depending on perspective, that it -introduces the new term "local" rather than drawing on existing -associations with the term "site". - - -Why not modify sys.prefix? --------------------------- - -As discussed above under `Backwards Compatibility`_, this PEP proposes -to add ``sys.site_prefix`` as "the prefix relative to which -site-package directories are found". This maintains compatibility -with the documented meaning of ``sys.prefix`` (as the location -relative to which the standard library can be found), but means that -code assuming that site-packages directories are found relative to -``sys.prefix`` will not respect the virtual environment correctly. - -Since it is unable to modify ``distutils``/``sysconfig``, -`virtualenv`_ is forced to instead re-point ``sys.prefix`` at the -virtual environment. - -An argument could be made that this PEP should follow virtualenv's -lead here (and introduce something like ``sys.base_prefix`` to point -to the standard library and header files), since virtualenv already -does this and it doesn't appear to have caused major problems with -existing code. - -Another argument in favor of this is that it would be preferable to -err on the side of greater, rather than lesser, isolation. Changing -``sys.prefix`` to point to the virtual environment and introducing a -new ``sys.base_prefix`` attribute would err on the side of greater -isolation in the face of existing code's use of ``sys.prefix``. - - What about include files? ------------------------- @@ -537,21 +468,6 @@ really because there's no supporting concept in ``Python/sysconfig``. -Interface with packaging tools ------------------------------- - -Some work will be needed in packaging tools (Python 3.3 packaging, -Distribute) to support implementation of this PEP. For example: - -* How Distribute and packaging use ``sys.prefix`` and/or - ``sys.site_prefix``. Clearly, in practice we'll need to use - Distribute for a while, until packages have migrated over to usage - of setup.cfg. - -* How packaging and Distribute set up shebang lines in scripts which they - install in virtual environments. - - Testability and Source Build Issues ----------------------------------- @@ -587,37 +503,6 @@ .. _Virtualenv uses: https://github.com/pypa/virtualenv/issues/168 -Activation and Utility Scripts ------------------------------- - -Virtualenv provides shell "activation" scripts as a user convenience, -to put the virtual environment's Python binary first on the shell -PATH. This is a maintenance burden, as separate activation scripts -need to be provided and maintained for every supported shell. For -this reason, this PEP proposes to leave such scripts to be provided by -third-party extensions; virtual environments created by the core -functionality would be used by directly invoking the environment's -Python binary or scripts. - -If we are going to rely on external code to provide these -conveniences, we need to check with existing third-party projects in -this space (virtualenv, zc.buildout) and ensure that the proposed API -meets their needs. - -(Virtualenv would be fine with the proposed API; it would become a -relatively thin wrapper with a subclass of the env builder that adds -shell activation and automatic installation of ``pip`` inside the -virtual environment). - - -Provide a mode that is isolated only from user site packages? -------------------------------------------------------------- - -Is there sufficient rationale for providing a mode that isolates the -venv from :pep:`370` user site packages, but not from the system-level -site-packages? - - Other Python implementations? ----------------------------- -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 6 11:51:43 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 06 Mar 2012 11:51:43 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Added_to_Post-History=2E?= Message-ID: http://hg.python.org/peps/rev/d43aefa4dc7f changeset: 4120:d43aefa4dc7f user: Vinay Sajip date: Tue Mar 06 10:51:38 2012 +0000 summary: Added to Post-History. files: pep-0405.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0405.txt b/pep-0405.txt --- a/pep-0405.txt +++ b/pep-0405.txt @@ -8,7 +8,7 @@ Content-Type: text/x-rst Created: 13-Jun-2011 Python-Version: 3.3 -Post-History: 24-Oct-2011, 28-Oct-2011 +Post-History: 24-Oct-2011, 28-Oct-2011, 06-Mar-2012 Abstract -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 6 12:50:27 2012 From: python-checkins at python.org (nick.coghlan) Date: Tue, 06 Mar 2012 12:50:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Add_PEP_414_to_What=27s_New?= =?utf8?q?=2C_consolidate_memoryview_entries?= Message-ID: http://hg.python.org/cpython/rev/e2f6730c5017 changeset: 75450:e2f6730c5017 user: Nick Coghlan date: Tue Mar 06 21:50:13 2012 +1000 summary: Add PEP 414 to What's New, consolidate memoryview entries files: Doc/whatsnew/3.3.rst | 25 ++++++++++++++++++++----- 1 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -49,6 +49,8 @@ This article explains the new features in Python 3.3, compared to 3.2. +.. pep-3118-update: + PEP 3118: New memoryview implementation and buffer protocol documentation ========================================================================= @@ -85,7 +87,9 @@ * Multi-dimensional comparisons are supported for any array type. * All array types are hashable if the exporting object is hashable - and the view is read-only. + and the view is read-only. (Contributed by Antoine Pitrou in + :issue:`13411`) + * Arbitrary slicing of any 1-D arrays type is supported. For example, it is now possible to reverse a memoryview in O(1) by using a negative step. @@ -327,6 +331,21 @@ KeyError('x',) +PEP 414: Explicit Unicode literals +====================================== + +:pep:`414` - Explicit Unicode literals + PEP written by Armin Ronacher. + +To ease the transition from Python 2 for Unicode aware Python applications +that make heavy use of Unicode literals, Python 3.3 once again supports the +"``u``" prefix for string literals. This prefix has no semantic significance +in Python 3, it is provided solely to reduce the number of purely mechanical +changes in migrating to Python 3, making it easier for developers to focus on +the more significant semantic changes (such as the stricter default +separation of binary and text data). + + PEP 3155: Qualified name for classes and functions ================================================== @@ -408,10 +427,6 @@ (:issue:`12170`) -* Memoryview objects are now hashable when the underlying object is hashable. - - (Contributed by Antoine Pitrou in :issue:`13411`) - New and Improved Modules ======================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 13:31:24 2012 From: python-checkins at python.org (nick.coghlan) Date: Tue, 06 Mar 2012 13:31:24 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Add_some_simple_examples_to?= =?utf8?q?_the_PEP_380_section_of_What=27s_New?= Message-ID: http://hg.python.org/cpython/rev/538cbae3ec2d changeset: 75451:538cbae3ec2d user: Nick Coghlan date: Tue Mar 06 22:31:12 2012 +1000 summary: Add some simple examples to the PEP 380 section of What's New files: Doc/whatsnew/3.3.rst | 47 ++++++++++++++++++++++++++++++++ 1 files changed, 47 insertions(+), 0 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -262,9 +262,56 @@ containing 'yield' to be factored out and placed in another generator. Additionally, the subgenerator is allowed to return with a value, and the value is made available to the delegating generator. + While designed primarily for use in delegating to a subgenerator, the ``yield from`` expression actually allows delegation to arbitrary subiterators. +For simple iterators, ``yield from iterable`` is essentially just a shortened +form of ``for item in iterable: yield item``:: + + >>> def g(x): + ... yield from range(x, 0, -1) + ... yield from range(x) + ... + >>> list(g(5)) + [5, 4, 3, 2, 1, 0, 1, 2, 3, 4] + +However, unlike an ordinary loop, ``yield from`` allows subgenerators to +receive sent and thrown values directly from the calling scope, and +return a final value to the outer generator:: + + >>> def accumulate(start=0): + ... tally = start + ... while 1: + ... next = yield + ... if next is None: + ... return tally + ... tally += next + ... + >>> def gather_tallies(tallies, start=0): + ... while 1: + ... tally = yield from accumulate() + ... tallies.append(tally) + ... + >>> tallies = [] + >>> acc = gather_tallies(tallies) + >>> next(acc) # Ensure the accumulator is ready to accept values + >>> for i in range(10): + ... acc.send(i) + ... + >>> acc.send(None) # Finish the first tally + >>> for i in range(5): + ... acc.send(i) + ... + >>> acc.send(None) # Finish the second tally + >>> tallies + [45, 10] + +The main principle driving this change is to allow even generators that are +designed to be used with the ``send`` and ``throw`` methods to be split into +multiple subgenerators as easily as a single large function can be split into +multiple subfunctions. + (Implementation by Greg Ewing, integrated into 3.3 by Renaud Blanch, Ryan Kelly and Nick Coghlan, documentation by Zbigniew J?drzejewski-Szmek and Nick Coghlan) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 13:50:04 2012 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 06 Mar 2012 13:50:04 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Reap_processes_at_test_end_?= =?utf8?q?to_avoid_false_positives_in_reference_leak_detection=2E?= Message-ID: http://hg.python.org/cpython/rev/7ee542192525 changeset: 75452:7ee542192525 parent: 75449:d916145b20c3 user: Antoine Pitrou date: Tue Mar 06 13:42:35 2012 +0100 summary: Reap processes at test end to avoid false positives in reference leak detection. files: Lib/test/test_multiprocessing.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -2508,6 +2508,7 @@ w.close() readers.append(r) procs.append(p) + self.addCleanup(p.join) while readers: for r in wait(readers): @@ -2549,6 +2550,7 @@ p.daemon = True p.start() procs.append(p) + self.addCleanup(p.join) for i in range(4): r, _ = l.accept() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 13:50:05 2012 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 06 Mar 2012 13:50:05 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_a_couple_of_local_im?= =?utf8?q?ports=2E?= Message-ID: http://hg.python.org/cpython/rev/7069d0a55470 changeset: 75453:7069d0a55470 user: Antoine Pitrou date: Tue Mar 06 13:43:24 2012 +0100 summary: Remove a couple of local imports. files: Lib/test/test_multiprocessing.py | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -2494,15 +2494,14 @@ w.close() def test_wait(self, slow=False): - from multiprocessing import Pipe, Process from multiprocessing.connection import wait readers = [] procs = [] messages = [] for i in range(4): - r, w = Pipe(duplex=False) - p = Process(target=self._child_test_wait, args=(w, slow)) + r, w = multiprocessing.Pipe(duplex=False) + p = multiprocessing.Process(target=self._child_test_wait, args=(w, slow)) p.daemon = True p.start() w.close() @@ -2535,7 +2534,6 @@ s.close() def test_wait_socket(self, slow=False): - from multiprocessing import Process from multiprocessing.connection import wait l = socket.socket() l.bind(('', 0)) @@ -2546,7 +2544,8 @@ dic = {} for i in range(4): - p = Process(target=self._child_test_wait_socket, args=(addr, slow)) + p = multiprocessing.Process(target=self._child_test_wait_socket, + args=(addr, slow)) p.daemon = True p.start() procs.append(p) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 13:50:05 2012 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 06 Mar 2012 13:50:05 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merge?= Message-ID: http://hg.python.org/cpython/rev/8639ec6f3d06 changeset: 75454:8639ec6f3d06 parent: 75453:7069d0a55470 parent: 75451:538cbae3ec2d user: Antoine Pitrou date: Tue Mar 06 13:45:57 2012 +0100 summary: Merge files: Doc/whatsnew/3.3.rst | 72 +++++++++++++++++++++++++++++-- 1 files changed, 67 insertions(+), 5 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -49,6 +49,8 @@ This article explains the new features in Python 3.3, compared to 3.2. +.. pep-3118-update: + PEP 3118: New memoryview implementation and buffer protocol documentation ========================================================================= @@ -85,7 +87,9 @@ * Multi-dimensional comparisons are supported for any array type. * All array types are hashable if the exporting object is hashable - and the view is read-only. + and the view is read-only. (Contributed by Antoine Pitrou in + :issue:`13411`) + * Arbitrary slicing of any 1-D arrays type is supported. For example, it is now possible to reverse a memoryview in O(1) by using a negative step. @@ -258,9 +262,56 @@ containing 'yield' to be factored out and placed in another generator. Additionally, the subgenerator is allowed to return with a value, and the value is made available to the delegating generator. + While designed primarily for use in delegating to a subgenerator, the ``yield from`` expression actually allows delegation to arbitrary subiterators. +For simple iterators, ``yield from iterable`` is essentially just a shortened +form of ``for item in iterable: yield item``:: + + >>> def g(x): + ... yield from range(x, 0, -1) + ... yield from range(x) + ... + >>> list(g(5)) + [5, 4, 3, 2, 1, 0, 1, 2, 3, 4] + +However, unlike an ordinary loop, ``yield from`` allows subgenerators to +receive sent and thrown values directly from the calling scope, and +return a final value to the outer generator:: + + >>> def accumulate(start=0): + ... tally = start + ... while 1: + ... next = yield + ... if next is None: + ... return tally + ... tally += next + ... + >>> def gather_tallies(tallies, start=0): + ... while 1: + ... tally = yield from accumulate() + ... tallies.append(tally) + ... + >>> tallies = [] + >>> acc = gather_tallies(tallies) + >>> next(acc) # Ensure the accumulator is ready to accept values + >>> for i in range(10): + ... acc.send(i) + ... + >>> acc.send(None) # Finish the first tally + >>> for i in range(5): + ... acc.send(i) + ... + >>> acc.send(None) # Finish the second tally + >>> tallies + [45, 10] + +The main principle driving this change is to allow even generators that are +designed to be used with the ``send`` and ``throw`` methods to be split into +multiple subgenerators as easily as a single large function can be split into +multiple subfunctions. + (Implementation by Greg Ewing, integrated into 3.3 by Renaud Blanch, Ryan Kelly and Nick Coghlan, documentation by Zbigniew J?drzejewski-Szmek and Nick Coghlan) @@ -327,6 +378,21 @@ KeyError('x',) +PEP 414: Explicit Unicode literals +====================================== + +:pep:`414` - Explicit Unicode literals + PEP written by Armin Ronacher. + +To ease the transition from Python 2 for Unicode aware Python applications +that make heavy use of Unicode literals, Python 3.3 once again supports the +"``u``" prefix for string literals. This prefix has no semantic significance +in Python 3, it is provided solely to reduce the number of purely mechanical +changes in migrating to Python 3, making it easier for developers to focus on +the more significant semantic changes (such as the stricter default +separation of binary and text data). + + PEP 3155: Qualified name for classes and functions ================================================== @@ -408,10 +474,6 @@ (:issue:`12170`) -* Memoryview objects are now hashable when the underlying object is hashable. - - (Contributed by Antoine Pitrou in :issue:`13411`) - New and Improved Modules ======================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 14:55:44 2012 From: python-checkins at python.org (stefan.krah) Date: Tue, 06 Mar 2012 14:55:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314181=3A_Improve_c?= =?utf8?q?larity_in_the_documentation_for_the_multi-purpose?= Message-ID: http://hg.python.org/cpython/rev/da2aaced21bd changeset: 75455:da2aaced21bd user: Stefan Krah date: Tue Mar 06 14:55:06 2012 +0100 summary: Issue #14181: Improve clarity in the documentation for the multi-purpose Py_buffer.obj field. files: Doc/c-api/buffer.rst | 20 +++++++++--- Doc/c-api/typeobj.rst | 48 ++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -81,17 +81,23 @@ around a buffer is needed, a :ref:`memoryview ` object can be created. +For short instructions how to write an exporting object, see +:ref:`Buffer Object Structures `. For obtaining +a buffer, see :c:func:`PyObject_GetBuffer`. .. c:type:: Py_buffer .. c:member:: void \*obj - A new reference to the exporting object or *NULL*. The reference is owned - by the consumer and automatically decremented and set to *NULL* by - :c:func:`PyBuffer_Release`. + A new reference to the exporting object. The reference is owned by + the consumer and automatically decremented and set to *NULL* by + :c:func:`PyBuffer_Release`. The field is the equivalent of the return + value of any standard C-API function. - For temporary buffers that are wrapped by :c:func:`PyMemoryView_FromBuffer` - this field must be *NULL*. + As a special case, for *temporary* buffers that are wrapped by + :c:func:`PyMemoryView_FromBuffer` or :c:func:`PyBuffer_FillInfo` + this field is *NULL*. In general, exporting objects MUST NOT + use this scheme. .. c:member:: void \*buf @@ -423,7 +429,9 @@ return -1. On success, fill in *view*, set :c:member:`view->obj` to a new reference - to *exporter* and return 0. + to *exporter* and return 0. In the case of chained buffer providers + that redirect requests to a single object, :c:member:`view->obj` MAY + refer to this object instead of *exporter* (See :ref:`Buffer Object Structures `). Successful calls to :c:func:`PyObject_GetBuffer` must be paired with calls to :c:func:`PyBuffer_Release`, similar to :c:func:`malloc` and :c:func:`free`. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1213,18 +1213,29 @@ int (PyObject *exporter, Py_buffer *view, int flags); Handle a request to *exporter* to fill in *view* as specified by *flags*. - A standard implementation of this function will take these steps: + Except for point (3), an implementation of this function MUST take these + steps: - - Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, - set :c:data:`view->obj` to *NULL* and return -1. + (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, + set :c:data:`view->obj` to *NULL* and return -1. - - Fill in the requested fields. + (2) Fill in the requested fields. - - Increment an internal counter for the number of exports. + (3) Increment an internal counter for the number of exports. - - Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. + (4) Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. - - Return 0. + (5) Return 0. + + If *exporter* is part of a chain or tree of buffer providers, two main + schemes can be used: + + * Re-export: Each member of the tree acts as the exporting object and + sets :c:data:`view->obj` to a new reference to itself. + + * Redirect: The buffer request is redirected to the root object of the + tree. Here, :c:data:`view->obj` will be a new reference to the root + object. The individual fields of *view* are described in section :ref:`Buffer structure `, the rules how an exporter @@ -1233,8 +1244,9 @@ All memory pointed to in the :c:type:`Py_buffer` structure belongs to the exporter and must remain valid until there are no consumers left. - :c:member:`~Py_buffer.shape`, :c:member:`~Py_buffer.strides`, - :c:member:`~Py_buffer.suboffsets` and :c:member:`~Py_buffer.internal` + :c:member:`~Py_buffer.format`, :c:member:`~Py_buffer.shape`, + :c:member:`~Py_buffer.strides`, :c:member:`~Py_buffer.suboffsets` + and :c:member:`~Py_buffer.internal` are read-only for the consumer. :c:func:`PyBuffer_FillInfo` provides an easy way of exposing a simple @@ -1250,21 +1262,23 @@ void (PyObject *exporter, Py_buffer *view); Handle a request to release the resources of the buffer. If no resources - need to be released, this field may be *NULL*. A standard implementation - of this function will take these steps: + need to be released, :c:member:`PyBufferProcs.bf_releasebuffer` may be + *NULL*. Otherwise, a standard implementation of this function will take + these optional steps: - - Decrement an internal counter for the number of exports. + (1) Decrement an internal counter for the number of exports. - - If the counter is 0, free all memory associated with *view*. + (2) If the counter is 0, free all memory associated with *view*. The exporter MUST use the :c:member:`~Py_buffer.internal` field to keep - track of buffer-specific resources (if present). This field is guaranteed - to remain constant, while a consumer MAY pass a copy of the original buffer - as the *view* argument. + track of buffer-specific resources. This field is guaranteed to remain + constant, while a consumer MAY pass a copy of the original buffer as the + *view* argument. This function MUST NOT decrement :c:data:`view->obj`, since that is - done automatically in :c:func:`PyBuffer_Release`. + done automatically in :c:func:`PyBuffer_Release` (this scheme is + useful for breaking reference cycles). :c:func:`PyBuffer_Release` is the interface for the consumer that -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 15:28:15 2012 From: python-checkins at python.org (stefan.krah) Date: Tue, 06 Mar 2012 15:28:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Whitespace=2E?= Message-ID: http://hg.python.org/cpython/rev/21d5e038120e changeset: 75456:21d5e038120e user: Stefan Krah date: Tue Mar 06 15:27:31 2012 +0100 summary: Whitespace. files: Objects/abstract.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -649,7 +649,7 @@ int PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, - int readonly, int flags) + int readonly, int flags) { if (view == NULL) return 0; /* XXX why not -1? */ if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 15:38:31 2012 From: python-checkins at python.org (stefan.krah) Date: Tue, 06 Mar 2012 15:38:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Whitespace=2E?= Message-ID: http://hg.python.org/cpython/rev/5d16d956506c changeset: 75457:5d16d956506c user: Stefan Krah date: Tue Mar 06 15:37:36 2012 +0100 summary: Whitespace. files: Modules/mmapmodule.c | 28 ++++++++++++++-------------- 1 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -959,13 +959,13 @@ } static PySequenceMethods mmap_as_sequence = { - (lenfunc)mmap_length, /*sq_length*/ - (binaryfunc)mmap_concat, /*sq_concat*/ - (ssizeargfunc)mmap_repeat, /*sq_repeat*/ - (ssizeargfunc)mmap_item, /*sq_item*/ - 0, /*sq_slice*/ - (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ + (lenfunc)mmap_length, /*sq_length*/ + (binaryfunc)mmap_concat, /*sq_concat*/ + (ssizeargfunc)mmap_repeat, /*sq_repeat*/ + (ssizeargfunc)mmap_item, /*sq_item*/ + 0, /*sq_slice*/ + (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ }; static PyMappingMethods mmap_as_mapping = { @@ -1027,7 +1027,7 @@ PyObject_GenericGetAttr, /*tp_getattro*/ 0, /*tp_setattro*/ &mmap_as_buffer, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ mmap_doc, /*tp_doc*/ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -1043,10 +1043,10 @@ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ new_mmap_object, /* tp_new */ - PyObject_Del, /* tp_free */ + PyObject_Del, /* tp_free */ }; @@ -1097,8 +1097,8 @@ int devzero = -1; int access = (int)ACCESS_DEFAULT; static char *keywords[] = {"fileno", "length", - "flags", "prot", - "access", "offset", NULL}; + "flags", "prot", + "access", "offset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords, &fd, &map_size_obj, &flags, &prot, @@ -1260,8 +1260,8 @@ int access = (access_mode)ACCESS_DEFAULT; DWORD flProtect, dwDesiredAccess; static char *keywords[] = { "fileno", "length", - "tagname", - "access", "offset", NULL }; + "tagname", + "access", "offset", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords, &fileno, &map_size_obj, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 17:54:45 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 06 Mar 2012 17:54:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Use_hg_manifest_to_compute_?= =?utf8?q?list_of_library_files_to_include=2E?= Message-ID: http://hg.python.org/cpython/rev/fb7bb61c8847 changeset: 75458:fb7bb61c8847 user: Martin v. L?wis date: Tue Mar 06 17:53:12 2012 +0100 summary: Use hg manifest to compute list of library files to include. files: Tools/msi/msi.py | 165 ++++++++-------------------------- 1 files changed, 39 insertions(+), 126 deletions(-) diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -2,11 +2,11 @@ # (C) 2003 Martin v. Loewis # See "FOO" in comments refers to MSDN sections with the title FOO. import msilib, schema, sequence, os, glob, time, re, shutil, zipfile +import subprocess, tempfile from msilib import Feature, CAB, Directory, Dialog, Binary, add_data import uisample from win32com.client import constants from distutils.spawn import find_executable -import tempfile # Settings can be overridden in config.py below # 0 for official python.org releases @@ -909,31 +909,27 @@ kw['componentflags'] = 2 #msidbComponentAttributesOptional Directory.__init__(self, *args, **kw) - def check_unpackaged(self): - self.unpackaged_files.discard('__pycache__') - self.unpackaged_files.discard('.svn') - if self.unpackaged_files: - print "Warning: Unpackaged files in %s" % self.absolute - print self.unpackaged_files +def hgmanifest(): + # Fetch file list from Mercurial + process = subprocess.Popen(['hg', 'manifest'], stdout=subprocess.PIPE) + stdout, stderr = process.communicate() + # Create nested directories for file tree + result = {} + for line in stdout.splitlines(): + components = line.split('/') + d = result + while len(components) > 1: + d1 = d.setdefault(components[0], {}) + d = d1 + del components[0] + d[components[0]] = None + return result -def inside_test(dir): - if dir.physical in ('test', 'tests'): - return True - if dir.basedir: - return inside_test(dir.basedir) - return False - -def in_packaging_tests(dir): - if dir.physical == 'tests' and dir.basedir.physical == 'packaging': - return True - if dir.basedir: - return in_packaging_tests(dir.basedir) - return False - # See "File Table", "Component Table", "Directory Table", # "FeatureComponents Table" def add_files(db): + hgfiles = hgmanifest() cab = CAB("python") tmpfiles = [] # Add all executables, icons, text files into the TARGETDIR component @@ -995,123 +991,40 @@ # Add all .py files in Lib, except tkinter, test dirs = [] - pydirs = [(root,"Lib")] + pydirs = [(root, "Lib", hgfiles["Lib"], default_feature)] while pydirs: # Commit every now and then, or else installer will complain db.Commit() - parent, dir = pydirs.pop() - if dir == ".svn" or dir == '__pycache__' or dir.startswith("plat-"): + parent, dir, files, feature = pydirs.pop() + if dir.startswith("plat-"): continue - elif dir in ["tkinter", "idlelib", "Icons"]: + if dir in ["tkinter", "idlelib", "turtledemo"]: if not have_tcl: continue + feature = tcltk tcltk.set_current() - elif dir in ('test', 'tests') or inside_test(parent): - testsuite.set_current() + elif dir in ('test', 'tests'): + feature = testsuite elif not have_ctypes and dir == "ctypes": continue - else: - default_feature.set_current() + feature.set_current() lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir)) - # Add additional files dirs.append(lib) - lib.glob("*.txt") - if dir=='site-packages': - lib.add_file("README.txt", src="README") - continue - files = lib.glob("*.py") - files += lib.glob("*.pyw") - if files: - # Add an entry to the RemoveFile table to remove bytecode files. + has_py = False + for name, subdir in files.items(): + if subdir is None: + assert os.path.isfile(os.path.join(lib.absolute, name)) + if name == 'README': + lib.add_file("README.txt", src="README") + else: + lib.add_file(name) + has_py = has_py or name.endswith(".py") or name.endswith(".pyw") + else: + assert os.path.isdir(os.path.join(lib.absolute, name)) + pydirs.append((lib, name, subdir, feature)) + + if has_py: lib.remove_pyc() - # package READMEs if present - lib.glob("README") - if dir=='Lib': - lib.add_file("sysconfig.cfg") - if dir=='test' and parent.physical=='Lib': - lib.add_file("185test.db") - lib.add_file("audiotest.au") - lib.add_file("sgml_input.html") - lib.add_file("testtar.tar") - lib.add_file("test_difflib_expect.html") - lib.add_file("check_soundcard.vbs") - lib.add_file("empty.vbs") - lib.add_file("Sine-1000Hz-300ms.aif") - lib.glob("*.uue") - lib.glob("*.pem") - lib.glob("*.pck") - lib.glob("cfgparser.*") - lib.add_file("zip_cp437_header.zip") - lib.add_file("zipdir.zip") - lib.add_file("mime.types") - if dir=='capath': - lib.glob("*.0") - if dir=='tests' and parent.physical=='distutils': - lib.add_file("Setup.sample") - if dir=='decimaltestdata': - lib.glob("*.decTest") - if dir=='xmltestdata': - lib.glob("*.xml") - lib.add_file("test.xml.out") - if dir=='output': - lib.glob("test_*") - if dir=='sndhdrdata': - lib.glob("sndhdr.*") - if dir=='idlelib': - lib.glob("*.def") - lib.add_file("idle.bat") - lib.add_file("ChangeLog") - if dir=="Icons": - lib.glob("*.gif") - lib.add_file("idle.icns") - if dir=="command" and parent.physical in ("distutils", "packaging"): - lib.glob("wininst*.exe") - lib.add_file("command_template") - if dir=="lib2to3": - lib.removefile("pickle", "*.pickle") - if dir=="macholib": - lib.add_file("README.ctypes") - lib.glob("fetch_macholib*") - if dir=='turtledemo': - lib.add_file("turtle.cfg") - if dir=="pydoc_data": - lib.add_file("_pydoc.css") - if dir.endswith('.dist-info'): - lib.add_file('INSTALLER') - lib.add_file('REQUESTED') - lib.add_file('RECORD') - lib.add_file('METADATA') - lib.glob('RESOURCES') - if dir.endswith('.egg-info') or dir == 'EGG-INFO': - lib.add_file('PKG-INFO') - if in_packaging_tests(parent): - lib.glob('*.html') - lib.glob('*.tar.gz') - if dir=='fake_dists': - # cannot use glob since there are also egg-info directories here - lib.add_file('cheese-2.0.2.egg-info') - lib.add_file('nut-funkyversion.egg-info') - lib.add_file('strawberry-0.6.egg') - lib.add_file('truffles-5.0.egg-info') - lib.add_file('babar.cfg') - lib.add_file('babar.png') - if dir=="data" and parent.physical=="test_email": - # This should contain all non-.svn files listed in subversion - for f in os.listdir(lib.absolute): - if f.endswith(".txt") or f==".svn":continue - if f.endswith(".au") or f.endswith(".gif"): - lib.add_file(f) - else: - print("WARNING: New file %s in test/test_email/data" % f) - if dir=='tests' and parent.physical == 'packaging': - lib.add_file('SETUPTOOLS-PKG-INFO2') - lib.add_file('SETUPTOOLS-PKG-INFO') - lib.add_file('PKG-INFO') - for f in os.listdir(lib.absolute): - if os.path.isdir(os.path.join(lib.absolute, f)): - pydirs.append((lib, f)) - for d in dirs: - d.check_unpackaged() # Add DLLs default_feature.set_current() lib = DLLs -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 17:54:46 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 06 Mar 2012 17:54:46 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_uuids=2C_as_they_are?= =?utf8?q?_now_computed=2E?= Message-ID: http://hg.python.org/cpython/rev/587f64d9ecf2 changeset: 75459:587f64d9ecf2 user: Martin v. L?wis date: Tue Mar 06 17:54:06 2012 +0100 summary: Remove uuids, as they are now computed. files: Tools/msi/uuids.py | 38 ---------------------------------- 1 files changed, 0 insertions(+), 38 deletions(-) diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py deleted file mode 100644 --- a/Tools/msi/uuids.py +++ /dev/null @@ -1,38 +0,0 @@ -# This should be extended for each Python release. -# The product code must change whenever the name of the MSI file -# changes, and when new component codes are issued for existing -# components. See "Changing the Product Code". As we change the -# component codes with every build, we need a new product code -# each time. For intermediate (snapshot) releases, they are automatically -# generated. For official releases, we record the product codes, -# so people can refer to them. -product_codes = { - '3.1.101': '{c423eada-c498-4d51-9eb4-bfeae647e0a0}', # 3.1a1 - '3.1.102': '{f6e199bf-dc64-42f3-87d4-1525991a013e}', # 3.1a2 - '3.1.111': '{c3c82893-69b2-4676-8554-1b6ee6c191e9}', # 3.1b1 - '3.1.121': '{da2b5170-12f3-4d99-8a1f-54926cca7acd}', # 3.1c1 - '3.1.122': '{bceb5133-e2ee-4109-951f-ac7e941a1692}', # 3.1c2 - '3.1.150': '{3ad61ee5-81d2-4d7e-adef-da1dd37277d1}', # 3.1.0 - '3.1.1121':'{5782f957-6d49-41d4-bad0-668715dfd638}', # 3.1.1c1 - '3.1.1150':'{7ff90460-89b7-435b-b583-b37b2815ccc7}', # 3.1.1 - '3.1.2121':'{ec45624a-378c-43be-91f3-3f7a59b0d90c}', # 3.1.2c1 - '3.1.2150':'{d40af016-506c-43fb-a738-bd54fa8c1e85}', # 3.1.2 - '3.2.101' :'{b411f168-7a36-4fff-902c-a554d1c78a4f}', # 3.2a1 - '3.2.102' :'{79ff73b7-8359-410f-b9c5-152d2026f8c8}', # 3.2a2 - '3.2.103' :'{e7635c65-c221-4b9b-b70a-5611b8369d77}', # 3.2a3 - '3.2.104' :'{748cd139-75b8-4ca8-98a7-58262298181e}', # 3.2a4 - '3.2.111' :'{20bfc16f-c7cd-4fc0-8f96-9914614a3c50}', # 3.2b1 - '3.2.112' :'{0e350c98-8d73-4993-b686-cfe87160046e}', # 3.2b2 - '3.2.121' :'{2094968d-7583-47f6-a7fd-22304532e09f}', # 3.2rc1 - '3.2.122' :'{4f3edfa6-cf70-469a-825f-e1206aa7f412}', # 3.2rc2 - '3.2.123' :'{90c673d7-8cfd-4969-9816-f7d70bad87f3}', # 3.2rc3 - '3.2.150' :'{b2042d5e-986d-44ec-aee3-afe4108ccc93}', # 3.2.0 - '3.2.1121':'{4f90de4a-83dd-4443-b625-ca130ff361dd}', # 3.2.1rc1 - '3.2.1122':'{dc5eb04d-ff8a-4bed-8f96-23942fd59e5f}', # 3.2.1rc2 - '3.2.1150':'{34b2530c-6349-4292-9dc3-60bda4aed93c}', # 3.2.1 - '3.2.2121':'{DFB29A53-ACC4-44e6-85A6-D0DA26FE8E4E}', # 3.2.2rc1 - '3.2.2150':'{4CDE3168-D060-4b7c-BC74-4D8F9BB01AFD}', # 3.2.2 - '3.2.3121':'{B8E8CFF7-E4C6-4a7c-9F06-BB3A8B75DDA8}', # 3.2.3rc1 - '3.2.3150':'{789C9644-9F82-44d3-B4CA-AC31F46F5882}', # 3.2.3 - -} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 21:08:09 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 06 Mar 2012 21:08:09 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314158?= =?utf8?q?=3A_We_now_track_test=5Fsupport=2ETESTFN_cleanup=2C_and_test=5Fm?= =?utf8?q?ailbox_uses?= Message-ID: http://hg.python.org/cpython/rev/1112c2f602b3 changeset: 75460:1112c2f602b3 branch: 2.7 parent: 75436:cec6bb749616 user: Vinay Sajip date: Tue Mar 06 20:07:15 2012 +0000 summary: Closes #14158: We now track test_support.TESTFN cleanup, and test_mailbox uses shutil.rmtree for simpler code. files: Lib/test/regrtest.py | 19 ++++++++++++++++++- Lib/test/test_mailbox.py | 8 ++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -758,7 +758,9 @@ # the corresponding method names. resources = ('sys.argv', 'cwd', 'sys.stdin', 'sys.stdout', 'sys.stderr', - 'os.environ', 'sys.path', 'asyncore.socket_map') + 'os.environ', 'sys.path', 'asyncore.socket_map', + 'test_support.TESTFN', + ) def get_sys_argv(self): return id(sys.argv), sys.argv, sys.argv[:] @@ -809,6 +811,21 @@ asyncore.close_all(ignore_all=True) asyncore.socket_map.update(saved_map) + def get_test_support_TESTFN(self): + if os.path.isfile(test_support.TESTFN): + result = 'f' + elif os.path.isdir(test_support.TESTFN): + result = 'd' + else: + result = None + return result + def restore_test_support_TESTFN(self, saved_value): + if saved_value is None: + if os.path.isfile(test_support.TESTFN): + os.unlink(test_support.TESTFN) + elif os.path.isdir(test_support.TESTFN): + shutil.rmtree(test_support.TESTFN) + def resource_info(self): for name in self.resources: method_suffix = name.replace('.', '_') diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -6,6 +6,7 @@ import email import email.message import re +import shutil import StringIO from test import test_support import unittest @@ -38,12 +39,7 @@ def _delete_recursively(self, target): # Delete a file or delete a directory recursively if os.path.isdir(target): - for path, dirs, files in os.walk(target, topdown=False): - for name in files: - os.remove(os.path.join(path, name)) - for name in dirs: - os.rmdir(os.path.join(path, name)) - os.rmdir(target) + shutil.rmtree(target) elif os.path.exists(target): os.remove(target) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 21:33:31 2012 From: python-checkins at python.org (brett.cannon) Date: Tue, 06 Mar 2012 21:33:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Minor_doc_cleanup=2E?= Message-ID: http://hg.python.org/cpython/rev/52d58b865e53 changeset: 75461:52d58b865e53 parent: 75362:82032c64dd89 user: Brett Cannon date: Fri Mar 02 11:58:25 2012 -0500 summary: Minor doc cleanup. files: Doc/library/importlib.rst | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -487,7 +487,7 @@ Class method that attempts to find a :term:`loader` for the module specified by *fullname* on :data:`sys.path` or, if defined, on *path*. For each path entry that is searched, - :data:`sys.path_importer_cache` is checked. If an non-false object is + :data:`sys.path_importer_cache` is checked. If a non-false object is found then it is used as the :term:`finder` to look for the module being searched for. If no entry is found in :data:`sys.path_importer_cache`, then :data:`sys.path_hooks` is @@ -500,7 +500,7 @@ --------------------------------------------------- .. module:: importlib.util - :synopsis: Importers and path hooks + :synopsis: Utility code for importers This module contains the various objects that help in the construction of an :term:`importer`. @@ -536,7 +536,7 @@ to set the :attr:`__loader__` attribute on loaded modules. If the attribute is already set the decorator does nothing. It is assumed that the first positional argument to the - wrapped method is what :attr:`__loader__` should be set to. + wrapped method (i.e. ``self``) is what :attr:`__loader__` should be set to. .. decorator:: set_package @@ -547,8 +547,8 @@ set on and not the module found in :data:`sys.modules`. Reliance on this decorator is discouraged when it is possible to set - :attr:`__package__` before the execution of the code is possible. By - setting it before the code for the module is executed it allows the - attribute to be used at the global level of the module during + :attr:`__package__` before importing. By + setting it beforehand the code for the module is executed with the + attribute set and thus can be used by global level code during initialization. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 21:33:32 2012 From: python-checkins at python.org (brett.cannon) Date: Tue, 06 Mar 2012 21:33:32 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Clarify_importlib=2Emachine?= =?utf8?q?ry=2EPathFinder=27s_difference_from_what_=5F=5Fimport=5F=5F=28?= =?utf8?q?=29_does=2E?= Message-ID: http://hg.python.org/cpython/rev/139d90ed368d changeset: 75462:139d90ed368d user: Brett Cannon date: Fri Mar 02 12:10:48 2012 -0500 summary: Clarify importlib.machinery.PathFinder's difference from what __import__() does. files: Doc/library/importlib.rst | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -477,7 +477,9 @@ This class does not perfectly mirror the semantics of :keyword:`import` in terms of :data:`sys.path`. No implicit path hooks are assumed for - simplification of the class and its semantics. + simplification of the class and its semantics. This implies that when + ``None`` is found in :data:`sys.path_importer_cache` that it is simply + ignored instead of implying a default finder. Only class methods are defined by this class to alleviate the need for instantiation. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 21:33:32 2012 From: python-checkins at python.org (brett.cannon) Date: Tue, 06 Mar 2012 21:33:32 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_a_dead_docstring=2E?= Message-ID: http://hg.python.org/cpython/rev/e4a510317172 changeset: 75463:e4a510317172 user: Brett Cannon date: Fri Mar 02 12:32:14 2012 -0500 summary: Remove a dead docstring. files: Lib/importlib/_bootstrap.py | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -625,12 +625,6 @@ """ def __init__(self, name, path): - """Initialize the loader. - - If is_pkg is True then an exception is raised as extension modules - cannot be the __init__ module for an extension module. - - """ self._name = name self._path = path -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 6 21:33:34 2012 From: python-checkins at python.org (brett.cannon) Date: Tue, 06 Mar 2012 21:33:34 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge?= Message-ID: http://hg.python.org/cpython/rev/2cf03b22020e changeset: 75464:2cf03b22020e parent: 75463:e4a510317172 parent: 75459:587f64d9ecf2 user: Brett Cannon date: Tue Mar 06 15:33:24 2012 -0500 summary: merge files: .hgtags | 1 + Doc/c-api/buffer.rst | 20 +- Doc/c-api/typeobj.rst | 48 +- Doc/howto/advocacy.rst | 3 +- Doc/howto/cporting.rst | 4 +- Doc/howto/regex.rst | 4 +- Doc/library/copyreg.rst | 8 +- Doc/library/markup.rst | 4 +- Doc/library/multiprocessing.rst | 82 ++- Doc/library/packaging.database.rst | 45 +- Doc/library/pickle.rst | 61 + Doc/library/signal.rst | 9 +- Doc/library/socket.rst | 4 +- Doc/library/sys.rst | 2 +- Doc/library/xml.dom.minidom.rst | 8 + Doc/license.rst | 2 +- Doc/reference/lexical_analysis.rst | 10 +- Doc/tools/sphinxext/pyspecific.py | 5 +- Doc/tools/sphinxext/susp-ignored.csv | 338 +++++---- Doc/whatsnew/3.3.rst | 95 ++- Include/abstract.h | 2 +- Include/patchlevel.h | 4 +- Include/pytime.h | 11 + Include/unicodeobject.h | 3 - LICENSE | 2 +- Lib/_weakrefset.py | 60 +- Lib/concurrent/futures/process.py | 12 +- Lib/distutils/__init__.py | 2 +- Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/tests/test_bdist_msi.py | 19 +- Lib/idlelib/idlever.py | 2 +- Lib/multiprocessing/connection.py | 332 ++++++--- Lib/multiprocessing/queues.py | 9 +- Lib/packaging/command/bdist_msi.py | 2 +- Lib/packaging/database.py | 1 + Lib/packaging/tests/test_command_bdist_msi.py | 13 +- Lib/pickle.py | 4 +- Lib/pydoc_data/topics.py | 49 +- Lib/test/crashers/loosing_mro_ref.py | 0 Lib/test/crashers/nasty_eq_vs_dict.py | 47 - Lib/test/pickletester.py | 99 ++ Lib/test/regrtest.py | 23 +- Lib/test/test_base64.py | 5 + Lib/test/test_buffer.py | 201 +++++- Lib/test/test_dict.py | 22 +- Lib/test/test_exceptions.py | 2 +- Lib/test/test_logging.py | 14 +- Lib/test/test_mailbox.py | 12 +- Lib/test/test_marshal.py | 30 +- Lib/test/test_minidom.py | 15 +- Lib/test/test_multiprocessing.py | 236 ++++++- Lib/test/test_mutants.py | 291 -------- Lib/test/test_pickle.py | 28 +- Lib/test/test_pty.py | 19 +- Lib/test/test_signal.py | 10 +- Lib/test/test_time.py | 21 +- Lib/test/test_tokenize.py | 12 + Lib/test/test_weakset.py | 56 +- Lib/test/test_xml_etree.py | 114 +++- Lib/test/test_xml_etree_c.py | 21 +- Lib/threading.py | 152 +--- Lib/tokenize.py | 42 +- Lib/xml/dom/__init__.py | 1 + Lib/xml/dom/domreg.py | 2 - Lib/xml/dom/expatbuilder.py | 4 +- Lib/xml/dom/minidom.py | 17 +- Lib/xml/etree/ElementTree.py | 81 +- Lib/xmlrpc/server.py | 2 +- Misc/ACKS | 1 + Misc/NEWS | 54 +- Misc/RPM/python-3.3.spec | 2 +- Misc/valgrind-python.supp | 32 + Modules/_elementtree.c | 258 ++++--- Modules/_multiprocessing/win32_functions.c | 69 +- Modules/_pickle.c | 39 +- Modules/_testbuffer.c | 174 ++++- Modules/_testcapimodule.c | 19 + Modules/mmapmodule.c | 28 +- Modules/signalmodule.c | 11 +- Objects/abstract.c | 2 +- Objects/dictobject.c | 18 +- Objects/frameobject.c | 1 - Objects/memoryobject.c | 5 +- Objects/unicodeobject.c | 10 +- PC/python_nt.rc | 2 +- PCbuild/pcbuild.sln | 12 +- Parser/tokenizer.c | 10 +- Python/ast.c | 3 + Python/getcopyright.c | 2 +- Python/marshal.c | 24 +- Python/pytime.c | 45 + README | 4 +- Tools/msi/msi.py | 184 +--- Tools/msi/uuids.py | 38 - 94 files changed, 2431 insertions(+), 1477 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -95,3 +95,4 @@ c860feaa348d663e598986894ee4680480577e15 v3.2.2rc1 137e45f15c0bd262c9ad4c032d97425bc0589456 v3.2.2 7085403daf439adb3f9e70ef13f6bedb1c447376 v3.2.3rc1 +f1a9a6505731714f0e157453ff850e3b71615c45 v3.3.0a1 diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -81,17 +81,23 @@ around a buffer is needed, a :ref:`memoryview ` object can be created. +For short instructions how to write an exporting object, see +:ref:`Buffer Object Structures `. For obtaining +a buffer, see :c:func:`PyObject_GetBuffer`. .. c:type:: Py_buffer .. c:member:: void \*obj - A new reference to the exporting object or *NULL*. The reference is owned - by the consumer and automatically decremented and set to *NULL* by - :c:func:`PyBuffer_Release`. + A new reference to the exporting object. The reference is owned by + the consumer and automatically decremented and set to *NULL* by + :c:func:`PyBuffer_Release`. The field is the equivalent of the return + value of any standard C-API function. - For temporary buffers that are wrapped by :c:func:`PyMemoryView_FromBuffer` - this field must be *NULL*. + As a special case, for *temporary* buffers that are wrapped by + :c:func:`PyMemoryView_FromBuffer` or :c:func:`PyBuffer_FillInfo` + this field is *NULL*. In general, exporting objects MUST NOT + use this scheme. .. c:member:: void \*buf @@ -423,7 +429,9 @@ return -1. On success, fill in *view*, set :c:member:`view->obj` to a new reference - to *exporter* and return 0. + to *exporter* and return 0. In the case of chained buffer providers + that redirect requests to a single object, :c:member:`view->obj` MAY + refer to this object instead of *exporter* (See :ref:`Buffer Object Structures `). Successful calls to :c:func:`PyObject_GetBuffer` must be paired with calls to :c:func:`PyBuffer_Release`, similar to :c:func:`malloc` and :c:func:`free`. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1213,18 +1213,29 @@ int (PyObject *exporter, Py_buffer *view, int flags); Handle a request to *exporter* to fill in *view* as specified by *flags*. - A standard implementation of this function will take these steps: + Except for point (3), an implementation of this function MUST take these + steps: - - Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, - set :c:data:`view->obj` to *NULL* and return -1. + (1) Check if the request can be met. If not, raise :c:data:`PyExc_BufferError`, + set :c:data:`view->obj` to *NULL* and return -1. - - Fill in the requested fields. + (2) Fill in the requested fields. - - Increment an internal counter for the number of exports. + (3) Increment an internal counter for the number of exports. - - Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. + (4) Set :c:data:`view->obj` to *exporter* and increment :c:data:`view->obj`. - - Return 0. + (5) Return 0. + + If *exporter* is part of a chain or tree of buffer providers, two main + schemes can be used: + + * Re-export: Each member of the tree acts as the exporting object and + sets :c:data:`view->obj` to a new reference to itself. + + * Redirect: The buffer request is redirected to the root object of the + tree. Here, :c:data:`view->obj` will be a new reference to the root + object. The individual fields of *view* are described in section :ref:`Buffer structure `, the rules how an exporter @@ -1233,8 +1244,9 @@ All memory pointed to in the :c:type:`Py_buffer` structure belongs to the exporter and must remain valid until there are no consumers left. - :c:member:`~Py_buffer.shape`, :c:member:`~Py_buffer.strides`, - :c:member:`~Py_buffer.suboffsets` and :c:member:`~Py_buffer.internal` + :c:member:`~Py_buffer.format`, :c:member:`~Py_buffer.shape`, + :c:member:`~Py_buffer.strides`, :c:member:`~Py_buffer.suboffsets` + and :c:member:`~Py_buffer.internal` are read-only for the consumer. :c:func:`PyBuffer_FillInfo` provides an easy way of exposing a simple @@ -1250,21 +1262,23 @@ void (PyObject *exporter, Py_buffer *view); Handle a request to release the resources of the buffer. If no resources - need to be released, this field may be *NULL*. A standard implementation - of this function will take these steps: + need to be released, :c:member:`PyBufferProcs.bf_releasebuffer` may be + *NULL*. Otherwise, a standard implementation of this function will take + these optional steps: - - Decrement an internal counter for the number of exports. + (1) Decrement an internal counter for the number of exports. - - If the counter is 0, free all memory associated with *view*. + (2) If the counter is 0, free all memory associated with *view*. The exporter MUST use the :c:member:`~Py_buffer.internal` field to keep - track of buffer-specific resources (if present). This field is guaranteed - to remain constant, while a consumer MAY pass a copy of the original buffer - as the *view* argument. + track of buffer-specific resources. This field is guaranteed to remain + constant, while a consumer MAY pass a copy of the original buffer as the + *view* argument. This function MUST NOT decrement :c:data:`view->obj`, since that is - done automatically in :c:func:`PyBuffer_Release`. + done automatically in :c:func:`PyBuffer_Release` (this scheme is + useful for breaking reference cycles). :c:func:`PyBuffer_Release` is the interface for the consumer that diff --git a/Doc/howto/advocacy.rst b/Doc/howto/advocacy.rst --- a/Doc/howto/advocacy.rst +++ b/Doc/howto/advocacy.rst @@ -264,8 +264,7 @@ **What are the restrictions on Python's use?** -They're practically nonexistent. Consult the :file:`Misc/COPYRIGHT` file in the -source distribution, or the section :ref:`history-and-license` for the full +They're practically nonexistent. Consult :ref:`history-and-license` for the full language, but it boils down to three conditions: * You have to leave the copyright notice on the software; if you don't include diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst --- a/Doc/howto/cporting.rst +++ b/Doc/howto/cporting.rst @@ -261,8 +261,8 @@ copy as you see fit.) You can find :file:`capsulethunk.h` in the Python source distribution -in the :file:`Doc/includes` directory. We also include it here for -your reference; here is :file:`capsulethunk.h`: +as :source:`Doc/includes/capsulethunk.h`. We also include it here for +your convenience: .. literalinclude:: ../includes/capsulethunk.h diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst --- a/Doc/howto/regex.rst +++ b/Doc/howto/regex.rst @@ -360,7 +360,7 @@ You can learn about this by interactively experimenting with the :mod:`re` module. If you have :mod:`tkinter` available, you may also want to look at -:file:`Tools/demo/redemo.py`, a demonstration program included with the +:source:`Tools/demo/redemo.py`, a demonstration program included with the Python distribution. It allows you to enter REs and strings, and displays whether the RE matches or fails. :file:`redemo.py` can be quite useful when trying to debug a complicated RE. Phil Schwartz's `Kodos @@ -495,7 +495,7 @@ the same ones in several locations, then it might be worthwhile to collect all the definitions in one place, in a section of code that compiles all the REs ahead of time. To take an example from the standard library, here's an extract -from the now deprecated :file:`xmllib.py`:: +from the now-defunct Python 2 standard :mod:`xmllib` module:: ref = re.compile( ... ) entityref = re.compile( ... ) diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -32,6 +32,8 @@ returned by *function* at pickling time. :exc:`TypeError` will be raised if *object* is a class or *constructor* is not callable. - See the :mod:`pickle` module for more details on the interface expected of - *function* and *constructor*. - + See the :mod:`pickle` module for more details on the interface + expected of *function* and *constructor*. Note that the + :attr:`~pickle.Pickler.dispatch_table` attribute of a pickler + object or subclass of :class:`pickle.Pickler` can also be used for + declaring reduction functions. diff --git a/Doc/library/markup.rst b/Doc/library/markup.rst --- a/Doc/library/markup.rst +++ b/Doc/library/markup.rst @@ -23,7 +23,7 @@ html.rst html.parser.rst html.entities.rst - pyexpat.rst + xml.etree.elementtree.rst xml.dom.rst xml.dom.minidom.rst xml.dom.pulldom.rst @@ -31,4 +31,4 @@ xml.sax.handler.rst xml.sax.utils.rst xml.sax.reader.rst - xml.etree.elementtree.rst + pyexpat.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -415,13 +415,14 @@ A numeric handle of a system object which will become "ready" when the process ends. + You can use this value if you want to wait on several events at + once using :func:`multiprocessing.connection.wait`. Otherwise + calling :meth:`join()` is simpler. + On Windows, this is an OS handle usable with the ``WaitForSingleObject`` and ``WaitForMultipleObjects`` family of API calls. On Unix, this is a file descriptor usable with primitives from the :mod:`select` module. - You can use this value if you want to wait on several events at once. - Otherwise calling :meth:`join()` is simpler. - .. versionadded:: 3.3 .. method:: terminate() @@ -785,6 +786,9 @@ *timeout* is a number then this specifies the maximum time in seconds to block. If *timeout* is ``None`` then an infinite timeout is used. + Note that multiple connection objects may be polled at once by + using :func:`multiprocessing.connection.wait`. + .. method:: send_bytes(buffer[, offset[, size]]) Send byte data from an object supporting the buffer interface as a @@ -1779,8 +1783,9 @@ However, the :mod:`multiprocessing.connection` module allows some extra flexibility. It basically gives a high level message oriented API for dealing -with sockets or Windows named pipes, and also has support for *digest -authentication* using the :mod:`hmac` module. +with sockets or Windows named pipes. It also has support for *digest +authentication* using the :mod:`hmac` module, and for polling +multiple connections at the same time. .. function:: deliver_challenge(connection, authkey) @@ -1878,6 +1883,38 @@ The address from which the last accepted connection came. If this is unavailable then it is ``None``. +.. function:: wait(object_list, timeout=None) + + Wait till an object in *object_list* is ready. Returns the list of + those objects in *object_list* which are ready. If *timeout* is a + float then the call blocks for at most that many seconds. If + *timeout* is ``None`` then it will block for an unlimited period. + + For both Unix and Windows, an object can appear in *object_list* if + it is + + * a readable :class:`~multiprocessing.Connection` object; + * a connected and readable :class:`socket.socket` object; or + * the :attr:`~multiprocessing.Process.sentinel` attribute of a + :class:`~multiprocessing.Process` object. + + A connection or socket object is ready when there is data available + to be read from it, or the other end has been closed. + + **Unix**: ``wait(object_list, timeout)`` almost equivalent + ``select.select(object_list, [], [], timeout)``. The difference is + that, if :func:`select.select` is interrupted by a signal, it can + raise :exc:`OSError` with an error number of ``EINTR``, whereas + :func:`wait` will not. + + **Windows**: An item in *object_list* must either be an integer + handle which is waitable (according to the definition used by the + documentation of the Win32 function ``WaitForMultipleObjects()``) + or it can be an object with a :meth:`fileno` method which returns a + socket handle or pipe handle. (Note that pipe handles and socket + handles are **not** waitable handles.) + + .. versionadded:: 3.3 The module defines two exceptions: @@ -1929,6 +1966,41 @@ conn.close() +The following code uses :func:`~multiprocessing.connection.wait` to +wait for messages from multiple processes at once:: + + import time, random + from multiprocessing import Process, Pipe, current_process + from multiprocessing.connection import wait + + def foo(w): + for i in range(10): + w.send((i, current_process().name)) + w.close() + + if __name__ == '__main__': + readers = [] + + for i in range(4): + r, w = Pipe(duplex=False) + readers.append(r) + p = Process(target=foo, args=(w,)) + p.start() + # We close the writable end of the pipe now to be sure that + # p is the only process which owns a handle for it. This + # ensures that when p closes its handle for the writable end, + # wait() will promptly report the readable end as being ready. + w.close() + + while readers: + for r in wait(readers): + try: + msg = r.recv() + except EOFError: + readers.remove(r) + else: + print(msg) + .. _multiprocessing-address-formats: diff --git a/Doc/library/packaging.database.rst b/Doc/library/packaging.database.rst --- a/Doc/library/packaging.database.rst +++ b/Doc/library/packaging.database.rst @@ -15,6 +15,11 @@ Most functions also provide an extra argument ``use_egg_info`` to take legacy distributions into account. +For the purpose of this module, "installed" means that the distribution's +:file:`.dist-info`, :file:`.egg-info` or :file:`egg` directory or file is found +on :data:`sys.path`. For example, if the parent directory of a +:file:`dist-info` directory is added to :envvar:`PYTHONPATH`, then it will be +available in the database. Classes representing installed distributions -------------------------------------------- @@ -128,7 +133,7 @@ for the first installed distribution matching *name*. Egg distributions are considered only if *use_egg_info* is true; if both a dist-info and an egg file are found, the dist-info prevails. The directories to be searched are - given in *paths*, which defaults to :data:`sys.path`. Return ``None`` if no + given in *paths*, which defaults to :data:`sys.path`. Returns ``None`` if no matching distribution is found. .. FIXME param should be named use_egg @@ -200,20 +205,23 @@ Examples -------- -Print all information about a distribution -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Printing all information about a distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Given a path to a ``.dist-info`` distribution, we shall print out all +Given the name of an installed distribution, we shall print out all information that can be obtained using functions provided in this module:: import sys import packaging.database - path = input() + try: + name = sys.argv[1] + except ValueError: + sys.exit('Not enough arguments') + # first create the Distribution instance - try: - dist = packaging.database.Distribution(path) - except FileNotFoundError: + dist = packaging.database.Distribution(path) + if dist is None: sys.exit('No such distribution') print('Information about %r' % dist.name) @@ -244,7 +252,7 @@ .. code-block:: sh - $ echo /tmp/choxie/choxie-2.0.0.9.dist-info | python3 print_info.py + python print_info.py choxie we get the following output: @@ -299,10 +307,23 @@ * It was installed as a dependency -Find out obsoleted distributions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Getting metadata about a distribution +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Now, we take tackle a different problem, we are interested in finding out +Sometimes you're not interested about the packaging information contained in a +full :class:`Distribution` object but just want to do something with its +:attr:`~Distribution.metadata`:: + + >>> from packaging.database import get_distribution + >>> info = get_distribution('chocolate').metadata + >>> info['Keywords'] + ['cooking', 'happiness'] + + +Finding out obsoleted distributions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now, we tackle a different problem, we are interested in finding out which distributions have been obsoleted. This can be easily done as follows:: import packaging.database diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -285,6 +285,29 @@ See :ref:`pickle-persistent` for details and examples of uses. + .. attribute:: dispatch_table + + A pickler object's dispatch table is a registry of *reduction + functions* of the kind which can be declared using + :func:`copyreg.pickle`. It is a mapping whose keys are classes + and whose values are reduction functions. A reduction function + takes a single argument of the associated class and should + conform to the same interface as a :meth:`~object.__reduce__` + method. + + By default, a pickler object will not have a + :attr:`dispatch_table` attribute, and it will instead use the + global dispatch table managed by the :mod:`copyreg` module. + However, to customize the pickling for a specific pickler object + one can set the :attr:`dispatch_table` attribute to a dict-like + object. Alternatively, if a subclass of :class:`Pickler` has a + :attr:`dispatch_table` attribute then this will be used as the + default dispatch table for instances of that class. + + See :ref:`pickle-dispatch` for usage examples. + + .. versionadded:: 3.3 + .. attribute:: fast Deprecated. Enable fast mode if set to a true value. The fast mode @@ -575,6 +598,44 @@ .. literalinclude:: ../includes/dbpickle.py +.. _pickle-dispatch: + +Dispatch Tables +^^^^^^^^^^^^^^^ + +If one wants to customize pickling of some classes without disturbing +any other code which depends on pickling, then one can create a +pickler with a private dispatch table. + +The global dispatch table managed by the :mod:`copyreg` module is +available as :data:`copyreg.dispatch_table`. Therefore, one may +choose to use a modified copy of :data:`copyreg.dispatch_table` as a +private dispatch table. + +For example :: + + f = io.BytesIO() + p = pickle.Pickler(f) + p.dispatch_table = copyreg.dispatch_table.copy() + p.dispatch_table[SomeClass] = reduce_SomeClass + +creates an instance of :class:`pickle.Pickler` with a private dispatch +table which handles the ``SomeClass`` class specially. Alternatively, +the code :: + + class MyPickler(pickle.Pickler): + dispatch_table = copyreg.dispatch_table.copy() + dispatch_table[SomeClass] = reduce_SomeClass + f = io.BytesIO() + p = MyPickler(f) + +does the same, but all instances of ``MyPickler`` will by default +share the same dispatch table. The equivalent code using the +:mod:`copyreg` module is :: + + copyreg.pickle(SomeClass, reduce_SomeClass) + f = io.BytesIO() + p = pickle.Pickler(f) .. _pickle-state: diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -369,12 +369,11 @@ .. versionadded:: 3.3 -.. function:: sigtimedwait(sigset, (timeout_sec, timeout_nsec)) +.. function:: sigtimedwait(sigset, timeout) - Like :func:`sigtimedwait`, but takes a tuple of ``(seconds, nanoseconds)`` - as an additional argument specifying a timeout. If both *timeout_sec* and - *timeout_nsec* are specified as :const:`0`, a poll is performed. Returns - :const:`None` if a timeout occurs. + Like :func:`sigwaitinfo`, but takes an additional *timeout* argument + specifying a timeout. If *timeout* is specified as :const:`0`, a poll is + performed. Returns :const:`None` if a timeout occurs. Availability: Unix (see the man page :manpage:`sigtimedwait(2)` for further information). diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1311,7 +1311,7 @@ import struct - # CAN frame packing/unpacking (see `struct can_frame` in ) + # CAN frame packing/unpacking (see 'struct can_frame' in ) can_frame_fmt = "=IB3x8s" can_frame_size = struct.calcsize(can_frame_fmt) @@ -1326,7 +1326,7 @@ return (can_id, can_dlc, data[:can_dlc]) - # create a raw socket and bind it to the `vcan0` interface + # create a raw socket and bind it to the 'vcan0' interface s = socket.socket(socket.AF_CAN, socket.SOCK_RAW, socket.CAN_RAW) s.bind(('vcan0',)) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -770,7 +770,7 @@ independent Python files are installed; by default, this is the string ``'/usr/local'``. This can be set at build time with the ``--prefix`` argument to the :program:`configure` script. The main collection of Python - library modules is installed in the directory :file:`{prefix}/lib/python{X.Y}`` + library modules is installed in the directory :file:`{prefix}/lib/python{X.Y}` while the platform independent header files (all except :file:`pyconfig.h`) are stored in :file:`{prefix}/include/python{X.Y}`, where *X.Y* is the version number of Python, for example ``3.2``. diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -15,6 +15,14 @@ Model interface. It is intended to be simpler than the full DOM and also significantly smaller. +.. note:: + + The :mod:`xml.dom.minidom` module provides an implementation of the W3C-DOM, + with an API similar to that in other programming languages. Users who are + unfamiliar with the W3C-DOM interface or who would like to write less code + for processing XML files should consider using the + :mod:`xml.etree.ElementTree` module instead. + DOM applications typically start by parsing some XML into a DOM. With :mod:`xml.dom.minidom`, this is done through the parse functions:: diff --git a/Doc/license.rst b/Doc/license.rst --- a/Doc/license.rst +++ b/Doc/license.rst @@ -118,7 +118,7 @@ +----------------+--------------+------------+------------+-----------------+ | 3.2.2 | 3.2.1 | 2011 | PSF | yes | +----------------+--------------+------------+------------+-----------------+ -| 3.3 | 3.2 | 2012 | PSF | yes | +| 3.3.0 | 3.2 | 2012 | PSF | yes | +----------------+--------------+------------+------------+-----------------+ .. note:: diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -401,7 +401,7 @@ .. productionlist:: stringliteral: [`stringprefix`](`shortstring` | `longstring`) - stringprefix: "r" | "R" + stringprefix: "r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR" shortstring: "'" `shortstringitem`* "'" | '"' `shortstringitem`* '"' longstring: "'''" `longstringitem`* "'''" | '"""' `longstringitem`* '"""' shortstringitem: `shortstringchar` | `stringescapeseq` @@ -441,6 +441,9 @@ may only contain ASCII characters; bytes with a numeric value of 128 or greater must be expressed with escapes. +As of Python 3.3 it is possible again to prefix unicode strings with a +``u`` prefix to simplify maintenance of dual 2.x and 3.x codebases. + Both string and bytes literals may optionally be prefixed with a letter ``'r'`` or ``'R'``; such strings are called :dfn:`raw strings` and treat backslashes as literal characters. As a result, in string literals, ``'\U'`` and ``'\u'`` @@ -450,6 +453,11 @@ The ``'rb'`` prefix of raw bytes literals has been added as a synonym of ``'br'``. + .. versionadded:: 3.3 + Support for the unicode legacy literal (``u'value'``) and other + versions were reintroduced to simplify the maintenance of dual + Python 2.x and 3.x codebases. See :pep:`414` for more information. + In triple-quoted strings, unescaped newlines and quotes are allowed (and are retained), except that three unescaped quotes in a row terminate the string. (A "quote" is the character used to open the string, i.e. either ``'`` or ``"``.) diff --git a/Doc/tools/sphinxext/pyspecific.py b/Doc/tools/sphinxext/pyspecific.py --- a/Doc/tools/sphinxext/pyspecific.py +++ b/Doc/tools/sphinxext/pyspecific.py @@ -5,7 +5,7 @@ Sphinx extension with Python doc-specific markup. - :copyright: 2008, 2009, 2010 by Georg Brandl. + :copyright: 2008, 2009, 2010, 2011, 2012 by Georg Brandl. :license: Python license. """ @@ -201,11 +201,12 @@ document.append(doctree.ids[labelid]) destination = StringOutput(encoding='utf-8') writer.write(document, destination) - self.topics[label] = str(writer.output) + self.topics[label] = writer.output.encode('utf-8') def finish(self): f = open(path.join(self.outdir, 'topics.py'), 'w') try: + f.write('# -*- coding: utf-8 -*-\n') f.write('# Autogenerated by Sphinx on %s\n' % asctime()) f.write('topics = ' + pformat(self.topics) + '\n') finally: diff --git a/Doc/tools/sphinxext/susp-ignored.csv b/Doc/tools/sphinxext/susp-ignored.csv --- a/Doc/tools/sphinxext/susp-ignored.csv +++ b/Doc/tools/sphinxext/susp-ignored.csv @@ -1,16 +1,24 @@ c-api/arg,,:ref,"PyArg_ParseTuple(args, ""O|O:ref"", &object, &callback)" c-api/list,,:high,list[low:high] c-api/list,,:high,list[low:high] = itemlist +c-api/sequence,,:i2,del o[i1:i2] c-api/sequence,,:i2,o[i1:i2] c-api/sequence,,:i2,o[i1:i2] = v -c-api/sequence,,:i2,del o[i1:i2] c-api/unicode,,:end,str[start:end] +c-api/unicode,,:start,unicode[start:start+length] +distutils/examples,267,`,This is the description of the ``foobar`` package. distutils/setupscript,,::, extending/embedding,,:numargs,"if(!PyArg_ParseTuple(args, "":numargs""))" +extending/extending,,:myfunction,"PyArg_ParseTuple(args, ""D:myfunction"", &c);" extending/extending,,:set,"if (PyArg_ParseTuple(args, ""O:set_callback"", &temp)) {" -extending/extending,,:myfunction,"PyArg_ParseTuple(args, ""D:myfunction"", &c);" extending/newtypes,,:call,"if (!PyArg_ParseTuple(args, ""sss:call"", &arg1, &arg2, &arg3)) {" extending/windows,,:initspam,/export:initspam +faq/programming,,:chr,">=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(" +faq/programming,,::,for x in sequence[::-1]: +faq/programming,,:reduce,"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y," +faq/programming,,:reduce,"Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro," +faq/windows,229,:EOF, at setlocal enableextensions & python -x %~f0 %* & goto :EOF +faq/windows,393,:REG,.py :REG_SZ: c:\\python.exe -u %s %s howto/cporting,,:add,"if (!PyArg_ParseTuple(args, ""ii:add_ints"", &one, &two))" howto/cporting,,:encode,"if (!PyArg_ParseTuple(args, ""O:encode_object"", &myobj))" howto/cporting,,:say,"if (!PyArg_ParseTuple(args, ""U:say_hello"", &name))" @@ -22,19 +30,53 @@ howto/curses,,:red,"They are: 0:black, 1:red, 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and" howto/curses,,:white,"7:white." howto/curses,,:yellow,"They are: 0:black, 1:red, 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and" +howto/logging,,:And,"WARNING:And this, too" +howto/logging,,:And,"WARNING:root:And this, too" +howto/logging,,:Doing,INFO:root:Doing something +howto/logging,,:Finished,INFO:root:Finished +howto/logging,,:logger,severity:logger name:message +howto/logging,,:Look,WARNING:root:Look before you leap! +howto/logging,,:message,severity:logger name:message +howto/logging,,:root,DEBUG:root:This message should go to the log file +howto/logging,,:root,INFO:root:Doing something +howto/logging,,:root,INFO:root:Finished +howto/logging,,:root,INFO:root:So should this +howto/logging,,:root,INFO:root:Started +howto/logging,,:root,"WARNING:root:And this, too" +howto/logging,,:root,WARNING:root:Look before you leap! +howto/logging,,:root,WARNING:root:Watch out! +howto/logging,,:So,INFO:root:So should this +howto/logging,,:So,INFO:So should this +howto/logging,,:Started,INFO:root:Started +howto/logging,,:This,DEBUG:root:This message should go to the log file +howto/logging,,:This,DEBUG:This message should appear on the console +howto/logging,,:Watch,WARNING:root:Watch out! +howto/pyporting,75,::,# make sure to use :: Python *and* :: Python :: 3 so +howto/pyporting,75,::,"'Programming Language :: Python'," +howto/pyporting,75,::,'Programming Language :: Python :: 3' howto/regex,,::, howto/regex,,:foo,(?:foo) howto/urllib2,,:example,"for example ""joe at password:example.com""" howto/webservers,,.. image:,.. image:: http.png library/audioop,,:ipos,"# factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)]," +library/bisect,32,:hi,all(val >= x for val in a[i:hi]) +library/bisect,42,:hi,all(val > x for val in a[i:hi]) +library/configparser,,:home,my_dir: ${Common:home_dir}/twosheds +library/configparser,,:option,${section:option} +library/configparser,,:path,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} +library/configparser,,:Python,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} +library/configparser,,`,# Set the optional `raw` argument of get() to True if you wish to disable +library/configparser,,:system,path: ${Common:system_dir}/Library/Frameworks/ +library/configparser,,`,# The optional `fallback` argument can be used to provide a fallback value +library/configparser,,`,# The optional `vars` argument is a dict with members that will take library/datetime,,:MM, library/datetime,,:SS, library/decimal,,:optional,"trailneg:optional trailing minus indicator" library/difflib,,:ahi,a[alo:ahi] library/difflib,,:bhi,b[blo:bhi] +library/difflib,,:i1, library/difflib,,:i2, library/difflib,,:j2, -library/difflib,,:i1, library/dis,,:TOS, library/dis,,`,TOS = `TOS` library/doctest,,`,``factorial`` from the ``example`` module: @@ -44,96 +86,164 @@ library/functions,,:stop,"a[start:stop, i]" library/functions,,:stop,a[start:stop:step] library/hotshot,,:lineno,"ncalls tottime percall cumtime percall filename:lineno(function)" +library/http.client,52,:port,host:port library/httplib,,:port,host:port library/imaplib,,:MM,"""DD-Mmm-YYYY HH:MM:SS" library/imaplib,,:SS,"""DD-Mmm-YYYY HH:MM:SS" +library/itertools,,:step,elements from seq[start:stop:step] library/itertools,,:stop,elements from seq[start:stop:step] -library/itertools,,:step,elements from seq[start:stop:step] library/linecache,,:sys,"sys:x:3:3:sys:/dev:/bin/sh" library/logging,,:And, +library/logging,,:Doing,INFO:root:Doing something +library/logging,,:Finished,INFO:root:Finished +library/logging,,:logger,severity:logger name:message +library/logging,,:Look,WARNING:root:Look before you leap! +library/logging,,:message,severity:logger name:message library/logging,,:package1, library/logging,,:package2, +library/logging,,:port,host:port library/logging,,:root, +library/logging,,:So,INFO:root:So should this +library/logging,,:So,INFO:So should this +library/logging,,:Started,INFO:root:Started library/logging,,:This, -library/logging,,:port,host:port +library/logging,,:Watch,WARNING:root:Watch out! +library/logging.handlers,,:port,host:port library/mmap,,:i2,obj[i1:i2] -library/multiprocessing,,:queue,">>> QueueManager.register('get_queue', callable=lambda:queue)" +library/multiprocessing,,`,# Add more tasks using `put()` +library/multiprocessing,,`,# A test file for the `multiprocessing` package +library/multiprocessing,,`,# A test of `multiprocessing.Pool` class +library/multiprocessing,,`,# `BaseManager`. +library/multiprocessing,,`,`Cluster` is a subclass of `SyncManager` so it allows creation of +library/multiprocessing,,`,# create server for a `HostManager` object +library/multiprocessing,,`,# Depends on `multiprocessing` package -- tested with `processing-0.60` +library/multiprocessing,,`,`hostname` gives the name of the host. If hostname is not +library/multiprocessing,,`,# in the original order then consider using `Pool.map()` or library/multiprocessing,,`,">>> l._callmethod('__getitem__', (20,)) # equiv to `l[20]`" library/multiprocessing,,`,">>> l._callmethod('__getslice__', (2, 7)) # equiv to `l[2:7]`" -library/multiprocessing,,`,# `BaseManager`. -library/multiprocessing,,`,# `Pool.imap()` (which will save on the amount of code needed anyway). -library/multiprocessing,,`,# A test file for the `multiprocessing` package -library/multiprocessing,,`,# A test of `multiprocessing.Pool` class -library/multiprocessing,,`,# Add more tasks using `put()` -library/multiprocessing,,`,# create server for a `HostManager` object -library/multiprocessing,,`,# Depends on `multiprocessing` package -- tested with `processing-0.60` -library/multiprocessing,,`,# in the original order then consider using `Pool.map()` or library/multiprocessing,,`,# Not sure if we should synchronize access to `socket.accept()` method by library/multiprocessing,,`,# object. (We import `multiprocessing.reduction` to enable this pickling.) +library/multiprocessing,,`,# `Pool.imap()` (which will save on the amount of code needed anyway). +library/multiprocessing,,:queue,">>> QueueManager.register('get_queue', callable=lambda:queue)" library/multiprocessing,,`,# register the Foo class; make `f()` and `g()` accessible via proxy library/multiprocessing,,`,# register the Foo class; make `g()` and `_h()` accessible via proxy library/multiprocessing,,`,# register the generator function baz; use `GeneratorProxy` to make proxies -library/multiprocessing,,`,`Cluster` is a subclass of `SyncManager` so it allows creation of -library/multiprocessing,,`,`hostname` gives the name of the host. If hostname is not library/multiprocessing,,`,`slots` is used to specify the number of slots for processes on +library/nntplib,,:bytes,:bytes +library/nntplib,,:bytes,"['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']" +library/nntplib,,:lines,:lines +library/nntplib,,:lines,"['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']" library/optparse,,:len,"del parser.rargs[:len(value)]" library/os.path,,:foo,c:foo library/parser,,`,"""Make a function that raises an argument to the exponent `exp`.""" +library/pdb,,:lineno,filename:lineno +library/pdb,,:lineno,[filename:lineno | bpnumber [bpnumber ...]] +library/pickle,,:memory,"conn = sqlite3.connect("":memory:"")" library/posix,,`,"CFLAGS=""`getconf LFS_CFLAGS`"" OPT=""-g -O2 $CFLAGS""" +library/pprint,209,::,"'classifiers': ['Development Status :: 4 - Beta'," +library/pprint,209,::,"'Intended Audience :: Developers'," +library/pprint,209,::,"'License :: OSI Approved :: MIT License'," +library/pprint,209,::,"'Natural Language :: English'," +library/pprint,209,::,"'Operating System :: OS Independent'," +library/pprint,209,::,"'Programming Language :: Python'," +library/pprint,209,::,"'Programming Language :: Python :: 2'," +library/pprint,209,::,"'Programming Language :: Python :: 2.6'," +library/pprint,209,::,"'Programming Language :: Python :: 2.7'," +library/pprint,209,::,"'Topic :: Software Development :: Libraries'," +library/pprint,209,::,"'Topic :: Software Development :: Libraries :: Python Modules']," +library/profile,,:lineno,filename:lineno(function) library/profile,,:lineno,ncalls tottime percall cumtime percall filename:lineno(function) -library/profile,,:lineno,filename:lineno(function) +library/profile,,:lineno,"(sort by filename:lineno)," library/pyexpat,,:elem1, library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">" library/repr,,`,"return `obj`" library/smtplib,,:port,"as well as a regular host:port server." +library/smtplib,,:port,method must support that as well as a regular host:port +library/socket,,::,"(10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0))]" library/socket,,::,'5aef:2b::8' +library/socket,,:can,"return (can_id, can_dlc, data[:can_dlc])" +library/socket,,:len,fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) +library/sqlite3,,:age,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" +library/sqlite3,,:age,"select name_last, age from people where name_last=:who and age=:age" library/sqlite3,,:memory, -library/sqlite3,,:age,"select name_last, age from people where name_last=:who and age=:age" -library/sqlite3,,:who,"select name_last, age from people where name_last=:who and age=:age" +library/sqlite3,,:who,"cur.execute(""select * from people where name_last=:who and age=:age"", {""who"": who, ""age"": age})" +library/ssl,,:My,"Organizational Unit Name (eg, section) []:My Group" library/ssl,,:My,"Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc." -library/ssl,,:My,"Organizational Unit Name (eg, section) []:My Group" library/ssl,,:myserver,"Common Name (eg, YOUR name) []:myserver.mygroup.myorganization.com" library/ssl,,:MyState,State or Province Name (full name) [Some-State]:MyState library/ssl,,:ops,Email Address []:ops at myserver.mygroup.myorganization.com library/ssl,,:Some,"Locality Name (eg, city) []:Some City" library/ssl,,:US,Country Name (2 letter code) [AU]:US +library/stdtypes,,::,>>> a[::-1].tolist() +library/stdtypes,,::,>>> a[::2].tolist() +library/stdtypes,,:end,s[start:end] +library/stdtypes,,::,>>> hash(v[::-2]) == hash(b'abcefg'[::-2]) library/stdtypes,,:len,s[len(s):len(s)] -library/stdtypes,,:len,s[len(s):len(s)] +library/stdtypes,,::,>>> y = m[::2] library/string,,:end,s[start:end] -library/string,,:end,s[start:end] +library/subprocess,,`,"output=`dmesg | grep hda`" library/subprocess,,`,"output=`mycmd myarg`" -library/subprocess,,`,"output=`dmesg | grep hda`" +library/tarfile,,:bz2, library/tarfile,,:compression,filemode[:compression] library/tarfile,,:gz, -library/tarfile,,:bz2, +library/tarfile,,:xz,'a:xz' +library/tarfile,,:xz,'r:xz' +library/tarfile,,:xz,'w:xz' library/time,,:mm, library/time,,:ss, library/turtle,,::,Example:: +library/urllib2,,:password,"""joe:password at python.org""" library/urllib,,:port,:port -library/urllib2,,:password,"""joe:password at python.org""" +library/urllib.request,,:close,Connection:close +library/urllib.request,,:lang,"xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en"" lang=""en"">\n\n\n" +library/urllib.request,,:password,"""joe:password at python.org""" library/uuid,,:uuid,urn:uuid:12345678-1234-5678-1234-567812345678 -library/xmlrpclib,,:pass,http://user:pass at host:port/path -library/xmlrpclib,,:pass,user:pass -library/xmlrpclib,,:port,http://user:pass at host:port/path +library/xmlrpc.client,,:pass,http://user:pass at host:port/path +library/xmlrpc.client,,:pass,user:pass +library/xmlrpc.client,,:port,http://user:pass at host:port/path +license,,`,"``Software''), to deal in the Software without restriction, including" +license,,`,"THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND," +license,,`,* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND +license,,`,THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +license,,`,* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY license,,`,THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND license,,:zooko,mailto:zooko at zooko.com -license,,`,THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +packaging/examples,,`,This is the description of the ``foobar`` project. +packaging/setupcfg,,::,Development Status :: 3 - Alpha +packaging/setupcfg,,::,License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1) +packaging/setupscript,,::,"'Development Status :: 4 - Beta'," +packaging/setupscript,,::,"'Environment :: Console'," +packaging/setupscript,,::,"'Environment :: Web Environment'," +packaging/setupscript,,::,"'Intended Audience :: Developers'," +packaging/setupscript,,::,"'Intended Audience :: End Users/Desktop'," +packaging/setupscript,,::,"'Intended Audience :: System Administrators'," +packaging/setupscript,,::,"'License :: OSI Approved :: Python Software Foundation License'," +packaging/setupscript,,::,"'Operating System :: MacOS :: MacOS X'," +packaging/setupscript,,::,"'Operating System :: Microsoft :: Windows'," +packaging/setupscript,,::,"'Operating System :: POSIX'," +packaging/setupscript,,::,"'Programming Language :: Python'," +packaging/setupscript,,::,"'Topic :: Communications :: Email'," +packaging/setupscript,,::,"'Topic :: Office/Business'," +packaging/setupscript,,::,"'Topic :: Software Development :: Bug Tracking'," +packaging/tutorial,,::,1) License :: OSI Approved :: GNU General Public License (GPL) +packaging/tutorial,,::,2) License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +packaging/tutorial,,::,classifier = Development Status :: 3 - Alpha +packaging/tutorial,,::,License :: OSI Approved :: GNU General Public License (GPL) +packaging/tutorial,,::,Type the number of the license you wish to use or ? to try again:: 1 +reference/datamodel,,:max, reference/datamodel,,:step,a[i:j:step] -reference/datamodel,,:max, -reference/expressions,,:index,x[index:index] reference/expressions,,:datum,{key:datum...} reference/expressions,,`,`expressions...` +reference/expressions,,:index,x[index:index] reference/grammar,,:output,#diagram:output reference/grammar,,:rules,#diagram:rules +reference/grammar,,`,'`' testlist1 '`' reference/grammar,,:token,#diagram:token -reference/grammar,,`,'`' testlist1 '`' +reference/lexical_analysis,,`,", : . ` = ;" +reference/lexical_analysis,,`,$ ? ` reference/lexical_analysis,,:fileencoding,# vim:fileencoding= -reference/lexical_analysis,,`,", : . ` = ;" +tutorial/datastructures,,:value,It is also possible to delete a key:value tutorial/datastructures,,:value,key:value pairs within the braces adds initial key:value pairs -tutorial/datastructures,,:value,It is also possible to delete a key:value -tutorial/stdlib2,,:start,"fields = struct.unpack('=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(" -faq/programming,,::,for x in sequence[::-1]: -faq/windows,229,:EOF, at setlocal enableextensions & python -x %~f0 %* & goto :EOF -faq/windows,393,:REG,.py :REG_SZ: c:\\python.exe -u %s %s -library/bisect,32,:hi,all(val >= x for val in a[i:hi]) -library/bisect,42,:hi,all(val > x for val in a[i:hi]) -library/http.client,52,:port,host:port -library/nntplib,,:bytes,:bytes -library/nntplib,,:lines,:lines -library/nntplib,,:lines,"['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']" -library/nntplib,,:bytes,"['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']" -library/pickle,,:memory,"conn = sqlite3.connect("":memory:"")" -library/profile,,:lineno,"(sort by filename:lineno)," -library/socket,,::,"(10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0))]" -library/stdtypes,,:end,s[start:end] -library/stdtypes,,:end,s[start:end] -library/urllib.request,,:close,Connection:close -library/urllib.request,,:password,"""joe:password at python.org""" -library/urllib.request,,:lang,"xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en"" lang=""en"">\n\n\n" -library/xmlrpc.client,103,:pass,http://user:pass at host:port/path -library/xmlrpc.client,103,:port,http://user:pass at host:port/path -library/xmlrpc.client,103,:pass,user:pass -license,,`,* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY -license,,`,* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND -license,,`,"``Software''), to deal in the Software without restriction, including" -license,,`,"THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND," -reference/lexical_analysis,704,`,$ ? ` +whatsnew/2.7,1619,::,"ParseResult(scheme='http', netloc='[1080::8:800:200C:417A]'," +whatsnew/2.7,1619,::,>>> urlparse.urlparse('http://[1080::8:800:200C:417A]/foo') whatsnew/2.7,735,:Sunday,'2009:4:Sunday' +whatsnew/2.7,862,:Cookie,"export PYTHONWARNINGS=all,error:::Cookie:0" whatsnew/2.7,862,::,"export PYTHONWARNINGS=all,error:::Cookie:0" -whatsnew/2.7,862,:Cookie,"export PYTHONWARNINGS=all,error:::Cookie:0" -whatsnew/2.7,1619,::,>>> urlparse.urlparse('http://[1080::8:800:200C:417A]/foo') -whatsnew/2.7,1619,::,"ParseResult(scheme='http', netloc='[1080::8:800:200C:417A]'," -library/configparser,,`,# Set the optional `raw` argument of get() to True if you wish to disable -library/configparser,,`,# The optional `vars` argument is a dict with members that will take -library/configparser,,`,# The optional `fallback` argument can be used to provide a fallback value -library/configparser,,:option,${section:option} -library/configparser,,:system,path: ${Common:system_dir}/Library/Frameworks/ -library/configparser,,:home,my_dir: ${Common:home_dir}/twosheds -library/configparser,,:path,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} -library/configparser,,:Python,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} -library/pdb,,:lineno,[filename:lineno | bpnumber [bpnumber ...]] -library/pdb,,:lineno,filename:lineno -library/logging,,:Watch,WARNING:root:Watch out! -library/logging,,:So,INFO:root:So should this -library/logging,,:Started,INFO:root:Started -library/logging,,:Doing,INFO:root:Doing something -library/logging,,:Finished,INFO:root:Finished -library/logging,,:Look,WARNING:root:Look before you leap! -library/logging,,:So,INFO:So should this -library/logging,,:logger,severity:logger name:message -library/logging,,:message,severity:logger name:message +whatsnew/3.2,,:affe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:affe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,,:beef,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:beef,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,,:cafe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:cafe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,,:deaf,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:deaf,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') whatsnew/3.2,,:directory,... ${buildout:directory}/downloads/dist +whatsnew/3.2,,:directory,${buildout:directory}/downloads/dist +whatsnew/3.2,,::,"$ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'" +whatsnew/3.2,,:feed,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,,:feed,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,,:gz,">>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:" whatsnew/3.2,,:location,... zope9-location = ${zope9:location} +whatsnew/3.2,,:location,zope9-location = ${zope9:location} whatsnew/3.2,,:prefix,... zope-conf = ${custom:prefix}/etc/zope.conf -howto/logging,,:root,WARNING:root:Watch out! -howto/logging,,:Watch,WARNING:root:Watch out! -howto/logging,,:root,DEBUG:root:This message should go to the log file -howto/logging,,:This,DEBUG:root:This message should go to the log file -howto/logging,,:root,INFO:root:So should this -howto/logging,,:So,INFO:root:So should this -howto/logging,,:root,"WARNING:root:And this, too" -howto/logging,,:And,"WARNING:root:And this, too" -howto/logging,,:root,INFO:root:Started -howto/logging,,:Started,INFO:root:Started -howto/logging,,:root,INFO:root:Doing something -howto/logging,,:Doing,INFO:root:Doing something -howto/logging,,:root,INFO:root:Finished -howto/logging,,:Finished,INFO:root:Finished -howto/logging,,:root,WARNING:root:Look before you leap! -howto/logging,,:Look,WARNING:root:Look before you leap! -howto/logging,,:This,DEBUG:This message should appear on the console -howto/logging,,:So,INFO:So should this -howto/logging,,:And,"WARNING:And this, too" -howto/logging,,:logger,severity:logger name:message -howto/logging,,:message,severity:logger name:message -library/logging.handlers,,:port,host:port -library/imaplib,116,:MM,"""DD-Mmm-YYYY HH:MM:SS" -library/imaplib,116,:SS,"""DD-Mmm-YYYY HH:MM:SS" -whatsnew/3.2,,::,"$ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'" -howto/pyporting,75,::,# make sure to use :: Python *and* :: Python :: 3 so -howto/pyporting,75,::,"'Programming Language :: Python'," -howto/pyporting,75,::,'Programming Language :: Python :: 3' -whatsnew/3.2,,:gz,">>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:" -whatsnew/3.2,,:directory,${buildout:directory}/downloads/dist -whatsnew/3.2,,:location,zope9-location = ${zope9:location} whatsnew/3.2,,:prefix,zope-conf = ${custom:prefix}/etc/zope.conf -whatsnew/3.2,,:beef,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:cafe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:affe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:deaf,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:feed,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') -whatsnew/3.2,,:beef,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:cafe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:affe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:deaf,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -whatsnew/3.2,,:feed,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," -library/pprint,209,::,"'classifiers': ['Development Status :: 4 - Beta'," -library/pprint,209,::,"'Intended Audience :: Developers'," -library/pprint,209,::,"'License :: OSI Approved :: MIT License'," -library/pprint,209,::,"'Natural Language :: English'," -library/pprint,209,::,"'Operating System :: OS Independent'," -library/pprint,209,::,"'Programming Language :: Python'," -library/pprint,209,::,"'Programming Language :: Python :: 2'," -library/pprint,209,::,"'Programming Language :: Python :: 2.6'," -library/pprint,209,::,"'Programming Language :: Python :: 2.7'," -library/pprint,209,::,"'Topic :: Software Development :: Libraries'," -library/pprint,209,::,"'Topic :: Software Development :: Libraries :: Python Modules']," -packaging/examples,,`,This is the description of the ``foobar`` project. -packaging/setupcfg,,::,Development Status :: 3 - Alpha -packaging/setupcfg,,::,License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1) -packaging/setupscript,,::,"'Development Status :: 4 - Beta'," -packaging/setupscript,,::,"'Environment :: Console'," -packaging/setupscript,,::,"'Environment :: Web Environment'," -packaging/setupscript,,::,"'Intended Audience :: End Users/Desktop'," -packaging/setupscript,,::,"'Intended Audience :: Developers'," -packaging/setupscript,,::,"'Intended Audience :: System Administrators'," -packaging/setupscript,,::,"'License :: OSI Approved :: Python Software Foundation License'," -packaging/setupscript,,::,"'Operating System :: MacOS :: MacOS X'," -packaging/setupscript,,::,"'Operating System :: Microsoft :: Windows'," -packaging/setupscript,,::,"'Operating System :: POSIX'," -packaging/setupscript,,::,"'Programming Language :: Python'," -packaging/setupscript,,::,"'Topic :: Communications :: Email'," -packaging/setupscript,,::,"'Topic :: Office/Business'," -packaging/setupscript,,::,"'Topic :: Software Development :: Bug Tracking'," -packaging/tutorial,,::,1) License :: OSI Approved :: GNU General Public License (GPL) -packaging/tutorial,,::,2) License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) -packaging/tutorial,,::,Type the number of the license you wish to use or ? to try again:: 1 -packaging/tutorial,,::,classifier = Development Status :: 3 - Alpha -packaging/tutorial,,::,License :: OSI Approved :: GNU General Public License (GPL) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -49,6 +49,8 @@ This article explains the new features in Python 3.3, compared to 3.2. +.. pep-3118-update: + PEP 3118: New memoryview implementation and buffer protocol documentation ========================================================================= @@ -85,7 +87,9 @@ * Multi-dimensional comparisons are supported for any array type. * All array types are hashable if the exporting object is hashable - and the view is read-only. + and the view is read-only. (Contributed by Antoine Pitrou in + :issue:`13411`) + * Arbitrary slicing of any 1-D arrays type is supported. For example, it is now possible to reverse a memoryview in O(1) by using a negative step. @@ -167,19 +171,16 @@ * non-BMP strings (``U+10000-U+10FFFF``) use 4 bytes per codepoint. -The net effect is that for most applications, memory usage of string storage -should decrease significantly - especially compared to former wide unicode -builds - as, in many cases, strings will be pure ASCII even in international -contexts (because many strings store non-human language data, such as XML -fragments, HTTP headers, JSON-encoded data, etc.). We also hope that it -will, for the same reasons, increase CPU cache efficiency on non-trivial -applications. - -.. The memory usage of Python 3.3 is two to three times smaller than Python 3.2, - and a little bit better than Python 2.7, on a `Django benchmark - `_. - XXX The result should be moved in the PEP and a link to the PEP should - be added here. +The net effect is that for most applications, memory usage of string +storage should decrease significantly - especially compared to former +wide unicode builds - as, in many cases, strings will be pure ASCII +even in international contexts (because many strings store non-human +language data, such as XML fragments, HTTP headers, JSON-encoded data, +etc.). We also hope that it will, for the same reasons, increase CPU +cache efficiency on non-trivial applications. The memory usage of +Python 3.3 is two to three times smaller than Python 3.2, and a little +bit better than Python 2.7, on a Django benchmark (see the PEP for +details). PEP 3151: Reworking the OS and IO exception hierarchy @@ -261,9 +262,56 @@ containing 'yield' to be factored out and placed in another generator. Additionally, the subgenerator is allowed to return with a value, and the value is made available to the delegating generator. + While designed primarily for use in delegating to a subgenerator, the ``yield from`` expression actually allows delegation to arbitrary subiterators. +For simple iterators, ``yield from iterable`` is essentially just a shortened +form of ``for item in iterable: yield item``:: + + >>> def g(x): + ... yield from range(x, 0, -1) + ... yield from range(x) + ... + >>> list(g(5)) + [5, 4, 3, 2, 1, 0, 1, 2, 3, 4] + +However, unlike an ordinary loop, ``yield from`` allows subgenerators to +receive sent and thrown values directly from the calling scope, and +return a final value to the outer generator:: + + >>> def accumulate(start=0): + ... tally = start + ... while 1: + ... next = yield + ... if next is None: + ... return tally + ... tally += next + ... + >>> def gather_tallies(tallies, start=0): + ... while 1: + ... tally = yield from accumulate() + ... tallies.append(tally) + ... + >>> tallies = [] + >>> acc = gather_tallies(tallies) + >>> next(acc) # Ensure the accumulator is ready to accept values + >>> for i in range(10): + ... acc.send(i) + ... + >>> acc.send(None) # Finish the first tally + >>> for i in range(5): + ... acc.send(i) + ... + >>> acc.send(None) # Finish the second tally + >>> tallies + [45, 10] + +The main principle driving this change is to allow even generators that are +designed to be used with the ``send`` and ``throw`` methods to be split into +multiple subgenerators as easily as a single large function can be split into +multiple subfunctions. + (Implementation by Greg Ewing, integrated into 3.3 by Renaud Blanch, Ryan Kelly and Nick Coghlan, documentation by Zbigniew J?drzejewski-Szmek and Nick Coghlan) @@ -330,6 +378,21 @@ KeyError('x',) +PEP 414: Explicit Unicode literals +====================================== + +:pep:`414` - Explicit Unicode literals + PEP written by Armin Ronacher. + +To ease the transition from Python 2 for Unicode aware Python applications +that make heavy use of Unicode literals, Python 3.3 once again supports the +"``u``" prefix for string literals. This prefix has no semantic significance +in Python 3, it is provided solely to reduce the number of purely mechanical +changes in migrating to Python 3, making it easier for developers to focus on +the more significant semantic changes (such as the stricter default +separation of binary and text data). + + PEP 3155: Qualified name for classes and functions ================================================== @@ -411,10 +474,6 @@ (:issue:`12170`) -* Memoryview objects are now hashable when the underlying object is hashable. - - (Contributed by Antoine Pitrou in :issue:`13411`) - New and Improved Modules ======================== diff --git a/Include/abstract.h b/Include/abstract.h --- a/Include/abstract.h +++ b/Include/abstract.h @@ -1026,7 +1026,7 @@ PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); /* - Returns the sequence, o, as a tuple, unless it's already a + Returns the sequence, o, as a list, unless it's already a tuple or list. Use PySequence_Fast_GET_ITEM to access the members of this list, and PySequence_Fast_GET_SIZE to get its length. diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 3 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 0 +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.3.0a0" +#define PY_VERSION "3.3.0a1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Include/pytime.h b/Include/pytime.h --- a/Include/pytime.h +++ b/Include/pytime.h @@ -3,6 +3,7 @@ #define Py_PYTIME_H #include "pyconfig.h" /* include for defines */ +#include "object.h" /************************************************************************** Symbols and macros to supply platform-independent interfaces to time related @@ -37,6 +38,16 @@ ((tv_end.tv_sec - tv_start.tv_sec) + \ (tv_end.tv_usec - tv_start.tv_usec) * 0.000001) +#ifndef Py_LIMITED_API +/* Convert a number of seconds, int or float, to a timespec structure. + nsec is always in the range [0; 999999999]. For example, -1.2 is converted + to (-2, 800000000). */ +PyAPI_FUNC(int) _PyTime_ObjectToTimespec( + PyObject *obj, + time_t *sec, + long *nsec); +#endif + /* Dummy to force linking. */ PyAPI_FUNC(void) _PyTime_Init(void); diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -499,17 +499,14 @@ do { \ switch ((kind)) { \ case PyUnicode_1BYTE_KIND: { \ - assert(value <= 0xff); \ ((Py_UCS1 *)(data))[(index)] = (Py_UCS1)(value); \ break; \ } \ case PyUnicode_2BYTE_KIND: { \ - assert(value <= 0xffff); \ ((Py_UCS2 *)(data))[(index)] = (Py_UCS2)(value); \ break; \ } \ default: { \ - assert(value <= 0x10ffff); \ assert((kind) == PyUnicode_4BYTE_KIND); \ ((Py_UCS4 *)(data))[(index)] = (Py_UCS4)(value); \ } \ diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -73,7 +73,7 @@ 3.2 3.1 2011 PSF yes 3.2.1 3.2 2011 PSF yes 3.2.2 3.2.1 2011 PSF yes - 3.3 3.2 2012 PSF yes + 3.3.0 3.2 2012 PSF yes Footnotes: diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -114,36 +114,21 @@ def update(self, other): if self._pending_removals: self._commit_removals() - if isinstance(other, self.__class__): - self.data.update(other.data) - else: - for element in other: - self.add(element) + for element in other: + self.add(element) def __ior__(self, other): self.update(other) return self - # Helper functions for simple delegating methods. - def _apply(self, other, method): - if not isinstance(other, self.__class__): - other = self.__class__(other) - newdata = method(other.data) - newset = self.__class__() - newset.data = newdata + def difference(self, other): + newset = self.copy() + newset.difference_update(other) return newset - - def difference(self, other): - return self._apply(other, self.data.difference) __sub__ = difference def difference_update(self, other): - if self._pending_removals: - self._commit_removals() - if self is other: - self.data.clear() - else: - self.data.difference_update(ref(item) for item in other) + self.__isub__(other) def __isub__(self, other): if self._pending_removals: self._commit_removals() @@ -154,13 +139,11 @@ return self def intersection(self, other): - return self._apply(other, self.data.intersection) + return self.__class__(item for item in other if item in self) __and__ = intersection def intersection_update(self, other): - if self._pending_removals: - self._commit_removals() - self.data.intersection_update(ref(item) for item in other) + self.__iand__(other) def __iand__(self, other): if self._pending_removals: self._commit_removals() @@ -169,17 +152,17 @@ def issubset(self, other): return self.data.issubset(ref(item) for item in other) - __lt__ = issubset + __le__ = issubset - def __le__(self, other): - return self.data <= set(ref(item) for item in other) + def __lt__(self, other): + return self.data < set(ref(item) for item in other) def issuperset(self, other): return self.data.issuperset(ref(item) for item in other) - __gt__ = issuperset + __ge__ = issuperset - def __ge__(self, other): - return self.data >= set(ref(item) for item in other) + def __gt__(self, other): + return self.data > set(ref(item) for item in other) def __eq__(self, other): if not isinstance(other, self.__class__): @@ -187,27 +170,24 @@ return self.data == set(ref(item) for item in other) def symmetric_difference(self, other): - return self._apply(other, self.data.symmetric_difference) + newset = self.copy() + newset.symmetric_difference_update(other) + return newset __xor__ = symmetric_difference def symmetric_difference_update(self, other): - if self._pending_removals: - self._commit_removals() - if self is other: - self.data.clear() - else: - self.data.symmetric_difference_update(ref(item) for item in other) + self.__ixor__(other) def __ixor__(self, other): if self._pending_removals: self._commit_removals() if self is other: self.data.clear() else: - self.data.symmetric_difference_update(ref(item) for item in other) + self.data.symmetric_difference_update(ref(item, self._remove) for item in other) return self def union(self, other): - return self._apply(other, self.data.union) + return self.__class__(e for s in (self, other) for e in s) __or__ = union def isdisjoint(self, other): diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -50,7 +50,8 @@ from concurrent.futures import _base import queue import multiprocessing -from multiprocessing.queues import SimpleQueue, SentinelReady, Full +from multiprocessing.queues import SimpleQueue, Full +from multiprocessing.connection import wait import threading import weakref @@ -212,6 +213,8 @@ for p in processes.values(): p.join() + reader = result_queue._reader + while True: _add_call_item_to_queue(pending_work_items, work_ids_queue, @@ -219,9 +222,10 @@ sentinels = [p.sentinel for p in processes.values()] assert sentinels - try: - result_item = result_queue.get(sentinels=sentinels) - except SentinelReady: + ready = wait([reader] + sentinels) + if reader in ready: + result_item = reader.recv() + else: # Mark the process pool broken so that submits fail right now. executor = executor_reference() if executor is not None: diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.3a0" +__version__ = "3.3.0a1" #--end constants-- diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -260,7 +260,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', fullname + tup = 'bdist_msi', self.target_version or 'any', installer_name self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,12 +1,12 @@ """Tests for distutils.command.bdist_msi.""" +import os +import sys import unittest -import sys - from test.support import run_unittest - from distutils.tests import support - at unittest.skipUnless(sys.platform=="win32", "These tests are only for win32") + + at unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows') class BDistMSITestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): @@ -14,9 +14,18 @@ def test_minimal(self): # minimal test XXX need more tests from distutils.command.bdist_msi import bdist_msi - pkg_pth, dist = self.create_dist() + project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() + cmd.run() + + bdists = os.listdir(os.path.join(project_dir, 'dist')) + self.assertEqual(bdists, ['foo-0.1.msi']) + + # bug #13719: upload ignores bdist_msi files + self.assertEqual(dist.dist_files, + [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) + def test_suite(): return unittest.makeSuite(BDistMSITestCase) diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.3a0" +IDLE_VERSION = "3.3.0a1" diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -32,7 +32,7 @@ # SUCH DAMAGE. # -__all__ = [ 'Client', 'Listener', 'Pipe' ] +__all__ = [ 'Client', 'Listener', 'Pipe', 'wait' ] import io import os @@ -58,8 +58,6 @@ raise win32 = None -_select = _eintr_retry(select.select) - # # # @@ -122,15 +120,6 @@ else: raise ValueError('address type of %r unrecognized' % address) - -class SentinelReady(Exception): - """ - Raised when a sentinel is ready when polling. - """ - def __init__(self, *args): - Exception.__init__(self, *args) - self.sentinels = args[0] - # # Connection classes # @@ -268,11 +257,11 @@ (offset + size) // itemsize]) return size - def recv(self, sentinels=None): + def recv(self): """Receive a (picklable) object""" self._check_closed() self._check_readable() - buf = self._recv_bytes(sentinels=sentinels) + buf = self._recv_bytes() return pickle.loads(buf.getbuffer()) def poll(self, timeout=0.0): @@ -290,85 +279,80 @@ Overlapped I/O is used, so the handles must have been created with FILE_FLAG_OVERLAPPED. """ - _buffered = b'' + _got_empty_message = False def _close(self, _CloseHandle=win32.CloseHandle): _CloseHandle(self._handle) def _send_bytes(self, buf): - overlapped = win32.WriteFile(self._handle, buf, overlapped=True) - nwritten, complete = overlapped.GetOverlappedResult(True) - assert complete + ov, err = win32.WriteFile(self._handle, buf, overlapped=True) + try: + if err == win32.ERROR_IO_PENDING: + waitres = win32.WaitForMultipleObjects( + [ov.event], False, INFINITE) + assert waitres == WAIT_OBJECT_0 + except: + ov.cancel() + raise + finally: + nwritten, err = ov.GetOverlappedResult(True) + assert err == 0 assert nwritten == len(buf) - def _recv_bytes(self, maxsize=None, sentinels=()): - if sentinels: - self._poll(-1.0, sentinels) - buf = io.BytesIO() - firstchunk = self._buffered - if firstchunk: - lenfirstchunk = len(firstchunk) - buf.write(firstchunk) - self._buffered = b'' + def _recv_bytes(self, maxsize=None): + if self._got_empty_message: + self._got_empty_message = False + return io.BytesIO() else: - # A reasonable size for the first chunk transfer - bufsize = 128 - if maxsize is not None and maxsize < bufsize: - bufsize = maxsize + bsize = 128 if maxsize is None else min(maxsize, 128) try: - overlapped = win32.ReadFile(self._handle, bufsize, overlapped=True) - lenfirstchunk, complete = overlapped.GetOverlappedResult(True) - firstchunk = overlapped.getbuffer() - assert lenfirstchunk == len(firstchunk) + ov, err = win32.ReadFile(self._handle, bsize, + overlapped=True) + try: + if err == win32.ERROR_IO_PENDING: + waitres = win32.WaitForMultipleObjects( + [ov.event], False, INFINITE) + assert waitres == WAIT_OBJECT_0 + except: + ov.cancel() + raise + finally: + nread, err = ov.GetOverlappedResult(True) + if err == 0: + f = io.BytesIO() + f.write(ov.getbuffer()) + return f + elif err == win32.ERROR_MORE_DATA: + return self._get_more_data(ov, maxsize) except IOError as e: if e.winerror == win32.ERROR_BROKEN_PIPE: raise EOFError - raise - buf.write(firstchunk) - if complete: - return buf - navail, nleft = win32.PeekNamedPipe(self._handle) - if maxsize is not None and lenfirstchunk + nleft > maxsize: - return None - if nleft > 0: - overlapped = win32.ReadFile(self._handle, nleft, overlapped=True) - res, complete = overlapped.GetOverlappedResult(True) - assert res == nleft - assert complete - buf.write(overlapped.getbuffer()) - return buf + else: + raise + raise RuntimeError("shouldn't get here; expected KeyboardInterrupt") - def _poll(self, timeout, sentinels=()): - # Fast non-blocking path - navail, nleft = win32.PeekNamedPipe(self._handle) - if navail > 0: + def _poll(self, timeout): + if (self._got_empty_message or + win32.PeekNamedPipe(self._handle)[0] != 0): return True - elif timeout == 0.0: - return False - # Blocking: use overlapped I/O - if timeout < 0.0: - timeout = INFINITE - else: - timeout = int(timeout * 1000 + 0.5) - overlapped = win32.ReadFile(self._handle, 1, overlapped=True) - try: - handles = [overlapped.event] - handles += sentinels - res = win32.WaitForMultipleObjects(handles, False, timeout) - finally: - # Always cancel overlapped I/O in the same thread - # (because CancelIoEx() appears only in Vista) - overlapped.cancel() - if res == WAIT_TIMEOUT: - return False - idx = res - WAIT_OBJECT_0 - if idx == 0: - # I/O was successful, store received data - overlapped.GetOverlappedResult(True) - self._buffered += overlapped.getbuffer() - return True - assert 0 < idx < len(handles) - raise SentinelReady([handles[idx]]) + if timeout < 0: + timeout = None + return bool(wait([self], timeout)) + + def _get_more_data(self, ov, maxsize): + buf = ov.getbuffer() + f = io.BytesIO() + f.write(buf) + left = win32.PeekNamedPipe(self._handle)[1] + assert left > 0 + if maxsize is not None and len(buf) + left > maxsize: + self._bad_message_length() + ov, err = win32.ReadFile(self._handle, left, overlapped=True) + rbytes, err = ov.GetOverlappedResult(True) + assert err == 0 + assert rbytes == left + f.write(ov.getbuffer()) + return f class Connection(_ConnectionBase): @@ -397,17 +381,11 @@ break buf = buf[n:] - def _recv(self, size, sentinels=(), read=_read): + def _recv(self, size, read=_read): buf = io.BytesIO() handle = self._handle - if sentinels: - handles = [handle] + sentinels remaining = size while remaining > 0: - if sentinels: - r = _select(handles, [], [])[0] - if handle not in r: - raise SentinelReady(r) chunk = read(handle, remaining) n = len(chunk) if n == 0: @@ -428,17 +406,17 @@ if n > 0: self._send(buf) - def _recv_bytes(self, maxsize=None, sentinels=()): - buf = self._recv(4, sentinels) + def _recv_bytes(self, maxsize=None): + buf = self._recv(4) size, = struct.unpack("!i", buf.getvalue()) if maxsize is not None and size > maxsize: return None - return self._recv(size, sentinels) + return self._recv(size) def _poll(self, timeout): if timeout < 0.0: timeout = None - r = _select([self._handle], [], [], timeout)[0] + r = wait([self._handle], timeout) return bool(r) @@ -559,7 +537,8 @@ ) overlapped = win32.ConnectNamedPipe(h1, overlapped=True) - overlapped.GetOverlappedResult(True) + _, err = overlapped.GetOverlappedResult(True) + assert err == 0 c1 = PipeConnection(h1, writable=duplex) c2 = PipeConnection(h2, readable=duplex) @@ -633,39 +612,40 @@ ''' def __init__(self, address, backlog=None): self._address = address - handle = win32.CreateNamedPipe( - address, win32.PIPE_ACCESS_DUPLEX | - win32.FILE_FLAG_FIRST_PIPE_INSTANCE, + self._handle_queue = [self._new_handle(first=True)] + + self._last_accepted = None + sub_debug('listener created with address=%r', self._address) + self.close = Finalize( + self, PipeListener._finalize_pipe_listener, + args=(self._handle_queue, self._address), exitpriority=0 + ) + + def _new_handle(self, first=False): + flags = win32.PIPE_ACCESS_DUPLEX | win32.FILE_FLAG_OVERLAPPED + if first: + flags |= win32.FILE_FLAG_FIRST_PIPE_INSTANCE + return win32.CreateNamedPipe( + self._address, flags, win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE | win32.PIPE_WAIT, win32.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, win32.NMPWAIT_WAIT_FOREVER, win32.NULL ) - self._handle_queue = [handle] - self._last_accepted = None - - sub_debug('listener created with address=%r', self._address) - - self.close = Finalize( - self, PipeListener._finalize_pipe_listener, - args=(self._handle_queue, self._address), exitpriority=0 - ) def accept(self): - newhandle = win32.CreateNamedPipe( - self._address, win32.PIPE_ACCESS_DUPLEX, - win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE | - win32.PIPE_WAIT, - win32.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, - win32.NMPWAIT_WAIT_FOREVER, win32.NULL - ) - self._handle_queue.append(newhandle) + self._handle_queue.append(self._new_handle()) handle = self._handle_queue.pop(0) + ov = win32.ConnectNamedPipe(handle, overlapped=True) try: - win32.ConnectNamedPipe(handle, win32.NULL) - except WindowsError as e: - if e.winerror != win32.ERROR_PIPE_CONNECTED: - raise + res = win32.WaitForMultipleObjects([ov.event], False, INFINITE) + except: + ov.cancel() + win32.CloseHandle(handle) + raise + finally: + _, err = ov.GetOverlappedResult(True) + assert err == 0 return PipeConnection(handle) @staticmethod @@ -684,7 +664,8 @@ win32.WaitNamedPipe(address, 1000) h = win32.CreateFile( address, win32.GENERIC_READ | win32.GENERIC_WRITE, - 0, win32.NULL, win32.OPEN_EXISTING, 0, win32.NULL + 0, win32.NULL, win32.OPEN_EXISTING, + win32.FILE_FLAG_OVERLAPPED, win32.NULL ) except WindowsError as e: if e.winerror not in (win32.ERROR_SEM_TIMEOUT, @@ -773,6 +754,125 @@ import xmlrpc.client as xmlrpclib return ConnectionWrapper(Client(*args, **kwds), _xml_dumps, _xml_loads) +# +# Wait +# + +if sys.platform == 'win32': + + def _exhaustive_wait(handles, timeout): + # Return ALL handles which are currently signalled. (Only + # returning the first signalled might create starvation issues.) + L = list(handles) + ready = [] + while L: + res = win32.WaitForMultipleObjects(L, False, timeout) + if res == WAIT_TIMEOUT: + break + elif WAIT_OBJECT_0 <= res < WAIT_OBJECT_0 + len(L): + res -= WAIT_OBJECT_0 + elif WAIT_ABANDONED_0 <= res < WAIT_ABANDONED_0 + len(L): + res -= WAIT_ABANDONED_0 + else: + raise RuntimeError('Should not get here') + ready.append(L[res]) + L = L[res+1:] + timeout = 0 + return ready + + _ready_errors = {win32.ERROR_BROKEN_PIPE, win32.ERROR_NETNAME_DELETED} + + def wait(object_list, timeout=None): + ''' + Wait till an object in object_list is ready/readable. + + Returns list of those objects in object_list which are ready/readable. + ''' + if timeout is None: + timeout = INFINITE + elif timeout < 0: + timeout = 0 + else: + timeout = int(timeout * 1000 + 0.5) + + object_list = list(object_list) + waithandle_to_obj = {} + ov_list = [] + ready_objects = set() + ready_handles = set() + + try: + for o in object_list: + try: + fileno = getattr(o, 'fileno') + except AttributeError: + waithandle_to_obj[o.__index__()] = o + else: + # start an overlapped read of length zero + try: + ov, err = win32.ReadFile(fileno(), 0, True) + except OSError as e: + err = e.winerror + if err not in _ready_errors: + raise + if err == win32.ERROR_IO_PENDING: + ov_list.append(ov) + waithandle_to_obj[ov.event] = o + else: + # If o.fileno() is an overlapped pipe handle and + # err == 0 then there is a zero length message + # in the pipe, but it HAS NOT been consumed. + ready_objects.add(o) + timeout = 0 + + ready_handles = _exhaustive_wait(waithandle_to_obj.keys(), timeout) + finally: + # request that overlapped reads stop + for ov in ov_list: + ov.cancel() + + # wait for all overlapped reads to stop + for ov in ov_list: + try: + _, err = ov.GetOverlappedResult(True) + except OSError as e: + err = e.winerror + if err not in _ready_errors: + raise + if err != win32.ERROR_OPERATION_ABORTED: + o = waithandle_to_obj[ov.event] + ready_objects.add(o) + if err == 0: + # If o.fileno() is an overlapped pipe handle then + # a zero length message HAS been consumed. + if hasattr(o, '_got_empty_message'): + o._got_empty_message = True + + ready_objects.update(waithandle_to_obj[h] for h in ready_handles) + return [o for o in object_list if o in ready_objects] + +else: + + def wait(object_list, timeout=None): + ''' + Wait till an object in object_list is ready/readable. + + Returns list of those objects in object_list which are ready/readable. + ''' + if timeout is not None: + if timeout <= 0: + return select.select(object_list, [], [], 0)[0] + else: + deadline = time.time() + timeout + while True: + try: + return select.select(object_list, [], [], timeout)[0] + except OSError as e: + if e.errno != errno.EINTR: + raise + if timeout is not None: + timeout = deadline - time.time() + # Late import because of circular import from multiprocessing.forking import duplicate, close diff --git a/Lib/multiprocessing/queues.py b/Lib/multiprocessing/queues.py --- a/Lib/multiprocessing/queues.py +++ b/Lib/multiprocessing/queues.py @@ -44,7 +44,7 @@ from queue import Empty, Full import _multiprocessing -from multiprocessing.connection import Pipe, SentinelReady +from multiprocessing.connection import Pipe from multiprocessing.synchronize import Lock, BoundedSemaphore, Semaphore, Condition from multiprocessing.util import debug, info, Finalize, register_after_fork from multiprocessing.forking import assert_spawning @@ -360,6 +360,7 @@ def __init__(self): self._reader, self._writer = Pipe(duplex=False) self._rlock = Lock() + self._poll = self._reader.poll if sys.platform == 'win32': self._wlock = None else: @@ -367,7 +368,7 @@ self._make_methods() def empty(self): - return not self._reader.poll() + return not self._poll() def __getstate__(self): assert_spawning(self) @@ -380,10 +381,10 @@ def _make_methods(self): recv = self._reader.recv racquire, rrelease = self._rlock.acquire, self._rlock.release - def get(*, sentinels=None): + def get(): racquire() try: - return recv(sentinels) + return recv() finally: rrelease() self.get = get diff --git a/Lib/packaging/command/bdist_msi.py b/Lib/packaging/command/bdist_msi.py --- a/Lib/packaging/command/bdist_msi.py +++ b/Lib/packaging/command/bdist_msi.py @@ -261,7 +261,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', fullname + tup = 'bdist_msi', self.target_version or 'any', installer_name self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/packaging/database.py b/Lib/packaging/database.py --- a/Lib/packaging/database.py +++ b/Lib/packaging/database.py @@ -19,6 +19,7 @@ 'get_distributions', 'get_distribution', 'get_file_users', 'provides_distribution', 'obsoletes_distribution', 'enable_cache', 'disable_cache', 'clear_cache', + # XXX these functions' names look like get_file_users but are not related 'get_file_path', 'get_file'] diff --git a/Lib/packaging/tests/test_command_bdist_msi.py b/Lib/packaging/tests/test_command_bdist_msi.py --- a/Lib/packaging/tests/test_command_bdist_msi.py +++ b/Lib/packaging/tests/test_command_bdist_msi.py @@ -1,20 +1,29 @@ """Tests for distutils.command.bdist_msi.""" +import os import sys from packaging.tests import unittest, support + at unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows') class BDistMSITestCase(support.TempdirManager, support.LoggingCatcher, unittest.TestCase): - @unittest.skipUnless(sys.platform == "win32", "runs only on win32") def test_minimal(self): # minimal test XXX need more tests from packaging.command.bdist_msi import bdist_msi - pkg_pth, dist = self.create_dist() + project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() + cmd.run() + + bdists = os.listdir(os.path.join(project_dir, 'dist')) + self.assertEqual(bdists, ['foo-0.1.msi']) + + # bug #13719: upload ignores bdist_msi files + self.assertEqual(dist.dist_files, + [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) def test_suite(): diff --git a/Lib/pickle.py b/Lib/pickle.py --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -297,8 +297,8 @@ f(self, obj) # Call unbound method with explicit self return - # Check copyreg.dispatch_table - reduce = dispatch_table.get(t) + # Check private dispatch table if any, or else copyreg.dispatch_table + reduce = getattr(self, 'dispatch_table', dispatch_table).get(t) if reduce: rv = reduce(obj) else: diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,30 +1,31 @@ -# Autogenerated by Sphinx on Thu Apr 28 07:53:12 2011 +# -*- coding: utf-8 -*- +# Autogenerated by Sphinx on Sun Mar 4 16:11:27 2012 topics = {'assert': '\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', - 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nWith the exception of bytes literals, these all correspond to\nimmutable data types, and hence the object's identity is less\nimportant than its value. Multiple evaluations of literals with the\nsame value (either the same occurrence in the program text or a\ndifferent occurrence) may obtain the same object or a different object\nwith the same value.\n", - 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', + 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nAll literals correspond to immutable data types, and hence the\nobject's identity is less important than its value. Multiple\nevaluations of literals with the same value (either the same\noccurrence in the program text or a different occurrence) may obtain\nthe same object or a different object with the same value.\n", + 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier (which can\nbe customized by overriding the ``__getattr__()`` method). If this\nattribute is not available, the exception ``AttributeError`` is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe ``*`` (multiplication) operator yields the product of its\narguments. The arguments must either both be numbers, or one argument\nmust be an integer and the other must be a sequence. In the former\ncase, the numbers are converted to a common type and then multiplied\ntogether. In the latter case, sequence repetition is performed; a\nnegative repetition factor yields an empty sequence.\n\nThe ``/`` (division) and ``//`` (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Integer division yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the ``ZeroDivisionError`` exception.\n\nThe ``%`` (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n``ZeroDivisionError`` exception. The arguments may be floating point\nnumbers, e.g., ``3.14%0.7`` equals ``0.34`` (since ``3.14`` equals\n``4*0.7 + 0.34``.) The modulo operator always yields a result with\nthe same sign as its second operand (or zero); the absolute value of\nthe result is strictly smaller than the absolute value of the second\noperand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: ``x == (x//y)*y + (x%y)``. Floor division and modulo are\nalso connected with the built-in function ``divmod()``: ``divmod(x, y)\n== (x//y, x%y)``. [2].\n\nIn addition to performing the modulo operation on numbers, the ``%``\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *Old String Formatting Operations*.\n\nThe floor division operator, the modulo operator, and the ``divmod()``\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the ``abs()`` function if appropriate.\n\nThe ``+`` (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe ``-`` (subtraction) operator yields the difference of its\narguments. The numeric arguments are first converted to a common\ntype.\n', 'bitwise': '\nBinary bitwise operations\n*************************\n\nEach of the three bitwise operations has a different priority level:\n\n and_expr ::= shift_expr | and_expr "&" shift_expr\n xor_expr ::= and_expr | xor_expr "^" and_expr\n or_expr ::= xor_expr | or_expr "|" xor_expr\n\nThe ``&`` operator yields the bitwise AND of its arguments, which must\nbe integers.\n\nThe ``^`` operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be integers.\n\nThe ``|`` operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be integers.\n', 'bltin-code-objects': '\nCode Objects\n************\n\nCode objects are used by the implementation to represent "pseudo-\ncompiled" executable Python code such as a function body. They differ\nfrom function objects because they don\'t contain a reference to their\nglobal execution environment. Code objects are returned by the built-\nin ``compile()`` function and can be extracted from function objects\nthrough their ``__code__`` attribute. See also the ``code`` module.\n\nA code object can be executed or evaluated by passing it (instead of a\nsource string) to the ``exec()`` or ``eval()`` built-in functions.\n\nSee *The standard type hierarchy* for more information.\n', - 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*). It supports\nno special operations. There is exactly one ellipsis object, named\n``Ellipsis`` (a built-in name).\n\nIt is written as ``Ellipsis`` or ``...``.\n', - 'bltin-null-object': "\nThe Null Object\n***************\n\nThis object is returned by functions that don't explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named ``None`` (a built-in name).\n\nIt is written as ``None``.\n", + 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*), but may also\nbe used in other situations where a sentinel value other than ``None``\nis needed. It supports no special operations. There is exactly one\nellipsis object, named ``Ellipsis`` (a built-in name).\n``type(Ellipsis)()`` produces the ``Ellipsis`` singleton.\n\nIt is written as ``Ellipsis`` or ``...``.\n', + 'bltin-null-object': "\nThe Null Object\n***************\n\nThis object is returned by functions that don't explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named ``None`` (a built-in name). ``type(None)()`` produces\nthe same singleton.\n\nIt is written as ``None``.\n", 'bltin-type-objects': "\nType Objects\n************\n\nType objects represent the various object types. An object's type is\naccessed by the built-in function ``type()``. There are no special\noperations on types. The standard module ``types`` defines names for\nall standard built-in types.\n\nTypes are written like this: ````.\n", 'booleans': '\nBoolean operations\n******************\n\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: ``False``, ``None``, numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a ``__bool__()`` method.\n\nThe operator ``not`` yields ``True`` if its argument is false,\n``False`` otherwise.\n\nThe expression ``x and y`` first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression ``x or y`` first evaluates *x*; if *x* is true, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\n(Note that neither ``and`` nor ``or`` restrict the value and type they\nreturn to ``False`` and ``True``, but rather return the last evaluated\nargument. This is sometimes useful, e.g., if ``s`` is a string that\nshould be replaced by a default value if it is empty, the expression\n``s or \'foo\'`` yields the desired value. Because ``not`` has to\ninvent a value anyway, it does not bother to return a value of the\nsame type as its argument, so e.g., ``not \'foo\'`` yields ``False``,\nnot ``\'\'``.)\n', 'break': '\nThe ``break`` statement\n***********************\n\n break_stmt ::= "break"\n\n``break`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition\nwithin that loop.\n\nIt terminates the nearest enclosing loop, skipping the optional\n``else`` clause if the loop has one.\n\nIf a ``for`` loop is terminated by ``break``, the loop control target\nkeeps its current value.\n\nWhen ``break`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the loop.\n', 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n', - 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to a sequence. Elements from this\nsequence are treated as if they were additional positional arguments;\nif there are positional arguments *x1*,..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to an iterable. Elements from this\niterable are treated as if they were additional positional arguments;\nif there are positional arguments *x1*, ..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', + 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is set as the context of the new exception. The exception\ninformation is not available to the program during execution of the\n``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that the same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', 'continue': '\nThe ``continue`` statement\n**************************\n\n continue_stmt ::= "continue"\n\n``continue`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition or\n``finally`` clause within that loop. It continues with the next cycle\nof the nearest enclosing loop.\n\nWhen ``continue`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nstarting the next loop cycle.\n', 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the other\n is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', - 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n', + 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__bytes__(self)\n\n Called by ``bytes()`` to compute a byte-string representation of an\n object. This should return a ``bytes`` object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\n Note: Note by default the ``__hash__()`` values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the order in which keys are\n retrieved from a dict. Note Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also ``PYTHONHASHSEED``.\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n', 'debugger': '\n``pdb`` --- The Python Debugger\n*******************************\n\nThe module ``pdb`` defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n``Pdb``. This is currently undocumented but easily understood by\nreading the source. The extension interface uses the modules ``bdb``\nand ``cmd``.\n\nThe debugger\'s prompt is ``(Pdb)``. Typical usage to run a program\nunder control of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\n``pdb.py`` can also be invoked as a script to debug other scripts.\nFor example:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: ``pdb.py`` now accepts a ``-c`` option that\nexecutes commands as if given in a ``.pdbrc`` file, see *Debugger\nCommands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the ``continue`` command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type ``continue``, or you can\n step through the statement using ``step`` or ``next`` (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module ``__main__`` is used. (See\n the explanation of the built-in ``exec()`` or ``eval()``\n functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When ``runeval()`` returns, it returns the\n value of the expression. Otherwise this function is similar to\n ``run()``.\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When ``runcall()`` returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n ``sys.last_traceback``.\n\nThe ``run*`` functions and ``set_trace()`` are aliases for\ninstantiating the ``Pdb`` class and calling the method of the same\nname. If you want to access further features, you have to do this\nyourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None, nosigint=False)\n\n ``Pdb`` is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying ``cmd.Cmd`` class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n By default, Pdb sets a handler for the SIGINT signal (which is sent\n when the user presses Ctrl-C on the console) when you give a\n ``continue`` command. This allows you to break into the debugger\n again by pressing Ctrl-C. If you want Pdb not to touch the SIGINT\n handler, set *nosigint* tot true.\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n New in version 3.2: The *nosigint* argument. Previously, a SIGINT\n handler was never set by Pdb.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n``h(elp)`` means that either ``h`` or ``help`` can be used to enter\nthe help command (but not ``he`` or ``hel``, nor ``H`` or ``Help`` or\n``HELP``). Arguments to commands must be separated by whitespace\n(spaces or tabs). Optional arguments are enclosed in square brackets\n(``[]``) in the command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n(``|``).\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a ``list`` command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint (``!``). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by\n``;;``. (A single ``;`` is not used as it is the separator for\nmultiple commands in a line that is passed to the Python parser.) No\nintelligence is applied to separating the commands; the input is split\nat the first ``;;`` pair, even if it is in the middle of a quoted\nstring.\n\nIf a file ``.pdbrc`` exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ``.pdbrc`` can now contain commands that\ncontinue debugging, such as ``continue`` or ``next``. Previously,\nthese commands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. ``help pdb``\n displays the full documentation (the docstring of the ``pdb``\n module). Since the *command* argument must be an identifier,\n ``help exec`` must be entered to get help on the ``!`` command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on ``sys.path``. Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for ``break``.\n\ncl(ear) [filename:lineno | bpnumber [bpnumber ...]]\n\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just ``end`` to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) print some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with ``end``; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between ``next`` and\n ``step`` is that ``step`` stops inside a called function, while\n ``next`` executes called functions at (nearly) full speed, only\n stopping at the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a ``for`` loop or out\n of a ``finally`` clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With ``.`` as argument, list 11 lines around the current line.\n With one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by ``->``. If\n an exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ``>>``, if it\n differs from the current line.\n\n New in version 3.2: The ``>>`` marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for ``list``.\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np(rint) expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\npp expression\n\n Like the ``print`` command, except the value of the expression is\n pretty-printed using the ``pprint`` module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\ndisplay [expression]\n\n Display the value of the expression if it changed, each time\n execution stops in the current frame.\n\n Without expression, list all display expressions for the current\n frame.\n\n New in version 3.2.\n\nundisplay [expression]\n\n Do not display the expression any more in the current frame.\n Without expression, clear all display expressions for the current\n frame.\n\n New in version 3.2.\n\ninteract\n\n Start an interative interpreter (using the ``code`` module) whose\n global namespace contains all the (global and local) names found in\n the current scope.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by ``%1``, ``%2``, and so on, while ``%*`` is replaced by\n all the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ``.pdbrc`` file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n ``global`` statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with ``shlex`` and the result is used as the new\n ``sys.argv``. History, breakpoints, actions and debugger options\n are preserved. ``restart`` is an alias for ``run``.\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module is\n determined by the ``__name__`` in the frame globals.\n', - 'del': '\nThe ``del`` statement\n*********************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather that spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a ``global``\nstatement in the same code block. If the name is unbound, a\n``NameError`` exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2.\n', + 'del': '\nThe ``del`` statement\n*********************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather than spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a ``global``\nstatement in the same code block. If the name is unbound, a\n``NameError`` exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2.\n', 'dict': '\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', 'else': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', @@ -33,8 +34,8 @@ 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: ``()``.)\n', 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, ``077e010`` is legal, and denotes the same\nnumber as ``77e10``. The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator ``-`` and the\nliteral ``1``.\n', 'for': '\nThe ``for`` statement\n*********************\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', - 'formatstrings': '\nFormat String Syntax\n********************\n\nThe ``str.format()`` method and the ``Formatter`` class share the same\nsyntax for format strings (although in the case of ``Formatter``,\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n``{}``. Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n``{{`` and ``}}``.\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point ``\'!\'``, and a *format_spec*, which\nis preceded by a colon ``\':\'``. These specify a non-default format\nfor the replacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either\neither a number or a keyword. If it\'s a number, it refers to a\npositional argument, and if it\'s a keyword, it refers to a named\nkeyword argument. If the numerical arg_names in a format string are\n0, 1, 2, ... in sequence, they can all be omitted (not just some) and\nthe numbers 0, 1, 2, ... will be automatically inserted in that order.\nThe *arg_name* can be followed by any number of index or attribute\nexpressions. An expression of the form ``\'.name\'`` selects the named\nattribute using ``getattr()``, while an expression of the form\n``\'[index]\'`` does an index lookup using ``__getitem__()``.\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so ``\'{} {}\'`` is equivalent to ``\'{0} {1}\'``.\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the\n``__format__()`` method of the value itself. However, in some cases\nit is desirable to force a type to be formatted as a string,\noverriding its own definition of formatting. By converting the value\nto a string before calling ``__format__()``, the normal formatting\nlogic is bypassed.\n\nThree conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, ``\'!r\'`` which calls ``repr()`` and ``\'!a\'``\nwhich calls ``ascii()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in ``format()`` function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string (``""``) produces\nthe same result as if you had called ``str()`` on the value. A non-\nempty format string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nThe *fill* character can be any character other than \'{\' or \'}\'. The\npresence of a fill character is signaled by the character following\nit, which must be one of the alignment options. If the second\ncharacter of *format_spec* is not a valid alignment option, then it is\nassumed that both the fill character and the alignment option are\nabsent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective ``\'0b\'``, ``\'0o\'``, or\n``\'0x\'`` to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for ``\'g\'`` and ``\'G\'``\nconversions, trailing zeros are not removed from the result.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 3.1: Added the ``\',\'`` option (see also **PEP\n378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nIf the *width* field is preceded by a zero (``\'0\'``) character, this\nenables zero-padding. This is equivalent to an *alignment* type of\n``\'=\'`` and a *fill* character of ``\'0\'``.\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with ``\'f\'`` and ``\'F\'``, or before and after the decimal\npoint for a floating point value formatted with ``\'g\'`` or ``\'G\'``.\nFor non-number types the field indicates the maximum field size - in\nother words, how many characters will be used from the field content.\nThe *precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'s\'`` | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'s\'``. |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'b\'`` | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | ``\'c\'`` | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | ``\'d\'`` | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | ``\'o\'`` | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | ``\'x\'`` | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'X\'`` | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'d\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'d\'``. |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except\n``\'n\'`` and None). When doing so, ``float()`` is used to convert the\ninteger to a floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'e\'`` | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``, but converts ``nan`` to |\n | | ``NAN`` and ``inf`` to ``INF``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. For a given precision ``p >= 1``, this |\n | | rounds the number to ``p`` significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1`` would have exponent ``exp``. Then if ``-4 <= exp |\n | | < p``, the number is formatted with presentation type |\n | | ``\'f\'`` and precision ``p-1-exp``. Otherwise, the number |\n | | is formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1``. In both cases insignificant trailing zeros are |\n | | removed from the significand, and the decimal point is |\n | | also removed if there are no remaining digits following |\n | | it. Positive and negative infinity, positive and negative |\n | | zero, and nans, are formatted as ``inf``, ``-inf``, ``0``, |\n | | ``-0`` and ``nan`` respectively, regardless of the |\n | | precision. A precision of ``0`` is treated as equivalent |\n | | to a precision of ``1``. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets too large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to ``\'g\'``, except with at least one digit past |\n | | the decimal point and a default precision of 12. This is |\n | | intended to match ``str()``, except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old ``%``-formatting.\n\nIn most of the cases the syntax is similar to the old\n``%``-formatting, with the addition of the ``{}`` and with ``:`` used\ninstead of ``%``. For example, ``\'%03.2f\'`` can be translated to\n``\'{:03.2f}\'``.\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing ``%s`` and ``%r``:\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing ``%x`` and ``%o`` and converting the value to different\nbases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}.\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12):\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', - 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n', + 'formatstrings': '\nFormat String Syntax\n********************\n\nThe ``str.format()`` method and the ``Formatter`` class share the same\nsyntax for format strings (although in the case of ``Formatter``,\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n``{}``. Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n``{{`` and ``}}``.\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point ``\'!\'``, and a *format_spec*, which\nis preceded by a colon ``\':\'``. These specify a non-default format\nfor the replacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either a\nnumber or a keyword. If it\'s a number, it refers to a positional\nargument, and if it\'s a keyword, it refers to a named keyword\nargument. If the numerical arg_names in a format string are 0, 1, 2,\n... in sequence, they can all be omitted (not just some) and the\nnumbers 0, 1, 2, ... will be automatically inserted in that order.\nBecause *arg_name* is not quote-delimited, it is not possible to\nspecify arbitrary dictionary keys (e.g., the strings ``\'10\'`` or\n``\':-]\'``) within a format string. The *arg_name* can be followed by\nany number of index or attribute expressions. An expression of the\nform ``\'.name\'`` selects the named attribute using ``getattr()``,\nwhile an expression of the form ``\'[index]\'`` does an index lookup\nusing ``__getitem__()``.\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so ``\'{} {}\'`` is equivalent to ``\'{0} {1}\'``.\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the\n``__format__()`` method of the value itself. However, in some cases\nit is desirable to force a type to be formatted as a string,\noverriding its own definition of formatting. By converting the value\nto a string before calling ``__format__()``, the normal formatting\nlogic is bypassed.\n\nThree conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, ``\'!r\'`` which calls ``repr()`` and ``\'!a\'``\nwhich calls ``ascii()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in ``format()`` function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string (``""``) produces\nthe same result as if you had called ``str()`` on the value. A non-\nempty format string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nThe *fill* character can be any character other than \'{\' or \'}\'. The\npresence of a fill character is signaled by the character following\nit, which must be one of the alignment options. If the second\ncharacter of *format_spec* is not a valid alignment option, then it is\nassumed that both the fill character and the alignment option are\nabsent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective ``\'0b\'``, ``\'0o\'``, or\n``\'0x\'`` to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for ``\'g\'`` and ``\'G\'``\nconversions, trailing zeros are not removed from the result.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 3.1: Added the ``\',\'`` option (see also **PEP\n378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nIf the *width* field is preceded by a zero (``\'0\'``) character, this\nenables zero-padding. This is equivalent to an *alignment* type of\n``\'=\'`` and a *fill* character of ``\'0\'``.\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with ``\'f\'`` and ``\'F\'``, or before and after the decimal\npoint for a floating point value formatted with ``\'g\'`` or ``\'G\'``.\nFor non-number types the field indicates the maximum field size - in\nother words, how many characters will be used from the field content.\nThe *precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'s\'`` | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'s\'``. |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'b\'`` | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | ``\'c\'`` | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | ``\'d\'`` | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | ``\'o\'`` | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | ``\'x\'`` | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'X\'`` | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'d\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'d\'``. |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except\n``\'n\'`` and None). When doing so, ``float()`` is used to convert the\ninteger to a floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'e\'`` | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``, but converts ``nan`` to |\n | | ``NAN`` and ``inf`` to ``INF``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. For a given precision ``p >= 1``, this |\n | | rounds the number to ``p`` significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1`` would have exponent ``exp``. Then if ``-4 <= exp |\n | | < p``, the number is formatted with presentation type |\n | | ``\'f\'`` and precision ``p-1-exp``. Otherwise, the number |\n | | is formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1``. In both cases insignificant trailing zeros are |\n | | removed from the significand, and the decimal point is |\n | | also removed if there are no remaining digits following |\n | | it. Positive and negative infinity, positive and negative |\n | | zero, and nans, are formatted as ``inf``, ``-inf``, ``0``, |\n | | ``-0`` and ``nan`` respectively, regardless of the |\n | | precision. A precision of ``0`` is treated as equivalent |\n | | to a precision of ``1``. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets too large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to ``\'g\'``, except with at least one digit past |\n | | the decimal point and a default precision of 12. This is |\n | | intended to match ``str()``, except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old ``%``-formatting.\n\nIn most of the cases the syntax is similar to the old\n``%``-formatting, with the addition of the ``{}`` and with ``:`` used\ninstead of ``%``. For example, ``\'%03.2f\'`` can be translated to\n``\'{:03.2f}\'``.\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing ``%s`` and ``%r``:\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing ``%x`` and ``%o`` and converting the value to different\nbases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12):\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', + 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that the same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n', 'global': '\nThe ``global`` statement\n************************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe ``global`` statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without ``global``, although free variables may refer to\nglobals without being declared global.\n\nNames listed in a ``global`` statement must not be used in the same\ncode block textually preceding that ``global`` statement.\n\nNames listed in a ``global`` statement must not be defined as formal\nparameters or in a ``for`` loop control target, ``class`` definition,\nfunction definition, or ``import`` statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the latter two restrictions, but programs should not abuse\nthis freedom, as future implementations may enforce them or silently\nchange the meaning of the program.\n\n**Programmer\'s note:** the ``global`` is a directive to the parser.\nIt applies only to code parsed at the same time as the ``global``\nstatement. In particular, a ``global`` statement contained in a string\nor code object supplied to the built-in ``exec()`` function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by ``global`` statements in\nthe code containing the function call. The same applies to the\n``eval()`` and ``compile()`` functions.\n', 'id-classes': '\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', 'identifiers': '\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters ``A`` through ``Z``, the underscore ``_`` and, except for the\nfirst character, the digits ``0`` through ``9``.\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n``unicodedata`` module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= xid_start xid_continue*\n id_start ::= \n id_continue ::= \n xid_start ::= \n xid_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\n* *Other_ID_Start* - explicit list of characters in PropList.txt to\n support backwards compatibility\n\n* *Other_ID_Continue* - likewise\n\nAll identifiers are converted into the normal form NFKC while parsing;\ncomparison of identifiers is based on NFKC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', @@ -53,26 +54,26 @@ 'operator-summary': '\nSummary\n*******\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| ``lambda`` | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| ``if`` -- ``else`` | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| ``or`` | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| ``and`` | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| ``not`` *x* | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``in``, ``not`` ``in``, ``is``, ``is not``, | Comparisons, including membership |\n| ``<``, ``<=``, ``>``, ``>=``, ``!=``, ``==`` | tests and identity tests, |\n+-------------------------------------------------+---------------------------------------+\n| ``|`` | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| ``^`` | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| ``&`` | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| ``<<``, ``>>`` | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| ``+``, ``-`` | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| ``x[index]``, ``x[index:index]``, | Subscription, slicing, call, |\n| ``x(arguments...)``, ``x.attribute`` | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| ``(expressions...)``, ``[expressions...]``, | Binding or tuple display, list |\n| ``{key:datum...}``, ``{expressions...}`` | display, dictionary display, set |\n| | display |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While ``abs(x%y) < abs(y)`` is true mathematically, for floats it\n may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that ``-1e-100 % 1e100`` have the same\n sign as ``1e100``, the computed result is ``-1e-100 + 1e100``,\n which is numerically exactly equal to ``1e100``. The function\n ``math.fmod()`` returns a result whose sign matches the sign of\n the first argument instead, and so returns ``-1e-100`` in this\n case. Which approach is more appropriate depends on the\n application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for ``x//y`` to be one larger than ``(x-x%y)//y`` due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[3] While comparisons between strings make sense at the byte level,\n they may be counter-intuitive to users. For example, the strings\n ``"\\u00C7"`` and ``"\\u0327\\u0043"`` compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using ``unicodedata.normalize()``.\n\n[4] Due to automatic garbage-collection, free lists, and the dynamic\n nature of descriptors, you may notice seemingly unusual behaviour\n in certain uses of the ``is`` operator, like those involving\n comparisons between instance methods, or constants. Check their\n documentation for more info.\n\n[5] The ``%`` operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator ``**`` binds less tightly than an arithmetic or\n bitwise unary operator on its right, that is, ``2**-1`` is\n ``0.5``.\n', 'pass': '\nThe ``pass`` statement\n**********************\n\n pass_stmt ::= "pass"\n\n``pass`` is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): ``-1**2`` results in ``-1``.\n\nThe power operator has the same semantics as the built-in ``pow()``\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n``10**2`` returns ``100``, but ``10**-2`` returns ``0.01``.\n\nRaising ``0.0`` to a negative power results in a\n``ZeroDivisionError``. Raising a negative number to a fractional power\nresults in a ``complex`` number. (In earlier versions it raised a\n``ValueError``.)\n', - 'raise': '\nThe ``raise`` statement\n***********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, ``raise`` re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a ``TypeError`` exception is raised indicating that\nthis is an error (if running under IDLE, a ``queue.Empty`` exception\nis raised instead).\n\nOtherwise, ``raise`` evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n``BaseException``. If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the ``__traceback__`` attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the ``with_traceback()`` exception method (which\nreturns the same exception instance, with its traceback set to its\nargument), like so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe ``from`` clause is used for exception chaining: if given, the\nsecond *expression* must be another exception class or instance, which\nwill then be attached to the raised exception as the ``__cause__``\nattribute (which is writable). If the raised exception is not\nhandled, both exceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s ``__context__`` attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', - 'return': '\nThe ``return`` statement\n************************\n\n return_stmt ::= "return" [expression_list]\n\n``return`` may only occur syntactically nested in a function\ndefinition, not within a nested class definition.\n\nIf an expression list is present, it is evaluated, else ``None`` is\nsubstituted.\n\n``return`` leaves the current function call with the expression list\n(or ``None``) as return value.\n\nWhen ``return`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the function.\n\nIn a generator function, the ``return`` statement is not allowed to\ninclude an ``expression_list``. In that context, a bare ``return``\nindicates that the generator is done and will cause ``StopIteration``\nto be raised.\n', + 'raise': '\nThe ``raise`` statement\n***********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, ``raise`` re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a ``RuntimeError`` exception is raised indicating\nthat this is an error.\n\nOtherwise, ``raise`` evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n``BaseException``. If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the ``__traceback__`` attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the ``with_traceback()`` exception method (which\nreturns the same exception instance, with its traceback set to its\nargument), like so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe ``from`` clause is used for exception chaining: if given, the\nsecond *expression* must be another exception class or instance, which\nwill then be attached to the raised exception as the ``__cause__``\nattribute (which is writable). If the raised exception is not\nhandled, both exceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s ``__context__`` attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', + 'return': '\nThe ``return`` statement\n************************\n\n return_stmt ::= "return" [expression_list]\n\n``return`` may only occur syntactically nested in a function\ndefinition, not within a nested class definition.\n\nIf an expression list is present, it is evaluated, else ``None`` is\nsubstituted.\n\n``return`` leaves the current function call with the expression list\n(or ``None``) as return value.\n\nWhen ``return`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the function.\n\nIn a generator function, the ``return`` statement indicates that the\ngenerator is done and will cause ``StopIteration`` to be raised. The\nreturned value (if any) is used as an argument to construct\n``StopIteration`` and becomes the ``StopIteration.value`` attribute.\n', 'sequence-types': "\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python's standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping's keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn't define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don't define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n", 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as division by ``pow(2,n)``. A\nleft shift by *n* bits is defined as multiplication with ``pow(2,n)``.\n\nNote: In the current implementation, the right-hand operand is required to\n be at most ``sys.maxsize``. If the right-hand operand is larger\n than ``sys.maxsize`` an ``OverflowError`` exception is raised.\n', 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or ``del`` statements. The syntax for a\nslicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same\n``__getitem__()`` method as normal subscription) with a key that is\nconstructed from the slice list, as follows. If the slice list\ncontains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n``start``, ``stop`` and ``step`` attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting ``None`` for missing expressions.\n', - 'specialattrs': "\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object's\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nThe following attributes are only supported by *new-style class*es.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each new-style class keeps a list of weak references to its\n immediate subclasses. This method returns a list of all those\n references still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can't tell the type of the\n operands.\n\n[4] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n", - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', - 'string-methods': '\nString Methods\n**************\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n', - 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "R"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` or\n``bytesprefix`` and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (4) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (5) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n5. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default). Exactly eight hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', + 'specialattrs': '\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object\'s\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nclass.__qualname__\n\n The *qualified name* of the class or type.\n\n New in version 3.3.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each class keeps a list of weak references to its immediate\n subclasses. This method returns a list of all those references\n still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] Cased characters are those with general category property being\n one of "Lu" (Letter, uppercase), "Ll" (Letter, lowercase), or "Lt"\n (Letter, titlecase).\n\n[5] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n', + 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__bytes__(self)\n\n Called by ``bytes()`` to compute a byte-string representation of an\n object. This should return a ``bytes`` object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\n Note: Note by default the ``__hash__()`` values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the order in which keys are\n retrieved from a dict. Note Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also ``PYTHONHASHSEED``.\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', + 'string-methods': '\nString Methods\n**************\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter ``\'\xc3\x9f\'`` is equivalent to\n ``"ss"``. Since it is already lowercase, ``lower()`` would do\n nothing to ``\'\xc3\x9f\'``; ``casefold()`` converts it to ``"ss"``.\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by zero or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\n Note: The ``find()`` method should be used only if you need to know the\n position of *sub*. To check if *sub* is a substring or not, use\n the ``in`` operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *iterable*, including ``bytes`` objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n ``s.swapcase().swapcase() == s``.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that ``str.upper().isupper()`` might\n be ``False`` if ``s`` contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than or equal to ``len(s)``.\n', + 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` or\n``bytesprefix`` and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nAs of Python 3.3 it is possible again to prefix unicode strings with a\n``u`` prefix to simplify maintenance of dual 2.x and 3.x codebases.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially.\n\n New in version 3.3: The ``\'rb\'`` prefix of raw bytes literals has\n been added as a synonym of ``\'br\'``.\n\n New in version 3.3: Support for the unicode legacy literal\n (``u\'value\'``) and other versions were reintroduced to simplify the\n maintenance of dual Python 2.x and 3.x codebases. See **PEP 414**\n for more information.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | (4) |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (5) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (6) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Changed in version 3.3: Support for name aliases [1] has been\n added.\n\n5. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n6. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default). Exactly eight hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a ``__getitem__()`` method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a ``__getitem__()``\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that ``x[-1]`` selects the last item of\n``x``). The resulting value must be a nonnegative integer less than\nthe number of items in the sequence, and the subscription selects the\nitem whose index is that value (counting from zero). Since the support\nfor negative indices and slicing occurs in the object\'s\n``__getitem__()`` method, subclasses overriding this method will need\nto explicitly add that support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', 'truth': "\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an ``if`` or\n``while`` condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* ``None``\n\n* ``False``\n\n* zero of any numeric type, for example, ``0``, ``0.0``, ``0j``.\n\n* any empty sequence, for example, ``''``, ``()``, ``[]``.\n\n* any empty mapping, for example, ``{}``.\n\n* instances of user-defined classes, if the class defines a\n ``__bool__()`` or ``__len__()`` method, when that method returns the\n integer zero or ``bool`` value ``False``. [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn ``0`` or ``False`` for false and ``1`` or ``True`` for true,\nunless otherwise stated. (Important exception: the Boolean operations\n``or`` and ``and`` always return one of their operands.)\n", - 'try': '\nThe ``try`` statement\n*********************\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n', - 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name ``None``.\n It is used to signify the absence of a value in many situations,\n e.g., it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n ``NotImplemented``. Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal ``...`` or the\n built-in name ``Ellipsis``. Its truth value is true.\n\n``numbers.Number``\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n ``numbers.Integral``\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers (``int``)\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans (``bool``)\n These represent the truth values False and True. The two\n objects representing the values False and True are the only\n Boolean objects. The Boolean type is a subtype of the integer\n type, and Boolean values behave like the values 0 and 1,\n respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ``"False"`` or\n ``"True"`` are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n ``numbers.Real`` (``float``)\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n ``numbers.Complex`` (``complex``)\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n The items of a string object are Unicode code units. A\n Unicode code unit is represented by a string object of one\n item and can hold either a 16-bit or 32-bit value\n representing a Unicode ordinal (the maximum value for the\n ordinal is given in ``sys.maxunicode``, and depends on how\n Python is configured at compile time). Surrogate pairs may\n be present in the Unicode object, and will be reported as two\n separate items. The built-in functions ``chr()`` and\n ``ord()`` convert between code units and nonnegative integers\n representing the Unicode ordinals as defined in the Unicode\n Standard 3.0. Conversion from and to other encodings are\n possible through the string method ``encode()``.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like ``b\'abc\'`` and the built-in function\n ``bytes()`` can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the ``decode()``\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and ``del`` (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in ``bytearray()`` constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module ``array`` provides an additional example of\n a mutable sequence type, as does the ``collections`` module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function ``len()``\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n ``set()`` constructor and can be modified afterwards by several\n methods, such as ``add()``.\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in ``frozenset()`` constructor. As a frozenset is\n immutable and *hashable*, it can be used again as an element of\n another set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation ``a[k]`` selects the item indexed by\n ``k`` from the mapping ``a``; this can be used in expressions and\n as the target of assignments or ``del`` statements. The built-in\n function ``len()`` returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``) then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the ``{...}``\n notation (see section *Dictionary displays*).\n\n The extension modules ``dbm.ndbm`` and ``dbm.gnu`` provide\n additional examples of mapping types, as does the\n ``collections`` module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | ``__doc__`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | ``__module__`` | The name of the module the | Writable |\n | | function was defined in, or | |\n | | ``None`` if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | ``__defaults__`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +---------------------------+---------------------------------+-------------+\n | ``__code__`` | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | ``__dict__`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | | that contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | ``__annotations__`` | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | or ``\'return\'`` for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | ``__kwdefaults__`` | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: ``__self__`` is the class instance\n object, ``__func__`` is the function object; ``__doc__`` is the\n method\'s documentation (same as ``__func__.__doc__``);\n ``__name__`` is the method name (same as ``__func__.__name__``);\n ``__module__`` is the name of the module the method was defined\n in, or ``None`` if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its ``__self__`` attribute is the instance, and the method\n object is said to be bound. The new method\'s ``__func__``\n attribute is the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the ``__func__``\n attribute of the new instance is not the original method object\n but its ``__func__`` attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its ``__self__``\n attribute is the class itself, and its ``__func__`` attribute is\n the function object underlying the class method.\n\n When an instance method object is called, the underlying\n function (``__func__``) is called, inserting the class instance\n (``__self__``) in front of the argument list. For instance,\n when ``C`` is a class which contains a definition for a function\n ``f()``, and ``x`` is an instance of ``C``, calling ``x.f(1)``\n is equivalent to calling ``C.f(x, 1)``.\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in ``__self__`` will\n actually be the class itself, so that calling either ``x.f(1)``\n or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is\n the underlying function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``__next__()`` method will cause the function to\n execute until it provides a value using the ``yield`` statement.\n When the function executes a ``return`` statement or falls off\n the end, a ``StopIteration`` exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override ``__new__()``. The arguments of the\n call are passed to ``__new__()`` and, in the typical case, to\n ``__init__()`` to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a ``__call__()`` method in their class.\n\nModules\n Modules are imported by the ``import`` statement (see section *The\n import statement*). A module object has a namespace implemented by\n a dictionary object (this is the dictionary referenced by the\n __globals__ attribute of functions defined in the module).\n Attribute references are translated to lookups in this dictionary,\n e.g., ``m.x`` is equivalent to ``m.__dict__["x"]``. A module object\n does not contain the code object used to initialize the module\n (since it isn\'t needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute is not present for C modules that are\n statically linked into the interpreter; for extension modules\n loaded dynamically from a shared library, it is the pathname of the\n shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., ``C.x`` is translated to\n ``C.__dict__["x"]`` (although there are a number of hooks which\n allow for other means of locating attributes). When the attribute\n name is not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a class method object, it is transformed into an instance method\n object whose ``__self__`` attributes is ``C``. When it would yield\n a static method object, it is transformed into the object wrapped\n by the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its ``__dict__``.\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: ``__name__`` is the class name; ``__module__``\n is the module name in which the class was defined; ``__dict__`` is\n the dictionary containing the class\'s namespace; ``__bases__`` is a\n tuple (possibly empty or a singleton) containing the base classes,\n in the order of their occurrence in the base class list;\n ``__doc__`` is the class\'s documentation string, or None if\n undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose ``__self__`` attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s\n ``__dict__``. If no class attribute is found, and the object\'s\n class has a ``__getattr__()`` method, that is called to satisfy the\n lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n ``__setattr__()`` or ``__delattr__()`` method, this is called\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the ``open()`` built-in function,\n and also ``os.popen()``, ``os.fdopen()``, and the ``makefile()``\n method of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n ``io.TextIOBase`` abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_lasti`` gives the precise instruction (this is an index into\n the bytecode string of the code object).\n\n Special writable attributes: ``f_trace``, if not ``None``, is a\n function called at the start of each source code line (this is\n used by the debugger); ``f_lineno`` is the current line number\n of the frame --- writing to this from within a trace function\n jumps to the given line (only for the bottom-most frame). A\n debugger can implement a Jump command (aka Set Next Statement)\n by writing to f_lineno.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by ``sys.exc_info()``. When the program contains\n no suitable handler, the stack trace is written (nicely\n formatted) to the standard error stream; if the interpreter is\n interactive, it is also made available to the user as\n ``sys.last_traceback``.\n\n Special read-only attributes: ``tb_next`` is the next level in\n the stack trace (towards the frame where the exception\n occurred), or ``None`` if there is no next level; ``tb_frame``\n points to the execution frame of the current level;\n ``tb_lineno`` gives the line number where the exception\n occurred; ``tb_lasti`` indicates the precise instruction. The\n line number and last instruction in the traceback may differ\n from the line number of its frame object if the exception\n occurred in a ``try`` statement with no matching except clause\n or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for ``__getitem__()``\n methods. They are also created by the built-in ``slice()``\n function.\n\n Special read-only attributes: ``start`` is the lower bound;\n ``stop`` is the upper bound; ``step`` is the step value; each is\n ``None`` if omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n ``staticmethod()`` constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in ``classmethod()`` constructor.\n', + 'try': '\nThe ``try`` statement\n*********************\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is set as the context of the new exception. The exception\ninformation is not available to the program during execution of the\n``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n', + 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name ``None``.\n It is used to signify the absence of a value in many situations,\n e.g., it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n ``NotImplemented``. Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal ``...`` or the\n built-in name ``Ellipsis``. Its truth value is true.\n\n``numbers.Number``\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n ``numbers.Integral``\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers (``int``)\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans (``bool``)\n These represent the truth values False and True. The two\n objects representing the values False and True are the only\n Boolean objects. The Boolean type is a subtype of the integer\n type, and Boolean values behave like the values 0 and 1,\n respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ``"False"`` or\n ``"True"`` are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n ``numbers.Real`` (``float``)\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n ``numbers.Complex`` (``complex``)\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode\n codepoints. All the codepoints in range ``U+0000 - U+10FFFF``\n can be represented in a string. Python doesn\'t have a\n ``chr`` type, and every character in the string is\n represented as a string object with length ``1``. The built-\n in function ``ord()`` converts a character to its codepoint\n (as an integer); ``chr()`` converts an integer in range ``0 -\n 10FFFF`` to the corresponding character. ``str.encode()`` can\n be used to convert a ``str`` to ``bytes`` using the given\n encoding, and ``bytes.decode()`` can be used to achieve the\n opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like ``b\'abc\'`` and the built-in function\n ``bytes()`` can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the ``decode()``\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and ``del`` (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in ``bytearray()`` constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module ``array`` provides an additional example of\n a mutable sequence type, as does the ``collections`` module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function ``len()``\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n ``set()`` constructor and can be modified afterwards by several\n methods, such as ``add()``.\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in ``frozenset()`` constructor. As a frozenset is\n immutable and *hashable*, it can be used again as an element of\n another set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation ``a[k]`` selects the item indexed by\n ``k`` from the mapping ``a``; this can be used in expressions and\n as the target of assignments or ``del`` statements. The built-in\n function ``len()`` returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``) then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the ``{...}``\n notation (see section *Dictionary displays*).\n\n The extension modules ``dbm.ndbm`` and ``dbm.gnu`` provide\n additional examples of mapping types, as does the\n ``collections`` module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | ``__doc__`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | ``__qualname__`` | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | ``__module__`` | The name of the module the | Writable |\n | | function was defined in, or | |\n | | ``None`` if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | ``__defaults__`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +---------------------------+---------------------------------+-------------+\n | ``__code__`` | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | ``__dict__`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | | that contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | ``__annotations__`` | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | or ``\'return\'`` for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | ``__kwdefaults__`` | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: ``__self__`` is the class instance\n object, ``__func__`` is the function object; ``__doc__`` is the\n method\'s documentation (same as ``__func__.__doc__``);\n ``__name__`` is the method name (same as ``__func__.__name__``);\n ``__module__`` is the name of the module the method was defined\n in, or ``None`` if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its ``__self__`` attribute is the instance, and the method\n object is said to be bound. The new method\'s ``__func__``\n attribute is the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the ``__func__``\n attribute of the new instance is not the original method object\n but its ``__func__`` attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its ``__self__``\n attribute is the class itself, and its ``__func__`` attribute is\n the function object underlying the class method.\n\n When an instance method object is called, the underlying\n function (``__func__``) is called, inserting the class instance\n (``__self__``) in front of the argument list. For instance,\n when ``C`` is a class which contains a definition for a function\n ``f()``, and ``x`` is an instance of ``C``, calling ``x.f(1)``\n is equivalent to calling ``C.f(x, 1)``.\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in ``__self__`` will\n actually be the class itself, so that calling either ``x.f(1)``\n or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is\n the underlying function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``__next__()`` method will cause the function to\n execute until it provides a value using the ``yield`` statement.\n When the function executes a ``return`` statement or falls off\n the end, a ``StopIteration`` exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override ``__new__()``. The arguments of the\n call are passed to ``__new__()`` and, in the typical case, to\n ``__init__()`` to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a ``__call__()`` method in their class.\n\nModules\n Modules are imported by the ``import`` statement (see section *The\n import statement*). A module object has a namespace implemented by\n a dictionary object (this is the dictionary referenced by the\n __globals__ attribute of functions defined in the module).\n Attribute references are translated to lookups in this dictionary,\n e.g., ``m.x`` is equivalent to ``m.__dict__["x"]``. A module object\n does not contain the code object used to initialize the module\n (since it isn\'t needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute is not present for C modules that are\n statically linked into the interpreter; for extension modules\n loaded dynamically from a shared library, it is the pathname of the\n shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., ``C.x`` is translated to\n ``C.__dict__["x"]`` (although there are a number of hooks which\n allow for other means of locating attributes). When the attribute\n name is not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a class method object, it is transformed into an instance method\n object whose ``__self__`` attributes is ``C``. When it would yield\n a static method object, it is transformed into the object wrapped\n by the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its ``__dict__``.\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: ``__name__`` is the class name; ``__module__``\n is the module name in which the class was defined; ``__dict__`` is\n the dictionary containing the class\'s namespace; ``__bases__`` is a\n tuple (possibly empty or a singleton) containing the base classes,\n in the order of their occurrence in the base class list;\n ``__doc__`` is the class\'s documentation string, or None if\n undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose ``__self__`` attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s\n ``__dict__``. If no class attribute is found, and the object\'s\n class has a ``__getattr__()`` method, that is called to satisfy the\n lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n ``__setattr__()`` or ``__delattr__()`` method, this is called\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the ``open()`` built-in function,\n and also ``os.popen()``, ``os.fdopen()``, and the ``makefile()``\n method of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n ``io.TextIOBase`` abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_lasti`` gives the precise instruction (this is an index into\n the bytecode string of the code object).\n\n Special writable attributes: ``f_trace``, if not ``None``, is a\n function called at the start of each source code line (this is\n used by the debugger); ``f_lineno`` is the current line number\n of the frame --- writing to this from within a trace function\n jumps to the given line (only for the bottom-most frame). A\n debugger can implement a Jump command (aka Set Next Statement)\n by writing to f_lineno.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by ``sys.exc_info()``. When the program contains\n no suitable handler, the stack trace is written (nicely\n formatted) to the standard error stream; if the interpreter is\n interactive, it is also made available to the user as\n ``sys.last_traceback``.\n\n Special read-only attributes: ``tb_next`` is the next level in\n the stack trace (towards the frame where the exception\n occurred), or ``None`` if there is no next level; ``tb_frame``\n points to the execution frame of the current level;\n ``tb_lineno`` gives the line number where the exception\n occurred; ``tb_lasti`` indicates the precise instruction. The\n line number and last instruction in the traceback may differ\n from the line number of its frame object if the exception\n occurred in a ``try`` statement with no matching except clause\n or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for ``__getitem__()``\n methods. They are also created by the built-in ``slice()``\n function.\n\n Special read-only attributes: ``start`` is the lower bound;\n ``stop`` is the upper bound; ``step`` is the step value; each is\n ``None`` if omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n ``staticmethod()`` constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in ``classmethod()`` constructor.\n', 'typesfunctions': '\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: ``func(argument-list)``.\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', - 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict([arg])\n\n Return a new dictionary initialized from an optional positional\n argument or from a set of keyword arguments. If no arguments are\n given, return a new empty dictionary. If the positional argument\n *arg* is a mapping object, return a dictionary mapping the same\n keys to the same values as does the mapping object. Otherwise the\n positional argument must be a sequence, a container that supports\n iteration, or an iterator object. The elements of the argument\n must each also be of one of those kinds, and each must in turn\n contain exactly two objects. The first is used as a key in the new\n dictionary, and the second as the key\'s value. If a given key is\n seen more than once, the last value associated with it is retained\n in the new dictionary.\n\n If keyword arguments are given, the keywords themselves with their\n associated values are added as items to the dictionary. If a key\n is specified both in the positional argument and as a keyword\n argument, the value associated with the keyword is retained in the\n dictionary. For example, these all return a dictionary equal to\n ``{"one": 1, "two": 2}``:\n\n * ``dict(one=1, two=2)``\n\n * ``dict({\'one\': 1, \'two\': 2})``\n\n * ``dict(zip((\'one\', \'two\'), (1, 2)))``\n\n * ``dict([[\'two\', 2], [\'one\', 1]])``\n\n The first example only works for keys that are valid Python\n identifiers; the others work with any valid keys.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See ``collections.Counter`` for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iter(d.keys())``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See below for documentation of view objects.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: ``d.update(red=1,\n blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that ``(key, value)`` pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class ``collections.Set`` are available (for example, ``==``,\n``<``, or ``^``).\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'eggs\', \'bacon\', \'spam\'}\n', + 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict([arg])\n\n Return a new dictionary initialized from an optional positional\n argument or from a set of keyword arguments. If no arguments are\n given, return a new empty dictionary. If the positional argument\n *arg* is a mapping object, return a dictionary mapping the same\n keys to the same values as does the mapping object. Otherwise the\n positional argument must be a sequence, a container that supports\n iteration, or an iterator object. The elements of the argument\n must each also be of one of those kinds, and each must in turn\n contain exactly two objects. The first is used as a key in the new\n dictionary, and the second as the key\'s value. If a given key is\n seen more than once, the last value associated with it is retained\n in the new dictionary.\n\n If keyword arguments are given, the keywords themselves with their\n associated values are added as items to the dictionary. If a key\n is specified both in the positional argument and as a keyword\n argument, the value associated with the keyword is retained in the\n dictionary. For example, these all return a dictionary equal to\n ``{"one": 1, "two": 2}``:\n\n * ``dict(one=1, two=2)``\n\n * ``dict({\'one\': 1, \'two\': 2})``\n\n * ``dict(zip((\'one\', \'two\'), (1, 2)))``\n\n * ``dict([[\'two\', 2], [\'one\', 1]])``\n\n The first example only works for keys that are valid Python\n identifiers; the others work with any valid keys.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See ``collections.Counter`` for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iter(d.keys())``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See below for documentation of view objects.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: ``d.update(red=1,\n blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that ``(key, value)`` pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class ``collections.Set`` are available (for example, ``==``,\n``<``, or ``^``).\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', 'typesmethods': "\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as ``append()`` on\nlists) and class instance methods. Built-in methods are described\nwith the types that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the\n``self`` argument to the argument list. Bound methods have two\nspecial read-only attributes: ``m.__self__`` is the object on which\nthe method operates, and ``m.__func__`` is the function implementing\nthe method. Calling ``m(arg-1, arg-2, ..., arg-n)`` is completely\nequivalent to calling ``m.__func__(m.__self__, arg-1, arg-2, ...,\narg-n)``.\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object (``meth.__func__``), setting method\nattributes on bound methods is disallowed. Attempting to set a method\nattribute results in a ``TypeError`` being raised. In order to set a\nmethod attribute, you need to explicitly set it on the underlying\nfunction object:\n\n class C:\n def method(self):\n pass\n\n c = C()\n c.method.__func__.whoami = 'my name is c'\n\nSee *The standard type hierarchy* for more information.\n", - 'typesmodules': "\nModules\n*******\n\nThe only special operation on a module is attribute access:\n``m.name``, where *m* is a module and *name* accesses a name defined\nin *m*'s symbol table. Module attributes can be assigned to. (Note\nthat the ``import`` statement is not, strictly speaking, an operation\non a module object; ``import foo`` does not require a module object\nnamed *foo* to exist, rather it requires an (external) *definition*\nfor a module named *foo* somewhere.)\n\nA special member of every module is ``__dict__``. This is the\ndictionary containing the module's symbol table. Modifying this\ndictionary will actually change the module's symbol table, but direct\nassignment to the ``__dict__`` attribute is not possible (you can\nwrite ``m.__dict__['a'] = 1``, which defines ``m.a`` to be ``1``, but\nyou can't write ``m.__dict__ = {}``). Modifying ``__dict__`` directly\nis not recommended.\n\nModules built into the interpreter are written like this: ````. If loaded from a file, they are written as\n````.\n", - 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWhile string objects are sequences of characters (represented by\nstrings of length 1), bytes and bytearray objects are sequences of\n*integers* (between 0 and 255), representing the ASCII value of single\nbytes. That means that for a bytes or bytearray object *b*, ``b[0]``\nwill be an integer, while ``b[0:1]`` will be a bytes or bytearray\nobject of length 1. The representation of bytes objects uses the\nliteral format (``b\'...\'``) since it is generally more useful than\ne.g. ``bytes([50, 19, 100])``. You can always convert a bytes object\ninto a list of integers using ``list(b)``.\n\nAlso, while in previous Python versions, byte strings and Unicode\nstrings could be exchanged for each other rather freely (barring\nencoding issues), strings and bytes are now completely separate\nconcepts. There\'s no implicit en-/decoding if you pass an object of\nthe wrong type. A string always compares unequal to a bytes or\nbytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support concatenation or repetition, and using ``min()`` or\n``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i*, *j* and *k* are\nintegers.\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*\'th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.index(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. **CPython implementation detail:** If *s* and *t* are both strings,\n some Python implementations such as CPython can usually perform an\n in-place optimization for assignments of the form ``s = s + t`` or\n ``s += t``. When applicable, this optimization makes quadratic\n run-time much less likely. This optimization is both version and\n implementation dependent. For performance sensitive code, it is\n preferable to use the ``str.join()`` method which assures\n consistent linear concatenation performance across versions and\n implementations.\n\n\nString Methods\n==============\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that that can be used\n to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT\n ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and lowercase characters are those with general\n category property "Ll".\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise. Cased\n characters are those with general category property being one of\n "Lu", "Ll", or "Lt" and uppercase characters are those with general\n category property "Lu".\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are obsolete and may go\n away in future versions of Python. Use the new *String Formatting*\n in new code.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [4] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(number)03d quote types.\' %\n... {\'language\': "Python", "number": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The precision determines the maximal number of characters used.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents.\n\nRange objects have relatively little behavior: they support indexing,\ncontains, iteration, the ``len()`` function, and the following\nmethods:\n\nrange.count(x)\n\n Return the number of *i*\'s for which ``s[i] == x``.\n\n New in version 3.2.\n\nrange.index(x)\n\n Return the smallest *i* such that ``s[i] == x``. Raises\n ``ValueError`` when *x* is not in the range.\n\n New in version 3.2.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | remove all items from ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | return a shallow copy of ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode(encoding="utf-8", errors="strict")\nbytearray.decode(encoding="utf-8", errors="strict")\n\n Return a string decoded from the given bytes. Default encoding is\n ``\'utf-8\'``. *errors* may be given to set a different error\n handling scheme. The default for *errors* is ``\'strict\'``, meaning\n that encoding errors raise a ``UnicodeError``. Other possible\n values are ``\'ignore\'``, ``\'replace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Added support for keyword arguments.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', + 'typesmodules': "\nModules\n*******\n\nThe only special operation on a module is attribute access:\n``m.name``, where *m* is a module and *name* accesses a name defined\nin *m*'s symbol table. Module attributes can be assigned to. (Note\nthat the ``import`` statement is not, strictly speaking, an operation\non a module object; ``import foo`` does not require a module object\nnamed *foo* to exist, rather it requires an (external) *definition*\nfor a module named *foo* somewhere.)\n\nA special attribute of every module is ``__dict__``. This is the\ndictionary containing the module's symbol table. Modifying this\ndictionary will actually change the module's symbol table, but direct\nassignment to the ``__dict__`` attribute is not possible (you can\nwrite ``m.__dict__['a'] = 1``, which defines ``m.a`` to be ``1``, but\nyou can't write ``m.__dict__ = {}``). Modifying ``__dict__`` directly\nis not recommended.\n\nModules built into the interpreter are written like this: ````. If loaded from a file, they are written as\n````.\n", + 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWhile string objects are sequences of characters (represented by\nstrings of length 1), bytes and bytearray objects are sequences of\n*integers* (between 0 and 255), representing the ASCII value of single\nbytes. That means that for a bytes or bytearray object *b*, ``b[0]``\nwill be an integer, while ``b[0:1]`` will be a bytes or bytearray\nobject of length 1. The representation of bytes objects uses the\nliteral format (``b\'...\'``) since it is generally more useful than\ne.g. ``bytes([50, 19, 100])``. You can always convert a bytes object\ninto a list of integers using ``list(b)``.\n\nAlso, while in previous Python versions, byte strings and Unicode\nstrings could be exchanged for each other rather freely (barring\nencoding issues), strings and bytes are now completely separate\nconcepts. There\'s no implicit en-/decoding if you pass an object of\nthe wrong type. A string always compares unequal to a bytes or\nbytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support concatenation or repetition, and using ``min()`` or\n``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i*, *j* and *k* are\nintegers.\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.index(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. Concatenating immutable strings always results in a new object.\n This means that building up a string by repeated concatenation will\n have a quadratic runtime cost in the total string length. To get a\n linear runtime cost, you must switch to one of the alternatives\n below:\n\n * if concatenating ``str`` objects, you can build a list and use\n ``str.join()`` at the end;\n\n * if concatenating ``bytes`` objects, you can similarly use\n ``bytes.join()``, or you can do in-place concatenation with a\n ``bytearray`` object. ``bytearray`` objects are mutable and have\n an efficient overallocation mechanism.\n\n\nString Methods\n==============\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter ``\'\xc3\x9f\'`` is equivalent to\n ``"ss"``. Since it is already lowercase, ``lower()`` would do\n nothing to ``\'\xc3\x9f\'``; ``casefold()`` converts it to ``"ss"``.\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by zero or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\n Note: The ``find()`` method should be used only if you need to know the\n position of *sub*. To check if *sub* is a substring or not, use\n the ``in`` operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *iterable*, including ``bytes`` objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n ``s.swapcase().swapcase() == s``.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that ``str.upper().isupper()`` might\n be ``False`` if ``s`` contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than or equal to ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are modelled on C\'s\n printf() syntax. They only support formatting of certain builtin\n types. The use of a binary operator means that care may be needed\n in order to format tuples and dictionaries correctly. As the new\n *String Formatting* syntax is more flexible and handles tuples and\n dictionaries naturally, it is recommended for new code. However,\n there are no current plans to deprecate printf-style formatting.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [5] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual\n precision is read from the next element of the tuple in *values*,\n and the value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(number)03d quote types.\' %\n... {\'language\': "Python", "number": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'a\'`` | String (converts any Python object using | (5) |\n| | ``ascii()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. If precision is ``N``, the output is truncated to ``N`` characters.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents.\n\nRange objects have relatively little behavior: they support indexing,\ncontains, iteration, the ``len()`` function, and the following\nmethods:\n\nrange.count(x)\n\n Return the number of *i*\'s for which ``s[i] == x``.\n\n New in version 3.2.\n\nrange.index(x)\n\n Return the smallest *i* such that ``s[i] == x``. Raises\n ``ValueError`` when *x* is not in the range.\n\n New in version 3.2.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | remove all items from ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | return a shallow copy of ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNew in version 3.3: The functions ``count()``, ``find()``,\n``index()``, ``rfind()`` and ``rindex()`` have additional semantics\ncompared to the corresponding string functions: They also accept an\ninteger in range 0 to 255 (a byte) as their first argument.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode(encoding="utf-8", errors="strict")\nbytearray.decode(encoding="utf-8", errors="strict")\n\n Return a string decoded from the given bytes. Default encoding is\n ``\'utf-8\'``. *errors* may be given to set a different error\n handling scheme. The default for *errors* is ``\'strict\'``, meaning\n that encoding errors raise a ``UnicodeError``. Other possible\n values are ``\'ignore\'``, ``\'replace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Added support for keyword arguments.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | remove all items from ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | return a shallow copy of ``s`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n', 'unary': '\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary ``-`` (minus) operator yields the negation of its numeric\nargument.\n\nThe unary ``+`` (plus) operator yields its numeric argument unchanged.\n\nThe unary ``~`` (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of ``x`` is defined as\n``-(x+1)``. It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n``TypeError`` exception is raised.\n', 'while': '\nThe ``while`` statement\n***********************\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n', 'with': '\nThe ``with`` statement\n**********************\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', - 'yield': '\nThe ``yield`` statement\n***********************\n\n yield_stmt ::= yield_expression\n\nThe ``yield`` statement is only used when defining a generator\nfunction, and is only used in the body of the generator function.\nUsing a ``yield`` statement in a function definition is sufficient to\ncause that definition to create a generator function instead of a\nnormal function. When a generator function is called, it returns an\niterator known as a generator iterator, or more commonly, a generator.\nThe body of the generator function is executed by calling the\n``next()`` function on the generator repeatedly until it raises an\nexception.\n\nWhen a ``yield`` statement is executed, the state of the generator is\nfrozen and the value of ``expression_list`` is returned to\n``next()``\'s caller. By "frozen" we mean that all local state is\nretained, including the current bindings of local variables, the\ninstruction pointer, and the internal evaluation stack: enough\ninformation is saved so that the next time ``next()`` is invoked, the\nfunction can proceed exactly as if the ``yield`` statement were just\nanother external call.\n\nThe ``yield`` statement is allowed in the ``try`` clause of a ``try``\n... ``finally`` construct. If the generator is not resumed before it\nis finalized (by reaching a zero reference count or by being garbage\ncollected), the generator-iterator\'s ``close()`` method will be\ncalled, allowing any pending ``finally`` clauses to execute.\n\nSee also:\n\n **PEP 0255** - Simple Generators\n The proposal for adding generators and the ``yield`` statement\n to Python.\n\n **PEP 0342** - Coroutines via Enhanced Generators\n The proposal that, among other generator enhancements, proposed\n allowing ``yield`` to appear inside a ``try`` ... ``finally``\n block.\n'} + 'yield': '\nThe ``yield`` statement\n***********************\n\n yield_stmt ::= yield_expression\n\nThe ``yield`` statement is only used when defining a generator\nfunction, and is only used in the body of the generator function.\nUsing a ``yield`` statement in a function definition is sufficient to\ncause that definition to create a generator function instead of a\nnormal function.\n\nWhen a generator function is called, it returns an iterator known as a\ngenerator iterator, or more commonly, a generator. The body of the\ngenerator function is executed by calling the ``next()`` function on\nthe generator repeatedly until it raises an exception.\n\nWhen a ``yield`` statement is executed, the state of the generator is\nfrozen and the value of ``expression_list`` is returned to\n``next()``\'s caller. By "frozen" we mean that all local state is\nretained, including the current bindings of local variables, the\ninstruction pointer, and the internal evaluation stack: enough\ninformation is saved so that the next time ``next()`` is invoked, the\nfunction can proceed exactly as if the ``yield`` statement were just\nanother external call.\n\nThe ``yield`` statement is allowed in the ``try`` clause of a ``try``\n... ``finally`` construct. If the generator is not resumed before it\nis finalized (by reaching a zero reference count or by being garbage\ncollected), the generator-iterator\'s ``close()`` method will be\ncalled, allowing any pending ``finally`` clauses to execute.\n\nWhen ``yield from `` is used, it treats the supplied expression\nas a subiterator, producing values from it until the underlying\niterator is exhausted.\n\n Changed in version 3.3: Added ``yield from `` to delegate\n control flow to a subiterator\n\nFor full details of ``yield`` semantics, refer to the *Yield\nexpressions* section.\n\nSee also:\n\n **PEP 0255** - Simple Generators\n The proposal for adding generators and the ``yield`` statement\n to Python.\n\n **PEP 0342** - Coroutines via Enhanced Generators\n The proposal to enhance the API and syntax of generators, making\n them usable as simple coroutines.\n\n **PEP 0380** - Syntax for Delegating to a Subgenerator\n The proposal to introduce the ``yield_from`` syntax, making\n delegation to sub-generators easy.\n'} diff --git a/Lib/test/crashers/loosing_mro_ref.py b/Lib/test/crashers/losing_mro_ref.py rename from Lib/test/crashers/loosing_mro_ref.py rename to Lib/test/crashers/losing_mro_ref.py diff --git a/Lib/test/crashers/nasty_eq_vs_dict.py b/Lib/test/crashers/nasty_eq_vs_dict.py deleted file mode 100644 --- a/Lib/test/crashers/nasty_eq_vs_dict.py +++ /dev/null @@ -1,47 +0,0 @@ -# from http://mail.python.org/pipermail/python-dev/2001-June/015239.html - -# if you keep changing a dictionary while looking up a key, you can -# provoke an infinite recursion in C - -# At the time neither Tim nor Michael could be bothered to think of a -# way to fix it. - -class Yuck: - def __init__(self): - self.i = 0 - - def make_dangerous(self): - self.i = 1 - - def __hash__(self): - # direct to slot 4 in table of size 8; slot 12 when size 16 - return 4 + 8 - - def __eq__(self, other): - if self.i == 0: - # leave dict alone - pass - elif self.i == 1: - # fiddle to 16 slots - self.__fill_dict(6) - self.i = 2 - else: - # fiddle to 8 slots - self.__fill_dict(4) - self.i = 1 - - return 1 - - def __fill_dict(self, n): - self.i = 0 - dict.clear() - for i in range(n): - dict[i] = i - dict[self] = "OK!" - -y = Yuck() -dict = {y: "OK!"} - -z = Yuck() -y.make_dangerous() -print(dict[z]) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1605,6 +1605,105 @@ self.assertEqual(unpickler.load(), data) +# Tests for dispatch_table attribute + +REDUCE_A = 'reduce_A' + +class AAA(object): + def __reduce__(self): + return str, (REDUCE_A,) + +class BBB(object): + pass + +class AbstractDispatchTableTests(unittest.TestCase): + + def test_default_dispatch_table(self): + # No dispatch_table attribute by default + f = io.BytesIO() + p = self.pickler_class(f, 0) + with self.assertRaises(AttributeError): + p.dispatch_table + self.assertFalse(hasattr(p, 'dispatch_table')) + + def test_class_dispatch_table(self): + # A dispatch_table attribute can be specified class-wide + dt = self.get_dispatch_table() + + class MyPickler(self.pickler_class): + dispatch_table = dt + + def dumps(obj, protocol=None): + f = io.BytesIO() + p = MyPickler(f, protocol) + self.assertEqual(p.dispatch_table, dt) + p.dump(obj) + return f.getvalue() + + self._test_dispatch_table(dumps, dt) + + def test_instance_dispatch_table(self): + # A dispatch_table attribute can also be specified instance-wide + dt = self.get_dispatch_table() + + def dumps(obj, protocol=None): + f = io.BytesIO() + p = self.pickler_class(f, protocol) + p.dispatch_table = dt + self.assertEqual(p.dispatch_table, dt) + p.dump(obj) + return f.getvalue() + + self._test_dispatch_table(dumps, dt) + + def _test_dispatch_table(self, dumps, dispatch_table): + def custom_load_dump(obj): + return pickle.loads(dumps(obj, 0)) + + def default_load_dump(obj): + return pickle.loads(pickle.dumps(obj, 0)) + + # pickling complex numbers using protocol 0 relies on copyreg + # so check pickling a complex number still works + z = 1 + 2j + self.assertEqual(custom_load_dump(z), z) + self.assertEqual(default_load_dump(z), z) + + # modify pickling of complex + REDUCE_1 = 'reduce_1' + def reduce_1(obj): + return str, (REDUCE_1,) + dispatch_table[complex] = reduce_1 + self.assertEqual(custom_load_dump(z), REDUCE_1) + self.assertEqual(default_load_dump(z), z) + + # check picklability of AAA and BBB + a = AAA() + b = BBB() + self.assertEqual(custom_load_dump(a), REDUCE_A) + self.assertIsInstance(custom_load_dump(b), BBB) + self.assertEqual(default_load_dump(a), REDUCE_A) + self.assertIsInstance(default_load_dump(b), BBB) + + # modify pickling of BBB + dispatch_table[BBB] = reduce_1 + self.assertEqual(custom_load_dump(a), REDUCE_A) + self.assertEqual(custom_load_dump(b), REDUCE_1) + self.assertEqual(default_load_dump(a), REDUCE_A) + self.assertIsInstance(default_load_dump(b), BBB) + + # revert pickling of BBB and modify pickling of AAA + REDUCE_2 = 'reduce_2' + def reduce_2(obj): + return str, (REDUCE_2,) + dispatch_table[AAA] = reduce_2 + del dispatch_table[BBB] + self.assertEqual(custom_load_dump(a), REDUCE_2) + self.assertIsInstance(custom_load_dump(b), BBB) + self.assertEqual(default_load_dump(a), REDUCE_A) + self.assertIsInstance(default_load_dump(b), BBB) + + if __name__ == "__main__": # Print some stuff that can be used to rewrite DATA{0,1,2} from pickletools import dis diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -749,10 +749,10 @@ if bad: print(count(len(bad), "test"), "failed:") printlist(bad) - if environment_changed: - print("{} altered the execution environment:".format( - count(len(environment_changed), "test"))) - printlist(environment_changed) + if environment_changed: + print("{} altered the execution environment:".format( + count(len(environment_changed), "test"))) + printlist(environment_changed) if skipped and not quiet: print(count(len(skipped), "test"), "skipped:") printlist(skipped) @@ -970,6 +970,7 @@ 'multiprocessing.process._dangling', 'sysconfig._CONFIG_VARS', 'sysconfig._SCHEMES', 'packaging.command._COMMANDS', 'packaging.database_caches', + 'support.TESTFN', ) def get_sys_argv(self): @@ -1163,6 +1164,20 @@ sysconfig._SCHEMES._sections.clear() sysconfig._SCHEMES._sections.update(saved[2]) + def get_support_TESTFN(self): + if os.path.isfile(support.TESTFN): + result = 'f' + elif os.path.isdir(support.TESTFN): + result = 'd' + else: + result = None + return result + def restore_support_TESTFN(self, saved_value): + if saved_value is None: + if os.path.isfile(support.TESTFN): + os.unlink(support.TESTFN) + elif os.path.isdir(support.TESTFN): + shutil.rmtree(support.TESTFN) def resource_info(self): for name in self.resources: diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -2,6 +2,7 @@ from test import support import base64 import binascii +import os import sys import subprocess @@ -274,6 +275,10 @@ class TestMain(unittest.TestCase): + def tearDown(self): + if os.path.exists(support.TESTFN): + os.unlink(support.TESTFN) + def get_output(self, *args, **options): args = (sys.executable, '-m', 'base64') + args return subprocess.check_output(args, **options) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -3373,6 +3373,15 @@ del nd m.release() + a = bytearray([1,2,3]) + m = memoryview(a) + nd1 = ndarray(m, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + nd2 = ndarray(nd1, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + self.assertIs(nd2.obj, m) + self.assertRaises(BufferError, m.release) + del nd1, nd2 + m.release() + # chained views a = bytearray([1,2,3]) m1 = memoryview(a) @@ -3383,6 +3392,17 @@ del nd m2.release() + a = bytearray([1,2,3]) + m1 = memoryview(a) + m2 = memoryview(m1) + nd1 = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + nd2 = ndarray(nd1, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + self.assertIs(nd2.obj, m2) + m1.release() + self.assertRaises(BufferError, m2.release) + del nd1, nd2 + m2.release() + # Allow changing layout while buffers are exported. nd = ndarray([1,2,3], shape=[3], flags=ND_VAREXPORT) m1 = memoryview(nd) @@ -3418,11 +3438,182 @@ catch22(m1) self.assertEqual(m1[0], ord(b'1')) - # XXX If m1 has exports, raise BufferError. - # x = bytearray(b'123') - # with memoryview(x) as m1: - # ex = ndarray(m1) - # m1[0] == ord(b'1') + x = ndarray(list(range(12)), shape=[2,2,3], format='l') + y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + self.assertIs(z.obj, x) + with memoryview(z) as m: + catch22(m) + self.assertEqual(m[0:1].tolist(), [[[0, 1, 2], [3, 4, 5]]]) + + # Test garbage collection. + for flags in (0, ND_REDIRECT): + x = bytearray(b'123') + with memoryview(x) as m1: + del x + y = ndarray(m1, getbuf=PyBUF_FULL_RO, flags=flags) + with memoryview(y) as m2: + del y + z = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=flags) + with memoryview(z) as m3: + del z + catch22(m3) + catch22(m2) + catch22(m1) + self.assertEqual(m1[0], ord(b'1')) + self.assertEqual(m2[1], ord(b'2')) + self.assertEqual(m3[2], ord(b'3')) + del m3 + del m2 + del m1 + + x = bytearray(b'123') + with memoryview(x) as m1: + del x + y = ndarray(m1, getbuf=PyBUF_FULL_RO, flags=flags) + with memoryview(y) as m2: + del y + z = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=flags) + with memoryview(z) as m3: + del z + catch22(m1) + catch22(m2) + catch22(m3) + self.assertEqual(m1[0], ord(b'1')) + self.assertEqual(m2[1], ord(b'2')) + self.assertEqual(m3[2], ord(b'3')) + del m1, m2, m3 + + # memoryview.release() fails if the view has exported buffers. + x = bytearray(b'123') + with self.assertRaises(BufferError): + with memoryview(x) as m: + ex = ndarray(m) + m[0] == ord(b'1') + + def test_memoryview_redirect(self): + + nd = ndarray([1.0 * x for x in range(12)], shape=[12], format='d') + a = array.array('d', [1.0 * x for x in range(12)]) + + for x in (nd, a): + y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + m = memoryview(z) + + self.assertIs(y.obj, x) + self.assertIs(z.obj, x) + self.assertIs(m.obj, x) + + self.assertEqual(m, x) + self.assertEqual(m, y) + self.assertEqual(m, z) + + self.assertEqual(m[1:3], x[1:3]) + self.assertEqual(m[1:3], y[1:3]) + self.assertEqual(m[1:3], z[1:3]) + del y, z + self.assertEqual(m[1:3], x[1:3]) + + def test_memoryview_from_static_exporter(self): + + fmt = 'B' + lst = [0,1,2,3,4,5,6,7,8,9,10,11] + + # exceptions + self.assertRaises(TypeError, staticarray, 1, 2, 3) + + # view.obj==x + x = staticarray() + y = memoryview(x) + self.verify(y, obj=x, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + for i in range(12): + self.assertEqual(y[i], i) + del x + del y + + x = staticarray() + y = memoryview(x) + del y + del x + + x = staticarray() + y = ndarray(x, getbuf=PyBUF_FULL_RO) + z = ndarray(y, getbuf=PyBUF_FULL_RO) + m = memoryview(z) + self.assertIs(y.obj, x) + self.assertIs(m.obj, z) + self.verify(m, obj=z, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + del x, y, z, m + + x = staticarray() + y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + m = memoryview(z) + self.assertIs(y.obj, x) + self.assertIs(z.obj, x) + self.assertIs(m.obj, x) + self.verify(m, obj=x, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + del x, y, z, m + + # view.obj==NULL + x = staticarray(legacy_mode=True) + y = memoryview(x) + self.verify(y, obj=None, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + for i in range(12): + self.assertEqual(y[i], i) + del x + del y + + x = staticarray(legacy_mode=True) + y = memoryview(x) + del y + del x + + x = staticarray(legacy_mode=True) + y = ndarray(x, getbuf=PyBUF_FULL_RO) + z = ndarray(y, getbuf=PyBUF_FULL_RO) + m = memoryview(z) + self.assertIs(y.obj, None) + self.assertIs(m.obj, z) + self.verify(m, obj=z, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + del x, y, z, m + + x = staticarray(legacy_mode=True) + y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) + m = memoryview(z) + # Clearly setting view.obj==NULL is inferior, since it + # messes up the redirection chain: + self.assertIs(y.obj, None) + self.assertIs(z.obj, y) + self.assertIs(m.obj, y) + self.verify(m, obj=y, + itemsize=1, fmt=fmt, readonly=1, + ndim=1, shape=[12], strides=[1], + lst=lst) + del x, y, z, m + + def test_memoryview_getbuffer_undefined(self): + + # getbufferproc does not adhere to the new documentation + nd = ndarray([1,2,3], [3], flags=ND_GETBUF_FAIL|ND_GETBUF_UNDEFINED) + self.assertRaises(BufferError, memoryview, nd) def test_issue_7385(self): x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -379,7 +379,7 @@ x.fail = True self.assertRaises(Exc, d.pop, x) - def test_mutatingiteration(self): + def test_mutating_iteration(self): # changing dict size during iteration d = {} d[1] = 1 @@ -387,6 +387,26 @@ for i in d: d[i+1] = 1 + def test_mutating_lookup(self): + # changing dict during a lookup + class NastyKey: + mutate_dict = None + + def __hash__(self): + # hash collision! + return 1 + + def __eq__(self, other): + if self.mutate_dict: + self.mutate_dict[self] = 1 + return self == other + + d = {} + d[NastyKey()] = 0 + NastyKey.mutate_dict = d + with self.assertRaises(RuntimeError): + d[NastyKey()] = None + def test_repr(self): d = {} self.assertEqual(repr(d), '{}') diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -38,7 +38,7 @@ try: try: import marshal - marshal.loads('') + marshal.loads(b'') except EOFError: pass finally: diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3651,11 +3651,14 @@ def test_rollover(self): fh = logging.handlers.TimedRotatingFileHandler(self.fn, 'S', backupCount=1) - r = logging.makeLogRecord({'msg': 'testing'}) - fh.emit(r) + fmt = logging.Formatter('%(asctime)s %(message)s') + fh.setFormatter(fmt) + r1 = logging.makeLogRecord({'msg': 'testing - initial'}) + fh.emit(r1) self.assertLogFile(self.fn) - time.sleep(1.01) # just a little over a second ... - fh.emit(r) + time.sleep(1.1) # a little over a second ... + r2 = logging.makeLogRecord({'msg': 'testing - after delay'}) + fh.emit(r2) fh.close() # At this point, we should have a recent rotated file which we # can test for the existence of. However, in practice, on some @@ -3682,7 +3685,8 @@ print('The only matching files are: %s' % files, file=sys.stderr) for f in files: print('Contents of %s:' % f) - with open(f, 'r') as tf: + path = os.path.join(dn, f) + with open(path, 'r') as tf: print(tf.read()) self.assertTrue(found, msg=msg) diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -7,6 +7,7 @@ import email.message import re import io +import shutil import tempfile from test import support import unittest @@ -38,12 +39,7 @@ def _delete_recursively(self, target): # Delete a file or delete a directory recursively if os.path.isdir(target): - for path, dirs, files in os.walk(target, topdown=False): - for name in files: - os.remove(os.path.join(path, name)) - for name in dirs: - os.rmdir(os.path.join(path, name)) - os.rmdir(target) + shutil.rmtree(target) elif os.path.exists(target): os.remove(target) @@ -2028,6 +2024,10 @@ def setUp(self): # create a new maildir mailbox to work with: self._dir = support.TESTFN + if os.path.isdir(self._dir): + shutil.rmtree(self._dir) + elif os.path.isfile(self._dir): + os.unlink(self._dir) os.mkdir(self._dir) os.mkdir(os.path.join(self._dir, "cur")) os.mkdir(os.path.join(self._dir, "tmp")) diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from test import support +import array import marshal import sys import unittest @@ -154,6 +155,27 @@ for constructor in (set, frozenset): self.helper(constructor(self.d.keys())) + +class BufferTestCase(unittest.TestCase, HelperMixin): + + def test_bytearray(self): + b = bytearray(b"abc") + self.helper(b) + new = marshal.loads(marshal.dumps(b)) + self.assertEqual(type(new), bytes) + + def test_memoryview(self): + b = memoryview(b"abc") + self.helper(b) + new = marshal.loads(marshal.dumps(b)) + self.assertEqual(type(new), bytes) + + def test_array(self): + a = array.array('B', b"abc") + new = marshal.loads(marshal.dumps(a)) + self.assertEqual(new, b"abc") + + class BugsTestCase(unittest.TestCase): def test_bug_5888452(self): # Simple-minded check for SF 588452: Debug build crashes @@ -179,7 +201,7 @@ pass def test_loads_recursion(self): - s = 'c' + ('X' * 4*4) + '{' * 2**20 + s = b'c' + (b'X' * 4*4) + b'{' * 2**20 self.assertRaises(ValueError, marshal.loads, s) def test_recursion_limit(self): @@ -252,6 +274,11 @@ finally: support.unlink(support.TESTFN) + def test_loads_reject_unicode_strings(self): + # Issue #14177: marshal.loads() should not accept unicode strings + unicode_string = 'T' + self.assertRaises(TypeError, marshal.loads, unicode_string) + def test_main(): support.run_unittest(IntTestCase, @@ -260,6 +287,7 @@ CodeTestCase, ContainerTestCase, ExceptionTestCase, + BufferTestCase, BugsTestCase) if __name__ == "__main__": diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -362,11 +362,17 @@ def testGetAttrList(self): pass - def testGetAttrValues(self): pass + def testGetAttrValues(self): + pass - def testGetAttrLength(self): pass + def testGetAttrLength(self): + pass - def testGetAttribute(self): pass + def testGetAttribute(self): + dom = Document() + child = dom.appendChild( + dom.createElementNS("http://www.python.org", "python:abc")) + self.assertEqual(child.getAttribute('missing'), '') def testGetAttributeNS(self): dom = Document() @@ -378,6 +384,9 @@ 'http://www.python.org') self.assertEqual(child.getAttributeNS("http://www.w3.org", "other"), '') + child2 = child.appendChild(dom.createElement('abc')) + self.assertEqual(child2.getAttributeNS("http://www.python.org", "missing"), + '') def testGetAttributeNode(self): pass diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -1811,6 +1811,84 @@ p.join() l.close() +class _TestPoll(unittest.TestCase): + + ALLOWED_TYPES = ('processes', 'threads') + + def test_empty_string(self): + a, b = self.Pipe() + self.assertEqual(a.poll(), False) + b.send_bytes(b'') + self.assertEqual(a.poll(), True) + self.assertEqual(a.poll(), True) + + @classmethod + def _child_strings(cls, conn, strings): + for s in strings: + time.sleep(0.1) + conn.send_bytes(s) + conn.close() + + def test_strings(self): + strings = (b'hello', b'', b'a', b'b', b'', b'bye', b'', b'lop') + a, b = self.Pipe() + p = self.Process(target=self._child_strings, args=(b, strings)) + p.start() + + for s in strings: + for i in range(200): + if a.poll(0.01): + break + x = a.recv_bytes() + self.assertEqual(s, x) + + p.join() + + @classmethod + def _child_boundaries(cls, r): + # Polling may "pull" a message in to the child process, but we + # don't want it to pull only part of a message, as that would + # corrupt the pipe for any other processes which might later + # read from it. + r.poll(5) + + def test_boundaries(self): + r, w = self.Pipe(False) + p = self.Process(target=self._child_boundaries, args=(r,)) + p.start() + time.sleep(2) + L = [b"first", b"second"] + for obj in L: + w.send_bytes(obj) + w.close() + p.join() + self.assertIn(r.recv_bytes(), L) + + @classmethod + def _child_dont_merge(cls, b): + b.send_bytes(b'a') + b.send_bytes(b'b') + b.send_bytes(b'cd') + + def test_dont_merge(self): + a, b = self.Pipe() + self.assertEqual(a.poll(0.0), False) + self.assertEqual(a.poll(0.1), False) + + p = self.Process(target=self._child_dont_merge, args=(b,)) + p.start() + + self.assertEqual(a.recv_bytes(), b'a') + self.assertEqual(a.poll(1.0), True) + self.assertEqual(a.poll(1.0), True) + self.assertEqual(a.recv_bytes(), b'b') + self.assertEqual(a.poll(1.0), True) + self.assertEqual(a.poll(1.0), True) + self.assertEqual(a.poll(0.0), True) + self.assertEqual(a.recv_bytes(), b'cd') + + p.join() + # # Test of sending connection and socket objects between processes # @@ -2404,8 +2482,164 @@ flike.flush() assert sio.getvalue() == 'foo' + +class TestWait(unittest.TestCase): + + @classmethod + def _child_test_wait(cls, w, slow): + for i in range(10): + if slow: + time.sleep(random.random()*0.1) + w.send((i, os.getpid())) + w.close() + + def test_wait(self, slow=False): + from multiprocessing.connection import wait + readers = [] + procs = [] + messages = [] + + for i in range(4): + r, w = multiprocessing.Pipe(duplex=False) + p = multiprocessing.Process(target=self._child_test_wait, args=(w, slow)) + p.daemon = True + p.start() + w.close() + readers.append(r) + procs.append(p) + self.addCleanup(p.join) + + while readers: + for r in wait(readers): + try: + msg = r.recv() + except EOFError: + readers.remove(r) + r.close() + else: + messages.append(msg) + + messages.sort() + expected = sorted((i, p.pid) for i in range(10) for p in procs) + self.assertEqual(messages, expected) + + @classmethod + def _child_test_wait_socket(cls, address, slow): + s = socket.socket() + s.connect(address) + for i in range(10): + if slow: + time.sleep(random.random()*0.1) + s.sendall(('%s\n' % i).encode('ascii')) + s.close() + + def test_wait_socket(self, slow=False): + from multiprocessing.connection import wait + l = socket.socket() + l.bind(('', 0)) + l.listen(4) + addr = ('localhost', l.getsockname()[1]) + readers = [] + procs = [] + dic = {} + + for i in range(4): + p = multiprocessing.Process(target=self._child_test_wait_socket, + args=(addr, slow)) + p.daemon = True + p.start() + procs.append(p) + self.addCleanup(p.join) + + for i in range(4): + r, _ = l.accept() + readers.append(r) + dic[r] = [] + l.close() + + while readers: + for r in wait(readers): + msg = r.recv(32) + if not msg: + readers.remove(r) + r.close() + else: + dic[r].append(msg) + + expected = ''.join('%s\n' % i for i in range(10)).encode('ascii') + for v in dic.values(): + self.assertEqual(b''.join(v), expected) + + def test_wait_slow(self): + self.test_wait(True) + + def test_wait_socket_slow(self): + self.test_wait(True) + + def test_wait_timeout(self): + from multiprocessing.connection import wait + + expected = 1 + a, b = multiprocessing.Pipe() + + start = time.time() + res = wait([a, b], 1) + delta = time.time() - start + + self.assertEqual(res, []) + self.assertLess(delta, expected + 0.2) + self.assertGreater(delta, expected - 0.2) + + b.send(None) + + start = time.time() + res = wait([a, b], 1) + delta = time.time() - start + + self.assertEqual(res, [a]) + self.assertLess(delta, 0.2) + + def test_wait_integer(self): + from multiprocessing.connection import wait + + expected = 5 + a, b = multiprocessing.Pipe() + p = multiprocessing.Process(target=time.sleep, args=(expected,)) + + p.start() + self.assertIsInstance(p.sentinel, int) + + start = time.time() + res = wait([a, p.sentinel, b], expected + 20) + delta = time.time() - start + + self.assertEqual(res, [p.sentinel]) + self.assertLess(delta, expected + 1) + self.assertGreater(delta, expected - 1) + + a.send(None) + + start = time.time() + res = wait([a, p.sentinel, b], 20) + delta = time.time() - start + + self.assertEqual(res, [p.sentinel, b]) + self.assertLess(delta, 0.2) + + b.send(None) + + start = time.time() + res = wait([a, p.sentinel, b], 20) + delta = time.time() - start + + self.assertEqual(res, [a, p.sentinel, b]) + self.assertLess(delta, 0.2) + + p.join() + + testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, - TestStdinBadfiledescriptor] + TestStdinBadfiledescriptor, TestWait] # # diff --git a/Lib/test/test_mutants.py b/Lib/test/test_mutants.py deleted file mode 100644 --- a/Lib/test/test_mutants.py +++ /dev/null @@ -1,291 +0,0 @@ -from test.support import verbose, TESTFN -import random -import os - -# From SF bug #422121: Insecurities in dict comparison. - -# Safety of code doing comparisons has been an historical Python weak spot. -# The problem is that comparison of structures written in C *naturally* -# wants to hold on to things like the size of the container, or "the -# biggest" containee so far, across a traversal of the container; but -# code to do containee comparisons can call back into Python and mutate -# the container in arbitrary ways while the C loop is in midstream. If the -# C code isn't extremely paranoid about digging things out of memory on -# each trip, and artificially boosting refcounts for the duration, anything -# from infinite loops to OS crashes can result (yes, I use Windows ). -# -# The other problem is that code designed to provoke a weakness is usually -# white-box code, and so catches only the particular vulnerabilities the -# author knew to protect against. For example, Python's list.sort() code -# went thru many iterations as one "new" vulnerability after another was -# discovered. -# -# So the dict comparison test here uses a black-box approach instead, -# generating dicts of various sizes at random, and performing random -# mutations on them at random times. This proved very effective, -# triggering at least six distinct failure modes the first 20 times I -# ran it. Indeed, at the start, the driver never got beyond 6 iterations -# before the test died. - -# The dicts are global to make it easy to mutate tham from within functions. -dict1 = {} -dict2 = {} - -# The current set of keys in dict1 and dict2. These are materialized as -# lists to make it easy to pick a dict key at random. -dict1keys = [] -dict2keys = [] - -# Global flag telling maybe_mutate() whether to *consider* mutating. -mutate = 0 - -# If global mutate is true, consider mutating a dict. May or may not -# mutate a dict even if mutate is true. If it does decide to mutate a -# dict, it picks one of {dict1, dict2} at random, and deletes a random -# entry from it; or, more rarely, adds a random element. - -def maybe_mutate(): - global mutate - if not mutate: - return - if random.random() < 0.5: - return - - if random.random() < 0.5: - target, keys = dict1, dict1keys - else: - target, keys = dict2, dict2keys - - if random.random() < 0.2: - # Insert a new key. - mutate = 0 # disable mutation until key inserted - while 1: - newkey = Horrid(random.randrange(100)) - if newkey not in target: - break - target[newkey] = Horrid(random.randrange(100)) - keys.append(newkey) - mutate = 1 - - elif keys: - # Delete a key at random. - mutate = 0 # disable mutation until key deleted - i = random.randrange(len(keys)) - key = keys[i] - del target[key] - del keys[i] - mutate = 1 - -# A horrid class that triggers random mutations of dict1 and dict2 when -# instances are compared. - -class Horrid: - def __init__(self, i): - # Comparison outcomes are determined by the value of i. - self.i = i - - # An artificial hashcode is selected at random so that we don't - # have any systematic relationship between comparison outcomes - # (based on self.i and other.i) and relative position within the - # hash vector (based on hashcode). - # XXX This is no longer effective. - ##self.hashcode = random.randrange(1000000000) - - def __hash__(self): - return 42 - return self.hashcode - - def __eq__(self, other): - maybe_mutate() # The point of the test. - return self.i == other.i - - def __ne__(self, other): - raise RuntimeError("I didn't expect some kind of Spanish inquisition!") - - __lt__ = __le__ = __gt__ = __ge__ = __ne__ - - def __repr__(self): - return "Horrid(%d)" % self.i - -# Fill dict d with numentries (Horrid(i), Horrid(j)) key-value pairs, -# where i and j are selected at random from the candidates list. -# Return d.keys() after filling. - -def fill_dict(d, candidates, numentries): - d.clear() - for i in range(numentries): - d[Horrid(random.choice(candidates))] = \ - Horrid(random.choice(candidates)) - return list(d.keys()) - -# Test one pair of randomly generated dicts, each with n entries. -# Note that dict comparison is trivial if they don't have the same number -# of entires (then the "shorter" dict is instantly considered to be the -# smaller one, without even looking at the entries). - -def test_one(n): - global mutate, dict1, dict2, dict1keys, dict2keys - - # Fill the dicts without mutating them. - mutate = 0 - dict1keys = fill_dict(dict1, range(n), n) - dict2keys = fill_dict(dict2, range(n), n) - - # Enable mutation, then compare the dicts so long as they have the - # same size. - mutate = 1 - if verbose: - print("trying w/ lengths", len(dict1), len(dict2), end=' ') - while dict1 and len(dict1) == len(dict2): - if verbose: - print(".", end=' ') - c = dict1 == dict2 - if verbose: - print() - -# Run test_one n times. At the start (before the bugs were fixed), 20 -# consecutive runs of this test each blew up on or before the sixth time -# test_one was run. So n doesn't have to be large to get an interesting -# test. -# OTOH, calling with large n is also interesting, to ensure that the fixed -# code doesn't hold on to refcounts *too* long (in which case memory would -# leak). - -def test(n): - for i in range(n): - test_one(random.randrange(1, 100)) - -# See last comment block for clues about good values for n. -test(100) - -########################################################################## -# Another segfault bug, distilled by Michael Hudson from a c.l.py post. - -class Child: - def __init__(self, parent): - self.__dict__['parent'] = parent - def __getattr__(self, attr): - self.parent.a = 1 - self.parent.b = 1 - self.parent.c = 1 - self.parent.d = 1 - self.parent.e = 1 - self.parent.f = 1 - self.parent.g = 1 - self.parent.h = 1 - self.parent.i = 1 - return getattr(self.parent, attr) - -class Parent: - def __init__(self): - self.a = Child(self) - -# Hard to say what this will print! May vary from time to time. But -# we're specifically trying to test the tp_print slot here, and this is -# the clearest way to do it. We print the result to a temp file so that -# the expected-output file doesn't need to change. - -f = open(TESTFN, "w") -print(Parent().__dict__, file=f) -f.close() -os.unlink(TESTFN) - -########################################################################## -# And another core-dumper from Michael Hudson. - -dict = {} - -# Force dict to malloc its table. -for i in range(1, 10): - dict[i] = i - -f = open(TESTFN, "w") - -class Machiavelli: - def __repr__(self): - dict.clear() - - # Michael sez: "doesn't crash without this. don't know why." - # Tim sez: "luck of the draw; crashes with or without for me." - print(file=f) - - return repr("machiavelli") - - def __hash__(self): - return 0 - -dict[Machiavelli()] = Machiavelli() - -print(str(dict), file=f) -f.close() -os.unlink(TESTFN) -del f, dict - - -########################################################################## -# And another core-dumper from Michael Hudson. - -dict = {} - -# let's force dict to malloc its table -for i in range(1, 10): - dict[i] = i - -class Machiavelli2: - def __eq__(self, other): - dict.clear() - return 1 - - def __hash__(self): - return 0 - -dict[Machiavelli2()] = Machiavelli2() - -try: - dict[Machiavelli2()] -except KeyError: - pass - -del dict - -########################################################################## -# And another core-dumper from Michael Hudson. - -dict = {} - -# let's force dict to malloc its table -for i in range(1, 10): - dict[i] = i - -class Machiavelli3: - def __init__(self, id): - self.id = id - - def __eq__(self, other): - if self.id == other.id: - dict.clear() - return 1 - else: - return 0 - - def __repr__(self): - return "%s(%s)"%(self.__class__.__name__, self.id) - - def __hash__(self): - return 0 - -dict[Machiavelli3(1)] = Machiavelli3(0) -dict[Machiavelli3(2)] = Machiavelli3(0) - -f = open(TESTFN, "w") -try: - try: - print(dict[Machiavelli3(2)], file=f) - except KeyError: - pass -finally: - f.close() - os.unlink(TESTFN) - -del dict -del dict1, dict2, dict1keys, dict2keys diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -1,5 +1,6 @@ import pickle import io +import collections from test import support @@ -7,6 +8,7 @@ from test.pickletester import AbstractPickleModuleTests from test.pickletester import AbstractPersistentPicklerTests from test.pickletester import AbstractPicklerUnpicklerObjectTests +from test.pickletester import AbstractDispatchTableTests from test.pickletester import BigmemPickleTests try: @@ -80,6 +82,18 @@ unpickler_class = pickle._Unpickler +class PyDispatchTableTests(AbstractDispatchTableTests): + pickler_class = pickle._Pickler + def get_dispatch_table(self): + return pickle.dispatch_table.copy() + + +class PyChainDispatchTableTests(AbstractDispatchTableTests): + pickler_class = pickle._Pickler + def get_dispatch_table(self): + return collections.ChainMap({}, pickle.dispatch_table) + + if has_c_implementation: class CPicklerTests(PyPicklerTests): pickler = _pickle.Pickler @@ -101,14 +115,26 @@ pickler_class = _pickle.Pickler unpickler_class = _pickle.Unpickler + class CDispatchTableTests(AbstractDispatchTableTests): + pickler_class = pickle.Pickler + def get_dispatch_table(self): + return pickle.dispatch_table.copy() + + class CChainDispatchTableTests(AbstractDispatchTableTests): + pickler_class = pickle.Pickler + def get_dispatch_table(self): + return collections.ChainMap({}, pickle.dispatch_table) + def test_main(): - tests = [PickleTests, PyPicklerTests, PyPersPicklerTests] + tests = [PickleTests, PyPicklerTests, PyPersPicklerTests, + PyDispatchTableTests, PyChainDispatchTableTests] if has_c_implementation: tests.extend([CPicklerTests, CPersPicklerTests, CDumpPickle_LoadPickle, DumpPickle_CLoadPickle, PyPicklerUnpicklerObjectTests, CPicklerUnpicklerObjectTests, + CDispatchTableTests, CChainDispatchTableTests, InMemoryPickleTests]) support.run_unittest(*tests) support.run_doctest(pickle) diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -205,6 +205,7 @@ self.orig_stdout_fileno = pty.STDOUT_FILENO self.orig_pty_select = pty.select self.fds = [] # A list of file descriptors to close. + self.files = [] self.select_rfds_lengths = [] self.select_rfds_results = [] @@ -212,10 +213,15 @@ pty.STDIN_FILENO = self.orig_stdin_fileno pty.STDOUT_FILENO = self.orig_stdout_fileno pty.select = self.orig_pty_select + for file in self.files: + try: + file.close() + except OSError: + pass for fd in self.fds: try: os.close(fd) - except: + except OSError: pass def _pipe(self): @@ -223,6 +229,11 @@ self.fds.extend(pipe_fds) return pipe_fds + def _socketpair(self): + socketpair = socket.socketpair() + self.files.extend(socketpair) + return socketpair + def _mock_select(self, rfds, wfds, xfds): # This will raise IndexError when no more expected calls exist. self.assertEqual(self.select_rfds_lengths.pop(0), len(rfds)) @@ -234,9 +245,8 @@ pty.STDOUT_FILENO = mock_stdout_fd mock_stdin_fd, write_to_stdin_fd = self._pipe() pty.STDIN_FILENO = mock_stdin_fd - socketpair = socket.socketpair() + socketpair = self._socketpair() masters = [s.fileno() for s in socketpair] - self.fds.extend(masters) # Feed data. Smaller than PIPEBUF. These writes will not block. os.write(masters[1], b'from master') @@ -263,9 +273,8 @@ pty.STDOUT_FILENO = mock_stdout_fd mock_stdin_fd, write_to_stdin_fd = self._pipe() pty.STDIN_FILENO = mock_stdin_fd - socketpair = socket.socketpair() + socketpair = self._socketpair() masters = [s.fileno() for s in socketpair] - self.fds.extend(masters) os.close(masters[1]) socketpair[1].close() diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -662,7 +662,7 @@ self.wait_helper(signal.SIGALRM, ''' def test(signum): signal.alarm(1) - info = signal.sigtimedwait([signum], (10, 1000)) + info = signal.sigtimedwait([signum], 10.1000) if info.si_signo != signum: raise Exception('info.si_signo != %s' % signum) ''') @@ -675,7 +675,7 @@ def test(signum): import os os.kill(os.getpid(), signum) - info = signal.sigtimedwait([signum], (0, 0)) + info = signal.sigtimedwait([signum], 0) if info.si_signo != signum: raise Exception('info.si_signo != %s' % signum) ''') @@ -685,7 +685,7 @@ def test_sigtimedwait_timeout(self): self.wait_helper(signal.SIGALRM, ''' def test(signum): - received = signal.sigtimedwait([signum], (1, 0)) + received = signal.sigtimedwait([signum], 1.0) if received is not None: raise Exception("received=%r" % (received,)) ''') @@ -694,9 +694,7 @@ 'need signal.sigtimedwait()') def test_sigtimedwait_negative_timeout(self): signum = signal.SIGALRM - self.assertRaises(ValueError, signal.sigtimedwait, [signum], (-1, -1)) - self.assertRaises(ValueError, signal.sigtimedwait, [signum], (0, -1)) - self.assertRaises(ValueError, signal.sigtimedwait, [signum], (-1, 0)) + self.assertRaises(ValueError, signal.sigtimedwait, [signum], -1.0) @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'), 'need signal.sigwaitinfo()') diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -497,12 +497,31 @@ pass +class TestPytime(unittest.TestCase): + def test_timespec(self): + from _testcapi import pytime_object_to_timespec + for obj, timespec in ( + (0, (0, 0)), + (-1, (-1, 0)), + (-1.0, (-1, 0)), + (-1e-9, (-1, 999999999)), + (-1.2, (-2, 800000000)), + (1.123456789, (1, 123456789)), + ): + self.assertEqual(pytime_object_to_timespec(obj), timespec) + + for invalid in (-(2 ** 100), -(2.0 ** 100.0), 2 ** 100, 2.0 ** 100.0): + self.assertRaises(OverflowError, pytime_object_to_timespec, invalid) + + + def test_main(): support.run_unittest( TimeTestCase, TestLocale, TestAsctime4dyear, - TestStrftime4dyear) + TestStrftime4dyear, + TestPytime) if __name__ == "__main__": test_main() diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -563,6 +563,18 @@ NAME 'gr?n' (2, 0) (2, 4) OP '=' (2, 5) (2, 6) STRING "'green'" (2, 7) (2, 14) + +Legacy unicode literals: + + >>> dump_tokens("?rter = u'places'\\ngr?n = UR'green'") + ENCODING 'utf-8' (0, 0) (0, 0) + NAME '?rter' (1, 0) (1, 5) + OP '=' (1, 6) (1, 7) + STRING "u'places'" (1, 8) (1, 17) + NEWLINE '\\n' (1, 17) (1, 18) + NAME 'gr?n' (2, 0) (2, 4) + OP '=' (2, 5) (2, 6) + STRING "UR'green'" (2, 7) (2, 16) """ from test import support diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -28,6 +28,12 @@ # need to keep references to them self.items = [ustr(c) for c in ('a', 'b', 'c')] self.items2 = [ustr(c) for c in ('x', 'y', 'z')] + self.ab_items = [ustr(c) for c in 'ab'] + self.abcde_items = [ustr(c) for c in 'abcde'] + self.def_items = [ustr(c) for c in 'def'] + self.ab_weakset = WeakSet(self.ab_items) + self.abcde_weakset = WeakSet(self.abcde_items) + self.def_weakset = WeakSet(self.def_items) self.letters = [ustr(c) for c in string.ascii_letters] self.s = WeakSet(self.items) self.d = dict.fromkeys(self.items) @@ -71,6 +77,11 @@ x = WeakSet(self.items + self.items2) c = C(self.items2) self.assertEqual(self.s.union(c), x) + del c + self.assertEqual(len(u), len(self.items) + len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(u), len(self.items) + len(self.items2)) def test_or(self): i = self.s.union(self.items2) @@ -78,14 +89,19 @@ self.assertEqual(self.s | frozenset(self.items2), i) def test_intersection(self): - i = self.s.intersection(self.items2) + s = WeakSet(self.letters) + i = s.intersection(self.items2) for c in self.letters: - self.assertEqual(c in i, c in self.d and c in self.items2) - self.assertEqual(self.s, WeakSet(self.items)) + self.assertEqual(c in i, c in self.items2 and c in self.letters) + self.assertEqual(s, WeakSet(self.letters)) self.assertEqual(type(i), WeakSet) for C in set, frozenset, dict.fromkeys, list, tuple: x = WeakSet([]) - self.assertEqual(self.s.intersection(C(self.items2)), x) + self.assertEqual(i.intersection(C(self.items)), x) + self.assertEqual(len(i), len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(i), len(self.items2)) def test_isdisjoint(self): self.assertTrue(self.s.isdisjoint(WeakSet(self.items2))) @@ -116,6 +132,10 @@ self.assertEqual(self.s, WeakSet(self.items)) self.assertEqual(type(i), WeakSet) self.assertRaises(TypeError, self.s.symmetric_difference, [[]]) + self.assertEqual(len(i), len(self.items) + len(self.items2)) + self.items2.pop() + gc.collect() + self.assertEqual(len(i), len(self.items) + len(self.items2)) def test_xor(self): i = self.s.symmetric_difference(self.items2) @@ -123,22 +143,28 @@ self.assertEqual(self.s ^ frozenset(self.items2), i) def test_sub_and_super(self): - pl, ql, rl = map(lambda s: [ustr(c) for c in s], ['ab', 'abcde', 'def']) - p, q, r = map(WeakSet, (pl, ql, rl)) - self.assertTrue(p < q) - self.assertTrue(p <= q) - self.assertTrue(q <= q) - self.assertTrue(q > p) - self.assertTrue(q >= p) - self.assertFalse(q < r) - self.assertFalse(q <= r) - self.assertFalse(q > r) - self.assertFalse(q >= r) + self.assertTrue(self.ab_weakset <= self.abcde_weakset) + self.assertTrue(self.abcde_weakset <= self.abcde_weakset) + self.assertTrue(self.abcde_weakset >= self.ab_weakset) + self.assertFalse(self.abcde_weakset <= self.def_weakset) + self.assertFalse(self.abcde_weakset >= self.def_weakset) self.assertTrue(set('a').issubset('abc')) self.assertTrue(set('abc').issuperset('a')) self.assertFalse(set('a').issubset('cbs')) self.assertFalse(set('cbs').issuperset('a')) + def test_lt(self): + self.assertTrue(self.ab_weakset < self.abcde_weakset) + self.assertFalse(self.abcde_weakset < self.def_weakset) + self.assertFalse(self.ab_weakset < self.ab_weakset) + self.assertFalse(WeakSet() < WeakSet()) + + def test_gt(self): + self.assertTrue(self.abcde_weakset > self.ab_weakset) + self.assertFalse(self.abcde_weakset > self.def_weakset) + self.assertFalse(self.ab_weakset > self.ab_weakset) + self.assertFalse(WeakSet() > WeakSet()) + def test_gc(self): # Create a nest of cycles to exercise overall ref count check s = WeakSet(Foo() for i in range(1000)) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1855,6 +1855,102 @@ # -------------------------------------------------------------------- +class ElementTreeTest(unittest.TestCase): + + def test_istype(self): + self.assertIsInstance(ET.ParseError, type) + self.assertIsInstance(ET.QName, type) + self.assertIsInstance(ET.ElementTree, type) + self.assertIsInstance(ET.Element, type) + # XXX issue 14128 with C ElementTree + # self.assertIsInstance(ET.TreeBuilder, type) + # self.assertIsInstance(ET.XMLParser, type) + + def test_Element_subclass_trivial(self): + class MyElement(ET.Element): + pass + + mye = MyElement('foo') + self.assertIsInstance(mye, ET.Element) + self.assertIsInstance(mye, MyElement) + self.assertEqual(mye.tag, 'foo') + + def test_Element_subclass_constructor(self): + class MyElement(ET.Element): + def __init__(self, tag, attrib={}, **extra): + super(MyElement, self).__init__(tag + '__', attrib, **extra) + + mye = MyElement('foo', {'a': 1, 'b': 2}, c=3, d=4) + self.assertEqual(mye.tag, 'foo__') + self.assertEqual(sorted(mye.items()), + [('a', 1), ('b', 2), ('c', 3), ('d', 4)]) + + def test_Element_subclass_new_method(self): + class MyElement(ET.Element): + def newmethod(self): + return self.tag + + mye = MyElement('joe') + self.assertEqual(mye.newmethod(), 'joe') + + +class TreeBuilderTest(unittest.TestCase): + + sample1 = ('' + 'text') + + def test_dummy_builder(self): + class BaseDummyBuilder: + def close(self): + return 42 + + class DummyBuilder(BaseDummyBuilder): + data = start = end = lambda *a: None + + parser = ET.XMLParser(target=DummyBuilder()) + parser.feed(self.sample1) + self.assertEqual(parser.close(), 42) + + parser = ET.XMLParser(target=BaseDummyBuilder()) + parser.feed(self.sample1) + self.assertEqual(parser.close(), 42) + + parser = ET.XMLParser(target=object()) + parser.feed(self.sample1) + self.assertIsNone(parser.close()) + + + @unittest.expectedFailure # XXX issue 14007 with C ElementTree + def test_doctype(self): + class DoctypeParser: + _doctype = None + + def doctype(self, name, pubid, system): + self._doctype = (name, pubid, system) + + def close(self): + return self._doctype + + parser = ET.XMLParser(target=DoctypeParser()) + parser.feed(self.sample1) + + self.assertEqual(parser.close(), + ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')) + + +class NoAcceleratorTest(unittest.TestCase): + + # Test that the C accelerator was not imported for pyET + def test_correct_import_pyET(self): + self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') + self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') + +# -------------------------------------------------------------------- + + class CleanContext(object): """Provide default namespace mapping and path cache.""" checkwarnings = None @@ -1873,10 +1969,7 @@ ("This method will be removed in future versions. " "Use .+ instead.", DeprecationWarning), ("This method will be removed in future versions. " - "Use .+ instead.", PendingDeprecationWarning), - # XMLParser.doctype() is deprecated. - ("This method of XMLParser is deprecated. Define doctype.. " - "method on the TreeBuilder target.", DeprecationWarning)) + "Use .+ instead.", PendingDeprecationWarning)) self.checkwarnings = support.check_warnings(*deprecations, quiet=quiet) def __enter__(self): @@ -1898,19 +1991,18 @@ self.checkwarnings.__exit__(*args) -class TestAcceleratorNotImported(unittest.TestCase): - # Test that the C accelerator was not imported for pyET - def test_correct_import_pyET(self): - self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') - - def test_main(module=pyET): from test import test_xml_etree # The same doctests are used for both the Python and the C implementations test_xml_etree.ET = module - support.run_unittest(TestAcceleratorNotImported) + test_classes = [ElementTreeTest, TreeBuilderTest] + if module is pyET: + # Run the tests specific to the Python implementation + test_classes += [NoAcceleratorTest] + + support.run_unittest(*test_classes) # XXX the C module should give the same warnings as the Python module with CleanContext(quiet=(module is not pyET)): diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -47,13 +47,20 @@ data = None @unittest.skipUnless(cET, 'requires _elementtree') +class TestAliasWorking(unittest.TestCase): + # Test that the cET alias module is alive + def test_alias_working(self): + e = cET_alias.Element('foo') + self.assertEqual(e.tag, 'foo') + + at unittest.skipUnless(cET, 'requires _elementtree') class TestAcceleratorImported(unittest.TestCase): # Test that the C accelerator was imported, as expected def test_correct_import_cET(self): - self.assertEqual(cET.Element.__module__, '_elementtree') + self.assertEqual(cET.SubElement.__module__, '_elementtree') def test_correct_import_cET_alias(self): - self.assertEqual(cET_alias.Element.__module__, '_elementtree') + self.assertEqual(cET_alias.SubElement.__module__, '_elementtree') def test_main(): @@ -61,13 +68,15 @@ # Run the tests specific to the C implementation support.run_doctest(test_xml_etree_c, verbosity=True) - - support.run_unittest(MiscTests, TestAcceleratorImported) + support.run_unittest( + MiscTests, + TestAliasWorking, + TestAcceleratorImported + ) # Run the same test suite as the Python module test_xml_etree.test_main(module=cET) - # Exercise the deprecated alias - test_xml_etree.test_main(module=cET_alias) + if __name__ == '__main__': test_main() diff --git a/Lib/threading.py b/Lib/threading.py --- a/Lib/threading.py +++ b/Lib/threading.py @@ -34,40 +34,6 @@ del _thread -# Debug support (adapted from ihooks.py). - -_VERBOSE = False - -if __debug__: - - class _Verbose(object): - - def __init__(self, verbose=None): - if verbose is None: - verbose = _VERBOSE - self._verbose = verbose - - def _note(self, format, *args): - if self._verbose: - format = format % args - # Issue #4188: calling current_thread() can incur an infinite - # recursion if it has to create a DummyThread on the fly. - ident = get_ident() - try: - name = _active[ident].name - except KeyError: - name = "" % ident - format = "%s: %s\n" % (name, format) - _sys.stderr.write(format) - -else: - # Disable this when using "python -O" - class _Verbose(object): - def __init__(self, verbose=None): - pass - def _note(self, *args): - pass - # Support for profile and trace hooks _profile_hook = None @@ -85,17 +51,14 @@ Lock = _allocate_lock -def RLock(verbose=None, *args, **kwargs): - if verbose is None: - verbose = _VERBOSE - if (__debug__ and verbose) or _CRLock is None: - return _PyRLock(verbose, *args, **kwargs) +def RLock(*args, **kwargs): + if _CRLock is None: + return _PyRLock(*args, **kwargs) return _CRLock(*args, **kwargs) -class _RLock(_Verbose): +class _RLock: - def __init__(self, verbose=None): - _Verbose.__init__(self, verbose) + def __init__(self): self._block = _allocate_lock() self._owner = None self._count = 0 @@ -113,18 +76,11 @@ me = get_ident() if self._owner == me: self._count = self._count + 1 - if __debug__: - self._note("%s.acquire(%s): recursive success", self, blocking) return 1 rc = self._block.acquire(blocking, timeout) if rc: self._owner = me self._count = 1 - if __debug__: - self._note("%s.acquire(%s): initial success", self, blocking) - else: - if __debug__: - self._note("%s.acquire(%s): failure", self, blocking) return rc __enter__ = acquire @@ -136,11 +92,6 @@ if not count: self._owner = None self._block.release() - if __debug__: - self._note("%s.release(): final release", self) - else: - if __debug__: - self._note("%s.release(): non-final release", self) def __exit__(self, t, v, tb): self.release() @@ -150,12 +101,8 @@ def _acquire_restore(self, state): self._block.acquire() self._count, self._owner = state - if __debug__: - self._note("%s._acquire_restore()", self) def _release_save(self): - if __debug__: - self._note("%s._release_save()", self) if self._count == 0: raise RuntimeError("cannot release un-acquired lock") count = self._count @@ -171,10 +118,9 @@ _PyRLock = _RLock -class Condition(_Verbose): +class Condition: - def __init__(self, lock=None, verbose=None): - _Verbose.__init__(self, verbose) + def __init__(self, lock=None): if lock is None: lock = RLock() self._lock = lock @@ -233,23 +179,16 @@ if timeout is None: waiter.acquire() gotit = True - if __debug__: - self._note("%s.wait(): got it", self) else: if timeout > 0: gotit = waiter.acquire(True, timeout) else: gotit = waiter.acquire(False) if not gotit: - if __debug__: - self._note("%s.wait(%s): timed out", self, timeout) try: self._waiters.remove(waiter) except ValueError: pass - else: - if __debug__: - self._note("%s.wait(%s): got it", self, timeout) return gotit finally: self._acquire_restore(saved_state) @@ -265,19 +204,9 @@ else: waittime = endtime - _time() if waittime <= 0: - if __debug__: - self._note("%s.wait_for(%r, %r): Timed out.", - self, predicate, timeout) break - if __debug__: - self._note("%s.wait_for(%r, %r): Waiting with timeout=%s.", - self, predicate, timeout, waittime) self.wait(waittime) result = predicate() - else: - if __debug__: - self._note("%s.wait_for(%r, %r): Success.", - self, predicate, timeout) return result def notify(self, n=1): @@ -286,11 +215,7 @@ __waiters = self._waiters waiters = __waiters[:n] if not waiters: - if __debug__: - self._note("%s.notify(): no waiters", self) return - self._note("%s.notify(): notifying %d waiter%s", self, n, - n!=1 and "s" or "") for waiter in waiters: waiter.release() try: @@ -304,14 +229,13 @@ notifyAll = notify_all -class Semaphore(_Verbose): +class Semaphore: # After Tim Peters' semaphore class, but not quite the same (no maximum) - def __init__(self, value=1, verbose=None): + def __init__(self, value=1): if value < 0: raise ValueError("semaphore initial value must be >= 0") - _Verbose.__init__(self, verbose) self._cond = Condition(Lock()) self._value = value @@ -324,9 +248,6 @@ while self._value == 0: if not blocking: break - if __debug__: - self._note("%s.acquire(%s): blocked waiting, value=%s", - self, blocking, self._value) if timeout is not None: if endtime is None: endtime = _time() + timeout @@ -337,9 +258,6 @@ self._cond.wait(timeout) else: self._value = self._value - 1 - if __debug__: - self._note("%s.acquire: success, value=%s", - self, self._value) rc = True self._cond.release() return rc @@ -349,9 +267,6 @@ def release(self): self._cond.acquire() self._value = self._value + 1 - if __debug__: - self._note("%s.release: success, value=%s", - self, self._value) self._cond.notify() self._cond.release() @@ -361,8 +276,8 @@ class BoundedSemaphore(Semaphore): """Semaphore that checks that # releases is <= # acquires""" - def __init__(self, value=1, verbose=None): - Semaphore.__init__(self, value, verbose) + def __init__(self, value=1): + Semaphore.__init__(self, value) self._initial_value = value def release(self): @@ -371,12 +286,11 @@ return Semaphore.release(self) -class Event(_Verbose): +class Event: # After Tim Peters' event class (without is_posted()) - def __init__(self, verbose=None): - _Verbose.__init__(self, verbose) + def __init__(self): self._cond = Condition(Lock()) self._flag = False @@ -426,13 +340,13 @@ # since the previous cycle. In addition, a 'resetting' state exists which is # similar to 'draining' except that threads leave with a BrokenBarrierError, # and a 'broken' state in which all threads get the exception. -class Barrier(_Verbose): +class Barrier: """ Barrier. Useful for synchronizing a fixed number of threads at known synchronization points. Threads block on 'wait()' and are simultaneously once they have all made that call. """ - def __init__(self, parties, action=None, timeout=None, verbose=None): + def __init__(self, parties, action=None, timeout=None): """ Create a barrier, initialised to 'parties' threads. 'action' is a callable which, when supplied, will be called @@ -441,7 +355,6 @@ If a 'timeout' is provided, it is uses as the default for all subsequent 'wait()' calls. """ - _Verbose.__init__(self, verbose) self._cond = Condition(Lock()) self._action = action self._timeout = timeout @@ -602,7 +515,7 @@ # Main class for threads -class Thread(_Verbose): +class Thread: __initialized = False # Need to store a reference to sys.exc_info for printing @@ -615,9 +528,8 @@ #XXX __exc_clear = _sys.exc_clear def __init__(self, group=None, target=None, name=None, - args=(), kwargs=None, verbose=None, *, daemon=None): + args=(), kwargs=None, *, daemon=None): assert group is None, "group argument must be None for now" - _Verbose.__init__(self, verbose) if kwargs is None: kwargs = {} self._target = target @@ -664,8 +576,6 @@ if self._started.is_set(): raise RuntimeError("threads can only be started once") - if __debug__: - self._note("%s.start(): starting thread", self) with _active_limbo_lock: _limbo[self] = self try: @@ -715,24 +625,17 @@ with _active_limbo_lock: _active[self._ident] = self del _limbo[self] - if __debug__: - self._note("%s._bootstrap(): thread started", self) if _trace_hook: - self._note("%s._bootstrap(): registering trace hook", self) _sys.settrace(_trace_hook) if _profile_hook: - self._note("%s._bootstrap(): registering profile hook", self) _sys.setprofile(_profile_hook) try: self.run() except SystemExit: - if __debug__: - self._note("%s._bootstrap(): raised SystemExit", self) + pass except: - if __debug__: - self._note("%s._bootstrap(): unhandled exception", self) # If sys.stderr is no more (most likely from interpreter # shutdown) use self._stderr. Otherwise still use sys (as in # _sys) in case sys.stderr was redefined since the creation of @@ -763,9 +666,6 @@ # hog; deleting everything else is just for thoroughness finally: del exc_type, exc_value, exc_tb - else: - if __debug__: - self._note("%s._bootstrap(): normal return", self) finally: # Prevent a race in # test_threading.test_no_refcycle_through_target when @@ -832,29 +732,18 @@ if self is current_thread(): raise RuntimeError("cannot join current thread") - if __debug__: - if not self._stopped: - self._note("%s.join(): waiting until thread stops", self) - self._block.acquire() try: if timeout is None: while not self._stopped: self._block.wait() - if __debug__: - self._note("%s.join(): thread stopped", self) else: deadline = _time() + timeout while not self._stopped: delay = deadline - _time() if delay <= 0: - if __debug__: - self._note("%s.join(): timed out", self) break self._block.wait(delay) - else: - if __debug__: - self._note("%s.join(): thread stopped", self) finally: self._block.release() @@ -947,14 +836,9 @@ def _exitfunc(self): self._stop() t = _pickSomeNonDaemonThread() - if t: - if __debug__: - self._note("%s: waiting for other threads", self) while t: t.join() t = _pickSomeNonDaemonThread() - if __debug__: - self._note("%s: exiting", self) self._delete() def _pickSomeNonDaemonThread(): diff --git a/Lib/tokenize.py b/Lib/tokenize.py --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -127,6 +127,8 @@ Imagnumber = group(r'[0-9]+[jJ]', Floatnumber + r'[jJ]') Number = group(Imagnumber, Floatnumber, Intnumber) +StringPrefix = r'(?:[uU][rR]?|[bB][rR]|[rR][bB]|[rR]|[uU])?' + # Tail end of ' string. Single = r"[^'\\]*(?:\\.[^'\\]*)*'" # Tail end of " string. @@ -135,10 +137,10 @@ Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" # Tail end of """ string. Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' -Triple = group("[bB]?[rR]?'''", '[bB]?[rR]?"""') +Triple = group(StringPrefix + "'''", StringPrefix + '"""') # Single-line ' or " string. -String = group(r"[bB]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*'", - r'[bB]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*"') +String = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'", + StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"') # Because of leftmost-then-longest match semantics, be sure to put the # longest operators first (e.g., if = came before ==, == would get @@ -156,9 +158,9 @@ Token = Ignore + PlainToken # First (or only) line of ' or " string. -ContStr = group(r"[bB]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*" + +ContStr = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + group("'", r'\\\r?\n'), - r'[bB]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*' + + StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + group('"', r'\\\r?\n')) PseudoExtras = group(r'\\\r?\n', Comment, Triple) PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) @@ -170,27 +172,49 @@ "'''": Single3, '"""': Double3, "r'''": Single3, 'r"""': Double3, "b'''": Single3, 'b"""': Double3, - "br'''": Single3, 'br"""': Double3, "R'''": Single3, 'R"""': Double3, "B'''": Single3, 'B"""': Double3, + "br'''": Single3, 'br"""': Double3, "bR'''": Single3, 'bR"""': Double3, "Br'''": Single3, 'Br"""': Double3, "BR'''": Single3, 'BR"""': Double3, - 'r': None, 'R': None, 'b': None, 'B': None} + "rb'''": Single3, 'rb"""': Double3, + "Rb'''": Single3, 'Rb"""': Double3, + "rB'''": Single3, 'rB"""': Double3, + "RB'''": Single3, 'RB"""': Double3, + "u'''": Single3, 'u"""': Double3, + "ur'''": Single3, 'ur"""': Double3, + "R'''": Single3, 'R"""': Double3, + "U'''": Single3, 'U"""': Double3, + "uR'''": Single3, 'uR"""': Double3, + "Ur'''": Single3, 'Ur"""': Double3, + "UR'''": Single3, 'UR"""': Double3, + 'r': None, 'R': None, 'b': None, 'B': None, + 'u': None, 'U': None} triple_quoted = {} for t in ("'''", '"""', "r'''", 'r"""', "R'''", 'R"""', "b'''", 'b"""', "B'''", 'B"""', "br'''", 'br"""', "Br'''", 'Br"""', - "bR'''", 'bR"""', "BR'''", 'BR"""'): + "bR'''", 'bR"""', "BR'''", 'BR"""', + "rb'''", 'rb"""', "rB'''", 'rB"""', + "Rb'''", 'Rb"""', "RB'''", 'RB"""', + "u'''", 'u"""', "U'''", 'U"""', + "ur'''", 'ur"""', "Ur'''", 'Ur"""', + "uR'''", 'uR"""', "UR'''", 'UR"""'): triple_quoted[t] = t single_quoted = {} for t in ("'", '"', "r'", 'r"', "R'", 'R"', "b'", 'b"', "B'", 'B"', "br'", 'br"', "Br'", 'Br"', - "bR'", 'bR"', "BR'", 'BR"' ): + "bR'", 'bR"', "BR'", 'BR"' , + "rb'", 'rb"', "rB'", 'rB"', + "Rb'", 'Rb"', "RB'", 'RB"' , + "u'", 'u"', "U'", 'U"', + "ur'", 'ur"', "Ur'", 'Ur"', + "uR'", 'uR"', "UR'", 'UR"' ): single_quoted[t] = t tabsize = 8 diff --git a/Lib/xml/dom/__init__.py b/Lib/xml/dom/__init__.py --- a/Lib/xml/dom/__init__.py +++ b/Lib/xml/dom/__init__.py @@ -17,6 +17,7 @@ class Node: """Class giving the NodeType constants.""" + __slots__ = () # DOM implementations may use this as a base class for their own # Node implementations. If they don't, the constants defined here diff --git a/Lib/xml/dom/domreg.py b/Lib/xml/dom/domreg.py --- a/Lib/xml/dom/domreg.py +++ b/Lib/xml/dom/domreg.py @@ -2,8 +2,6 @@ directly. Instead, the functions getDOMImplementation and registerDOMImplementation should be imported from xml.dom.""" -from xml.dom.minicompat import * # isinstance, StringTypes - # This is a list of well-known implementations. Well-known names # should be published by posting to xml-sig at python.org, and are # subsequently recorded in this file. diff --git a/Lib/xml/dom/expatbuilder.py b/Lib/xml/dom/expatbuilder.py --- a/Lib/xml/dom/expatbuilder.py +++ b/Lib/xml/dom/expatbuilder.py @@ -33,8 +33,6 @@ from xml.dom.minidom import _append_child, _set_attribute_node from xml.dom.NodeFilter import NodeFilter -from xml.dom.minicompat import * - TEXT_NODE = Node.TEXT_NODE CDATA_SECTION_NODE = Node.CDATA_SECTION_NODE DOCUMENT_NODE = Node.DOCUMENT_NODE @@ -755,7 +753,7 @@ a = minidom.Attr("xmlns", XMLNS_NAMESPACE, "xmlns", EMPTY_PREFIX) a.value = uri - a.ownerDocuemnt = self.document + a.ownerDocument = self.document _set_attribute_node(node, a) del self._ns_ordered_prefixes[:] diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -62,10 +62,7 @@ return writer.stream.getvalue() def hasChildNodes(self): - if self.childNodes: - return True - else: - return False + return bool(self.childNodes) def _get_childNodes(self): return self.childNodes @@ -723,12 +720,16 @@ Node.unlink(self) def getAttribute(self, attname): + if self._attrs is None: + return "" try: return self._attrs[attname].value except KeyError: return "" def getAttributeNS(self, namespaceURI, localName): + if self._attrsNS is None: + return "" try: return self._attrsNS[(namespaceURI, localName)].value except KeyError: @@ -926,6 +927,7 @@ """Mixin that makes childless-ness easy to implement and avoids the complexity of the Node methods that deal with children. """ + __slots__ = () attributes = None childNodes = EmptyNodeList() @@ -1063,6 +1065,8 @@ class Text(CharacterData): + __slots__ = () + nodeType = Node.TEXT_NODE nodeName = "#text" attributes = None @@ -1184,6 +1188,8 @@ class CDATASection(Text): + __slots__ = () + nodeType = Node.CDATA_SECTION_NODE nodeName = "#cdata-section" @@ -1262,8 +1268,7 @@ class Identified: """Mix-in class that supports the publicId and systemId attributes.""" - # XXX this does not work, this is an old-style class - # __slots__ = 'publicId', 'systemId' + __slots__ = 'publicId', 'systemId' def _identified_mixin_init(self, publicId, systemId): self.publicId = publicId diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -101,7 +101,6 @@ import re import warnings - class _SimpleElementPath: # emulate pre-1.2 find/findtext/findall behaviour def find(self, element, tag, namespaces=None): @@ -1512,24 +1511,30 @@ self.target = self._target = target self._error = expat.error self._names = {} # name memo cache - # callbacks + # main callbacks parser.DefaultHandlerExpand = self._default - parser.StartElementHandler = self._start - parser.EndElementHandler = self._end - parser.CharacterDataHandler = self._data - # optional callbacks - parser.CommentHandler = self._comment - parser.ProcessingInstructionHandler = self._pi + if hasattr(target, 'start'): + parser.StartElementHandler = self._start + if hasattr(target, 'end'): + parser.EndElementHandler = self._end + if hasattr(target, 'data'): + parser.CharacterDataHandler = target.data + # miscellaneous callbacks + if hasattr(target, 'comment'): + parser.CommentHandler = target.comment + if hasattr(target, 'pi'): + parser.ProcessingInstructionHandler = target.pi # let expat do the buffering, if supported try: - self._parser.buffer_text = 1 + parser.buffer_text = 1 except AttributeError: pass # use new-style attribute handling, if supported try: - self._parser.ordered_attributes = 1 - self._parser.specified_attributes = 1 - parser.StartElementHandler = self._start_list + parser.ordered_attributes = 1 + parser.specified_attributes = 1 + if hasattr(target, 'start'): + parser.StartElementHandler = self._start_list except AttributeError: pass self._doctype = None @@ -1573,44 +1578,29 @@ attrib[fixname(attrib_in[i])] = attrib_in[i+1] return self.target.start(tag, attrib) - def _data(self, text): - return self.target.data(text) - def _end(self, tag): return self.target.end(self._fixname(tag)) - def _comment(self, data): - try: - comment = self.target.comment - except AttributeError: - pass - else: - return comment(data) - - def _pi(self, target, data): - try: - pi = self.target.pi - except AttributeError: - pass - else: - return pi(target, data) - def _default(self, text): prefix = text[:1] if prefix == "&": # deal with undefined entities try: - self.target.data(self.entity[text[1:-1]]) + data_handler = self.target.data + except AttributeError: + return + try: + data_handler(self.entity[text[1:-1]]) except KeyError: from xml.parsers import expat err = expat.error( "undefined entity %s: line %d, column %d" % - (text, self._parser.ErrorLineNumber, - self._parser.ErrorColumnNumber) + (text, self.parser.ErrorLineNumber, + self.parser.ErrorColumnNumber) ) err.code = 11 # XML_ERROR_UNDEFINED_ENTITY - err.lineno = self._parser.ErrorLineNumber - err.offset = self._parser.ErrorColumnNumber + err.lineno = self.parser.ErrorLineNumber + err.offset = self.parser.ErrorColumnNumber raise err elif prefix == "<" and text[:9] == " a' has been + fixed. + +- Issue #14166: Pickler objects now have an optional ``dispatch_table`` + attribute which allows to set custom per-pickler reduction functions. + Patch by sbt. + +- Issue #14177: marshal.loads() now raises TypeError when given an unicode + string. Patch by Guilherme Gon?alves. + +- Issue #13550: Remove the debug machinery from the threading module: remove + verbose arguments from all threading classes and functions. + - Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, WeakValueDictionary) to return a better approximation when some objects are dead or dying. Moreover, the implementation is now O(1) rather than diff --git a/Misc/RPM/python-3.3.spec b/Misc/RPM/python-3.3.spec --- a/Misc/RPM/python-3.3.spec +++ b/Misc/RPM/python-3.3.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.3a0 +%define version 3.3.0a1 %define libvers 3.3 #--end constants-- %define release 1pydotorg diff --git a/Misc/valgrind-python.supp b/Misc/valgrind-python.supp --- a/Misc/valgrind-python.supp +++ b/Misc/valgrind-python.supp @@ -310,6 +310,38 @@ ### fun:MD5_Update ###} +# Fedora's package "openssl-1.0.1-0.1.beta2.fc17.x86_64" on x86_64 +# See http://bugs.python.org/issue14171 +{ + openssl 1.0.1 prng 1 + Memcheck:Cond + fun:bcmp + fun:fips_get_entropy + fun:FIPS_drbg_instantiate + fun:RAND_init_fips + fun:OPENSSL_init_library + fun:SSL_library_init + fun:init_hashlib +} + +{ + openssl 1.0.1 prng 2 + Memcheck:Cond + fun:fips_get_entropy + fun:FIPS_drbg_instantiate + fun:RAND_init_fips + fun:OPENSSL_init_library + fun:SSL_library_init + fun:init_hashlib +} + +{ + openssl 1.0.1 prng 3 + Memcheck:Value8 + fun:_x86_64_AES_encrypt_compact + fun:AES_encrypt +} + # # All of these problems come from using test_socket_ssl # diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -191,7 +191,7 @@ } /* -------------------------------------------------------------------- */ -/* the element type */ +/* the Element type */ typedef struct { @@ -236,10 +236,10 @@ #define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type) /* -------------------------------------------------------------------- */ -/* element constructor and destructor */ +/* Element constructors and destructor */ LOCAL(int) -element_new_extra(ElementObject* self, PyObject* attrib) +create_extra(ElementObject* self, PyObject* attrib) { self->extra = PyObject_Malloc(sizeof(ElementObjectExtra)); if (!self->extra) @@ -259,7 +259,7 @@ } LOCAL(void) -element_dealloc_extra(ElementObject* self) +dealloc_extra(ElementObject* self) { int i; @@ -274,8 +274,11 @@ PyObject_Free(self->extra); } +/* Convenience internal function to create new Element objects with the given + * tag and attributes. +*/ LOCAL(PyObject*) -element_new(PyObject* tag, PyObject* attrib) +create_new_element(PyObject* tag, PyObject* attrib) { ElementObject* self; @@ -290,16 +293,10 @@ self->extra = NULL; if (attrib != Py_None) { - - if (element_new_extra(self, attrib) < 0) { + if (create_extra(self, attrib) < 0) { PyObject_Del(self); return NULL; } - - self->extra->length = 0; - self->extra->allocated = STATIC_CHILDREN; - self->extra->children = self->extra->_children; - } Py_INCREF(tag); @@ -316,6 +313,86 @@ return (PyObject*) self; } +static PyObject * +element_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + ElementObject *e = (ElementObject *)type->tp_alloc(type, 0); + if (e != NULL) { + Py_INCREF(Py_None); + e->tag = Py_None; + + Py_INCREF(Py_None); + e->text = Py_None; + + Py_INCREF(Py_None); + e->tail = Py_None; + + e->extra = NULL; + } + return (PyObject *)e; +} + +static int +element_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *tag; + PyObject *tmp; + PyObject *attrib = NULL; + ElementObject *self_elem; + + if (!PyArg_ParseTuple(args, "O|O!:Element", &tag, &PyDict_Type, &attrib)) + return -1; + + if (attrib || kwds) { + attrib = (attrib) ? PyDict_Copy(attrib) : PyDict_New(); + if (!attrib) + return -1; + if (kwds) + PyDict_Update(attrib, kwds); + } else { + Py_INCREF(Py_None); + attrib = Py_None; + } + + self_elem = (ElementObject *)self; + + /* Use None for empty dictionaries */ + if (PyDict_CheckExact(attrib) && PyDict_Size(attrib) == 0) { + Py_INCREF(Py_None); + attrib = Py_None; + } + + if (attrib != Py_None) { + if (create_extra(self_elem, attrib) < 0) { + PyObject_Del(self_elem); + return -1; + } + } + + /* If create_extra needed attrib, it took a reference to it, so we can + * release ours anyway. + */ + Py_DECREF(attrib); + + /* Replace the objects already pointed to by tag, text and tail. */ + tmp = self_elem->tag; + self_elem->tag = tag; + Py_INCREF(tag); + Py_DECREF(tmp); + + tmp = self_elem->text; + self_elem->text = Py_None; + Py_INCREF(Py_None); + Py_DECREF(JOIN_OBJ(tmp)); + + tmp = self_elem->tail; + self_elem->tail = Py_None; + Py_INCREF(Py_None); + Py_DECREF(JOIN_OBJ(tmp)); + + return 0; +} + LOCAL(int) element_resize(ElementObject* self, int extra) { @@ -326,7 +403,7 @@ elements. set an exception and return -1 if allocation failed */ if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); size = self->extra->length + extra; @@ -444,13 +521,15 @@ } static PyObject* -element(PyObject* self, PyObject* args, PyObject* kw) +subelement(PyObject* self, PyObject* args, PyObject* kw) { PyObject* elem; + ElementObject* parent; PyObject* tag; PyObject* attrib = NULL; - if (!PyArg_ParseTuple(args, "O|O!:Element", &tag, + if (!PyArg_ParseTuple(args, "O!O|O!:SubElement", + &Element_Type, &parent, &tag, &PyDict_Type, &attrib)) return NULL; @@ -465,38 +544,7 @@ attrib = Py_None; } - elem = element_new(tag, attrib); - - Py_DECREF(attrib); - - return elem; -} - -static PyObject* -subelement(PyObject* self, PyObject* args, PyObject* kw) -{ - PyObject* elem; - - ElementObject* parent; - PyObject* tag; - PyObject* attrib = NULL; - if (!PyArg_ParseTuple(args, "O!O|O!:SubElement", - &Element_Type, &parent, &tag, - &PyDict_Type, &attrib)) - return NULL; - - if (attrib || kw) { - attrib = (attrib) ? PyDict_Copy(attrib) : PyDict_New(); - if (!attrib) - return NULL; - if (kw) - PyDict_Update(attrib, kw); - } else { - Py_INCREF(Py_None); - attrib = Py_None; - } - - elem = element_new(tag, attrib); + elem = create_new_element(tag, attrib); Py_DECREF(attrib); @@ -512,7 +560,7 @@ element_dealloc(ElementObject* self) { if (self->extra) - element_dealloc_extra(self); + dealloc_extra(self); /* discard attributes */ Py_DECREF(self->tag); @@ -521,7 +569,7 @@ RELEASE(sizeof(ElementObject), "destroy element"); - PyObject_Del(self); + Py_TYPE(self)->tp_free((PyObject *)self); } /* -------------------------------------------------------------------- */ @@ -547,7 +595,7 @@ return NULL; if (self->extra) { - element_dealloc_extra(self); + dealloc_extra(self); self->extra = NULL; } @@ -571,7 +619,7 @@ if (!PyArg_ParseTuple(args, ":__copy__")) return NULL; - element = (ElementObject*) element_new( + element = (ElementObject*) create_new_element( self->tag, (self->extra) ? self->extra->attrib : Py_None ); if (!element) @@ -634,7 +682,7 @@ attrib = Py_None; } - element = (ElementObject*) element_new(tag, attrib); + element = (ElementObject*) create_new_element(tag, attrib); Py_DECREF(tag); Py_DECREF(attrib); @@ -1029,7 +1077,7 @@ return NULL; if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); if (index < 0) { index += self->extra->length; @@ -1100,7 +1148,7 @@ if (!attrib) return NULL; - elem = element_new(tag, attrib); + elem = create_new_element(tag, attrib); Py_DECREF(attrib); @@ -1154,7 +1202,10 @@ static PyObject* element_repr(ElementObject* self) { - return PyUnicode_FromFormat("", self->tag, self); + if (self->tag) + return PyUnicode_FromFormat("", self->tag, self); + else + return PyUnicode_FromFormat("", self); } static PyObject* @@ -1168,7 +1219,7 @@ return NULL; if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); attrib = element_get_attrib(self); if (!attrib) @@ -1284,7 +1335,7 @@ PyObject* seq = NULL; if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); if (PySlice_GetIndicesEx(item, self->extra->length, @@ -1448,7 +1499,7 @@ } else if (strcmp(name, "attrib") == 0) { PyErr_Clear(); if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); res = element_get_attrib(self); } @@ -1484,7 +1535,7 @@ Py_INCREF(self->tail); } else if (strcmp(name, "attrib") == 0) { if (!self->extra) - element_new_extra(self, NULL); + create_extra(self, NULL); Py_DECREF(self->extra->attrib); self->extra->attrib = value; Py_INCREF(self->extra->attrib); @@ -1516,31 +1567,41 @@ PyVarObject_HEAD_INIT(NULL, 0) "Element", sizeof(ElementObject), 0, /* methods */ - (destructor)element_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - (setattrfunc)element_setattr, /* tp_setattr */ - 0, /* tp_reserved */ - (reprfunc)element_repr, /* tp_repr */ - 0, /* tp_as_number */ - &element_as_sequence, /* tp_as_sequence */ - &element_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc)element_getattro, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - element_methods, /* tp_methods */ - 0, /* tp_members */ + (destructor)element_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + (setattrfunc)element_setattr, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc)element_repr, /* tp_repr */ + 0, /* tp_as_number */ + &element_as_sequence, /* tp_as_sequence */ + &element_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + (getattrofunc)element_getattro, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + element_methods, /* 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 */ + (initproc)element_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + element_new, /* tp_new */ + 0, /* tp_free */ }; /* ==================================================================== */ @@ -1638,13 +1699,6 @@ /* handlers */ LOCAL(PyObject*) -treebuilder_handle_xml(TreeBuilderObject* self, PyObject* encoding, - PyObject* standalone) -{ - Py_RETURN_NONE; -} - -LOCAL(PyObject*) treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag, PyObject* attrib) { @@ -1666,7 +1720,7 @@ self->data = NULL; } - node = element_new(tag, attrib); + node = create_new_element(tag, attrib); if (!node) return NULL; @@ -1915,22 +1969,10 @@ return treebuilder_handle_start(self, tag, attrib); } -static PyObject* -treebuilder_xml(TreeBuilderObject* self, PyObject* args) -{ - PyObject* encoding; - PyObject* standalone; - if (!PyArg_ParseTuple(args, "OO:xml", &encoding, &standalone)) - return NULL; - - return treebuilder_handle_xml(self, encoding, standalone); -} - static PyMethodDef treebuilder_methods[] = { {"data", (PyCFunction) treebuilder_data, METH_VARARGS}, {"start", (PyCFunction) treebuilder_start, METH_VARARGS}, {"end", (PyCFunction) treebuilder_end, METH_VARARGS}, - {"xml", (PyCFunction) treebuilder_xml, METH_VARARGS}, {"close", (PyCFunction) treebuilder_close, METH_VARARGS}, {NULL, NULL} }; @@ -1991,8 +2033,6 @@ PyObject* names; - PyObject* handle_xml; - PyObject* handle_start; PyObject* handle_data; PyObject* handle_end; @@ -2445,7 +2485,6 @@ Py_INCREF(target); self->target = target; - self->handle_xml = PyObject_GetAttrString(target, "xml"); self->handle_start = PyObject_GetAttrString(target, "start"); self->handle_data = PyObject_GetAttrString(target, "data"); self->handle_end = PyObject_GetAttrString(target, "end"); @@ -2501,7 +2540,6 @@ Py_XDECREF(self->handle_end); Py_XDECREF(self->handle_data); Py_XDECREF(self->handle_start); - Py_XDECREF(self->handle_xml); Py_DECREF(self->target); Py_DECREF(self->entity); @@ -2801,7 +2839,6 @@ /* python module interface */ static PyMethodDef _functions[] = { - {"Element", (PyCFunction) element, METH_VARARGS|METH_KEYWORDS}, {"SubElement", (PyCFunction) subelement, METH_VARARGS|METH_KEYWORDS}, {"TreeBuilder", (PyCFunction) treebuilder, METH_VARARGS}, #if defined(USE_EXPAT) @@ -2911,5 +2948,8 @@ Py_INCREF(elementtree_parseerror_obj); PyModule_AddObject(m, "ParseError", elementtree_parseerror_obj); + Py_INCREF((PyObject *)&Element_Type); + PyModule_AddObject(m, "Element", (PyObject *)&Element_Type); + return m; } diff --git a/Modules/_multiprocessing/win32_functions.c b/Modules/_multiprocessing/win32_functions.c --- a/Modules/_multiprocessing/win32_functions.c +++ b/Modules/_multiprocessing/win32_functions.c @@ -60,16 +60,18 @@ static void overlapped_dealloc(OverlappedObject *self) { + DWORD bytes; int err = GetLastError(); if (self->pending) { - if (check_CancelIoEx()) - Py_CancelIoEx(self->handle, &self->overlapped); - else { - PyErr_SetString(PyExc_RuntimeError, - "I/O operations still in flight while destroying " - "Overlapped object, the process may crash"); - PyErr_WriteUnraisable(NULL); - } + /* make it a programming error to deallocate while operation + is pending, even if we can safely cancel it */ + if (check_CancelIoEx() && + Py_CancelIoEx(self->handle, &self->overlapped)) + GetOverlappedResult(self->handle, &self->overlapped, &bytes, TRUE); + PyErr_SetString(PyExc_RuntimeError, + "I/O operations still in flight while destroying " + "Overlapped object, the process may crash"); + PyErr_WriteUnraisable(NULL); } CloseHandle(self->overlapped.hEvent); SetLastError(err); @@ -85,6 +87,7 @@ int wait; BOOL res; DWORD transferred = 0; + DWORD err; wait = PyObject_IsTrue(waitobj); if (wait < 0) @@ -94,23 +97,27 @@ wait != 0); Py_END_ALLOW_THREADS - if (!res) { - int err = GetLastError(); - if (err == ERROR_IO_INCOMPLETE) - Py_RETURN_NONE; - if (err != ERROR_MORE_DATA) { + err = res ? ERROR_SUCCESS : GetLastError(); + switch (err) { + case ERROR_SUCCESS: + case ERROR_MORE_DATA: + case ERROR_OPERATION_ABORTED: + self->completed = 1; + self->pending = 0; + break; + case ERROR_IO_INCOMPLETE: + break; + default: self->pending = 0; return PyErr_SetExcFromWindowsErr(PyExc_IOError, err); - } } - self->pending = 0; - self->completed = 1; - if (self->read_buffer) { + if (self->completed && self->read_buffer != NULL) { assert(PyBytes_CheckExact(self->read_buffer)); - if (_PyBytes_Resize(&self->read_buffer, transferred)) + if (transferred != PyBytes_GET_SIZE(self->read_buffer) && + _PyBytes_Resize(&self->read_buffer, transferred)) return NULL; } - return Py_BuildValue("lN", (long) transferred, PyBool_FromLong(res)); + return Py_BuildValue("II", (unsigned) transferred, (unsigned) err); } static PyObject * @@ -522,9 +529,10 @@ HANDLE handle; Py_buffer _buf, *buf; PyObject *bufobj; - int written; + DWORD written; BOOL ret; int use_overlapped = 0; + DWORD err; OverlappedObject *overlapped = NULL; static char *kwlist[] = {"handle", "buffer", "overlapped", NULL}; @@ -553,8 +561,9 @@ overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS + err = ret ? 0 : GetLastError(); + if (overlapped) { - int err = GetLastError(); if (!ret) { if (err == ERROR_IO_PENDING) overlapped->pending = 1; @@ -563,13 +572,13 @@ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } } - return (PyObject *) overlapped; + return Py_BuildValue("NI", (PyObject *) overlapped, err); } PyBuffer_Release(buf); if (!ret) return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); - return PyLong_FromLong(written); + return Py_BuildValue("II", written, err); } static PyObject * @@ -581,6 +590,7 @@ PyObject *buf; BOOL ret; int use_overlapped = 0; + DWORD err; OverlappedObject *overlapped = NULL; static char *kwlist[] = {"handle", "size", "overlapped", NULL}; @@ -607,8 +617,9 @@ overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS + err = ret ? 0 : GetLastError(); + if (overlapped) { - int err = GetLastError(); if (!ret) { if (err == ERROR_IO_PENDING) overlapped->pending = 1; @@ -617,16 +628,16 @@ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } } - return (PyObject *) overlapped; + return Py_BuildValue("NI", (PyObject *) overlapped, err); } - if (!ret && GetLastError() != ERROR_MORE_DATA) { + if (!ret && err != ERROR_MORE_DATA) { Py_DECREF(buf); return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } if (_PyBytes_Resize(&buf, nread)) return NULL; - return Py_BuildValue("NN", buf, PyBool_FromLong(ret)); + return Py_BuildValue("NI", buf, err); } static PyObject * @@ -783,7 +794,11 @@ WIN32_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS); WIN32_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE); + WIN32_CONSTANT(F_DWORD, ERROR_IO_PENDING); + WIN32_CONSTANT(F_DWORD, ERROR_MORE_DATA); + WIN32_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); WIN32_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); + WIN32_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED); WIN32_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); WIN32_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); WIN32_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -319,6 +319,7 @@ objects to support self-referential objects pickling. */ PyObject *pers_func; /* persistent_id() method, can be NULL */ + PyObject *dispatch_table; /* private dispatch_table, can be NULL */ PyObject *arg; PyObject *write; /* write() method of the output stream. */ @@ -764,6 +765,7 @@ return NULL; self->pers_func = NULL; + self->dispatch_table = NULL; self->arg = NULL; self->write = NULL; self->proto = 0; @@ -3176,17 +3178,24 @@ /* XXX: This part needs some unit tests. */ /* Get a reduction callable, and call it. This may come from - * copyreg.dispatch_table, the object's __reduce_ex__ method, - * or the object's __reduce__ method. + * self.dispatch_table, copyreg.dispatch_table, the object's + * __reduce_ex__ method, or the object's __reduce__ method. */ - reduce_func = PyDict_GetItem(dispatch_table, (PyObject *)type); + if (self->dispatch_table == NULL) { + reduce_func = PyDict_GetItem(dispatch_table, (PyObject *)type); + /* PyDict_GetItem() unlike PyObject_GetItem() and + PyObject_GetAttr() returns a borrowed ref */ + Py_XINCREF(reduce_func); + } else { + reduce_func = PyObject_GetItem(self->dispatch_table, (PyObject *)type); + if (reduce_func == NULL) { + if (PyErr_ExceptionMatches(PyExc_KeyError)) + PyErr_Clear(); + else + goto error; + } + } if (reduce_func != NULL) { - /* Here, the reference count of the reduce_func object returned by - PyDict_GetItem needs to be increased to be consistent with the one - returned by PyObject_GetAttr. This is allow us to blindly DECREF - reduce_func at the end of the save() routine. - */ - Py_INCREF(reduce_func); Py_INCREF(obj); reduce_value = _Pickler_FastCall(self, reduce_func, obj); } @@ -3359,6 +3368,7 @@ Py_XDECREF(self->output_buffer); Py_XDECREF(self->write); Py_XDECREF(self->pers_func); + Py_XDECREF(self->dispatch_table); Py_XDECREF(self->arg); Py_XDECREF(self->fast_memo); @@ -3372,6 +3382,7 @@ { Py_VISIT(self->write); Py_VISIT(self->pers_func); + Py_VISIT(self->dispatch_table); Py_VISIT(self->arg); Py_VISIT(self->fast_memo); return 0; @@ -3383,6 +3394,7 @@ Py_CLEAR(self->output_buffer); Py_CLEAR(self->write); Py_CLEAR(self->pers_func); + Py_CLEAR(self->dispatch_table); Py_CLEAR(self->arg); Py_CLEAR(self->fast_memo); @@ -3427,6 +3439,7 @@ PyObject *proto_obj = NULL; PyObject *fix_imports = Py_True; _Py_IDENTIFIER(persistent_id); + _Py_IDENTIFIER(dispatch_table); if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO:Pickler", kwlist, &file, &proto_obj, &fix_imports)) @@ -3468,6 +3481,13 @@ if (self->pers_func == NULL) return -1; } + self->dispatch_table = NULL; + if (_PyObject_HasAttrId((PyObject *)self, &PyId_dispatch_table)) { + self->dispatch_table = _PyObject_GetAttrId((PyObject *)self, + &PyId_dispatch_table); + if (self->dispatch_table == NULL) + return -1; + } return 0; } @@ -3749,6 +3769,7 @@ static PyMemberDef Pickler_members[] = { {"bin", T_INT, offsetof(PicklerObject, bin)}, {"fast", T_INT, offsetof(PicklerObject, fast)}, + {"dispatch_table", T_OBJECT_EX, offsetof(PicklerObject, dispatch_table)}, {NULL} }; diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -44,23 +44,21 @@ #define ADJUST_PTR(ptr, suboffsets) \ (HAVE_PTR(suboffsets) ? *((char**)ptr) + suboffsets[0] : ptr) +/* Default: NumPy style (strides), read-only, no var-export, C-style layout */ +#define ND_DEFAULT 0x000 /* User configurable flags for the ndarray */ -#define ND_VAREXPORT 0x001 /* change layout while buffers are exported */ - +#define ND_VAREXPORT 0x001 /* change layout while buffers are exported */ /* User configurable flags for each base buffer */ -#define ND_WRITABLE 0x002 /* mark base buffer as writable */ -#define ND_FORTRAN 0x004 /* Fortran contiguous layout */ -#define ND_SCALAR 0x008 /* scalar: ndim = 0 */ -#define ND_PIL 0x010 /* convert to PIL-style array (suboffsets) */ -#define ND_GETBUF_FAIL 0x020 /* test issue 7385 */ - -/* Default: NumPy style (strides), read-only, no var-export, C-style layout */ -#define ND_DEFAULT 0x0 - +#define ND_WRITABLE 0x002 /* mark base buffer as writable */ +#define ND_FORTRAN 0x004 /* Fortran contiguous layout */ +#define ND_SCALAR 0x008 /* scalar: ndim = 0 */ +#define ND_PIL 0x010 /* convert to PIL-style array (suboffsets) */ +#define ND_REDIRECT 0x020 /* redirect buffer requests */ +#define ND_GETBUF_FAIL 0x040 /* trigger getbuffer failure */ +#define ND_GETBUF_UNDEFINED 0x080 /* undefined view.obj */ /* Internal flags for the base buffer */ -#define ND_C 0x040 /* C contiguous layout (default) */ -#define ND_OWN_ARRAYS 0x080 /* consumer owns arrays */ -#define ND_UNUSED 0x100 /* initializer */ +#define ND_C 0x100 /* C contiguous layout (default) */ +#define ND_OWN_ARRAYS 0x200 /* consumer owns arrays */ /* ndarray properties */ #define ND_IS_CONSUMER(nd) \ @@ -1290,7 +1288,7 @@ PyObject *strides = NULL; /* number of bytes to the next elt in each dim */ Py_ssize_t offset = 0; /* buffer offset */ PyObject *format = simple_format; /* struct module specifier: "B" */ - int flags = ND_UNUSED; /* base buffer and ndarray flags */ + int flags = ND_DEFAULT; /* base buffer and ndarray flags */ int getbuf = PyBUF_UNUSED; /* re-exporter: getbuffer request flags */ @@ -1302,10 +1300,10 @@ /* NDArrayObject is re-exporter */ if (PyObject_CheckBuffer(v) && shape == NULL) { if (strides || offset || format != simple_format || - flags != ND_UNUSED) { + !(flags == ND_DEFAULT || flags == ND_REDIRECT)) { PyErr_SetString(PyExc_TypeError, - "construction from exporter object only takes a single " - "additional getbuf argument"); + "construction from exporter object only takes 'obj', 'getbuf' " + "and 'flags' arguments"); return -1; } @@ -1315,6 +1313,7 @@ return -1; init_flags(nd->head); + nd->head->flags |= flags; return 0; } @@ -1333,8 +1332,6 @@ return -1; } - if (flags == ND_UNUSED) - flags = ND_DEFAULT; if (flags & ND_VAREXPORT) { nd->flags |= ND_VAREXPORT; flags &= ~ND_VAREXPORT; @@ -1357,7 +1354,7 @@ PyObject *strides = NULL; /* number of bytes to the next elt in each dim */ PyObject *format = simple_format; /* struct module specifier: "B" */ Py_ssize_t offset = 0; /* buffer offset */ - int flags = ND_UNUSED; /* base buffer flags */ + int flags = ND_DEFAULT; /* base buffer flags */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OnOi", kwlist, &items, &shape, &strides, &offset, &format, &flags)) @@ -1423,6 +1420,11 @@ Py_buffer *base = &ndbuf->base; int baseflags = ndbuf->flags; + /* redirect mode */ + if (base->obj != NULL && (baseflags&ND_REDIRECT)) { + return PyObject_GetBuffer(base->obj, view, flags); + } + /* start with complete information */ *view = *base; view->obj = NULL; @@ -1445,6 +1447,8 @@ if (baseflags & ND_GETBUF_FAIL) { PyErr_SetString(PyExc_BufferError, "ND_GETBUF_FAIL: forced test exception"); + if (baseflags & ND_GETBUF_UNDEFINED) + view->obj = (PyObject *)0x1; /* wrong but permitted in <= 3.2 */ return -1; } @@ -2598,6 +2602,126 @@ ndarray_new, /* tp_new */ }; +/**************************************************************************/ +/* StaticArray Object */ +/**************************************************************************/ + +static PyTypeObject StaticArray_Type; + +typedef struct { + PyObject_HEAD + int legacy_mode; /* if true, use the view.obj==NULL hack */ +} StaticArrayObject; + +static char static_mem[12] = {0,1,2,3,4,5,6,7,8,9,10,11}; +static Py_ssize_t static_shape[1] = {12}; +static Py_ssize_t static_strides[1] = {1}; +static Py_buffer static_buffer = { + static_mem, /* buf */ + NULL, /* obj */ + 12, /* len */ + 1, /* itemsize */ + 1, /* readonly */ + 1, /* ndim */ + "B", /* format */ + static_shape, /* shape */ + static_strides, /* strides */ + NULL, /* suboffsets */ + NULL /* internal */ +}; + +static PyObject * +staticarray_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return (PyObject *)PyObject_New(StaticArrayObject, &StaticArray_Type); +} + +static int +staticarray_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + StaticArrayObject *a = (StaticArrayObject *)self; + static char *kwlist[] = { + "legacy_mode", NULL + }; + PyObject *legacy_mode = Py_False; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &legacy_mode)) + return -1; + + a->legacy_mode = (legacy_mode != Py_False); + return 0; +} + +static void +staticarray_dealloc(StaticArrayObject *self) +{ + PyObject_Del(self); +} + +/* Return a buffer for a PyBUF_FULL_RO request. Flags are not checked, + which makes this object a non-compliant exporter! */ +static int +staticarray_getbuf(StaticArrayObject *self, Py_buffer *view, int flags) +{ + *view = static_buffer; + + if (self->legacy_mode) { + view->obj = NULL; /* Don't use this in new code. */ + } + else { + view->obj = (PyObject *)self; + Py_INCREF(view->obj); + } + + return 0; +} + +static PyBufferProcs staticarray_as_buffer = { + (getbufferproc)staticarray_getbuf, /* bf_getbuffer */ + NULL, /* bf_releasebuffer */ +}; + +static PyTypeObject StaticArray_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "staticarray", /* Name of this type */ + sizeof(StaticArrayObject), /* Basic object size */ + 0, /* Item size for varobject */ + (destructor)staticarray_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 */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &staticarray_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* 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 */ + staticarray_init, /* tp_init */ + 0, /* tp_alloc */ + staticarray_new, /* tp_new */ +}; + static struct PyMethodDef _testbuffer_functions[] = { {"slice_indices", slice_indices, METH_VARARGS, NULL}, @@ -2630,10 +2754,14 @@ if (m == NULL) return NULL; - Py_TYPE(&NDArray_Type)=&PyType_Type; + Py_TYPE(&NDArray_Type) = &PyType_Type; Py_INCREF(&NDArray_Type); PyModule_AddObject(m, "ndarray", (PyObject *)&NDArray_Type); + Py_TYPE(&StaticArray_Type) = &PyType_Type; + Py_INCREF(&StaticArray_Type); + PyModule_AddObject(m, "staticarray", (PyObject *)&StaticArray_Type); + structmodule = PyImport_ImportModule("struct"); if (structmodule == NULL) return NULL; @@ -2654,6 +2782,8 @@ PyModule_AddIntConstant(m, "ND_SCALAR", ND_SCALAR); PyModule_AddIntConstant(m, "ND_PIL", ND_PIL); PyModule_AddIntConstant(m, "ND_GETBUF_FAIL", ND_GETBUF_FAIL); + PyModule_AddIntConstant(m, "ND_GETBUF_UNDEFINED", ND_GETBUF_UNDEFINED); + PyModule_AddIntConstant(m, "ND_REDIRECT", ND_REDIRECT); PyModule_AddIntConstant(m, "PyBUF_SIMPLE", PyBUF_SIMPLE); PyModule_AddIntConstant(m, "PyBUF_WRITABLE", PyBUF_WRITABLE); diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2323,6 +2323,24 @@ return PyLong_FromLong(r); } +static PyObject * +test_pytime_object_to_timespec(PyObject *self, PyObject *args) +{ + PyObject *obj; + time_t sec; + long nsec; + if (!PyArg_ParseTuple(args, "O:pytime_object_to_timespec", &obj)) + return NULL; + if (_PyTime_ObjectToTimespec(obj, &sec, &nsec) == -1) + return NULL; +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + return Py_BuildValue("Ll", (PY_LONG_LONG)sec, nsec); +#else + assert(sizeof(time_t) <= sizeof(long)); + return Py_BuildValue("ll", (long)sec, nsec); +#endif +} + static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, @@ -2412,6 +2430,7 @@ METH_NOARGS}, {"crash_no_current_thread", (PyCFunction)crash_no_current_thread, METH_NOARGS}, {"run_in_subinterp", run_in_subinterp, METH_VARARGS}, + {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -959,13 +959,13 @@ } static PySequenceMethods mmap_as_sequence = { - (lenfunc)mmap_length, /*sq_length*/ - (binaryfunc)mmap_concat, /*sq_concat*/ - (ssizeargfunc)mmap_repeat, /*sq_repeat*/ - (ssizeargfunc)mmap_item, /*sq_item*/ - 0, /*sq_slice*/ - (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ + (lenfunc)mmap_length, /*sq_length*/ + (binaryfunc)mmap_concat, /*sq_concat*/ + (ssizeargfunc)mmap_repeat, /*sq_repeat*/ + (ssizeargfunc)mmap_item, /*sq_item*/ + 0, /*sq_slice*/ + (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ }; static PyMappingMethods mmap_as_mapping = { @@ -1027,7 +1027,7 @@ PyObject_GenericGetAttr, /*tp_getattro*/ 0, /*tp_setattro*/ &mmap_as_buffer, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ mmap_doc, /*tp_doc*/ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -1043,10 +1043,10 @@ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ new_mmap_object, /* tp_new */ - PyObject_Del, /* tp_free */ + PyObject_Del, /* tp_free */ }; @@ -1097,8 +1097,8 @@ int devzero = -1; int access = (int)ACCESS_DEFAULT; static char *keywords[] = {"fileno", "length", - "flags", "prot", - "access", "offset", NULL}; + "flags", "prot", + "access", "offset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords, &fd, &map_size_obj, &flags, &prot, @@ -1260,8 +1260,8 @@ int access = (access_mode)ACCESS_DEFAULT; DWORD flProtect, dwDesiredAccess; static char *keywords[] = { "fileno", "length", - "tagname", - "access", "offset", NULL }; + "tagname", + "access", "offset", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords, &fileno, &map_size_obj, diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -783,16 +783,11 @@ siginfo_t si; int err; - if (!PyArg_ParseTuple(args, "OO:sigtimedwait", &signals, &timeout)) + if (!PyArg_ParseTuple(args, "OO:sigtimedwait", + &signals, &timeout)) return NULL; - if (!PyTuple_Check(timeout) || PyTuple_Size(timeout) != 2) { - PyErr_SetString(PyExc_TypeError, - "sigtimedwait() arg 2 must be a tuple " - "(timeout_sec, timeout_nsec)"); - return NULL; - } else if (!PyArg_ParseTuple(timeout, "ll:sigtimedwait", - &(buf.tv_sec), &(buf.tv_nsec))) + if (_PyTime_ObjectToTimespec(timeout, &buf.tv_sec, &buf.tv_nsec) == -1) return NULL; if (buf.tv_sec < 0 || buf.tv_nsec < 0) { diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -649,7 +649,7 @@ int PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, - int readonly, int flags) + int readonly, int flags) { if (view == NULL) return 0; /* XXX why not -1? */ if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -347,12 +347,9 @@ return ep; } else { - /* The compare did major nasty stuff to the - * dict: start over. - * XXX A clever adversary could prevent this - * XXX from terminating. - */ - return lookdict(mp, key, hash); + PyErr_SetString(PyExc_RuntimeError, + "dictionary changed size during lookup"); + return NULL; } } freeslot = NULL; @@ -379,12 +376,9 @@ return ep; } else { - /* The compare did major nasty stuff to the - * dict: start over. - * XXX A clever adversary could prevent this - * XXX from terminating. - */ - return lookdict(mp, key, hash); + PyErr_SetString(PyExc_RuntimeError, + "dictionary changed size during lookup"); + return NULL; } } else if (ep->me_key == dummy && freeslot == NULL) diff --git a/Objects/frameobject.c b/Objects/frameobject.c --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -20,7 +20,6 @@ {"f_builtins", T_OBJECT, OFF(f_builtins), READONLY}, {"f_globals", T_OBJECT, OFF(f_globals), READONLY}, {"f_lasti", T_INT, OFF(f_lasti), READONLY}, - {"f_yieldfrom", T_OBJECT, OFF(f_yieldfrom), READONLY}, {NULL} /* Sentinel */ }; diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -86,14 +86,11 @@ return NULL; if (PyObject_GetBuffer(base, &mbuf->master, PyBUF_FULL_RO) < 0) { - /* mbuf->master.obj must be NULL. */ + mbuf->master.obj = NULL; Py_DECREF(mbuf); return NULL; } - /* Assume that master.obj is a new reference to base. */ - assert(mbuf->master.obj == base); - return (PyObject *)mbuf; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -998,7 +998,11 @@ is_sharing = 1; } else { - assert(maxchar <= MAX_UNICODE); + if (maxchar > MAX_UNICODE) { + PyErr_SetString(PyExc_SystemError, + "invalid maximum character passed to PyUnicode_New"); + return NULL; + } kind_state = PyUnicode_4BYTE_KIND; char_size = 4; if (sizeof(wchar_t) == 4) @@ -3942,6 +3946,10 @@ } if (unicode_check_modifiable(unicode)) return -1; + if (ch > PyUnicode_MAX_CHAR_VALUE(unicode)) { + PyErr_SetString(PyExc_ValueError, "character out of range"); + return -1; + } PyUnicode_WRITE(PyUnicode_KIND(unicode), PyUnicode_DATA(unicode), index, ch); return 0; diff --git a/PC/python_nt.rc b/PC/python_nt.rc --- a/PC/python_nt.rc +++ b/PC/python_nt.rc @@ -12,7 +12,7 @@ # include "pythonnt_rc.h" #endif -/* e.g., 2.1a2 +/* e.g., 3.3.0a1 * PY_VERSION comes from patchevel.h */ #define PYTHON_VERSION PY_VERSION "\0" diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -584,16 +584,16 @@ {6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.ActiveCfg = Release|x64 {6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.Build.0 = Release|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|Win32.ActiveCfg = PGInstrument|Win32 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = Debug|x64 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = Debug|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = PGUpdate|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = PGUpdate|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = Release|x64 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = PGInstrument|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = Release|x64 - {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = PGUpdate|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.ActiveCfg = Release|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.Build.0 = Release|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.ActiveCfg = Release|x64 diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1412,11 +1412,15 @@ /* Identifier (most frequent token!) */ nonascii = 0; if (is_potential_identifier_start(c)) { - /* Process b"", r"", br"" and rb"" */ - int saw_b = 0, saw_r = 0; + /* Process b"", r"", u"", br"", rb"" and ur"" */ + int saw_b = 0, saw_r = 0, saw_u = 0; while (1) { - if (!saw_b && (c == 'b' || c == 'B')) + if (!(saw_b || saw_u) && (c == 'b' || c == 'B')) saw_b = 1; + /* Since this is a backwards compatibility support literal we don't + want to support it in arbitrary order like byte literals. */ + else if (!(saw_b || saw_u || saw_r) && (c == 'u' || c == 'U')) + saw_u = 1; else if (!saw_r && (c == 'r' || c == 'R')) saw_r = 1; else diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -3796,6 +3796,9 @@ quote = *++s; *bytesmode = 1; } + else if (quote == 'u' || quote == 'U') { + quote = *++s; + } else if (quote == 'r' || quote == 'R') { quote = *++s; rawmode = 1; diff --git a/Python/getcopyright.c b/Python/getcopyright.c --- a/Python/getcopyright.c +++ b/Python/getcopyright.c @@ -19,5 +19,5 @@ const char * Py_GetCopyright(void) { - return cprt; + return cprt; } diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -409,11 +409,12 @@ else if (PyObject_CheckBuffer(v)) { /* Write unknown buffer-style objects as a string */ char *s; - PyBufferProcs *pb = v->ob_type->tp_as_buffer; Py_buffer view; - if ((*pb->bf_getbuffer)(v, &view, PyBUF_SIMPLE) != 0) { + if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) != 0) { w_byte(TYPE_UNKNOWN, p); + p->depth--; p->error = WFERR_UNMARSHALLABLE; + return; } w_byte(TYPE_STRING, p); n = view.len; @@ -425,8 +426,7 @@ } w_long((long)n, p); w_string(s, (int)n, p); - if (pb->bf_releasebuffer != NULL) - (*pb->bf_releasebuffer)(v, &view); + PyBuffer_Release(&view); } else { w_byte(TYPE_UNKNOWN, p); @@ -1239,7 +1239,6 @@ PyMarshal_WriteObjectToString(PyObject *x, int version) { WFILE wf; - PyObject *res = NULL; wf.fp = NULL; wf.readable = NULL; @@ -1273,12 +1272,7 @@ :"object too deeply nested to marshal"); return NULL; } - if (wf.str != NULL) { - /* XXX Quick hack -- need to do this differently */ - res = PyBytes_FromObject(wf.str); - Py_DECREF(wf.str); - } - return res; + return wf.str; } /* And an interface for Python programs... */ @@ -1390,7 +1384,7 @@ char *s; Py_ssize_t n; PyObject* result; - if (!PyArg_ParseTuple(args, "s*:loads", &p)) + if (!PyArg_ParseTuple(args, "y*:loads", &p)) return NULL; s = p.buf; n = p.len; @@ -1406,10 +1400,10 @@ } PyDoc_STRVAR(loads_doc, -"loads(string)\n\ +"loads(bytes)\n\ \n\ -Convert the string to a value. If no valid value is found, raise\n\ -EOFError, ValueError or TypeError. Extra characters in the string are\n\ +Convert the bytes object to a value. If no valid value is found, raise\n\ +EOFError, ValueError or TypeError. Extra characters in the input are\n\ ignored."); static PyMethodDef marshal_methods[] = { diff --git a/Python/pytime.c b/Python/pytime.c --- a/Python/pytime.c +++ b/Python/pytime.c @@ -70,6 +70,51 @@ #endif /* MS_WINDOWS */ } +int +_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec) +{ + if (PyFloat_Check(obj)) { + double d, intpart, floatpart, err; + + d = PyFloat_AsDouble(obj); + floatpart = modf(d, &intpart); + if (floatpart < 0) { + floatpart = 1.0 + floatpart; + intpart -= 1.0; + } + + *sec = (time_t)intpart; + err = intpart - (double)*sec; + if (err <= -1.0 || err >= 1.0) + goto overflow; + + floatpart *= 1e9; + *nsec = (long)floatpart; + return 0; + } + else { +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + *sec = PyLong_AsLongLong(obj); +#else + assert(sizeof(time_t) <= sizeof(long)); + *sec = PyLong_AsLong(obj); +#endif + if (*sec == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + goto overflow; + else + return -1; + } + *nsec = 0; + return 0; + } + +overflow: + PyErr_SetString(PyExc_OverflowError, + "timestamp out of range for platform time_t"); + return -1; +} + void _PyTime_Init() { diff --git a/README b/README --- a/README +++ b/README @@ -1,5 +1,5 @@ -This is Python version 3.3 alpha 0 -================================== +This is Python version 3.3.0 alpha 1 +==================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Python Software Foundation. All rights reserved. diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -2,12 +2,11 @@ # (C) 2003 Martin v. Loewis # See "FOO" in comments refers to MSDN sections with the title FOO. import msilib, schema, sequence, os, glob, time, re, shutil, zipfile +import subprocess, tempfile from msilib import Feature, CAB, Directory, Dialog, Binary, add_data import uisample from win32com.client import constants from distutils.spawn import find_executable -from uuids import product_codes -import tempfile # Settings can be overridden in config.py below # 0 for official python.org releases @@ -77,9 +76,6 @@ if snapshot: current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24)) - product_code = msilib.gen_uuid() -else: - product_code = product_codes[current_version] if full_current_version is None: full_current_version = current_version @@ -187,12 +183,19 @@ msilib.set_arch_from_file(dll_path) if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"): raise SystemError("msisupport.dll for incorrect architecture") + if msilib.Win64: upgrade_code = upgrade_code_64 - # Bump the last digit of the code by one, so that 32-bit and 64-bit - # releases get separate product codes - digit = hex((int(product_code[-2],16)+1)%16)[-1] - product_code = product_code[:-2] + digit + '}' + +if snapshot: + product_code = msilib.gen_uuid() +else: + # official release: generate UUID from the download link that the file will have + import uuid + product_code = uuid.uuid3(uuid.NAMESPACE_URL, + 'http://www.python.org/ftp/python/%s.%s.%s/python-%s%s.msi' % + (major, minor, micro, full_current_version, msilib.arch_ext)) + product_code = '{%s}' % product_code if testpackage: ext = 'px' @@ -906,31 +909,27 @@ kw['componentflags'] = 2 #msidbComponentAttributesOptional Directory.__init__(self, *args, **kw) - def check_unpackaged(self): - self.unpackaged_files.discard('__pycache__') - self.unpackaged_files.discard('.svn') - if self.unpackaged_files: - print "Warning: Unpackaged files in %s" % self.absolute - print self.unpackaged_files +def hgmanifest(): + # Fetch file list from Mercurial + process = subprocess.Popen(['hg', 'manifest'], stdout=subprocess.PIPE) + stdout, stderr = process.communicate() + # Create nested directories for file tree + result = {} + for line in stdout.splitlines(): + components = line.split('/') + d = result + while len(components) > 1: + d1 = d.setdefault(components[0], {}) + d = d1 + del components[0] + d[components[0]] = None + return result -def inside_test(dir): - if dir.physical in ('test', 'tests'): - return True - if dir.basedir: - return inside_test(dir.basedir) - return False - -def in_packaging_tests(dir): - if dir.physical == 'tests' and dir.basedir.physical == 'packaging': - return True - if dir.basedir: - return in_packaging_tests(dir.basedir) - return False - # See "File Table", "Component Table", "Directory Table", # "FeatureComponents Table" def add_files(db): + hgfiles = hgmanifest() cab = CAB("python") tmpfiles = [] # Add all executables, icons, text files into the TARGETDIR component @@ -992,123 +991,40 @@ # Add all .py files in Lib, except tkinter, test dirs = [] - pydirs = [(root,"Lib")] + pydirs = [(root, "Lib", hgfiles["Lib"], default_feature)] while pydirs: # Commit every now and then, or else installer will complain db.Commit() - parent, dir = pydirs.pop() - if dir == ".svn" or dir == '__pycache__' or dir.startswith("plat-"): + parent, dir, files, feature = pydirs.pop() + if dir.startswith("plat-"): continue - elif dir in ["tkinter", "idlelib", "Icons"]: + if dir in ["tkinter", "idlelib", "turtledemo"]: if not have_tcl: continue + feature = tcltk tcltk.set_current() - elif dir in ('test', 'tests') or inside_test(parent): - testsuite.set_current() + elif dir in ('test', 'tests'): + feature = testsuite elif not have_ctypes and dir == "ctypes": continue - else: - default_feature.set_current() + feature.set_current() lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir)) - # Add additional files dirs.append(lib) - lib.glob("*.txt") - if dir=='site-packages': - lib.add_file("README.txt", src="README") - continue - files = lib.glob("*.py") - files += lib.glob("*.pyw") - if files: - # Add an entry to the RemoveFile table to remove bytecode files. + has_py = False + for name, subdir in files.items(): + if subdir is None: + assert os.path.isfile(os.path.join(lib.absolute, name)) + if name == 'README': + lib.add_file("README.txt", src="README") + else: + lib.add_file(name) + has_py = has_py or name.endswith(".py") or name.endswith(".pyw") + else: + assert os.path.isdir(os.path.join(lib.absolute, name)) + pydirs.append((lib, name, subdir, feature)) + + if has_py: lib.remove_pyc() - # package READMEs if present - lib.glob("README") - if dir=='Lib': - lib.add_file("sysconfig.cfg") - if dir=='test' and parent.physical=='Lib': - lib.add_file("185test.db") - lib.add_file("audiotest.au") - lib.add_file("sgml_input.html") - lib.add_file("testtar.tar") - lib.add_file("test_difflib_expect.html") - lib.add_file("check_soundcard.vbs") - lib.add_file("empty.vbs") - lib.add_file("Sine-1000Hz-300ms.aif") - lib.glob("*.uue") - lib.glob("*.pem") - lib.glob("*.pck") - lib.glob("cfgparser.*") - lib.add_file("zip_cp437_header.zip") - lib.add_file("zipdir.zip") - lib.add_file("mime.types") - if dir=='capath': - lib.glob("*.0") - if dir=='tests' and parent.physical=='distutils': - lib.add_file("Setup.sample") - if dir=='decimaltestdata': - lib.glob("*.decTest") - if dir=='xmltestdata': - lib.glob("*.xml") - lib.add_file("test.xml.out") - if dir=='output': - lib.glob("test_*") - if dir=='sndhdrdata': - lib.glob("sndhdr.*") - if dir=='idlelib': - lib.glob("*.def") - lib.add_file("idle.bat") - lib.add_file("ChangeLog") - if dir=="Icons": - lib.glob("*.gif") - lib.add_file("idle.icns") - if dir=="command" and parent.physical in ("distutils", "packaging"): - lib.glob("wininst*.exe") - lib.add_file("command_template") - if dir=="lib2to3": - lib.removefile("pickle", "*.pickle") - if dir=="macholib": - lib.add_file("README.ctypes") - lib.glob("fetch_macholib*") - if dir=='turtledemo': - lib.add_file("turtle.cfg") - if dir=="pydoc_data": - lib.add_file("_pydoc.css") - if dir.endswith('.dist-info'): - lib.add_file('INSTALLER') - lib.add_file('REQUESTED') - lib.add_file('RECORD') - lib.add_file('METADATA') - lib.glob('RESOURCES') - if dir.endswith('.egg-info') or dir == 'EGG-INFO': - lib.add_file('PKG-INFO') - if in_packaging_tests(parent): - lib.glob('*.html') - lib.glob('*.tar.gz') - if dir=='fake_dists': - # cannot use glob since there are also egg-info directories here - lib.add_file('cheese-2.0.2.egg-info') - lib.add_file('nut-funkyversion.egg-info') - lib.add_file('strawberry-0.6.egg') - lib.add_file('truffles-5.0.egg-info') - lib.add_file('babar.cfg') - lib.add_file('babar.png') - if dir=="data" and parent.physical=="test_email": - # This should contain all non-.svn files listed in subversion - for f in os.listdir(lib.absolute): - if f.endswith(".txt") or f==".svn":continue - if f.endswith(".au") or f.endswith(".gif"): - lib.add_file(f) - else: - print("WARNING: New file %s in test/test_email/data" % f) - if dir=='tests' and parent.physical == 'packaging': - lib.add_file('SETUPTOOLS-PKG-INFO2') - lib.add_file('SETUPTOOLS-PKG-INFO') - lib.add_file('PKG-INFO') - for f in os.listdir(lib.absolute): - if os.path.isdir(os.path.join(lib.absolute, f)): - pydirs.append((lib, f)) - for d in dirs: - d.check_unpackaged() # Add DLLs default_feature.set_current() lib = DLLs diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py deleted file mode 100644 --- a/Tools/msi/uuids.py +++ /dev/null @@ -1,38 +0,0 @@ -# This should be extended for each Python release. -# The product code must change whenever the name of the MSI file -# changes, and when new component codes are issued for existing -# components. See "Changing the Product Code". As we change the -# component codes with every build, we need a new product code -# each time. For intermediate (snapshot) releases, they are automatically -# generated. For official releases, we record the product codes, -# so people can refer to them. -product_codes = { - '3.1.101': '{c423eada-c498-4d51-9eb4-bfeae647e0a0}', # 3.1a1 - '3.1.102': '{f6e199bf-dc64-42f3-87d4-1525991a013e}', # 3.1a2 - '3.1.111': '{c3c82893-69b2-4676-8554-1b6ee6c191e9}', # 3.1b1 - '3.1.121': '{da2b5170-12f3-4d99-8a1f-54926cca7acd}', # 3.1c1 - '3.1.122': '{bceb5133-e2ee-4109-951f-ac7e941a1692}', # 3.1c2 - '3.1.150': '{3ad61ee5-81d2-4d7e-adef-da1dd37277d1}', # 3.1.0 - '3.1.1121':'{5782f957-6d49-41d4-bad0-668715dfd638}', # 3.1.1c1 - '3.1.1150':'{7ff90460-89b7-435b-b583-b37b2815ccc7}', # 3.1.1 - '3.1.2121':'{ec45624a-378c-43be-91f3-3f7a59b0d90c}', # 3.1.2c1 - '3.1.2150':'{d40af016-506c-43fb-a738-bd54fa8c1e85}', # 3.1.2 - '3.2.101' :'{b411f168-7a36-4fff-902c-a554d1c78a4f}', # 3.2a1 - '3.2.102' :'{79ff73b7-8359-410f-b9c5-152d2026f8c8}', # 3.2a2 - '3.2.103' :'{e7635c65-c221-4b9b-b70a-5611b8369d77}', # 3.2a3 - '3.2.104' :'{748cd139-75b8-4ca8-98a7-58262298181e}', # 3.2a4 - '3.2.111' :'{20bfc16f-c7cd-4fc0-8f96-9914614a3c50}', # 3.2b1 - '3.2.112' :'{0e350c98-8d73-4993-b686-cfe87160046e}', # 3.2b2 - '3.2.121' :'{2094968d-7583-47f6-a7fd-22304532e09f}', # 3.2rc1 - '3.2.122' :'{4f3edfa6-cf70-469a-825f-e1206aa7f412}', # 3.2rc2 - '3.2.123' :'{90c673d7-8cfd-4969-9816-f7d70bad87f3}', # 3.2rc3 - '3.2.150' :'{b2042d5e-986d-44ec-aee3-afe4108ccc93}', # 3.2.0 - '3.2.1121':'{4f90de4a-83dd-4443-b625-ca130ff361dd}', # 3.2.1rc1 - '3.2.1122':'{dc5eb04d-ff8a-4bed-8f96-23942fd59e5f}', # 3.2.1rc2 - '3.2.1150':'{34b2530c-6349-4292-9dc3-60bda4aed93c}', # 3.2.1 - '3.2.2121':'{DFB29A53-ACC4-44e6-85A6-D0DA26FE8E4E}', # 3.2.2rc1 - '3.2.2150':'{4CDE3168-D060-4b7c-BC74-4D8F9BB01AFD}', # 3.2.2 - '3.2.3121':'{B8E8CFF7-E4C6-4a7c-9F06-BB3A8B75DDA8}', # 3.2.3rc1 - '3.2.3150':'{789C9644-9F82-44d3-B4CA-AC31F46F5882}', # 3.2.3 - -} -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Mar 7 05:35:10 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 07 Mar 2012 05:35:10 +0100 Subject: [Python-checkins] Daily reference leaks (2cf03b22020e): sum=0 Message-ID: results for 2cf03b22020e on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogkYjiFk', '-x'] From python-checkins at python.org Wed Mar 7 08:51:49 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 07 Mar 2012 08:51:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Add_todo_item_about_hash_ra?= =?utf8?q?ndomization=2E?= Message-ID: http://hg.python.org/cpython/rev/b8be6ac4395d changeset: 75465:b8be6ac4395d user: Georg Brandl date: Wed Mar 07 08:55:52 2012 +0100 summary: Add todo item about hash randomization. files: Doc/whatsnew/3.3.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1100,6 +1100,8 @@ Porting Python code ------------------- +.. XXX add a point about hash randomization and that it's always on in 3.3 + * :issue:`12326`: On Linux, sys.platform doesn't contain the major version anymore. It is now always 'linux', instead of 'linux2' or 'linux3' depending on the Linux version used to build Python. Replace sys.platform == 'linux2' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 16:27:24 2012 From: python-checkins at python.org (jason.coombs) Date: Wed, 07 Mar 2012 16:27:24 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Use_PEP-8_style?= =?utf8?q?_in_logging_example?= Message-ID: http://hg.python.org/cpython/rev/1e3c18c923ca changeset: 75466:1e3c18c923ca branch: 2.7 parent: 75460:1112c2f602b3 user: Jason R. Coombs date: Wed Mar 07 10:24:04 2012 -0500 summary: Use PEP-8 style in logging example files: Doc/library/logging.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -138,7 +138,7 @@ FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s' logging.basicConfig(format=FORMAT) - d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' } + d = {'clientip': '192.168.0.1', 'user': 'fbloggs'} logger = logging.getLogger('tcpserver') logger.warning('Protocol problem: %s', 'connection reset', extra=d) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 16:27:25 2012 From: python-checkins at python.org (jason.coombs) Date: Wed, 07 Mar 2012 16:27:25 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Use_PEP-8_style?= =?utf8?q?_in_logging_example?= Message-ID: http://hg.python.org/cpython/rev/7b65ea9c9972 changeset: 75467:7b65ea9c9972 branch: 3.2 parent: 75437:4cfcda9e80cb user: Jason R. Coombs date: Wed Mar 07 10:26:08 2012 -0500 summary: Use PEP-8 style in logging example files: Doc/library/logging.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -159,7 +159,7 @@ FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s' logging.basicConfig(format=FORMAT) - d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' } + d = {'clientip': '192.168.0.1', 'user': 'fbloggs'} logger = logging.getLogger('tcpserver') logger.warning('Protocol problem: %s', 'connection reset', extra=d) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 16:27:26 2012 From: python-checkins at python.org (jason.coombs) Date: Wed, 07 Mar 2012 16:27:26 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge=3A_Use_PEP-8_style_in_logging_example?= Message-ID: http://hg.python.org/cpython/rev/2073b0522319 changeset: 75468:2073b0522319 parent: 75465:b8be6ac4395d parent: 75467:7b65ea9c9972 user: Jason R. Coombs date: Wed Mar 07 10:27:07 2012 -0500 summary: Merge: Use PEP-8 style in logging example files: Doc/library/logging.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -159,7 +159,7 @@ FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s' logging.basicConfig(format=FORMAT) - d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' } + d = {'clientip': '192.168.0.1', 'user': 'fbloggs'} logger = logging.getLogger('tcpserver') logger.warning('Protocol problem: %s', 'connection reset', extra=d) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 18:08:19 2012 From: python-checkins at python.org (ross.lagerwall) Date: Wed, 07 Mar 2012 18:08:19 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2310951=3A_Fix_warni?= =?utf8?q?ngs_in_the_socket_module=2E?= Message-ID: http://hg.python.org/cpython/rev/2f10c1ad4b21 changeset: 75469:2f10c1ad4b21 user: Ross Lagerwall date: Tue Mar 06 21:36:18 2012 +0200 summary: Issue #10951: Fix warnings in the socket module. files: Modules/socketmodule.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4263,7 +4263,7 @@ int buf_len = (sizeof buf) - 1; int errnop; #endif -#if defined(HAVE_GETHOSTBYNAME_R_3_ARG) || defined(HAVE_GETHOSTBYNAME_R_6_ARG) +#ifdef HAVE_GETHOSTBYNAME_R_3_ARG int result; #endif #endif /* HAVE_GETHOSTBYNAME_R */ @@ -4275,7 +4275,7 @@ Py_BEGIN_ALLOW_THREADS #ifdef HAVE_GETHOSTBYNAME_R #if defined(HAVE_GETHOSTBYNAME_R_6_ARG) - result = gethostbyname_r(name, &hp_allocated, buf, buf_len, + gethostbyname_r(name, &hp_allocated, buf, buf_len, &h, &errnop); #elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) h = gethostbyname_r(name, &hp_allocated, buf, buf_len, &errnop); @@ -4337,7 +4337,7 @@ int buf_len = (sizeof buf) - 1; int errnop; #endif -#if defined(HAVE_GETHOSTBYNAME_R_3_ARG) || defined(HAVE_GETHOSTBYNAME_R_6_ARG) +#ifdef HAVE_GETHOSTBYNAME_R_3_ARG int result; #endif #endif /* HAVE_GETHOSTBYNAME_R */ @@ -4371,7 +4371,7 @@ Py_BEGIN_ALLOW_THREADS #ifdef HAVE_GETHOSTBYNAME_R #if defined(HAVE_GETHOSTBYNAME_R_6_ARG) - result = gethostbyaddr_r(ap, al, af, + gethostbyaddr_r(ap, al, af, &hp_allocated, buf, buf_len, &h, &errnop); #elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 18:08:23 2012 From: python-checkins at python.org (ross.lagerwall) Date: Wed, 07 Mar 2012 18:08:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2310951=3A_Fix_compi?= =?utf8?q?ler_warnings_in_=5Fsre=2Ec?= Message-ID: http://hg.python.org/cpython/rev/1dd43e939c07 changeset: 75470:1dd43e939c07 user: Ross Lagerwall date: Tue Mar 06 21:48:57 2012 +0200 summary: Issue #10951: Fix compiler warnings in _sre.c files: Modules/_sre.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -2933,13 +2933,13 @@ <1=skip> <2=flags> <3=min> <4=max>; If SRE_INFO_PREFIX or SRE_INFO_CHARSET is in the flags, more follows. */ - SRE_CODE flags, min, max, i; + SRE_CODE flags, i; SRE_CODE *newcode; GET_SKIP; newcode = code+skip-1; GET_ARG; flags = arg; - GET_ARG; min = arg; - GET_ARG; max = arg; + GET_ARG; + GET_ARG; /* Check that only valid flags are present */ if ((flags & ~(SRE_INFO_PREFIX | SRE_INFO_LITERAL | @@ -2955,9 +2955,9 @@ FAIL; /* Validate the prefix */ if (flags & SRE_INFO_PREFIX) { - SRE_CODE prefix_len, prefix_skip; + SRE_CODE prefix_len; GET_ARG; prefix_len = arg; - GET_ARG; prefix_skip = arg; + GET_ARG; /* Here comes the prefix string */ if (code+prefix_len < code || code+prefix_len > newcode) FAIL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 19:07:23 2012 From: python-checkins at python.org (ross.lagerwall) Date: Wed, 07 Mar 2012 19:07:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Use_ANSI_C_prototype_instea?= =?utf8?q?d_of_K=26R_style=2E?= Message-ID: http://hg.python.org/cpython/rev/e4c3a3a6371f changeset: 75471:e4c3a3a6371f user: Ross Lagerwall date: Wed Mar 07 20:06:33 2012 +0200 summary: Use ANSI C prototype instead of K&R style. files: Modules/_posixsubprocess.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -80,7 +80,7 @@ * that properly supports /dev/fd. */ static int -_is_fdescfs_mounted_on_dev_fd() +_is_fdescfs_mounted_on_dev_fd(void) { struct stat dev_stat; struct stat dev_fd_stat; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 21:00:52 2012 From: python-checkins at python.org (eric.araujo) Date: Wed, 07 Mar 2012 21:00:52 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Backout_buggy_p?= =?utf8?q?atch_for_=2313719?= Message-ID: http://hg.python.org/cpython/rev/077b42a54803 changeset: 75472:077b42a54803 branch: 2.7 parent: 75466:1e3c18c923ca user: ?ric Araujo date: Wed Mar 07 21:00:44 2012 +0100 summary: Backout buggy patch for #13719 files: Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/tests/test_bdist_msi.py | 9 --------- Misc/NEWS | 2 -- 3 files changed, 1 insertions(+), 12 deletions(-) diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -262,7 +262,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', installer_name + tup = 'bdist_msi', self.target_version or 'any', fullname self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,5 +1,4 @@ """Tests for distutils.command.bdist_msi.""" -import os import sys import unittest from test.test_support import run_unittest @@ -17,14 +16,6 @@ project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() - cmd.run() - - bdists = os.listdir(os.path.join(project_dir, 'dist')) - self.assertEqual(bdists, ['foo-0.1.msi']) - - # bug #13719: upload ignores bdist_msi files - self.assertEqual(dist.dist_files, - [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) def test_suite(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -101,8 +101,6 @@ Library ------- -- Issue #13719: Make the distutils upload command aware of bdist_msi products. - - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been fixed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 21:08:27 2012 From: python-checkins at python.org (eric.araujo) Date: Wed, 07 Mar 2012 21:08:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Backout_buggy_p?= =?utf8?q?atch_committed_for_=2313719?= Message-ID: http://hg.python.org/cpython/rev/7e629bacec87 changeset: 75473:7e629bacec87 branch: 3.2 parent: 75467:7b65ea9c9972 user: ?ric Araujo date: Wed Mar 07 20:48:55 2012 +0100 summary: Backout buggy patch committed for #13719 files: Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/tests/test_bdist_msi.py | 9 --------- Misc/NEWS | 2 -- 3 files changed, 1 insertions(+), 12 deletions(-) diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -260,7 +260,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', installer_name + tup = 'bdist_msi', self.target_version or 'any', fullname self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,5 +1,4 @@ """Tests for distutils.command.bdist_msi.""" -import os import sys import unittest from test.support import run_unittest @@ -17,14 +16,6 @@ project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() - cmd.run() - - bdists = os.listdir(os.path.join(project_dir, 'dist')) - self.assertEqual(bdists, ['foo-0.1.msi']) - - # bug #13719: upload ignores bdist_msi files - self.assertEqual(dist.dist_files, - [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) def test_suite(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -130,8 +130,6 @@ Library ------- -- Issue #13719: Make the distutils upload command aware of bdist_msi products. - - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been fixed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 21:08:28 2012 From: python-checkins at python.org (eric.araujo) Date: Wed, 07 Mar 2012 21:08:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/e52a31b83062 changeset: 75474:e52a31b83062 parent: 75471:e4c3a3a6371f parent: 75473:7e629bacec87 user: ?ric Araujo date: Wed Mar 07 20:50:06 2012 +0100 summary: Merge 3.2 files: Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/tests/test_bdist_msi.py | 9 --------- 2 files changed, 1 insertions(+), 10 deletions(-) diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -260,7 +260,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', installer_name + tup = 'bdist_msi', self.target_version or 'any', fullname self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,5 +1,4 @@ """Tests for distutils.command.bdist_msi.""" -import os import sys import unittest from test.support import run_unittest @@ -17,14 +16,6 @@ project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() - cmd.run() - - bdists = os.listdir(os.path.join(project_dir, 'dist')) - self.assertEqual(bdists, ['foo-0.1.msi']) - - # bug #13719: upload ignores bdist_msi files - self.assertEqual(dist.dist_files, - [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) def test_suite(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 21:08:29 2012 From: python-checkins at python.org (eric.araujo) Date: Wed, 07 Mar 2012 21:08:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_buggy_change_for_=23?= =?utf8?q?13719_in_packaging?= Message-ID: http://hg.python.org/cpython/rev/17106d7d34b4 changeset: 75475:17106d7d34b4 user: ?ric Araujo date: Wed Mar 07 20:56:18 2012 +0100 summary: Remove buggy change for #13719 in packaging files: Lib/packaging/command/bdist_msi.py | 2 +- Lib/packaging/tests/test_command_bdist_msi.py | 9 --------- Misc/NEWS | 3 --- 3 files changed, 1 insertions(+), 13 deletions(-) diff --git a/Lib/packaging/command/bdist_msi.py b/Lib/packaging/command/bdist_msi.py --- a/Lib/packaging/command/bdist_msi.py +++ b/Lib/packaging/command/bdist_msi.py @@ -261,7 +261,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', installer_name + tup = 'bdist_msi', self.target_version or 'any', fullname self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/packaging/tests/test_command_bdist_msi.py b/Lib/packaging/tests/test_command_bdist_msi.py --- a/Lib/packaging/tests/test_command_bdist_msi.py +++ b/Lib/packaging/tests/test_command_bdist_msi.py @@ -1,5 +1,4 @@ """Tests for distutils.command.bdist_msi.""" -import os import sys from packaging.tests import unittest, support @@ -16,14 +15,6 @@ project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() - cmd.run() - - bdists = os.listdir(os.path.join(project_dir, 'dist')) - self.assertEqual(bdists, ['foo-0.1.msi']) - - # bug #13719: upload ignores bdist_msi files - self.assertEqual(dist.dist_files, - [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) def test_suite(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,9 +23,6 @@ Also, add a multiprocessing.connection.wait(rlist, timeout=None) function for polling multiple objects at once. Patch by sbt. -- Issue #13719: Make the distutils and packaging upload commands aware of - bdist_msi products. - - Issue #14007: Accept incomplete TreeBuilder objects (missing start, end, data or close method) for the Python implementation as well. Drop the no-op TreeBuilder().xml() method from the C implementation. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 21:59:27 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 07 Mar 2012 21:59:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_keep_the_buffer?= =?utf8?q?_object_around_while_we=27re_using_it_=28closes_=2314212=29?= Message-ID: http://hg.python.org/cpython/rev/10a79a33d09b changeset: 75476:10a79a33d09b branch: 3.2 parent: 75467:7b65ea9c9972 user: Benjamin Peterson date: Wed Mar 07 14:50:25 2012 -0600 summary: keep the buffer object around while we're using it (closes #14212) files: Lib/test/test_re.py | 14 +++++- Misc/NEWS | 3 + Modules/_sre.c | 82 +++++++++++++++++++------------- Modules/sre.h | 2 + 4 files changed, 66 insertions(+), 35 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1,4 +1,5 @@ -from test.support import verbose, run_unittest +from test.support import verbose, run_unittest, gc_collect +import io import re from re import Scanner import sys @@ -16,6 +17,17 @@ class ReTests(unittest.TestCase): + def test_keep_buffer(self): + # See bug 14212 + b = bytearray(b'x') + it = re.finditer(b'a', b) + with self.assertRaises(BufferError): + b.extend(b'x'*400) + list(it) + del it + gc_collect() + b.extend(b'x'*400) + def test_weakref(self): s = 'QabbbcR' x = re.compile('ab+c') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -549,6 +549,9 @@ Extension Modules ----------------- +- Issue #14212: The re module didn't retain a reference to buffers it was + scanning, resulting in segfaults. + - Issue #13840: The error message produced by ctypes.create_string_buffer when given a Unicode string has been fixed. diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -1664,7 +1664,7 @@ } static void* -getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize) +getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize, Py_buffer *view) { /* given a python object, return a data pointer, a length (in characters), and a character size. return NULL if the object @@ -1674,7 +1674,6 @@ Py_ssize_t size, bytes; int charsize; void* ptr; - Py_buffer view; /* Unicode objects do not support the buffer API. So, get the data directly instead. */ @@ -1686,26 +1685,21 @@ } /* get pointer to string buffer */ - view.len = -1; + view->len = -1; buffer = Py_TYPE(string)->tp_as_buffer; if (!buffer || !buffer->bf_getbuffer || - (*buffer->bf_getbuffer)(string, &view, PyBUF_SIMPLE) < 0) { + (*buffer->bf_getbuffer)(string, view, PyBUF_SIMPLE) < 0) { PyErr_SetString(PyExc_TypeError, "expected string or buffer"); return NULL; } /* determine buffer size */ - bytes = view.len; - ptr = view.buf; - - /* Release the buffer immediately --- possibly dangerous - but doing something else would require some re-factoring - */ - PyBuffer_Release(&view); + bytes = view->len; + ptr = view->buf; if (bytes < 0) { PyErr_SetString(PyExc_TypeError, "buffer has negative size"); - return NULL; + goto err; } /* determine character size */ @@ -1719,7 +1713,7 @@ #endif else { PyErr_SetString(PyExc_TypeError, "buffer size mismatch"); - return NULL; + goto err; } *p_length = size; @@ -1728,8 +1722,13 @@ if (ptr == NULL) { PyErr_SetString(PyExc_ValueError, "Buffer is NULL"); + goto err; } return ptr; + err: + PyBuffer_Release(view); + view->buf = NULL; + return NULL; } LOCAL(PyObject*) @@ -1747,20 +1746,21 @@ state->lastmark = -1; state->lastindex = -1; - ptr = getstring(string, &length, &charsize); + state->buffer.buf = NULL; + ptr = getstring(string, &length, &charsize, &state->buffer); if (!ptr) - return NULL; - - if (charsize == 1 && pattern->charsize > 1) { - PyErr_SetString(PyExc_TypeError, + goto err; + + if (charsize == 1 && pattern->charsize > 1) { + PyErr_SetString(PyExc_TypeError, "can't use a string pattern on a bytes-like object"); - return NULL; - } - if (charsize > 1 && pattern->charsize == 1) { - PyErr_SetString(PyExc_TypeError, + goto err; + } + if (charsize > 1 && pattern->charsize == 1) { + PyErr_SetString(PyExc_TypeError, "can't use a bytes pattern on a string-like object"); - return NULL; - } + goto err; + } /* adjust boundaries */ if (start < 0) @@ -1797,11 +1797,17 @@ state->lower = sre_lower; return string; + err: + if (state->buffer.buf) + PyBuffer_Release(&state->buffer); + return NULL; } LOCAL(void) state_fini(SRE_STATE* state) { + if (state->buffer.buf) + PyBuffer_Release(&state->buffer); Py_XDECREF(state->string); data_stack_dealloc(state); } @@ -1863,6 +1869,8 @@ { if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); + if (self->view.buf) + PyBuffer_Release(&self->view); Py_XDECREF(self->pattern); Py_XDECREF(self->groupindex); Py_XDECREF(self->indexgroup); @@ -2297,6 +2305,7 @@ Py_ssize_t i, b, e; int bint; int filter_is_callable; + Py_buffer view; if (PyCallable_Check(ptemplate)) { /* sub/subn takes either a function or a template */ @@ -2306,7 +2315,8 @@ } else { /* if not callable, check if it's a literal string */ int literal; - ptr = getstring(ptemplate, &n, &bint); + view.buf = NULL; + ptr = getstring(ptemplate, &n, &bint, &view); b = bint; if (ptr) { if (b == 1) { @@ -2320,6 +2330,8 @@ PyErr_Clear(); literal = 0; } + if (view.buf) + PyBuffer_Release(&view); if (literal) { filter = ptemplate; Py_INCREF(filter); @@ -2661,6 +2673,7 @@ Py_ssize_t groups = 0; PyObject* groupindex = NULL; PyObject* indexgroup = NULL; + if (!PyArg_ParseTuple(args, "OiO!|nOO", &pattern, &flags, &PyList_Type, &code, &groups, &groupindex, &indexgroup)) @@ -2675,6 +2688,7 @@ self->pattern = NULL; self->groupindex = NULL; self->indexgroup = NULL; + self->view.buf = NULL; self->codesize = n; @@ -2694,15 +2708,15 @@ return NULL; } - if (pattern == Py_None) - self->charsize = -1; - else { - Py_ssize_t p_length; - if (!getstring(pattern, &p_length, &self->charsize)) { - Py_DECREF(self); - return NULL; - } - } + if (pattern == Py_None) + self->charsize = -1; + else { + Py_ssize_t p_length; + if (!getstring(pattern, &p_length, &self->charsize, &self->view)) { + Py_DECREF(self); + return NULL; + } + } Py_INCREF(pattern); self->pattern = pattern; diff --git a/Modules/sre.h b/Modules/sre.h --- a/Modules/sre.h +++ b/Modules/sre.h @@ -31,6 +31,7 @@ int flags; /* flags used when compiling pattern source */ PyObject *weakreflist; /* List of weak references */ int charsize; /* pattern charsize (or -1) */ + Py_buffer view; /* pattern code */ Py_ssize_t codesize; SRE_CODE code[1]; @@ -80,6 +81,7 @@ char* data_stack; size_t data_stack_size; size_t data_stack_base; + Py_buffer buffer; /* current repeat context */ SRE_REPEAT *repeat; /* hooks */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 21:59:27 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 07 Mar 2012 21:59:27 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/95bbe3229cd0 changeset: 75477:95bbe3229cd0 branch: 3.2 parent: 75476:10a79a33d09b parent: 75473:7e629bacec87 user: Benjamin Peterson date: Wed Mar 07 14:50:35 2012 -0600 summary: merge heads files: Lib/distutils/command/bdist_msi.py | 2 +- Lib/distutils/tests/test_bdist_msi.py | 9 --------- Misc/NEWS | 2 -- 3 files changed, 1 insertions(+), 12 deletions(-) diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -260,7 +260,7 @@ self.db.Commit() if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', installer_name + tup = 'bdist_msi', self.target_version or 'any', fullname self.distribution.dist_files.append(tup) if not self.keep_temp: diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py --- a/Lib/distutils/tests/test_bdist_msi.py +++ b/Lib/distutils/tests/test_bdist_msi.py @@ -1,5 +1,4 @@ """Tests for distutils.command.bdist_msi.""" -import os import sys import unittest from test.support import run_unittest @@ -17,14 +16,6 @@ project_dir, dist = self.create_dist() cmd = bdist_msi(dist) cmd.ensure_finalized() - cmd.run() - - bdists = os.listdir(os.path.join(project_dir, 'dist')) - self.assertEqual(bdists, ['foo-0.1.msi']) - - # bug #13719: upload ignores bdist_msi files - self.assertEqual(dist.dist_files, - [('bdist_msi', 'any', 'dist/foo-0.1.msi')]) def test_suite(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -130,8 +130,6 @@ Library ------- -- Issue #13719: Make the distutils upload command aware of bdist_msi products. - - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been fixed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 7 21:59:29 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 07 Mar 2012 21:59:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiBtZXJnZSAzLjIgKCMxNDIxMik=?= Message-ID: http://hg.python.org/cpython/rev/17dfe24e5107 changeset: 75478:17dfe24e5107 parent: 75475:17106d7d34b4 parent: 75477:95bbe3229cd0 user: Benjamin Peterson date: Wed Mar 07 14:59:13 2012 -0600 summary: merge 3.2 (#14212) files: Lib/test/test_re.py | 14 ++++++- Misc/NEWS | 6 ++ Modules/_sre.c | 67 ++++++++++++++++++++------------ Modules/sre.h | 2 + 4 files changed, 62 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1,4 +1,5 @@ -from test.support import verbose, run_unittest +from test.support import verbose, run_unittest, gc_collect +import io import re from re import Scanner import sys @@ -16,6 +17,17 @@ class ReTests(unittest.TestCase): + def test_keep_buffer(self): + # See bug 14212 + b = bytearray(b'x') + it = re.finditer(b'a', b) + with self.assertRaises(BufferError): + b.extend(b'x'*400) + list(it) + del it + gc_collect() + b.extend(b'x'*400) + def test_weakref(self): s = 'QabbbcR' x = re.compile('ab+c') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,12 @@ data or close method) for the Python implementation as well. Drop the no-op TreeBuilder().xml() method from the C implementation. +Extension Modules +----------------- + +- Issue #14212: The re module didn't retain a reference to buffers it was + scanning, resulting in segfaults. + What's New in Python 3.3.0 Alpha 1? =================================== diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -1650,7 +1650,8 @@ static void* getstring(PyObject* string, Py_ssize_t* p_length, - int* p_logical_charsize, int* p_charsize) + int* p_logical_charsize, int* p_charsize, + Py_buffer *view) { /* given a python object, return a data pointer, a length (in characters), and a character size. return NULL if the object @@ -1660,7 +1661,6 @@ Py_ssize_t size, bytes; int charsize; void* ptr; - Py_buffer view; /* Unicode objects do not support the buffer API. So, get the data directly instead. */ @@ -1675,26 +1675,21 @@ } /* get pointer to byte string buffer */ - view.len = -1; + view->len = -1; buffer = Py_TYPE(string)->tp_as_buffer; if (!buffer || !buffer->bf_getbuffer || - (*buffer->bf_getbuffer)(string, &view, PyBUF_SIMPLE) < 0) { + (*buffer->bf_getbuffer)(string, view, PyBUF_SIMPLE) < 0) { PyErr_SetString(PyExc_TypeError, "expected string or buffer"); return NULL; } /* determine buffer size */ - bytes = view.len; - ptr = view.buf; - - /* Release the buffer immediately --- possibly dangerous - but doing something else would require some re-factoring - */ - PyBuffer_Release(&view); + bytes = view->len; + ptr = view->buf; if (bytes < 0) { PyErr_SetString(PyExc_TypeError, "buffer has negative size"); - return NULL; + goto err; } /* determine character size */ @@ -1704,7 +1699,7 @@ charsize = 1; else { PyErr_SetString(PyExc_TypeError, "buffer size mismatch"); - return NULL; + goto err; } *p_length = size; @@ -1714,8 +1709,13 @@ if (ptr == NULL) { PyErr_SetString(PyExc_ValueError, "Buffer is NULL"); + goto err; } return ptr; + err: + PyBuffer_Release(view); + view->buf = NULL; + return NULL; } LOCAL(PyObject*) @@ -1733,20 +1733,21 @@ state->lastmark = -1; state->lastindex = -1; - ptr = getstring(string, &length, &logical_charsize, &charsize); + state->buffer.buf = NULL; + ptr = getstring(string, &length, &logical_charsize, &charsize, &state->buffer); if (!ptr) - return NULL; - - if (logical_charsize == 1 && pattern->logical_charsize > 1) { - PyErr_SetString(PyExc_TypeError, + goto err; + + if (logical_charsize == 1 && pattern->logical_charsize > 1) { + PyErr_SetString(PyExc_TypeError, "can't use a string pattern on a bytes-like object"); - return NULL; - } - if (logical_charsize > 1 && pattern->logical_charsize == 1) { - PyErr_SetString(PyExc_TypeError, + goto err; + } + if (logical_charsize > 1 && pattern->logical_charsize == 1) { + PyErr_SetString(PyExc_TypeError, "can't use a bytes pattern on a string-like object"); - return NULL; - } + goto err; + } /* adjust boundaries */ if (start < 0) @@ -1780,11 +1781,17 @@ state->lower = sre_lower; return string; + err: + if (state->buffer.buf) + PyBuffer_Release(&state->buffer); + return NULL; } LOCAL(void) state_fini(SRE_STATE* state) { + if (state->buffer.buf) + PyBuffer_Release(&state->buffer); Py_XDECREF(state->string); data_stack_dealloc(state); } @@ -1846,6 +1853,8 @@ { if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); + if (self->view.buf) + PyBuffer_Release(&self->view); Py_XDECREF(self->pattern); Py_XDECREF(self->groupindex); Py_XDECREF(self->indexgroup); @@ -2272,6 +2281,7 @@ Py_ssize_t i, b, e; int logical_charsize, charsize; int filter_is_callable; + Py_buffer view; if (PyCallable_Check(ptemplate)) { /* sub/subn takes either a function or a template */ @@ -2281,7 +2291,8 @@ } else { /* if not callable, check if it's a literal string */ int literal; - ptr = getstring(ptemplate, &n, &logical_charsize, &charsize); + view.buf = NULL; + ptr = getstring(ptemplate, &n, &logical_charsize, &charsize, &view); b = charsize; if (ptr) { literal = sre_literal_template(b, ptr, n); @@ -2289,6 +2300,8 @@ PyErr_Clear(); literal = 0; } + if (view.buf) + PyBuffer_Release(&view); if (literal) { filter = ptemplate; Py_INCREF(filter); @@ -2628,6 +2641,7 @@ Py_ssize_t groups = 0; PyObject* groupindex = NULL; PyObject* indexgroup = NULL; + if (!PyArg_ParseTuple(args, "OiO!|nOO", &pattern, &flags, &PyList_Type, &code, &groups, &groupindex, &indexgroup)) @@ -2642,6 +2656,7 @@ self->pattern = NULL; self->groupindex = NULL; self->indexgroup = NULL; + self->view.buf = NULL; self->codesize = n; @@ -2668,7 +2683,7 @@ else { Py_ssize_t p_length; if (!getstring(pattern, &p_length, &self->logical_charsize, - &self->charsize)) { + &self->charsize, &self->view)) { Py_DECREF(self); return NULL; } diff --git a/Modules/sre.h b/Modules/sre.h --- a/Modules/sre.h +++ b/Modules/sre.h @@ -32,6 +32,7 @@ PyObject *weakreflist; /* List of weak references */ int logical_charsize; /* pattern charsize (or -1) */ int charsize; + Py_buffer view; /* pattern code */ Py_ssize_t codesize; SRE_CODE code[1]; @@ -82,6 +83,7 @@ char* data_stack; size_t data_stack_size; size_t data_stack_base; + Py_buffer buffer; /* current repeat context */ SRE_REPEAT *repeat; /* hooks */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 00:57:15 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 08 Mar 2012 00:57:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_make_delegating_generators_?= =?utf8?q?say_they_running_=28closes_=2314220=29?= Message-ID: http://hg.python.org/cpython/rev/3357eac1ba62 changeset: 75479:3357eac1ba62 user: Benjamin Peterson date: Wed Mar 07 17:57:04 2012 -0600 summary: make delegating generators say they running (closes #14220) files: Lib/test/test_pep380.py | 72 +++++++++++++++++++++++++++++ Misc/NEWS | 3 + Objects/genobject.c | 51 ++++++++++++++----- 3 files changed, 112 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_pep380.py b/Lib/test/test_pep380.py --- a/Lib/test/test_pep380.py +++ b/Lib/test/test_pep380.py @@ -847,6 +847,78 @@ yield from () self.assertRaises(StopIteration, next, g()) + def test_delegating_generators_claim_to_be_running(self): + # Check with basic iteration + def one(): + yield 0 + yield from two() + yield 3 + def two(): + yield 1 + try: + yield from g1 + except ValueError: + pass + yield 2 + g1 = one() + self.assertEqual(list(g1), [0, 1, 2, 3]) + # Check with send + g1 = one() + res = [next(g1)] + try: + while True: + res.append(g1.send(42)) + except StopIteration: + pass + self.assertEqual(res, [0, 1, 2, 3]) + # Check with throw + class MyErr(Exception): + pass + def one(): + try: + yield 0 + except MyErr: + pass + yield from two() + try: + yield 3 + except MyErr: + pass + def two(): + try: + yield 1 + except MyErr: + pass + try: + yield from g1 + except ValueError: + pass + try: + yield 2 + except MyErr: + pass + g1 = one() + res = [next(g1)] + try: + while True: + res.append(g1.throw(MyErr)) + except StopIteration: + pass + # Check with close + class MyIt(object): + def __iter__(self): + return self + def __next__(self): + return 42 + def close(self_): + self.assertTrue(g1.gi_running) + self.assertRaises(ValueError, next, g1) + def one(): + yield from MyIt() + g1 = one() + next(g1) + g1.close() + def test_main(): from test import support diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ - Issue #14205: dict lookup raises a RuntimeError if the dict is modified during a lookup. +- Issue #14220: When a generator is delegating to another iterator with the + yield from syntax, it needs to have its ``gi_running`` flag set to True. + Library ------- diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -41,6 +41,15 @@ PyObject_GC_Del(gen); } +static int +gen_running(PyGenObject *gen) +{ + if (gen->gi_running) { + PyErr_SetString(PyExc_ValueError, "generator already executing"); + return 1; + } + return 0; +} static PyObject * gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) @@ -49,11 +58,7 @@ PyFrameObject *f = gen->gi_frame; PyObject *result; - if (gen->gi_running) { - PyErr_SetString(PyExc_ValueError, - "generator already executing"); - return NULL; - } + assert(!gen->gi_running); if (f==NULL || f->f_stacktop == NULL) { /* Only set exception if called from send() */ if (arg && !exc) @@ -137,12 +142,15 @@ int exc = 0; PyObject *ret; PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL; + if (gen_running(gen)) + return NULL; /* XXX (ncoghlan): Are the incref/decref on arg and yf strictly needed? * Or would it be valid to rely on borrowed references? */ Py_INCREF(arg); if (yf) { Py_INCREF(yf); + gen->gi_running = 1; if (PyGen_CheckExact(yf)) { ret = gen_send((PyGenObject *)yf, arg); } else { @@ -151,6 +159,7 @@ else ret = PyObject_CallMethod(yf, "send", "O", arg); } + gen->gi_running = 0; if (ret) { Py_DECREF(yf); goto done; @@ -177,17 +186,19 @@ */ static int -gen_close_iter(PyObject *yf) +gen_close_iter(PyGenObject *gen, PyObject *yf) { PyObject *retval = NULL; + int err = 0; if (PyGen_CheckExact(yf)) { retval = gen_close((PyGenObject *)yf, NULL); - if (retval == NULL) { - return -1; - } + if (!retval) + err = -1; } else { - PyObject *meth = PyObject_GetAttrString(yf, "close"); + PyObject *meth; + gen->gi_running = 1; + meth = PyObject_GetAttrString(yf, "close"); if (meth == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_WriteUnraisable(yf); @@ -197,11 +208,12 @@ retval = PyObject_CallFunction(meth, ""); Py_DECREF(meth); if (!retval) - return -1; + err = -1; } + gen->gi_running = 0; } Py_XDECREF(retval); - return 0; + return err; } static PyObject * @@ -211,9 +223,11 @@ PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL; int err = 0; + if (gen_running(gen)) + return NULL; if (yf) { Py_INCREF(yf); - err = gen_close_iter(yf); + err = gen_close_iter(gen, yf); gen_undelegate(gen); Py_DECREF(yf); } @@ -314,18 +328,22 @@ if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) return NULL; + if (gen_running(gen)) + return NULL; + if (yf) { PyObject *ret; int err; Py_INCREF(yf); if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) { - err = gen_close_iter(yf); + err = gen_close_iter(gen, yf); Py_DECREF(yf); gen_undelegate(gen); if (err < 0) return gen_send_ex(gen, Py_None, 1); goto throw_here; } + gen->gi_running = 1; if (PyGen_CheckExact(yf)) { ret = gen_throw((PyGenObject *)yf, args); } else { @@ -343,6 +361,7 @@ ret = PyObject_CallObject(meth, args); Py_DECREF(meth); } + gen->gi_running = 0; Py_DECREF(yf); if (!ret) { PyObject *val; @@ -423,10 +442,14 @@ PyObject *ret; int exc = 0; PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL; + if (gen_running(gen)) + return NULL; if (yf) { Py_INCREF(yf); /* ceval.c ensures that yf is an iterator */ + gen->gi_running = 1; ret = Py_TYPE(yf)->tp_iternext(yf); + gen->gi_running = 0; if (ret) { Py_DECREF(yf); return ret; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 01:11:42 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 08 Mar 2012 01:11:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_indicate_we=27re_not_runnin?= =?utf8?q?g_as_we_leave_this_block?= Message-ID: http://hg.python.org/cpython/rev/354c7dc03095 changeset: 75480:354c7dc03095 user: Benjamin Peterson date: Wed Mar 07 18:11:31 2012 -0600 summary: indicate we're not running as we leave this block files: Objects/genobject.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -356,6 +356,7 @@ PyErr_Clear(); Py_DECREF(yf); gen_undelegate(gen); + gen->gi_running = 0; goto throw_here; } ret = PyObject_CallObject(meth, args); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 01:17:13 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 08 Mar 2012 01:17:13 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_make_gi=5Frunning_a_boolean?= Message-ID: http://hg.python.org/cpython/rev/c8d1df9ac987 changeset: 75481:c8d1df9ac987 user: Benjamin Peterson date: Wed Mar 07 18:17:03 2012 -0600 summary: make gi_running a boolean files: Objects/genobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -542,7 +542,7 @@ static PyMemberDef gen_memberlist[] = { {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY}, - {"gi_running", T_INT, offsetof(PyGenObject, gi_running), READONLY}, + {"gi_running", T_BOOL, offsetof(PyGenObject, gi_running), READONLY}, {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY}, {NULL} /* Sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 01:53:07 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 08 Mar 2012 01:53:07 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_allow_cycles_th?= =?utf8?q?rought_the_=5F=5Fdict=5F=5F_slot_to_be_cleared_=28closes_=231469?= =?utf8?q?629=29?= Message-ID: http://hg.python.org/cpython/rev/3787e896dbe9 changeset: 75482:3787e896dbe9 branch: 3.2 parent: 75477:95bbe3229cd0 user: Benjamin Peterson date: Wed Mar 07 18:41:11 2012 -0600 summary: allow cycles throught the __dict__ slot to be cleared (closes #1469629) Patch from Armin, test from me. files: Lib/test/test_descr.py | 19 +++++++++++++++++-- Misc/NEWS | 3 +++ Objects/typeobject.c | 9 +++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1,8 +1,10 @@ import builtins +import gc import sys import types import math import unittest +import weakref from copy import deepcopy from test import support @@ -1186,7 +1188,6 @@ self.assertEqual(Counted.counter, 0) # Test lookup leaks [SF bug 572567] - import gc if hasattr(gc, 'get_objects'): class G(object): def __eq__(self, other): @@ -4380,7 +4381,6 @@ self.assertRaises(AttributeError, getattr, C(), "attr") self.assertEqual(descr.counter, 4) - import gc class EvilGetattribute(object): # This used to segfault def __getattr__(self, name): @@ -4429,6 +4429,21 @@ foo = Foo() str(foo) + def test_cycle_through_dict(self): + # See bug #1469629 + class X(dict): + def __init__(self): + dict.__init__(self) + self.__dict__ = self + x = X() + x.attr = 42 + wr = weakref.ref(x) + del x + support.gc_collect() + self.assertIsNone(wr()) + for o in gc.get_objects(): + self.assertIsNot(type(o), X) + class DictProxyTests(unittest.TestCase): def setUp(self): class C(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #1469629: Allow cycles through an object's __dict__ slot to be + collected. (For example if ``x.__dict__ is x``). + - Issue #14172: Fix reference leak when marshalling a buffer-like object (other than a bytes object). diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -830,8 +830,13 @@ assert(base); } - /* There's no need to clear the instance dict (if any); - the collector will call its tp_clear handler. */ + /* Clear the instance dict (if any), to break cycles involving only + __dict__ slots (as in the case 'self.__dict__ is self'). */ + if (type->tp_dictoffset != base->tp_dictoffset) { + PyObject **dictptr = _PyObject_GetDictPtr(self); + if (dictptr && *dictptr) + Py_CLEAR(*dictptr); + } if (baseclear) return baseclear(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 01:53:08 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 08 Mar 2012 01:53:08 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_this_stuff_will?= =?utf8?q?_actually_be_new_in_3=2E2=2E4?= Message-ID: http://hg.python.org/cpython/rev/509b222679e8 changeset: 75483:509b222679e8 branch: 3.2 user: Benjamin Peterson date: Wed Mar 07 18:49:43 2012 -0600 summary: this stuff will actually be new in 3.2.4 files: Misc/NEWS | 87 +++++++++++++++++++++++++----------------- 1 files changed, 51 insertions(+), 36 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,57 @@ Python News +++++++++++ +What's New in Python 3.2.4 +========================== + +*Release date: XX-XX-XXXX* + +Core and Builtins +----------------- + +- Issue #1469629: Allow cycles through an object's __dict__ slot to be + collected. (For example if ``x.__dict__ is x``). + +- Issue #14172: Fix reference leak when marshalling a buffer-like object + (other than a bytes object). + +- Issue #13521: dict.setdefault() now does only one lookup for the given key, + making it "atomic" for many purposes. Patch by Filip Gruszczy?ski. + +Library +------- + +- Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly + return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been + fixed. + +- Issue #14177: marshal.loads() now raises TypeError when given an unicode + string. Patch by Guilherme Gon?alves. + +- Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, + WeakValueDictionary) to return a better approximation when some objects + are dead or dying. Moreover, the implementation is now O(1) rather than + O(n). + +- Issue #13125: Silence spurious test_lib2to3 output when in non-verbose mode. + Patch by Mikhail Novikov. + +- Issue #13447: Add a test file to host regression tests for bugs in the + scripts found in the Tools directory. + +- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils + on Windows. + +- Issue #8033: sqlite3: Fix 64-bit integer handling in user functions + on 32-bit architectures. Initial patch by Philippe Devalkeneer. + +Extension Modules +----------------- + +- Issue #14212: The re module didn't retain a reference to buffers it was + scanning, resulting in segfaults. + + What's New in Python 3.2.3 release candidate 1? =============================================== @@ -10,15 +61,6 @@ Core and Builtins ----------------- -- Issue #1469629: Allow cycles through an object's __dict__ slot to be - collected. (For example if ``x.__dict__ is x``). - -- Issue #14172: Fix reference leak when marshalling a buffer-like object - (other than a bytes object). - -- Issue #13521: dict.setdefault() now does only one lookup for the given key, - making it "atomic" for many purposes. Patch by Filip Gruszczy?ski. - - Issue #13703: oCERT-2011-003: add -R command-line option and PYTHONHASHSEED environment variable, to provide an opt-in way to protect against denial of service attacks due to hash collisions within the dict and set types. Patch @@ -133,30 +175,6 @@ Library ------- -- Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly - return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been - fixed. - -- Issue #14177: marshal.loads() now raises TypeError when given an unicode - string. Patch by Guilherme Gon?alves. - -- Issue #14159: Fix the len() of weak containers (WeakSet, WeakKeyDictionary, - WeakValueDictionary) to return a better approximation when some objects - are dead or dying. Moreover, the implementation is now O(1) rather than - O(n). - -- Issue #13125: Silence spurious test_lib2to3 output when in non-verbose mode. - Patch by Mikhail Novikov. - -- Issue #13447: Add a test file to host regression tests for bugs in the - scripts found in the Tools directory. - -- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils - on Windows. - -- Issue #8033: sqlite3: Fix 64-bit integer handling in user functions - on 32-bit architectures. Initial patch by Philippe Devalkeneer. - - HTMLParser is now able to handle slashes in the start tag. - Issue #14001: CVE-2012-0845: xmlrpc: Fix an endless loop in @@ -550,9 +568,6 @@ Extension Modules ----------------- -- Issue #14212: The re module didn't retain a reference to buffers it was - scanning, resulting in segfaults. - - Issue #13840: The error message produced by ctypes.create_string_buffer when given a Unicode string has been fixed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 01:53:09 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 08 Mar 2012 01:53:09 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiBtZXJnZSAzLjIgKCMzNzg3ZTg5NmRiZTkp?= Message-ID: http://hg.python.org/cpython/rev/b595e1ad5722 changeset: 75484:b595e1ad5722 parent: 75481:c8d1df9ac987 parent: 75482:3787e896dbe9 user: Benjamin Peterson date: Wed Mar 07 18:52:52 2012 -0600 summary: merge 3.2 (#3787e896dbe9) files: Lib/test/test_descr.py | 19 +++++++++++++++++-- Misc/NEWS | 3 +++ Objects/typeobject.c | 9 +++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1,8 +1,10 @@ import builtins +import gc import sys import types import math import unittest +import weakref from copy import deepcopy from test import support @@ -1186,7 +1188,6 @@ self.assertEqual(Counted.counter, 0) # Test lookup leaks [SF bug 572567] - import gc if hasattr(gc, 'get_objects'): class G(object): def __eq__(self, other): @@ -4387,7 +4388,6 @@ self.assertRaises(AttributeError, getattr, C(), "attr") self.assertEqual(descr.counter, 4) - import gc class EvilGetattribute(object): # This used to segfault def __getattr__(self, name): @@ -4484,6 +4484,21 @@ ns = {'__qualname__': 1} self.assertRaises(TypeError, type, 'Foo', (), ns) + def test_cycle_through_dict(self): + # See bug #1469629 + class X(dict): + def __init__(self): + dict.__init__(self) + self.__dict__ = self + x = X() + x.attr = 42 + wr = weakref.ref(x) + del x + support.gc_collect() + self.assertIsNone(wr()) + for o in gc.get_objects(): + self.assertIsNot(type(o), X) + class DictProxyTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #1469629: Allow cycles through an object's __dict__ slot to be + collected. (For example if ``x.__dict__ is x``). + - Issue #14205: dict lookup raises a RuntimeError if the dict is modified during a lookup. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -862,8 +862,13 @@ assert(base); } - /* There's no need to clear the instance dict (if any); - the collector will call its tp_clear handler. */ + /* Clear the instance dict (if any), to break cycles involving only + __dict__ slots (as in the case 'self.__dict__ is self'). */ + if (type->tp_dictoffset != base->tp_dictoffset) { + PyObject **dictptr = _PyObject_GetDictPtr(self); + if (dictptr && *dictptr) + Py_CLEAR(*dictptr); + } if (baseclear) return baseclear(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 02:08:47 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 08 Mar 2012 02:08:47 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_=2314223=3A_curses=2E?= =?utf8?q?addch=28=29_is_no_more_limited_to_the_range_0-255_when_the?= Message-ID: http://hg.python.org/cpython/rev/861a5f3e7453 changeset: 75485:861a5f3e7453 user: Victor Stinner date: Thu Mar 08 02:08:48 2012 +0100 summary: Close #14223: curses.addch() is no more limited to the range 0-255 when the Python curses is not linked to libncursesw. It was a regression introduced in Python 3.3a1. files: Misc/NEWS | 4 ++++ Modules/_cursesmodule.c | 2 +- 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,10 @@ Library ------- +- Issue #14223: curses.addch() is no more limited to the range 0-255 when the + Python curses is not linked to libncursesw. It was a regression introduced + in Python 3.3a1. + - Issue #14168: Check for presence of Element._attrs in minidom before accessing it. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -340,7 +340,7 @@ #endif { *ch = (chtype)value; - if ((long)*ch != value || value < 0 || value > 255) { + if ((long)*ch != value) { PyErr_Format(PyExc_OverflowError, "byte doesn't fit in chtype"); return 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 02:10:53 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 08 Mar 2012 02:10:53 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiBtZXJnZSAzLjIgKG51bGwp?= Message-ID: http://hg.python.org/cpython/rev/ae6cda85451a changeset: 75486:ae6cda85451a parent: 75485:861a5f3e7453 parent: 75483:509b222679e8 user: Benjamin Peterson date: Wed Mar 07 19:10:42 2012 -0600 summary: merge 3.2 (null) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 02:15:36 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 08 Mar 2012 02:15:36 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_allow_cycles_th?= =?utf8?q?rought_the_=5F=5Fdict=5F=5F_slot_to_be_cleared_=28closes_=231469?= =?utf8?q?629=29?= Message-ID: http://hg.python.org/cpython/rev/c7623da4e2af changeset: 75487:c7623da4e2af branch: 2.7 parent: 75472:077b42a54803 user: Benjamin Peterson date: Wed Mar 07 18:41:11 2012 -0600 summary: allow cycles throught the __dict__ slot to be cleared (closes #1469629) Patch from Armin, test from me. files: Lib/test/test_descr.py | 19 +++++++++++++++++-- Misc/NEWS | 3 +++ Objects/typeobject.c | 9 +++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1,7 +1,9 @@ import __builtin__ +import gc import sys import types import unittest +import weakref from copy import deepcopy from test import test_support @@ -1127,7 +1129,6 @@ self.assertEqual(Counted.counter, 0) # Test lookup leaks [SF bug 572567] - import gc if hasattr(gc, 'get_objects'): class G(object): def __cmp__(self, other): @@ -4541,7 +4542,6 @@ self.assertRaises(AttributeError, getattr, C(), "attr") self.assertEqual(descr.counter, 4) - import gc class EvilGetattribute(object): # This used to segfault def __getattr__(self, name): @@ -4590,6 +4590,21 @@ foo = Foo() str(foo) + def test_cycle_through_dict(self): + # See bug #1469629 + class X(dict): + def __init__(self): + dict.__init__(self) + self.__dict__ = self + x = X() + x.attr = 42 + wr = weakref.ref(x) + del x + test_support.gc_collect() + self.assertIsNone(wr()) + for o in gc.get_objects(): + self.assertIsNot(type(o), X) + class DictProxyTests(unittest.TestCase): def setUp(self): class C(object): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #1469629: Allow cycles through an object's __dict__ slot to be + collected. (For example if ``x.__dict__ is x``). + - Issue #13521: dict.setdefault() now does only one lookup for the given key, making it "atomic" for many purposes. Patch by Filip Gruszczy?ski. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -876,8 +876,13 @@ assert(base); } - /* There's no need to clear the instance dict (if any); - the collector will call its tp_clear handler. */ + /* Clear the instance dict (if any), to break cycles involving only + __dict__ slots (as in the case 'self.__dict__ is self'). */ + if (type->tp_dictoffset != base->tp_dictoffset) { + PyObject **dictptr = _PyObject_GetDictPtr(self); + if (dictptr && *dictptr) + Py_CLEAR(*dictptr); + } if (baseclear) return baseclear(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 02:18:12 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 08 Mar 2012 02:18:12 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_move_notes_for_?= =?utf8?q?2=2E7=2E4_to_the_right_place?= Message-ID: http://hg.python.org/cpython/rev/ac776931ac81 changeset: 75488:ac776931ac81 branch: 2.7 user: Benjamin Peterson date: Wed Mar 07 19:17:57 2012 -0600 summary: move notes for 2.7.4 to the right place files: Misc/NEWS | 56 ++++++++++++++++++++++++++---------------- 1 files changed, 34 insertions(+), 22 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1,6 +1,40 @@ Python News +++++++++++ +What's New in Python 2.7.4 +========================== + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +- Issue #1469629: Allow cycles through an object's __dict__ slot to be + collected. (For example if ``x.__dict__ is x``). + +- Issue #13521: dict.setdefault() now does only one lookup for the given key, + making it "atomic" for many purposes. Patch by Filip Gruszczy?ski. + +Library +------- + +- Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly + return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been + fixed. + +- Issue #14159: Fix the len() of weak sets to return a better approximation + when some objects are dead or dying. Moreover, the implementation is now + O(1) rather than O(n). + +- Issue #2945: Make the distutils upload command aware of bdist_rpm products. + +- Issue #13447: Add a test file to host regression tests for bugs in the + scripts found in the Tools directory. + +- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils + on Windows. + + What's New in Python 2.7.3 release candidate 1? =============================================== @@ -9,12 +43,6 @@ Core and Builtins ----------------- -- Issue #1469629: Allow cycles through an object's __dict__ slot to be - collected. (For example if ``x.__dict__ is x``). - -- Issue #13521: dict.setdefault() now does only one lookup for the given key, - making it "atomic" for many purposes. Patch by Filip Gruszczy?ski. - - Issue #13020: Fix a reference leak when allocating a structsequence object fails. Patch by Suman Saha. @@ -104,22 +132,6 @@ Library ------- -- Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly - return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been - fixed. - -- Issue #14159: Fix the len() of weak sets to return a better approximation - when some objects are dead or dying. Moreover, the implementation is now - O(1) rather than O(n). - -- Issue #2945: Make the distutils upload command aware of bdist_rpm products. - -- Issue #13447: Add a test file to host regression tests for bugs in the - scripts found in the Tools directory. - -- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils - on Windows. - - Issue #8033: sqlite3: Fix 64-bit integer handling in user functions on 32-bit architectures. Initial patch by Philippe Devalkeneer. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 02:50:32 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 08 Mar 2012 02:50:32 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314205=3A_document_?= =?utf8?q?the_change_of_dict=5Bkey=5D_behaviour_if_dict_is_modified?= Message-ID: http://hg.python.org/cpython/rev/0255bafbccf2 changeset: 75489:0255bafbccf2 parent: 75486:ae6cda85451a user: Victor Stinner date: Thu Mar 08 02:50:17 2012 +0100 summary: Issue #14205: document the change of dict[key] behaviour if dict is modified during the lookup files: Doc/library/stdtypes.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2208,6 +2208,10 @@ See :class:`collections.Counter` for a complete implementation including other methods helpful for accumulating and managing tallies. + .. versionchanged:: 3.3 + If the dict is modified during the lookup, a :exc:`RuntimeError` + exception is now raised. + .. describe:: d[key] = value Set ``d[key]`` to *value*. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Mar 8 05:36:23 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 08 Mar 2012 05:36:23 +0100 Subject: [Python-checkins] Daily reference leaks (0255bafbccf2): sum=0 Message-ID: results for 0255bafbccf2 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog1_7XLm', '-x'] From python-checkins at python.org Thu Mar 8 15:40:41 2012 From: python-checkins at python.org (jason.coombs) Date: Thu, 08 Mar 2012 15:40:41 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Moved_directory?= =?utf8?q?_detection_into_an_isdir_function?= Message-ID: http://hg.python.org/cpython/rev/2218a6cf75fc changeset: 75490:2218a6cf75fc branch: 2.7 parent: 75488:ac776931ac81 user: Jason R. Coombs date: Fri Jan 13 17:12:25 2012 -0500 summary: Moved directory detection into an isdir function files: Python/import.c | 42 ++++++++++++------------------------ 1 files changed, 14 insertions(+), 28 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -114,6 +114,19 @@ }; #endif +#ifdef HAVE_STAT +int isdir(char *path) { + struct stat statbuf; + return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode); +} +#else +/* with RISCOS, isdir is in unixstuff */ +#ifndef RISCOS +int isdir(char *path) { + return 0; +} +#endif +#endif /* Initialize things */ @@ -1204,9 +1217,6 @@ char *filemode; FILE *fp = NULL; PyObject *path_hooks, *path_importer_cache; -#ifndef RISCOS - struct stat statbuf; -#endif static struct filedescr fd_frozen = {"", "", PY_FROZEN}; static struct filedescr fd_builtin = {"", "", C_BUILTIN}; static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; @@ -1392,9 +1402,7 @@ /* Check for package import (buf holds a directory name, and there's an __init__ module in that directory */ -#ifdef HAVE_STAT - if (stat(buf, &statbuf) == 0 && /* it exists */ - S_ISDIR(statbuf.st_mode) && /* it's a directory */ + if (isdir(buf) && /* it's an existing directory */ case_ok(buf, len, namelen, name)) { /* case matches */ if (find_init_module(buf)) { /* and has __init__.py */ Py_XDECREF(copy); @@ -1412,28 +1420,6 @@ } } } -#else - /* XXX How are you going to test for directories? */ -#ifdef RISCOS - if (isdir(buf) && - case_ok(buf, len, namelen, name)) { - if (find_init_module(buf)) { - Py_XDECREF(copy); - return &fd_package; - } - else { - char warnstr[MAXPATHLEN+80]; - sprintf(warnstr, "Not importing directory " - "'%.*s': missing __init__.py", - MAXPATHLEN, buf); - if (PyErr_Warn(PyExc_ImportWarning, - warnstr)) { - Py_XDECREF(copy); - return NULL; - } - } -#endif -#endif #if defined(PYOS_OS2) /* take a snapshot of the module spec for restoration * after the 8 character DLL hackery -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 15:40:42 2012 From: python-checkins at python.org (jason.coombs) Date: Thu, 08 Mar 2012 15:40:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Extracted_Windo?= =?utf8?q?ws_directory_detection_from_NullImporter=2E=5F=5Finit=5F=5F=2E_T?= =?utf8?q?his_greatly?= Message-ID: http://hg.python.org/cpython/rev/6c218b9c5c4c changeset: 75491:6c218b9c5c4c branch: 2.7 user: Jason R. Coombs date: Fri Jan 13 17:37:18 2012 -0500 summary: Extracted Windows directory detection from NullImporter.__init__. This greatly simplifies the code and fixes issue6727. files: Python/import.c | 71 ++++++++++++------------------------ 1 files changed, 24 insertions(+), 47 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -114,19 +114,34 @@ }; #endif -#ifdef HAVE_STAT +#ifdef MS_WINDOWS +int isdir(char *path) { + DWORD rv; + /* see issue1293 and issue3677: + * stat() on Windows doesn't recognise paths like + * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs. + * Also reference issue6727: + * stat() on Windows is broken and doesn't resolve symlinks properly. + */ + rv = GetFileAttributesA(path); + return rv != INVALID_FILE_ATTRIBUTES && rv & FILE_ATTRIBUTE_DIRECTORY; +} +#else +#if HAVE_STAT int isdir(char *path) { struct stat statbuf; return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode); } #else +#ifdef RISCOS /* with RISCOS, isdir is in unixstuff */ -#ifndef RISCOS +#else int isdir(char *path) { return 0; } -#endif -#endif +#endif /* RISCOS */ +#endif /* HAVE_STAT */ +#endif /* MS_WINDOWS */ /* Initialize things */ @@ -3185,49 +3200,11 @@ PyErr_SetString(PyExc_ImportError, "empty pathname"); return -1; } else { -#ifndef RISCOS -#ifndef MS_WINDOWS - struct stat statbuf; - int rv; - - rv = stat(path, &statbuf); - if (rv == 0) { - /* it exists */ - if (S_ISDIR(statbuf.st_mode)) { - /* it's a directory */ - PyErr_SetString(PyExc_ImportError, - "existing directory"); - return -1; - } - } -#else /* MS_WINDOWS */ - DWORD rv; - /* see issue1293 and issue3677: - * stat() on Windows doesn't recognise paths like - * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs. - */ - rv = GetFileAttributesA(path); - if (rv != INVALID_FILE_ATTRIBUTES) { - /* it exists */ - if (rv & FILE_ATTRIBUTE_DIRECTORY) { - /* it's a directory */ - PyErr_SetString(PyExc_ImportError, - "existing directory"); - return -1; - } - } -#endif -#else /* RISCOS */ - if (object_exists(path)) { - /* it exists */ - if (isdir(path)) { - /* it's a directory */ - PyErr_SetString(PyExc_ImportError, - "existing directory"); - return -1; - } - } -#endif + if(isdir(path)) { + PyErr_SetString(PyExc_ImportError, + "existing directory"); + return -1; + } } return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 15:40:45 2012 From: python-checkins at python.org (jason.coombs) Date: Thu, 08 Mar 2012 15:40:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_indentation?= Message-ID: http://hg.python.org/cpython/rev/52170802ebd2 changeset: 75492:52170802ebd2 branch: 2.7 user: Jason R. Coombs date: Fri Jan 13 17:59:05 2012 -0500 summary: Fix indentation files: Python/import.c | 32 ++++++++++++++++---------------- 1 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -116,28 +116,28 @@ #ifdef MS_WINDOWS int isdir(char *path) { - DWORD rv; - /* see issue1293 and issue3677: - * stat() on Windows doesn't recognise paths like - * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs. - * Also reference issue6727: - * stat() on Windows is broken and doesn't resolve symlinks properly. - */ - rv = GetFileAttributesA(path); - return rv != INVALID_FILE_ATTRIBUTES && rv & FILE_ATTRIBUTE_DIRECTORY; + DWORD rv; + /* see issue1293 and issue3677: + * stat() on Windows doesn't recognise paths like + * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs. + * Also reference issue6727: + * stat() on Windows is broken and doesn't resolve symlinks properly. + */ + rv = GetFileAttributesA(path); + return rv != INVALID_FILE_ATTRIBUTES && rv & FILE_ATTRIBUTE_DIRECTORY; } #else #if HAVE_STAT int isdir(char *path) { struct stat statbuf; - return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode); + return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode); } #else #ifdef RISCOS /* with RISCOS, isdir is in unixstuff */ #else int isdir(char *path) { - return 0; + return 0; } #endif /* RISCOS */ #endif /* HAVE_STAT */ @@ -3200,11 +3200,11 @@ PyErr_SetString(PyExc_ImportError, "empty pathname"); return -1; } else { - if(isdir(path)) { - PyErr_SetString(PyExc_ImportError, - "existing directory"); - return -1; - } + if(isdir(path)) { + PyErr_SetString(PyExc_ImportError, + "existing directory"); + return -1; + } } return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 15:40:46 2012 From: python-checkins at python.org (jason.coombs) Date: Thu, 08 Mar 2012 15:40:46 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Adding_regressi?= =?utf8?q?on_test_for_issue6727?= Message-ID: http://hg.python.org/cpython/rev/92f4d4eebed1 changeset: 75493:92f4d4eebed1 branch: 2.7 user: Jason R. Coombs date: Sun Jan 15 11:45:27 2012 -0500 summary: Adding regression test for issue6727 files: Lib/test/test_import.py | 118 +++++++++++++++++++++++++++- 1 files changed, 116 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -7,9 +7,11 @@ import stat import sys import unittest +import textwrap +import shutil + from test.test_support import (unlink, TESTFN, unload, run_unittest, rmtree, is_jython, check_warnings, EnvironmentVarGuard) -import textwrap from test import script_helper def remove_files(name): @@ -488,8 +490,120 @@ "implicit absolute import") +class TestSymbolicallyLinkedPackage(unittest.TestCase): + package_name = 'sample' + + def setUp(self): + if os.path.exists('sample-tagged'): shutil.rmtree('sample-tagged') + self.orig_sys_path = sys.path[:] + + symlink = getattr(os, 'symlink', None) or self._symlink_win32 + + # create a sample package; imagine you have a package with a tag and + # you want to symbolically link it from its untagged name. + os.mkdir(self.tagged) + init_file = os.path.join(self.tagged, '__init__.py') + open(init_file, 'w').close() + assert os.path.exists(init_file) + + # now create a symlink to the tagged package + # sample -> sample-tagged + symlink(self.tagged, self.package_name) + + assert os.path.isdir(self.package_name) + assert os.path.isfile(os.path.join(self.package_name, '__init__.py')) + + @property + def tagged(self): + return self.package_name + '-tagged' + + @classmethod + def _symlink_win32(cls, target, link, target_is_directory=False): + """ + Ctypes symlink implementation since Python doesn't support + symlinks in windows yet. Borrowed from jaraco.windows project. + """ + import ctypes.wintypes + CreateSymbolicLink = ctypes.windll.kernel32.CreateSymbolicLinkW + CreateSymbolicLink.argtypes = ( + ctypes.wintypes.LPWSTR, + ctypes.wintypes.LPWSTR, + ctypes.wintypes.DWORD, + ) + CreateSymbolicLink.restype = ctypes.wintypes.BOOLEAN + + def format_system_message(errno): + """ + Call FormatMessage with a system error number to retrieve + the descriptive error message. + """ + # first some flags used by FormatMessageW + ALLOCATE_BUFFER = 0x100 + ARGUMENT_ARRAY = 0x2000 + FROM_HMODULE = 0x800 + FROM_STRING = 0x400 + FROM_SYSTEM = 0x1000 + IGNORE_INSERTS = 0x200 + + # Let FormatMessageW allocate the buffer (we'll free it below) + # Also, let it know we want a system error message. + flags = ALLOCATE_BUFFER | FROM_SYSTEM + source = None + message_id = errno + language_id = 0 + result_buffer = ctypes.wintypes.LPWSTR() + buffer_size = 0 + arguments = None + bytes = ctypes.windll.kernel32.FormatMessageW( + flags, + source, + message_id, + language_id, + ctypes.byref(result_buffer), + buffer_size, + arguments, + ) + # note the following will cause an infinite loop if GetLastError + # repeatedly returns an error that cannot be formatted, although + # this should not happen. + handle_nonzero_success(bytes) + message = result_buffer.value + ctypes.windll.kernel32.LocalFree(result_buffer) + return message + + def handle_nonzero_success(result): + if result == 0: + value = ctypes.windll.kernel32.GetLastError() + strerror = format_system_message(value) + raise WindowsError(value, strerror) + + target_is_directory = target_is_directory or os.path.isdir(target) + handle_nonzero_success(CreateSymbolicLink(link, target, target_is_directory)) + + # regression test for issue6727 + @unittest.skipUnless( + not hasattr(sys, 'getwindowsversion') + or sys.getwindowsversion() >= (6,0), + "Windows Vista or later required") + def test_symlinked_dir_importable(self): + # make sure sample can only be imported from the current directory. + sys.path[:] = ['.'] + + # and try to import the package + pkg = __import__(self.package_name) + + def tearDown(self): + # now cleanup + if os.path.exists(self.package_name): + os.rmdir(self.package_name) + if os.path.exists(self.tagged): + shutil.rmtree(self.tagged) + sys.path[:] = self.orig_sys_path + + def test_main(verbose=None): - run_unittest(ImportTests, PycRewritingTests, PathsTests, RelativeImportTests) + run_unittest(ImportTests, PycRewritingTests, PathsTests, + RelativeImportTests, TestSymbolicallyLinkedPackage) if __name__ == '__main__': # Test needs to be a package, so we can do relative imports. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 15:56:15 2012 From: python-checkins at python.org (jason.coombs) Date: Thu, 08 Mar 2012 15:56:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Test_in_6c218b9?= =?utf8?q?c5c4c_was_inadvertently_converted_from_=23ifdef_to_=23if=2E_Now_?= =?utf8?q?=23ifdef?= Message-ID: http://hg.python.org/cpython/rev/7ec441d4d818 changeset: 75494:7ec441d4d818 branch: 2.7 user: Jason R. Coombs date: Thu Mar 08 09:56:00 2012 -0500 summary: Test in 6c218b9c5c4c was inadvertently converted from #ifdef to #if. Now #ifdef again. files: Python/import.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -127,7 +127,7 @@ return rv != INVALID_FILE_ATTRIBUTES && rv & FILE_ATTRIBUTE_DIRECTORY; } #else -#if HAVE_STAT +#ifdef HAVE_STAT int isdir(char *path) { struct stat statbuf; return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 16:43:30 2012 From: python-checkins at python.org (jason.coombs) Date: Thu, 08 Mar 2012 16:43:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Improve_the_tes?= =?utf8?q?t_case_to_avoid_spurious_errors_about_already_existing_symlinks?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/c3bd31d3c7f5 changeset: 75495:c3bd31d3c7f5 branch: 2.7 user: Jason R. Coombs date: Thu Mar 08 10:31:29 2012 -0500 summary: Improve the test case to avoid spurious errors about already existing symlinks. files: Lib/test/test_import.py | 18 ++++++++++++++---- 1 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -494,7 +494,10 @@ package_name = 'sample' def setUp(self): - if os.path.exists('sample-tagged'): shutil.rmtree('sample-tagged') + if os.path.exists(self.tagged): + shutil.rmtree(self.tagged) + if os.path.exists(self.package_name): + self.remove_symlink(self.package_name) self.orig_sys_path = sys.path[:] symlink = getattr(os, 'symlink', None) or self._symlink_win32 @@ -583,23 +586,30 @@ # regression test for issue6727 @unittest.skipUnless( not hasattr(sys, 'getwindowsversion') - or sys.getwindowsversion() >= (6,0), + or sys.getwindowsversion() >= (6, 0), "Windows Vista or later required") def test_symlinked_dir_importable(self): # make sure sample can only be imported from the current directory. sys.path[:] = ['.'] # and try to import the package - pkg = __import__(self.package_name) + __import__(self.package_name) def tearDown(self): # now cleanup if os.path.exists(self.package_name): - os.rmdir(self.package_name) + self.remove_symlink(self.package_name) if os.path.exists(self.tagged): shutil.rmtree(self.tagged) sys.path[:] = self.orig_sys_path + @staticmethod + def remove_symlink(name): + # On Windows, to remove a directory symlink, one must use rmdir + try: + os.rmdir(name) + except OSError: + os.remove(name) def test_main(verbose=None): run_unittest(ImportTests, PycRewritingTests, PathsTests, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 8 20:31:11 2012 From: python-checkins at python.org (georg.brandl) Date: Thu, 08 Mar 2012 20:31:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_indentation=2E?= Message-ID: http://hg.python.org/cpython/rev/0225309a844f changeset: 75496:0225309a844f parent: 75489:0255bafbccf2 user: Georg Brandl date: Thu Mar 08 20:35:08 2012 +0100 summary: Fix indentation. files: Doc/library/collections.rst | 95 ++++++++++++------------ 1 files changed, 48 insertions(+), 47 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -91,65 +91,66 @@ The use-cases also parallel those for the builtin :func:`super` function. A reference to ``d.parents`` is equivalent to: ``ChainMap(*d.maps[1:])``. - .. versionadded:: 3.3 + .. versionadded:: 3.3 - Example of simulating Python's internal lookup chain:: + Example of simulating Python's internal lookup chain:: - import builtins - pylookup = ChainMap(locals(), globals(), vars(builtins)) + import builtins + pylookup = ChainMap(locals(), globals(), vars(builtins)) - Example of letting user specified values take precedence over environment - variables which in turn take precedence over default values:: + Example of letting user specified values take precedence over environment + variables which in turn take precedence over default values:: - import os, argparse - defaults = {'color': 'red', 'user': guest} - parser = argparse.ArgumentParser() - parser.add_argument('-u', '--user') - parser.add_argument('-c', '--color') - user_specified = vars(parser.parse_args()) - combined = ChainMap(user_specified, os.environ, defaults) + import os, argparse + defaults = {'color': 'red', 'user': guest} + parser = argparse.ArgumentParser() + parser.add_argument('-u', '--user') + parser.add_argument('-c', '--color') + user_specified = vars(parser.parse_args()) + combined = ChainMap(user_specified, os.environ, defaults) - Example patterns for using the :class:`ChainMap` class to simulate nested - contexts:: + Example patterns for using the :class:`ChainMap` class to simulate nested + contexts:: - c = ChainMap() Create root context - d = c.new_child() Create nested child context - e = c.new_child() Child of c, independent from d - e.maps[0] Current context dictionary -- like Python's locals() - e.maps[-1] Root context -- like Python's globals() - e.parents Enclosing context chain -- like Python's nonlocals + c = ChainMap() # Create root context + d = c.new_child() # Create nested child context + e = c.new_child() # Child of c, independent from d + e.maps[0] # Current context dictionary -- like Python's locals() + e.maps[-1] # Root context -- like Python's globals() + e.parents # Enclosing context chain -- like Python's nonlocals - d['x'] Get first key in the chain of contexts - d['x'] = 1 Set value in current context - del['x'] Delete from current context - list(d) All nested values - k in d Check all nested values - len(d) Number of nested values - d.items() All nested items - dict(d) Flatten into a regular dictionary + d['x'] # Get first key in the chain of contexts + d['x'] = 1 # Set value in current context + del['x'] # Delete from current context + list(d) # All nested values + k in d # Check all nested values + len(d) # Number of nested values + d.items() # All nested items + dict(d) # Flatten into a regular dictionary - .. seealso:: + .. seealso:: - * The `MultiContext class - `_ - in the Enthought `CodeTools package - `_ has options to support - writing to any mapping in the chain. + * The `MultiContext class + `_ + in the Enthought `CodeTools package + `_ has options to support + writing to any mapping in the chain. - * Django's `Context class - `_ - for templating is a read-only chain of mappings. It also features - pushing and popping of contexts similar to the - :meth:`~collections.ChainMap.new_child` method and the - :meth:`~collections.ChainMap.parents` property. + * Django's `Context class + `_ + for templating is a read-only chain of mappings. It also features + pushing and popping of contexts similar to the + :meth:`~collections.ChainMap.new_child` method and the + :meth:`~collections.ChainMap.parents` property. - * The `Nested Contexts recipe - `_ has options to control - whether writes and other mutations apply only to the first mapping or to - any mapping in the chain. + * The `Nested Contexts recipe + `_ has options to control + whether writes and other mutations apply only to the first mapping or to + any mapping in the chain. - * A `greatly simplified read-only version of Chainmap - `_. + * A `greatly simplified read-only version of Chainmap + `_. + :class:`Counter` objects ------------------------ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 00:39:08 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 09 Mar 2012 00:39:08 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_=2314199=3A_=5FPyType?= =?utf8?q?=5FLookup=28=29_and_super=5Fgetattro=28=29_keep_a_strong_referen?= =?utf8?q?ce_to?= Message-ID: http://hg.python.org/cpython/rev/21e245ed3747 changeset: 75497:21e245ed3747 user: Victor Stinner date: Fri Mar 09 00:39:08 2012 +0100 summary: Close #14199: _PyType_Lookup() and super_getattro() keep a strong reference to the type MRO to avoid a crash if the MRO is changed during the lookup. files: Lib/test/crashers/losing_mro_ref.py | 35 ----------------- Lib/test/test_descr.py | 30 ++++++++++++++- Objects/typeobject.c | 9 ++++ 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/Lib/test/crashers/losing_mro_ref.py b/Lib/test/crashers/losing_mro_ref.py deleted file mode 100644 --- a/Lib/test/crashers/losing_mro_ref.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -There is a way to put keys of any type in a type's dictionary. -I think this allows various kinds of crashes, but so far I have only -found a convoluted attack of _PyType_Lookup(), which uses the mro of the -type without holding a strong reference to it. Probably works with -super.__getattribute__() too, which uses the same kind of code. -""" - -class MyKey(object): - def __hash__(self): - return hash('mykey') - - def __eq__(self, other): - # the following line decrefs the previous X.__mro__ - X.__bases__ = (Base2,) - # trash all tuples of length 3, to make sure that the items of - # the previous X.__mro__ are really garbage - z = [] - for i in range(1000): - z.append((i, None, None)) - return 0 - - -class Base(object): - mykey = 'from Base' - -class Base2(object): - mykey = 'from Base2' - -# you can't add a non-string key to X.__dict__, but it can be -# there from the beginning :-) -X = type('X', (Base,), {MyKey(): 5}) - -print(X.mykey) -# I get a segfault, or a slightly wrong assertion error in a debug build. diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4582,10 +4582,38 @@ type.mro(tuple) +class MiscTests(unittest.TestCase): + def test_type_lookup_mro_reference(self): + # Issue #14199: _PyType_Lookup() has to keep a strong reference to + # the type MRO because it may be modified during the lookup, if + # __bases__ is set during the lookup for example. + class MyKey(object): + def __hash__(self): + return hash('mykey') + + def __eq__(self, other): + X.__bases__ = (Base2,) + + class Base(object): + mykey = 'from Base' + mykey2 = 'from Base' + + class Base2(object): + mykey = 'from Base2' + mykey2 = 'from Base2' + + X = type('X', (Base,), {MyKey(): 5}) + # mykey is read from Base + self.assertEqual(X.mykey, 'from Base') + # mykey2 is read from Base2 because MyKey.__eq__ has set __bases__ + self.assertEqual(X.mykey2, 'from Base2') + + def test_main(): # Run all local test cases, with PTypesLongInitTest first. support.run_unittest(PTypesLongInitTest, OperatorsTest, - ClassPropertiesAndMethods, DictProxyTests) + ClassPropertiesAndMethods, DictProxyTests, + MiscTests) if __name__ == "__main__": test_main() diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2450,6 +2450,9 @@ return NULL; res = NULL; + /* keep a strong reference to mro because type->tp_mro can be replaced + during PyDict_GetItem(dict, name) */ + Py_INCREF(mro); assert(PyTuple_Check(mro)); n = PyTuple_GET_SIZE(mro); for (i = 0; i < n; i++) { @@ -2461,6 +2464,7 @@ if (res != NULL) break; } + Py_DECREF(mro); if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(type)) { h = MCACHE_HASH_METHOD(type, name); @@ -6281,6 +6285,9 @@ } i++; res = NULL; + /* keep a strong reference to mro because starttype->tp_mro can be + replaced during PyDict_GetItem(dict, name) */ + Py_INCREF(mro); for (; i < n; i++) { tmp = PyTuple_GET_ITEM(mro, i); if (PyType_Check(tmp)) @@ -6305,9 +6312,11 @@ Py_DECREF(res); res = tmp; } + Py_DECREF(mro); return res; } } + Py_DECREF(mro); } return PyObject_GenericGetAttr(self, name); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 00:47:21 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 09 Mar 2012 00:47:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314211=3A_=5FPyObje?= =?utf8?q?ct=5FGenericSetAttrWithDict=28=29_keeps_a_strong_reference_to?= Message-ID: http://hg.python.org/cpython/rev/579f845ac396 changeset: 75498:579f845ac396 user: Victor Stinner date: Fri Mar 09 00:44:13 2012 +0100 summary: Issue #14211: _PyObject_GenericSetAttrWithDict() keeps a strong reference to the descriptor because it may be destroyed before being used, destroyed during the update of the dict for example. files: Lib/test/crashers/borrowed_ref_1.py | 29 ----------------- Objects/object.c | 9 ++-- 2 files changed, 5 insertions(+), 33 deletions(-) diff --git a/Lib/test/crashers/borrowed_ref_1.py b/Lib/test/crashers/borrowed_ref_1.py deleted file mode 100644 --- a/Lib/test/crashers/borrowed_ref_1.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -_PyType_Lookup() returns a borrowed reference. -This attacks the call in dictobject.c. -""" - -class A(object): - pass - -class B(object): - def __del__(self): - print('hi') - del D.__missing__ - -class D(dict): - class __missing__: - def __init__(self, *args): - pass - - -d = D() -a = A() -a.cycle = a -a.other = B() -del a - -prev = None -while 1: - d[5] - prev = (prev,) diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -1074,7 +1074,6 @@ f = descr->ob_type->tp_descr_get; if (f != NULL && PyDescr_IsData(descr)) { res = f(descr, obj, (PyObject *)obj->ob_type); - Py_DECREF(descr); goto done; } } @@ -1105,7 +1104,6 @@ res = PyDict_GetItem(dict, name); if (res != NULL) { Py_INCREF(res); - Py_XDECREF(descr); Py_DECREF(dict); goto done; } @@ -1114,13 +1112,12 @@ if (f != NULL) { res = f(descr, obj, (PyObject *)Py_TYPE(obj)); - Py_DECREF(descr); goto done; } if (descr != NULL) { res = descr; - /* descr was already increfed above */ + descr = NULL; goto done; } @@ -1128,6 +1125,7 @@ "'%.50s' object has no attribute '%U'", tp->tp_name, name); done: + Py_XDECREF(descr); Py_DECREF(name); return res; } @@ -1163,6 +1161,8 @@ } descr = _PyType_Lookup(tp, name); + Py_XINCREF(descr); + f = NULL; if (descr != NULL) { f = descr->ob_type->tp_descr_set; @@ -1212,6 +1212,7 @@ "'%.50s' object attribute '%U' is read-only", tp->tp_name, name); done: + Py_XDECREF(descr); Py_DECREF(name); return res; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 00:52:33 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 09 Mar 2012 00:52:33 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314211=3A_Oops=2C_I?= =?utf8?q?_removed_the_wrong_file_=3A-=29?= Message-ID: http://hg.python.org/cpython/rev/2cc44cd8098e changeset: 75499:2cc44cd8098e user: Victor Stinner date: Fri Mar 09 00:52:07 2012 +0100 summary: Issue #14211: Oops, I removed the wrong file :-) files: Lib/test/crashers/borrowed_ref_1.py | 29 ++++++++++++ Lib/test/crashers/borrowed_ref_2.py | 38 ----------------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/Lib/test/crashers/borrowed_ref_1.py b/Lib/test/crashers/borrowed_ref_1.py new file mode 100644 --- /dev/null +++ b/Lib/test/crashers/borrowed_ref_1.py @@ -0,0 +1,29 @@ +""" +_PyType_Lookup() returns a borrowed reference. +This attacks the call in dictobject.c. +""" + +class A(object): + pass + +class B(object): + def __del__(self): + print('hi') + del D.__missing__ + +class D(dict): + class __missing__: + def __init__(self, *args): + pass + + +d = D() +a = A() +a.cycle = a +a.other = B() +del a + +prev = None +while 1: + d[5] + prev = (prev,) diff --git a/Lib/test/crashers/borrowed_ref_2.py b/Lib/test/crashers/borrowed_ref_2.py deleted file mode 100644 --- a/Lib/test/crashers/borrowed_ref_2.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -_PyType_Lookup() returns a borrowed reference. -This attacks PyObject_GenericSetAttr(). - -NB. on my machine this crashes in 2.5 debug but not release. -""" - -class A(object): - pass - -class B(object): - def __del__(self): - print("hi") - del C.d - -class D(object): - def __set__(self, obj, value): - self.hello = 42 - -class C(object): - d = D() - - def g(): - pass - - -c = C() -a = A() -a.cycle = a -a.other = B() - -lst = [None] * 1000000 -i = 0 -del a -while 1: - c.d = 42 # segfaults in PyMethod_New(__func__=D.__set__, __self__=d) - lst[i] = c.g # consume the free list of instancemethod objects - i += 1 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 05:11:39 2012 From: python-checkins at python.org (jason.coombs) Date: Fri, 09 Mar 2012 05:11:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Moved_symlink_s?= =?utf8?q?upport_into_its_own_module=2E_Ported_can=5Fsymlink_from_Python_3?= =?utf8?b?LjIs?= Message-ID: http://hg.python.org/cpython/rev/f8efcca7e90f changeset: 75500:f8efcca7e90f branch: 2.7 parent: 75495:c3bd31d3c7f5 user: Jason R. Coombs date: Thu Mar 08 18:28:08 2012 -0500 summary: Moved symlink support into its own module. Ported can_symlink from Python 3.2, skipping symlink test when it cannot be invoked (such as when the symlink privilege is not present). files: Lib/test/symlink_support.py | 100 ++++++++++++++++++++++++ Lib/test/test_import.py | 81 +------------------ 2 files changed, 105 insertions(+), 76 deletions(-) diff --git a/Lib/test/symlink_support.py b/Lib/test/symlink_support.py new file mode 100644 --- /dev/null +++ b/Lib/test/symlink_support.py @@ -0,0 +1,100 @@ +import os +import unittest +import platform + +from test.test_support import TESTFN + +def can_symlink(): + # cache the result in can_symlink.prev_val + prev_val = getattr(can_symlink, 'prev_val', None) + if prev_val is not None: + return prev_val + symlink_path = TESTFN + "can_symlink" + try: + symlink(TESTFN, symlink_path) + can = True + except (OSError, NotImplementedError, AttributeError): + can = False + else: + os.remove(symlink_path) + can_symlink.prev_val = can + return can + +def skip_unless_symlink(test): + """Skip decorator for tests that require functional symlink""" + ok = can_symlink() + msg = "Requires functional symlink implementation" + return test if ok else unittest.skip(msg)(test) + +def _symlink_win32(target, link, target_is_directory=False): + """ + Ctypes symlink implementation since Python doesn't support + symlinks in windows yet. Borrowed from jaraco.windows project. + """ + import ctypes.wintypes + CreateSymbolicLink = ctypes.windll.kernel32.CreateSymbolicLinkW + CreateSymbolicLink.argtypes = ( + ctypes.wintypes.LPWSTR, + ctypes.wintypes.LPWSTR, + ctypes.wintypes.DWORD, + ) + CreateSymbolicLink.restype = ctypes.wintypes.BOOLEAN + + def format_system_message(errno): + """ + Call FormatMessage with a system error number to retrieve + the descriptive error message. + """ + # first some flags used by FormatMessageW + ALLOCATE_BUFFER = 0x100 + ARGUMENT_ARRAY = 0x2000 + FROM_HMODULE = 0x800 + FROM_STRING = 0x400 + FROM_SYSTEM = 0x1000 + IGNORE_INSERTS = 0x200 + + # Let FormatMessageW allocate the buffer (we'll free it below) + # Also, let it know we want a system error message. + flags = ALLOCATE_BUFFER | FROM_SYSTEM + source = None + message_id = errno + language_id = 0 + result_buffer = ctypes.wintypes.LPWSTR() + buffer_size = 0 + arguments = None + bytes = ctypes.windll.kernel32.FormatMessageW( + flags, + source, + message_id, + language_id, + ctypes.byref(result_buffer), + buffer_size, + arguments, + ) + # note the following will cause an infinite loop if GetLastError + # repeatedly returns an error that cannot be formatted, although + # this should not happen. + handle_nonzero_success(bytes) + message = result_buffer.value + ctypes.windll.kernel32.LocalFree(result_buffer) + return message + + def handle_nonzero_success(result): + if result == 0: + value = ctypes.windll.kernel32.GetLastError() + strerror = format_system_message(value) + raise WindowsError(value, strerror) + + target_is_directory = target_is_directory or os.path.isdir(target) + handle_nonzero_success(CreateSymbolicLink(link, target, target_is_directory)) + +symlink = os.symlink if hasattr(os, 'symlink') else ( + _symlink_win32 if platform.system() == 'Windows' else None +) + +def remove_symlink(name): + # On Windows, to remove a directory symlink, one must use rmdir + try: + os.rmdir(name) + except OSError: + os.remove(name) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -12,6 +12,7 @@ from test.test_support import (unlink, TESTFN, unload, run_unittest, rmtree, is_jython, check_warnings, EnvironmentVarGuard) +from test import symlink_support from test import script_helper def remove_files(name): @@ -497,11 +498,9 @@ if os.path.exists(self.tagged): shutil.rmtree(self.tagged) if os.path.exists(self.package_name): - self.remove_symlink(self.package_name) + symlink_support.remove_symlink(self.package_name) self.orig_sys_path = sys.path[:] - symlink = getattr(os, 'symlink', None) or self._symlink_win32 - # create a sample package; imagine you have a package with a tag and # you want to symbolically link it from its untagged name. os.mkdir(self.tagged) @@ -511,7 +510,7 @@ # now create a symlink to the tagged package # sample -> sample-tagged - symlink(self.tagged, self.package_name) + symlink_support.symlink(self.tagged, self.package_name) assert os.path.isdir(self.package_name) assert os.path.isfile(os.path.join(self.package_name, '__init__.py')) @@ -520,74 +519,12 @@ def tagged(self): return self.package_name + '-tagged' - @classmethod - def _symlink_win32(cls, target, link, target_is_directory=False): - """ - Ctypes symlink implementation since Python doesn't support - symlinks in windows yet. Borrowed from jaraco.windows project. - """ - import ctypes.wintypes - CreateSymbolicLink = ctypes.windll.kernel32.CreateSymbolicLinkW - CreateSymbolicLink.argtypes = ( - ctypes.wintypes.LPWSTR, - ctypes.wintypes.LPWSTR, - ctypes.wintypes.DWORD, - ) - CreateSymbolicLink.restype = ctypes.wintypes.BOOLEAN - - def format_system_message(errno): - """ - Call FormatMessage with a system error number to retrieve - the descriptive error message. - """ - # first some flags used by FormatMessageW - ALLOCATE_BUFFER = 0x100 - ARGUMENT_ARRAY = 0x2000 - FROM_HMODULE = 0x800 - FROM_STRING = 0x400 - FROM_SYSTEM = 0x1000 - IGNORE_INSERTS = 0x200 - - # Let FormatMessageW allocate the buffer (we'll free it below) - # Also, let it know we want a system error message. - flags = ALLOCATE_BUFFER | FROM_SYSTEM - source = None - message_id = errno - language_id = 0 - result_buffer = ctypes.wintypes.LPWSTR() - buffer_size = 0 - arguments = None - bytes = ctypes.windll.kernel32.FormatMessageW( - flags, - source, - message_id, - language_id, - ctypes.byref(result_buffer), - buffer_size, - arguments, - ) - # note the following will cause an infinite loop if GetLastError - # repeatedly returns an error that cannot be formatted, although - # this should not happen. - handle_nonzero_success(bytes) - message = result_buffer.value - ctypes.windll.kernel32.LocalFree(result_buffer) - return message - - def handle_nonzero_success(result): - if result == 0: - value = ctypes.windll.kernel32.GetLastError() - strerror = format_system_message(value) - raise WindowsError(value, strerror) - - target_is_directory = target_is_directory or os.path.isdir(target) - handle_nonzero_success(CreateSymbolicLink(link, target, target_is_directory)) - # regression test for issue6727 @unittest.skipUnless( not hasattr(sys, 'getwindowsversion') or sys.getwindowsversion() >= (6, 0), "Windows Vista or later required") + @symlink_support.skip_unless_symlink def test_symlinked_dir_importable(self): # make sure sample can only be imported from the current directory. sys.path[:] = ['.'] @@ -598,19 +535,11 @@ def tearDown(self): # now cleanup if os.path.exists(self.package_name): - self.remove_symlink(self.package_name) + symlink_support.remove_symlink(self.package_name) if os.path.exists(self.tagged): shutil.rmtree(self.tagged) sys.path[:] = self.orig_sys_path - @staticmethod - def remove_symlink(name): - # On Windows, to remove a directory symlink, one must use rmdir - try: - os.rmdir(name) - except OSError: - os.remove(name) - def test_main(verbose=None): run_unittest(ImportTests, PycRewritingTests, PathsTests, RelativeImportTests, TestSymbolicallyLinkedPackage) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Mar 9 05:37:19 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 09 Mar 2012 05:37:19 +0100 Subject: [Python-checkins] Daily reference leaks (2cc44cd8098e): sum=0 Message-ID: results for 2cc44cd8098e on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogWnAhbk', '-x'] From python-checkins at python.org Fri Mar 9 05:54:41 2012 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 09 Mar 2012 05:54:41 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_closes_Issue=3A_14217_-?= =?utf8?q?_Appropriate_sphinx_directive_for_output=2E_Patch_by?= Message-ID: http://hg.python.org/cpython/rev/3d877dee1bde changeset: 75501:3d877dee1bde parent: 75499:2cc44cd8098e user: Senthil Kumaran date: Thu Mar 08 20:54:34 2012 -0800 summary: Fix closes Issue: 14217 - Appropriate sphinx directive for output. Patch by Tshepang Lekhonkhobe files: Doc/tutorial/classes.rst | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -180,7 +180,9 @@ scope_test() print("In global scope:", spam) -The output of the example code is:: +The output of the example code is: + +.. code-block:: none After local assignment: test spam After nonlocal assignment: nonlocal spam -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 05:58:37 2012 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 09 Mar 2012 05:58:37 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_closes_Issu?= =?utf8?q?e=3A_14217_-_3=2E2_branch?= Message-ID: http://hg.python.org/cpython/rev/aaf45928899c changeset: 75502:aaf45928899c branch: 3.2 parent: 75483:509b222679e8 user: Senthil Kumaran date: Thu Mar 08 20:56:52 2012 -0800 summary: Fix closes Issue: 14217 - 3.2 branch files: Doc/tutorial/classes.rst | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -180,7 +180,10 @@ scope_test() print("In global scope:", spam) -The output of the example code is:: +The output of the example code is: + +.. code-block:: none + After local assignment: test spam After nonlocal assignment: nonlocal spam -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 05:58:38 2012 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 09 Mar 2012 05:58:38 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_null_merge_from_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/2a142141e5fd changeset: 75503:2a142141e5fd parent: 75501:3d877dee1bde parent: 75502:aaf45928899c user: Senthil Kumaran date: Thu Mar 08 20:58:29 2012 -0800 summary: null merge from 3.2 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 12:16:17 2012 From: python-checkins at python.org (nick.coghlan) Date: Fri, 09 Mar 2012 12:16:17 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Add_PEP_3144_to_the_list_of_ca?= =?utf8?q?ndidate_PEPs_for_3=2E3?= Message-ID: http://hg.python.org/peps/rev/a5b008992f8f changeset: 4121:a5b008992f8f user: Nick Coghlan date: Fri Mar 09 21:16:05 2012 +1000 summary: Add PEP 3144 to the list of candidate PEPs for 3.3 files: pep-0398.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -80,6 +80,7 @@ * PEP 395: Module Aliasing * PEP 397: Python launcher for Windows * PEP 3143: Standard daemon process library +* PEP 3144: IP Address manipulation library (Note that these are not accepted yet and even if they are, they might not be finished in time for Python 3.3.) -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Mar 9 12:18:09 2012 From: python-checkins at python.org (georg.brandl) Date: Fri, 09 Mar 2012 12:18:09 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_indentation=2E?= Message-ID: http://hg.python.org/cpython/rev/00ae6567a57d changeset: 75504:00ae6567a57d user: Georg Brandl date: Fri Mar 09 12:22:12 2012 +0100 summary: Fix indentation. files: Doc/library/asyncore.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst --- a/Doc/library/asyncore.rst +++ b/Doc/library/asyncore.rst @@ -190,7 +190,8 @@ same options for creation. Refer to the :mod:`socket` documentation for information on creating sockets. - .. versionchanged:: 3.3 family and type arguments can be omitted. + .. versionchanged:: 3.3 + *family* and *type* arguments can be omitted. .. method:: connect(address) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 12:39:15 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 09 Mar 2012 12:39:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314178=3A_Problem_d?= =?utf8?q?eleting_slices_with_steps_!=3D_+1_in_the_=5Felementtree?= Message-ID: http://hg.python.org/cpython/rev/1a721b9a4039 changeset: 75505:1a721b9a4039 user: Eli Bendersky date: Fri Mar 09 13:38:15 2012 +0200 summary: Issue #14178: Problem deleting slices with steps != +1 in the _elementtree module. Fixed the problem and added some tests. Closes #14178 files: Lib/test/test_xml_etree.py | 91 ++++++++++++++++++++++++- Modules/_elementtree.c | 70 +++++++++++++++++++- 2 files changed, 153 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1,10 +1,13 @@ # xml.etree test. This file contains enough tests to make sure that # all included components work as they should. # Large parts are extracted from the upstream test suite. - -# IMPORTANT: the same doctests are run from "test_xml_etree_c" in -# order to ensure consistency between the C implementation and the -# Python implementation. +# +# PLEASE write all new tests using the standard unittest infrastructure and +# not doctest. +# +# IMPORTANT: the same tests are run from "test_xml_etree_c" in order +# to ensure consistency between the C implementation and the Python +# implementation. # # For this purpose, the module-level "ET" symbol is temporarily # monkey-patched when running the "test_xml_etree_c" test suite. @@ -1948,6 +1951,81 @@ self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') + +class ElementSlicingTest(unittest.TestCase): + def _elem_tags(self, elemlist): + return [e.tag for e in elemlist] + + def _subelem_tags(self, elem): + return self._elem_tags(list(elem)) + + def _make_elem_with_children(self, numchildren): + """Create an Element with a tag 'a', with the given amount of children + named 'a0', 'a1' ... and so on. + + """ + e = ET.Element('a') + for i in range(numchildren): + ET.SubElement(e, 'a%s' % i) + return e + + def test_getslice_single_index(self): + e = self._make_elem_with_children(10) + + self.assertEqual(e[1].tag, 'a1') + self.assertEqual(e[-2].tag, 'a8') + + self.assertRaises(IndexError, lambda: e[12]) + + def test_getslice_range(self): + e = self._make_elem_with_children(6) + + self.assertEqual(self._elem_tags(e[3:]), ['a3', 'a4', 'a5']) + self.assertEqual(self._elem_tags(e[3:6]), ['a3', 'a4', 'a5']) + self.assertEqual(self._elem_tags(e[3:16]), ['a3', 'a4', 'a5']) + self.assertEqual(self._elem_tags(e[3:5]), ['a3', 'a4']) + self.assertEqual(self._elem_tags(e[3:-1]), ['a3', 'a4']) + self.assertEqual(self._elem_tags(e[:2]), ['a0', 'a1']) + + def test_getslice_steps(self): + e = self._make_elem_with_children(10) + + self.assertEqual(self._elem_tags(e[8:10:1]), ['a8', 'a9']) + self.assertEqual(self._elem_tags(e[::3]), ['a0', 'a3', 'a6', 'a9']) + self.assertEqual(self._elem_tags(e[::8]), ['a0', 'a8']) + self.assertEqual(self._elem_tags(e[1::8]), ['a1', 'a9']) + + def test_getslice_negative_steps(self): + e = self._make_elem_with_children(4) + + self.assertEqual(self._elem_tags(e[::-1]), ['a3', 'a2', 'a1', 'a0']) + self.assertEqual(self._elem_tags(e[::-2]), ['a3', 'a1']) + + def test_delslice(self): + e = self._make_elem_with_children(4) + del e[0:2] + self.assertEqual(self._subelem_tags(e), ['a2', 'a3']) + + e = self._make_elem_with_children(4) + del e[0:] + self.assertEqual(self._subelem_tags(e), []) + + e = self._make_elem_with_children(4) + del e[::-1] + self.assertEqual(self._subelem_tags(e), []) + + e = self._make_elem_with_children(4) + del e[::-2] + self.assertEqual(self._subelem_tags(e), ['a0', 'a2']) + + e = self._make_elem_with_children(4) + del e[1::2] + self.assertEqual(self._subelem_tags(e), ['a0', 'a2']) + + e = self._make_elem_with_children(2) + del e[::2] + self.assertEqual(self._subelem_tags(e), ['a1']) + # -------------------------------------------------------------------- @@ -1997,7 +2075,10 @@ # The same doctests are used for both the Python and the C implementations test_xml_etree.ET = module - test_classes = [ElementTreeTest, TreeBuilderTest] + test_classes = [ + ElementSlicingTest, + ElementTreeTest, + TreeBuilderTest] if module is pyET: # Run the tests specific to the Python implementation test_classes += [NoAcceleratorTest] diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1343,9 +1343,74 @@ return -1; } - if (value == NULL) - newlen = 0; + if (value == NULL) { + /* Delete slice */ + size_t cur; + Py_ssize_t i; + + if (slicelen <= 0) + return 0; + + /* Since we're deleting, the direction of the range doesn't matter, + * so for simplicity make it always ascending. + */ + if (step < 0) { + stop = start + 1; + start = stop + step * (slicelen - 1) - 1; + step = -step; + } + + assert((size_t)slicelen <= PY_SIZE_MAX / sizeof(PyObject *)); + + /* recycle is a list that will contain all the children + * scheduled for removal. + */ + if (!(recycle = PyList_New(slicelen))) { + PyErr_NoMemory(); + return -1; + } + + /* This loop walks over all the children that have to be deleted, + * with cur pointing at them. num_moved is the amount of children + * until the next deleted child that have to be "shifted down" to + * occupy the deleted's places. + * Note that in the ith iteration, shifting is done i+i places down + * because i children were already removed. + */ + for (cur = start, i = 0; cur < (size_t)stop; cur += step, ++i) { + /* Compute how many children have to be moved, clipping at the + * list end. + */ + Py_ssize_t num_moved = step - 1; + if (cur + step >= (size_t)self->extra->length) { + num_moved = self->extra->length - cur - 1; + } + + PyList_SET_ITEM(recycle, i, self->extra->children[cur]); + + memmove( + self->extra->children + cur - i, + self->extra->children + cur + 1, + num_moved * sizeof(PyObject *)); + } + + /* Leftover "tail" after the last removed child */ + cur = start + (size_t)slicelen * step; + if (cur < (size_t)self->extra->length) { + memmove( + self->extra->children + cur - slicelen, + self->extra->children + cur, + (self->extra->length - cur) * sizeof(PyObject *)); + } + + self->extra->length -= slicelen; + + /* Discard the recycle list with all the deleted sub-elements */ + Py_XDECREF(recycle); + return 0; + } else { + /* A new slice is actually being assigned */ seq = PySequence_Fast(value, ""); if (!seq) { PyErr_Format( @@ -1367,7 +1432,6 @@ return -1; } - /* Resize before creating the recycle bin, to prevent refleaks. */ if (newlen > slicelen) { if (element_resize(self, newlen - slicelen) < 0) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 14:00:13 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 09 Mar 2012 14:00:13 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314231=3A_Lib/test/?= =?utf8?q?crashers/borrowed=5Fref=5F1=2Epy_was_fixed_by_ba6376dff6c4=2E?= Message-ID: http://hg.python.org/cpython/rev/850d7f6af1b0 changeset: 75506:850d7f6af1b0 user: Victor Stinner date: Fri Mar 09 13:59:42 2012 +0100 summary: Issue #14231: Lib/test/crashers/borrowed_ref_1.py was fixed by ba6376dff6c4. files: Lib/test/crashers/borrowed_ref_1.py | 29 ----------------- 1 files changed, 0 insertions(+), 29 deletions(-) diff --git a/Lib/test/crashers/borrowed_ref_1.py b/Lib/test/crashers/borrowed_ref_1.py deleted file mode 100644 --- a/Lib/test/crashers/borrowed_ref_1.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -_PyType_Lookup() returns a borrowed reference. -This attacks the call in dictobject.c. -""" - -class A(object): - pass - -class B(object): - def __del__(self): - print('hi') - del D.__missing__ - -class D(dict): - class __missing__: - def __init__(self, *args): - pass - - -d = D() -a = A() -a.cycle = a -a.other = B() -del a - -prev = None -while 1: - d[5] - prev = (prev,) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 14:04:08 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 09 Mar 2012 14:04:08 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314205=3A_Document_?= =?utf8?q?the_dict_lookup_change_in_What=27s_New_in_Python_3=2E3?= Message-ID: http://hg.python.org/cpython/rev/a428f85de29c changeset: 75507:a428f85de29c user: Victor Stinner date: Fri Mar 09 14:04:01 2012 +0100 summary: Issue #14205: Document the dict lookup change in What's New in Python 3.3 files: Doc/whatsnew/3.3.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -474,6 +474,13 @@ (:issue:`12170`) +* A dict lookup now raises a :exc:`RuntimeError` if the dict is modified during + the lookup. If you implement your own comparaison function for objects used + as dict keys and the dict is shared by multiple threads, access to the dict + should be protected by a lock. + + (:issue:`14205`) + New and Improved Modules ======================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 16:25:39 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 09 Mar 2012 16:25:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_refactor_and_avoid_warnings?= Message-ID: http://hg.python.org/cpython/rev/46e600fa8d05 changeset: 75508:46e600fa8d05 user: Benjamin Peterson date: Fri Mar 09 07:25:32 2012 -0800 summary: refactor and avoid warnings files: Objects/object.c | 12 +++++------- 1 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -1152,13 +1152,11 @@ name->ob_type->tp_name); return -1; } - else - Py_INCREF(name); - if (tp->tp_dict == NULL) { - if (PyType_Ready(tp) < 0) - goto done; - } + if (tp->tp_dict == NULL && PyType_Ready(tp) < 0) + return -1; + + Py_INCREF(name); descr = _PyType_Lookup(tp, name); Py_XINCREF(descr); @@ -1190,9 +1188,9 @@ res = PyDict_DelItem(dict, name); else res = PyDict_SetItem(dict, name, value); + Py_DECREF(dict); if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) PyErr_SetObject(PyExc_AttributeError, name); - Py_DECREF(dict); goto done; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 9 18:44:29 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 09 Mar 2012 18:44:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Relax_timeout_tests_for_wea?= =?utf8?q?k_Windows_buildbot?= Message-ID: http://hg.python.org/cpython/rev/a796acf2759c changeset: 75509:a796acf2759c user: Antoine Pitrou date: Fri Mar 09 18:40:15 2012 +0100 summary: Relax timeout tests for weak Windows buildbot files: Lib/test/test_multiprocessing.py | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -2587,8 +2587,8 @@ delta = time.time() - start self.assertEqual(res, []) - self.assertLess(delta, expected + 0.2) - self.assertGreater(delta, expected - 0.2) + self.assertLess(delta, expected + 0.5) + self.assertGreater(delta, expected - 0.5) b.send(None) @@ -2597,7 +2597,7 @@ delta = time.time() - start self.assertEqual(res, [a]) - self.assertLess(delta, 0.2) + self.assertLess(delta, 0.4) def test_wait_integer(self): from multiprocessing.connection import wait @@ -2614,8 +2614,8 @@ delta = time.time() - start self.assertEqual(res, [p.sentinel]) - self.assertLess(delta, expected + 1) - self.assertGreater(delta, expected - 1) + self.assertLess(delta, expected + 2) + self.assertGreater(delta, expected - 2) a.send(None) @@ -2624,7 +2624,7 @@ delta = time.time() - start self.assertEqual(res, [p.sentinel, b]) - self.assertLess(delta, 0.2) + self.assertLess(delta, 0.4) b.send(None) @@ -2633,7 +2633,7 @@ delta = time.time() - start self.assertEqual(res, [a, p.sentinel, b]) - self.assertLess(delta, 0.2) + self.assertLess(delta, 0.4) p.join() -- Repository URL: http://hg.python.org/cpython From jimjjewett at gmail.com Fri Mar 9 22:32:33 2012 From: jimjjewett at gmail.com (Jim Jewett) Date: Fri, 9 Mar 2012 16:32:33 -0500 Subject: [Python-checkins] cpython: Close #14205: dict lookup raises a RuntimeError if the dict is modified during In-Reply-To: References: Message-ID: I do not believe the change set below is valid. As I read it, the new test verifies that one particular type of Nasty key will provoke a RuntimeError -- but that particular type already did so, by hitting the recursion limit. (It doesn't even really mutate the dict.) Meanwhile, the patch throws out tests for several different types of mutations that have caused problems -- even segfaults -- in the past, even after the dict implementation code was already "fixed". Changing these tests to "assertRaises" would be fine, but they should all be kept; if nothing else, they test whether you've caught all mutation avenues. -jJ On Mon, Mar 5, 2012 at 7:13 PM, victor.stinner wrote: > http://hg.python.org/cpython/rev/934aaf2191d0 > changeset: ? 75445:934aaf2191d0 > user: ? ? ? ?Victor Stinner > date: ? ? ? ?Tue Mar 06 01:03:13 2012 +0100 > summary: > ?Close #14205: dict lookup raises a RuntimeError if the dict is modified during > a lookup. > > "if you want to make a sandbox on top of CPython, you have to fix segfaults" > so let's fix segfaults! > > files: > ?Lib/test/crashers/nasty_eq_vs_dict.py | ? 47 -- > ?Lib/test/test_dict.py ? ? ? ? ? ? ? ? | ? 22 +- > ?Lib/test/test_mutants.py ? ? ? ? ? ? ?| ?291 -------------- > ?Misc/NEWS ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ?5 +- > ?Objects/dictobject.c ? ? ? ? ? ? ? ? ?| ? 18 +- > ?5 files changed, 31 insertions(+), 352 deletions(-) > > > diff --git a/Lib/test/crashers/nasty_eq_vs_dict.py b/Lib/test/crashers/nasty_eq_vs_dict.py > deleted file mode 100644 > --- a/Lib/test/crashers/nasty_eq_vs_dict.py > +++ /dev/null > @@ -1,47 +0,0 @@ > -# from http://mail.python.org/pipermail/python-dev/2001-June/015239.html > - > -# if you keep changing a dictionary while looking up a key, you can > -# provoke an infinite recursion in C > - > -# At the time neither Tim nor Michael could be bothered to think of a > -# way to fix it. > - > -class Yuck: > - ? ?def __init__(self): > - ? ? ? ?self.i = 0 > - > - ? ?def make_dangerous(self): > - ? ? ? ?self.i = 1 > - > - ? ?def __hash__(self): > - ? ? ? ?# direct to slot 4 in table of size 8; slot 12 when size 16 > - ? ? ? ?return 4 + 8 > - > - ? ?def __eq__(self, other): > - ? ? ? ?if self.i == 0: > - ? ? ? ? ? ?# leave dict alone > - ? ? ? ? ? ?pass > - ? ? ? ?elif self.i == 1: > - ? ? ? ? ? ?# fiddle to 16 slots > - ? ? ? ? ? ?self.__fill_dict(6) > - ? ? ? ? ? ?self.i = 2 > - ? ? ? ?else: > - ? ? ? ? ? ?# fiddle to 8 slots > - ? ? ? ? ? ?self.__fill_dict(4) > - ? ? ? ? ? ?self.i = 1 > - > - ? ? ? ?return 1 > - > - ? ?def __fill_dict(self, n): > - ? ? ? ?self.i = 0 > - ? ? ? ?dict.clear() > - ? ? ? ?for i in range(n): > - ? ? ? ? ? ?dict[i] = i > - ? ? ? ?dict[self] = "OK!" > - > -y = Yuck() > -dict = {y: "OK!"} > - > -z = Yuck() > -y.make_dangerous() > -print(dict[z]) > diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py > --- a/Lib/test/test_dict.py > +++ b/Lib/test/test_dict.py > @@ -379,7 +379,7 @@ > ? ? ? ? x.fail = True > ? ? ? ? self.assertRaises(Exc, d.pop, x) > > - ? ?def test_mutatingiteration(self): > + ? ?def test_mutating_iteration(self): > ? ? ? ? # changing dict size during iteration > ? ? ? ? d = {} > ? ? ? ? d[1] = 1 > @@ -387,6 +387,26 @@ > ? ? ? ? ? ? for i in d: > ? ? ? ? ? ? ? ? d[i+1] = 1 > > + ? ?def test_mutating_lookup(self): > + ? ? ? ?# changing dict during a lookup > + ? ? ? ?class NastyKey: > + ? ? ? ? ? ?mutate_dict = None > + > + ? ? ? ? ? ?def __hash__(self): > + ? ? ? ? ? ? ? ?# hash collision! > + ? ? ? ? ? ? ? ?return 1 > + > + ? ? ? ? ? ?def __eq__(self, other): > + ? ? ? ? ? ? ? ?if self.mutate_dict: > + ? ? ? ? ? ? ? ? ? ?self.mutate_dict[self] = 1 > + ? ? ? ? ? ? ? ?return self == other > + > + ? ? ? ?d = {} > + ? ? ? ?d[NastyKey()] = 0 > + ? ? ? ?NastyKey.mutate_dict = d > + ? ? ? ?with self.assertRaises(RuntimeError): > + ? ? ? ? ? ?d[NastyKey()] = None > + > ? ? def test_repr(self): > ? ? ? ? d = {} > ? ? ? ? self.assertEqual(repr(d), '{}') > diff --git a/Lib/test/test_mutants.py b/Lib/test/test_mutants.py > deleted file mode 100644 > --- a/Lib/test/test_mutants.py > +++ /dev/null > @@ -1,291 +0,0 @@ > -from test.support import verbose, TESTFN > -import random > -import os > - > -# From SF bug #422121: ?Insecurities in dict comparison. > - > -# Safety of code doing comparisons has been an historical Python weak spot. > -# The problem is that comparison of structures written in C *naturally* > -# wants to hold on to things like the size of the container, or "the > -# biggest" containee so far, across a traversal of the container; but > -# code to do containee comparisons can call back into Python and mutate > -# the container in arbitrary ways while the C loop is in midstream. ?If the > -# C code isn't extremely paranoid about digging things out of memory on > -# each trip, and artificially boosting refcounts for the duration, anything > -# from infinite loops to OS crashes can result (yes, I use Windows ). > -# > -# The other problem is that code designed to provoke a weakness is usually > -# white-box code, and so catches only the particular vulnerabilities the > -# author knew to protect against. ?For example, Python's list.sort() code > -# went thru many iterations as one "new" vulnerability after another was > -# discovered. > -# > -# So the dict comparison test here uses a black-box approach instead, > -# generating dicts of various sizes at random, and performing random > -# mutations on them at random times. ?This proved very effective, > -# triggering at least six distinct failure modes the first 20 times I > -# ran it. ?Indeed, at the start, the driver never got beyond 6 iterations > -# before the test died. > - > -# The dicts are global to make it easy to mutate tham from within functions. > -dict1 = {} > -dict2 = {} > - > -# The current set of keys in dict1 and dict2. ?These are materialized as > -# lists to make it easy to pick a dict key at random. > -dict1keys = [] > -dict2keys = [] > - > -# Global flag telling maybe_mutate() whether to *consider* mutating. > -mutate = 0 > - > -# If global mutate is true, consider mutating a dict. ?May or may not > -# mutate a dict even if mutate is true. ?If it does decide to mutate a > -# dict, it picks one of {dict1, dict2} at random, and deletes a random > -# entry from it; or, more rarely, adds a random element. > - > -def maybe_mutate(): > - ? ?global mutate > - ? ?if not mutate: > - ? ? ? ?return > - ? ?if random.random() < 0.5: > - ? ? ? ?return > - > - ? ?if random.random() < 0.5: > - ? ? ? ?target, keys = dict1, dict1keys > - ? ?else: > - ? ? ? ?target, keys = dict2, dict2keys > - > - ? ?if random.random() < 0.2: > - ? ? ? ?# Insert a new key. > - ? ? ? ?mutate = 0 ? # disable mutation until key inserted > - ? ? ? ?while 1: > - ? ? ? ? ? ?newkey = Horrid(random.randrange(100)) > - ? ? ? ? ? ?if newkey not in target: > - ? ? ? ? ? ? ? ?break > - ? ? ? ?target[newkey] = Horrid(random.randrange(100)) > - ? ? ? ?keys.append(newkey) > - ? ? ? ?mutate = 1 > - > - ? ?elif keys: > - ? ? ? ?# Delete a key at random. > - ? ? ? ?mutate = 0 ? # disable mutation until key deleted > - ? ? ? ?i = random.randrange(len(keys)) > - ? ? ? ?key = keys[i] > - ? ? ? ?del target[key] > - ? ? ? ?del keys[i] > - ? ? ? ?mutate = 1 > - > -# A horrid class that triggers random mutations of dict1 and dict2 when > -# instances are compared. > - > -class Horrid: > - ? ?def __init__(self, i): > - ? ? ? ?# Comparison outcomes are determined by the value of i. > - ? ? ? ?self.i = i > - > - ? ? ? ?# An artificial hashcode is selected at random so that we don't > - ? ? ? ?# have any systematic relationship between comparison outcomes > - ? ? ? ?# (based on self.i and other.i) and relative position within the > - ? ? ? ?# hash vector (based on hashcode). > - ? ? ? ?# XXX This is no longer effective. > - ? ? ? ?##self.hashcode = random.randrange(1000000000) > - > - ? ?def __hash__(self): > - ? ? ? ?return 42 > - ? ? ? ?return self.hashcode > - > - ? ?def __eq__(self, other): > - ? ? ? ?maybe_mutate() ? # The point of the test. > - ? ? ? ?return self.i == other.i > - > - ? ?def __ne__(self, other): > - ? ? ? ?raise RuntimeError("I didn't expect some kind of Spanish inquisition!") > - > - ? ?__lt__ = __le__ = __gt__ = __ge__ = __ne__ > - > - ? ?def __repr__(self): > - ? ? ? ?return "Horrid(%d)" % self.i > - > -# Fill dict d with numentries (Horrid(i), Horrid(j)) key-value pairs, > -# where i and j are selected at random from the candidates list. > -# Return d.keys() after filling. > - > -def fill_dict(d, candidates, numentries): > - ? ?d.clear() > - ? ?for i in range(numentries): > - ? ? ? ?d[Horrid(random.choice(candidates))] = \ > - ? ? ? ? ? ?Horrid(random.choice(candidates)) > - ? ?return list(d.keys()) > - > -# Test one pair of randomly generated dicts, each with n entries. > -# Note that dict comparison is trivial if they don't have the same number > -# of entires (then the "shorter" dict is instantly considered to be the > -# smaller one, without even looking at the entries). > - > -def test_one(n): > - ? ?global mutate, dict1, dict2, dict1keys, dict2keys > - > - ? ?# Fill the dicts without mutating them. > - ? ?mutate = 0 > - ? ?dict1keys = fill_dict(dict1, range(n), n) > - ? ?dict2keys = fill_dict(dict2, range(n), n) > - > - ? ?# Enable mutation, then compare the dicts so long as they have the > - ? ?# same size. > - ? ?mutate = 1 > - ? ?if verbose: > - ? ? ? ?print("trying w/ lengths", len(dict1), len(dict2), end=' ') > - ? ?while dict1 and len(dict1) == len(dict2): > - ? ? ? ?if verbose: > - ? ? ? ? ? ?print(".", end=' ') > - ? ? ? ?c = dict1 == dict2 > - ? ?if verbose: > - ? ? ? ?print() > - > -# Run test_one n times. ?At the start (before the bugs were fixed), 20 > -# consecutive runs of this test each blew up on or before the sixth time > -# test_one was run. ?So n doesn't have to be large to get an interesting > -# test. > -# OTOH, calling with large n is also interesting, to ensure that the fixed > -# code doesn't hold on to refcounts *too* long (in which case memory would > -# leak). > - > -def test(n): > - ? ?for i in range(n): > - ? ? ? ?test_one(random.randrange(1, 100)) > - > -# See last comment block for clues about good values for n. > -test(100) > - > -########################################################################## > -# Another segfault bug, distilled by Michael Hudson from a c.l.py post. > - > -class Child: > - ? ?def __init__(self, parent): > - ? ? ? ?self.__dict__['parent'] = parent > - ? ?def __getattr__(self, attr): > - ? ? ? ?self.parent.a = 1 > - ? ? ? ?self.parent.b = 1 > - ? ? ? ?self.parent.c = 1 > - ? ? ? ?self.parent.d = 1 > - ? ? ? ?self.parent.e = 1 > - ? ? ? ?self.parent.f = 1 > - ? ? ? ?self.parent.g = 1 > - ? ? ? ?self.parent.h = 1 > - ? ? ? ?self.parent.i = 1 > - ? ? ? ?return getattr(self.parent, attr) > - > -class Parent: > - ? ?def __init__(self): > - ? ? ? ?self.a = Child(self) > - > -# Hard to say what this will print! ?May vary from time to time. ?But > -# we're specifically trying to test the tp_print slot here, and this is > -# the clearest way to do it. ?We print the result to a temp file so that > -# the expected-output file doesn't need to change. > - > -f = open(TESTFN, "w") > -print(Parent().__dict__, file=f) > -f.close() > -os.unlink(TESTFN) > - > -########################################################################## > -# And another core-dumper from Michael Hudson. > - > -dict = {} > - > -# Force dict to malloc its table. > -for i in range(1, 10): > - ? ?dict[i] = i > - > -f = open(TESTFN, "w") > - > -class Machiavelli: > - ? ?def __repr__(self): > - ? ? ? ?dict.clear() > - > - ? ? ? ?# Michael sez: ?"doesn't crash without this. ?don't know why." > - ? ? ? ?# Tim sez: ?"luck of the draw; crashes with or without for me." > - ? ? ? ?print(file=f) > - > - ? ? ? ?return repr("machiavelli") > - > - ? ?def __hash__(self): > - ? ? ? ?return 0 > - > -dict[Machiavelli()] = Machiavelli() > - > -print(str(dict), file=f) > -f.close() > -os.unlink(TESTFN) > -del f, dict > - > - > -########################################################################## > -# And another core-dumper from Michael Hudson. > - > -dict = {} > - > -# let's force dict to malloc its table > -for i in range(1, 10): > - ? ?dict[i] = i > - > -class Machiavelli2: > - ? ?def __eq__(self, other): > - ? ? ? ?dict.clear() > - ? ? ? ?return 1 > - > - ? ?def __hash__(self): > - ? ? ? ?return 0 > - > -dict[Machiavelli2()] = Machiavelli2() > - > -try: > - ? ?dict[Machiavelli2()] > -except KeyError: > - ? ?pass > - > -del dict > - > -########################################################################## > -# And another core-dumper from Michael Hudson. > - > -dict = {} > - > -# let's force dict to malloc its table > -for i in range(1, 10): > - ? ?dict[i] = i > - > -class Machiavelli3: > - ? ?def __init__(self, id): > - ? ? ? ?self.id = id > - > - ? ?def __eq__(self, other): > - ? ? ? ?if self.id == other.id: > - ? ? ? ? ? ?dict.clear() > - ? ? ? ? ? ?return 1 > - ? ? ? ?else: > - ? ? ? ? ? ?return 0 > - > - ? ?def __repr__(self): > - ? ? ? ?return "%s(%s)"%(self.__class__.__name__, self.id) > - > - ? ?def __hash__(self): > - ? ? ? ?return 0 > - > -dict[Machiavelli3(1)] = Machiavelli3(0) > -dict[Machiavelli3(2)] = Machiavelli3(0) > - > -f = open(TESTFN, "w") > -try: > - ? ?try: > - ? ? ? ?print(dict[Machiavelli3(2)], file=f) > - ? ?except KeyError: > - ? ? ? ?pass > -finally: > - ? ?f.close() > - ? ?os.unlink(TESTFN) > - > -del dict > -del dict1, dict2, dict1keys, dict2keys > diff --git a/Misc/NEWS b/Misc/NEWS > --- a/Misc/NEWS > +++ b/Misc/NEWS > @@ -10,10 +10,13 @@ > ?Core and Builtins > ?----------------- > > +- Issue #14205: dict lookup raises a RuntimeError if the dict is modified > + ?during a lookup. > + > ?Library > ?------- > > -- Issue #14168: Check for presence of Element._attrs in minidom before > +- Issue #14168: Check for presence of Element._attrs in minidom before > ? accessing it. > > ?- Issue #12328: Fix multiprocessing's use of overlapped I/O on Windows. > diff --git a/Objects/dictobject.c b/Objects/dictobject.c > --- a/Objects/dictobject.c > +++ b/Objects/dictobject.c > @@ -347,12 +347,9 @@ > ? ? ? ? ? ? ? ? ? ? return ep; > ? ? ? ? ? ? } > ? ? ? ? ? ? else { > - ? ? ? ? ? ? ? ?/* The compare did major nasty stuff to the > - ? ? ? ? ? ? ? ? * dict: ?start over. > - ? ? ? ? ? ? ? ? * XXX A clever adversary could prevent this > - ? ? ? ? ? ? ? ? * XXX from terminating. > - ? ? ? ? ? ? ? ? */ > - ? ? ? ? ? ? ? ?return lookdict(mp, key, hash); > + ? ? ? ? ? ? ? ?PyErr_SetString(PyExc_RuntimeError, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"dictionary changed size during lookup"); > + ? ? ? ? ? ? ? ?return NULL; > ? ? ? ? ? ? } > ? ? ? ? } > ? ? ? ? freeslot = NULL; > @@ -379,12 +376,9 @@ > ? ? ? ? ? ? ? ? ? ? return ep; > ? ? ? ? ? ? } > ? ? ? ? ? ? else { > - ? ? ? ? ? ? ? ?/* The compare did major nasty stuff to the > - ? ? ? ? ? ? ? ? * dict: ?start over. > - ? ? ? ? ? ? ? ? * XXX A clever adversary could prevent this > - ? ? ? ? ? ? ? ? * XXX from terminating. > - ? ? ? ? ? ? ? ? */ > - ? ? ? ? ? ? ? ?return lookdict(mp, key, hash); > + ? ? ? ? ? ? ? ?PyErr_SetString(PyExc_RuntimeError, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"dictionary changed size during lookup"); > + ? ? ? ? ? ? ? ?return NULL; > ? ? ? ? ? ? } > ? ? ? ? } > ? ? ? ? else if (ep->me_key == dummy && freeslot == NULL) > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > From python-checkins at python.org Fri Mar 9 22:59:08 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 09 Mar 2012 22:59:08 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314205=3A_Fix_test?= =?utf8?q?=5Fdict=2Etest=5Fmutating=5Flookup=28=29?= Message-ID: http://hg.python.org/cpython/rev/70fbb02d588c changeset: 75510:70fbb02d588c user: Victor Stinner date: Fri Mar 09 22:58:51 2012 +0100 summary: Issue #14205: Fix test_dict.test_mutating_lookup() files: Lib/test/test_dict.py | 23 +++++++++++++++-------- 1 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -392,20 +392,27 @@ class NastyKey: mutate_dict = None + def __init__(self, value): + self.value = value + def __hash__(self): # hash collision! return 1 def __eq__(self, other): - if self.mutate_dict: - self.mutate_dict[self] = 1 - return self == other + if NastyKey.mutate_dict: + mydict, key = NastyKey.mutate_dict + NastyKey.mutate_dict = None + del mydict[key] + return self.value == other.value - d = {} - d[NastyKey()] = 0 - NastyKey.mutate_dict = d - with self.assertRaises(RuntimeError): - d[NastyKey()] = None + key1 = NastyKey(1) + key2 = NastyKey(2) + d = {key1: 1} + NastyKey.mutate_dict = (d, key1) + with self.assertRaisesRegex(RuntimeError, + 'dictionary changed size during lookup'): + d[key2] = 2 def test_repr(self): d = {} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 00:11:38 2012 From: python-checkins at python.org (brett.cannon) Date: Sat, 10 Mar 2012 00:11:38 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Note_that_PEP_412_=28key-shari?= =?utf8?q?ng_dict=29_has_been_cleared_for_Python_3=2E3=2E?= Message-ID: http://hg.python.org/peps/rev/821ead703390 changeset: 4122:821ead703390 user: Brett Cannon date: Fri Mar 09 18:11:32 2012 -0500 summary: Note that PEP 412 (key-sharing dict) has been cleared for Python 3.3. files: pep-0398.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -79,6 +79,7 @@ * PEP 382: Namespace Packages * PEP 395: Module Aliasing * PEP 397: Python launcher for Windows +* PEP 414: Key-Sharing Dictionary * PEP 3143: Standard daemon process library * PEP 3144: IP Address manipulation library -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 10 00:21:41 2012 From: python-checkins at python.org (victor.stinner) Date: Sat, 10 Mar 2012 00:21:41 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_=2314232=3A_catch_mma?= =?utf8?q?p=28=29_failure_in_new=5Farena=28=29_of_obmalloc?= Message-ID: http://hg.python.org/cpython/rev/ba8f85e16dd9 changeset: 75511:ba8f85e16dd9 user: Victor Stinner date: Sat Mar 10 00:21:44 2012 +0100 summary: Close #14232: catch mmap() failure in new_arena() of obmalloc files: Objects/obmalloc.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -540,6 +540,8 @@ { struct arena_object* arenaobj; uint excess; /* number of bytes above pool alignment */ + void *address; + int err; #ifdef PYMALLOC_DEBUG if (Py_GETENV("PYTHONMALLOCSTATS")) @@ -593,12 +595,14 @@ unused_arena_objects = arenaobj->nextarena; assert(arenaobj->address == 0); #ifdef ARENAS_USE_MMAP - arenaobj->address = (uptr)mmap(NULL, ARENA_SIZE, PROT_READ|PROT_WRITE, + address = mmap(NULL, ARENA_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + err = (address == MAP_FAILED); #else - arenaobj->address = (uptr)malloc(ARENA_SIZE); + address = malloc(ARENA_SIZE); + err = (address == 0); #endif - if (arenaobj->address == 0) { + if (err) { /* The allocation failed: return NULL after putting the * arenaobj back. */ @@ -606,6 +610,7 @@ unused_arena_objects = arenaobj; return NULL; } + arenaobj->address = (uptr)address; ++narenas_currently_allocated; #ifdef PYMALLOC_DEBUG -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Mar 10 05:37:42 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 10 Mar 2012 05:37:42 +0100 Subject: [Python-checkins] Daily reference leaks (ba8f85e16dd9): sum=0 Message-ID: results for ba8f85e16dd9 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogyR_pKd', '-x'] From python-checkins at python.org Sat Mar 10 07:52:49 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 10 Mar 2012 07:52:49 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Fix_typo=2E?= Message-ID: http://hg.python.org/peps/rev/7dfbd4848412 changeset: 4123:7dfbd4848412 user: Georg Brandl date: Sat Mar 10 07:56:55 2012 +0100 summary: Fix typo. files: pep-0398.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -79,7 +79,7 @@ * PEP 382: Namespace Packages * PEP 395: Module Aliasing * PEP 397: Python launcher for Windows -* PEP 414: Key-Sharing Dictionary +* PEP 412: Key-Sharing Dictionary * PEP 3143: Standard daemon process library * PEP 3144: IP Address manipulation library -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 10 09:23:27 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 10 Mar 2012 09:23:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314186?= =?utf8?q?=3A_add_link_to_PEP_3107_=28function_annotations=29_to_the_funct?= =?utf8?q?ion?= Message-ID: http://hg.python.org/cpython/rev/c18d538d2ece changeset: 75512:c18d538d2ece branch: 3.2 parent: 75502:aaf45928899c user: Georg Brandl date: Sat Mar 10 09:22:47 2012 +0100 summary: Closes #14186: add link to PEP 3107 (function annotations) to the function definition section. files: Doc/reference/compound_stmts.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -535,6 +535,11 @@ access the local variables of the function containing the def. See section :ref:`naming` for details. +.. seealso:: + + :pep:`3107` - Function Annotations + The original specification for function annotations. + .. _class: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 09:23:28 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 10 Mar 2012 09:23:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314244?= =?utf8?q?=3A_add_info_about_capturing_groups_and_maxsplit_to_the_docstrin?= =?utf8?q?g_of?= Message-ID: http://hg.python.org/cpython/rev/b96251d9f36a changeset: 75513:b96251d9f36a branch: 3.2 user: Georg Brandl date: Sat Mar 10 09:26:53 2012 +0100 summary: Closes #14244: add info about capturing groups and maxsplit to the docstring of re.split(). files: Lib/re.py | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -179,14 +179,19 @@ def split(pattern, string, maxsplit=0, flags=0): """Split the source string by the occurrences of the pattern, - returning a list containing the resulting substrings.""" + returning a list containing the resulting substrings. If + capturing parentheses are used in pattern, then the text of all + groups in the pattern are also returned as part of the resulting + list. If maxsplit is nonzero, at most maxsplit splits occur, + and the remainder of the string is returned as the final element + of the list.""" return _compile(pattern, flags).split(string, maxsplit) def findall(pattern, string, flags=0): """Return a list of all non-overlapping matches in the string. - If one or more groups are present in the pattern, return a - list of groups; this will be a list of tuples if the pattern + If one or more capturing groups are present in the pattern, return + a list of groups; this will be a list of tuples if the pattern has more than one group. Empty matches are included in the result.""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 09:23:28 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 10 Mar 2012 09:23:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_with_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/7e8ac22a4cf2 changeset: 75514:7e8ac22a4cf2 parent: 75511:ba8f85e16dd9 parent: 75513:b96251d9f36a user: Georg Brandl date: Sat Mar 10 09:27:30 2012 +0100 summary: Merge with 3.2. files: Doc/reference/compound_stmts.rst | 5 +++++ Lib/re.py | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -535,6 +535,11 @@ access the local variables of the function containing the def. See section :ref:`naming` for details. +.. seealso:: + + :pep:`3107` - Function Annotations + The original specification for function annotations. + .. _class: diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -179,14 +179,19 @@ def split(pattern, string, maxsplit=0, flags=0): """Split the source string by the occurrences of the pattern, - returning a list containing the resulting substrings.""" + returning a list containing the resulting substrings. If + capturing parentheses are used in pattern, then the text of all + groups in the pattern are also returned as part of the resulting + list. If maxsplit is nonzero, at most maxsplit splits occur, + and the remainder of the string is returned as the final element + of the list.""" return _compile(pattern, flags).split(string, maxsplit) def findall(pattern, string, flags=0): """Return a list of all non-overlapping matches in the string. - If one or more groups are present in the pattern, return a - list of groups; this will be a list of tuples if the pattern + If one or more capturing groups are present in the pattern, return + a list of groups; this will be a list of tuples if the pattern has more than one group. Empty matches are included in the result.""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 11:43:54 2012 From: python-checkins at python.org (victor.stinner) Date: Sat, 10 Mar 2012 11:43:54 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_416=3A_remove_mentions_of_?= =?utf8?q?mutable/immutable?= Message-ID: http://hg.python.org/peps/rev/7278026a5db9 changeset: 4124:7278026a5db9 user: Victor Stinner date: Sat Mar 10 11:43:45 2012 +0100 summary: PEP 416: remove mentions of mutable/immutable files: pep-0416.txt | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pep-0416.txt b/pep-0416.txt --- a/pep-0416.txt +++ b/pep-0416.txt @@ -20,9 +20,8 @@ ========= A frozendict is a read-only mapping: a key cannot be added nor removed, and a -key is always mapped to the same value. However, frozendict values can be -mutable (not hashable). A frozendict is hashable and so immutable if and only -if all values are hashable (immutable). +key is always mapped to the same value. However, frozendict values can be not +hashable. A frozendict is hashable if and only if all values are hashable. Use cases: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 10 16:38:55 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 10 Mar 2012 16:38:55 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_useless_failOnExcept?= =?utf8?q?ion=28=29_method?= Message-ID: http://hg.python.org/cpython/rev/42cf2a06a472 changeset: 75515:42cf2a06a472 user: Antoine Pitrou date: Sat Mar 10 16:20:24 2012 +0100 summary: Remove useless failOnException() method files: Lib/test/test_tempfile.py | 118 +++++++------------------ 1 files changed, 32 insertions(+), 86 deletions(-) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -45,11 +45,6 @@ self._warnings_manager.__exit__(None, None, None) - def failOnException(self, what, ei=None): - if ei is None: - ei = sys.exc_info() - self.fail("%s raised %s: %s" % (what, ei[0], ei[1])) - def nameCheck(self, name, dir, pre, suf): (ndir, nbase) = os.path.split(name) npre = nbase[:len(pre)] @@ -128,13 +123,10 @@ i = 0 r = self.r - try: - for s in r: - i += 1 - if i == 20: - break - except: - self.failOnException("iteration") + for s in r: + i += 1 + if i == 20: + break @unittest.skipUnless(hasattr(os, 'fork'), "os.fork is required for this test") @@ -258,10 +250,7 @@ def do_create(self, dir=None, pre="", suf="", bin=1): if dir is None: dir = tempfile.gettempdir() - try: - file = self.mkstemped(dir, pre, suf, bin) - except: - self.failOnException("_mkstemp_inner") + file = self.mkstemped(dir, pre, suf, bin) self.nameCheck(file.name, dir, pre, suf) return file @@ -376,10 +365,7 @@ d = tempfile.mkdtemp(prefix="") try: p = os.path.join(d, p) - try: - fd = os.open(p, os.O_RDWR | os.O_CREAT) - except: - self.failOnException("os.open") + fd = os.open(p, os.O_RDWR | os.O_CREAT) os.close(fd) os.unlink(p) finally: @@ -406,12 +392,9 @@ # sneaky: just instantiate a NamedTemporaryFile, which # defaults to writing into the directory returned by # gettempdir. - try: - file = tempfile.NamedTemporaryFile() - file.write(b"blat") - file.close() - except: - self.failOnException("create file in %s" % tempfile.gettempdir()) + file = tempfile.NamedTemporaryFile() + file.write(b"blat") + file.close() def test_same_thing(self): # gettempdir always returns the same object @@ -429,14 +412,11 @@ def do_create(self, dir=None, pre="", suf=""): if dir is None: dir = tempfile.gettempdir() - try: - (fd, name) = tempfile.mkstemp(dir=dir, prefix=pre, suffix=suf) - (ndir, nbase) = os.path.split(name) - adir = os.path.abspath(dir) - self.assertEqual(adir, ndir, - "Directory '%s' incorrectly returned as '%s'" % (adir, ndir)) - except: - self.failOnException("mkstemp") + (fd, name) = tempfile.mkstemp(dir=dir, prefix=pre, suffix=suf) + (ndir, nbase) = os.path.split(name) + adir = os.path.abspath(dir) + self.assertEqual(adir, ndir, + "Directory '%s' incorrectly returned as '%s'" % (adir, ndir)) try: self.nameCheck(name, dir, pre, suf) @@ -470,10 +450,7 @@ def do_create(self, dir=None, pre="", suf=""): if dir is None: dir = tempfile.gettempdir() - try: - name = tempfile.mkdtemp(dir=dir, prefix=pre, suffix=suf) - except: - self.failOnException("mkdtemp") + name = tempfile.mkdtemp(dir=dir, prefix=pre, suffix=suf) try: self.nameCheck(name, dir, pre, suf) @@ -560,10 +537,7 @@ self._unlink(self.name) def do_create(self, pre="", suf=""): - try: - file = self.mktemped(self.dir, pre, suf) - except: - self.failOnException("mktemp") + file = self.mktemped(self.dir, pre, suf) self.nameCheck(file.name, self.dir, pre, suf) return file @@ -602,11 +576,8 @@ def do_create(self, dir=None, pre="", suf="", delete=True): if dir is None: dir = tempfile.gettempdir() - try: - file = tempfile.NamedTemporaryFile(dir=dir, prefix=pre, suffix=suf, - delete=delete) - except: - self.failOnException("NamedTemporaryFile") + file = tempfile.NamedTemporaryFile(dir=dir, prefix=pre, suffix=suf, + delete=delete) self.nameCheck(file.name, dir, pre, suf) return file @@ -659,11 +630,8 @@ f = tempfile.NamedTemporaryFile() f.write(b'abc\n') f.close() - try: - f.close() - f.close() - except: - self.failOnException("close") + f.close() + f.close() def test_context_manager(self): # A NamedTemporaryFile can be used as a context manager @@ -685,10 +653,7 @@ def do_create(self, max_size=0, dir=None, pre="", suf=""): if dir is None: dir = tempfile.gettempdir() - try: - file = tempfile.SpooledTemporaryFile(max_size=max_size, dir=dir, prefix=pre, suffix=suf) - except: - self.failOnException("SpooledTemporaryFile") + file = tempfile.SpooledTemporaryFile(max_size=max_size, dir=dir, prefix=pre, suffix=suf) return file @@ -776,11 +741,8 @@ f.write(b'abc\n') self.assertFalse(f._rolled) f.close() - try: - f.close() - f.close() - except: - self.failOnException("close") + f.close() + f.close() def test_multiple_close_after_rollover(self): # A SpooledTemporaryFile can be closed many times without error @@ -788,11 +750,8 @@ f.write(b'abc\n') self.assertTrue(f._rolled) f.close() - try: - f.close() - f.close() - except: - self.failOnException("close") + f.close() + f.close() def test_bound_methods(self): # It should be OK to steal a bound method from a SpooledTemporaryFile @@ -909,10 +868,7 @@ def test_basic(self): # TemporaryFile can create files # No point in testing the name params - the file has no name. - try: - tempfile.TemporaryFile() - except: - self.failOnException("TemporaryFile") + tempfile.TemporaryFile() def test_has_no_name(self): # TemporaryFile creates files with no names (on this system) @@ -925,22 +881,18 @@ try: os.rmdir(dir) except: - ei = sys.exc_info() # cleanup f.close() os.rmdir(dir) - self.failOnException("rmdir", ei) + raise def test_multiple_close(self): # A TemporaryFile can be closed many times without error f = tempfile.TemporaryFile() f.write(b'abc\n') f.close() - try: - f.close() - f.close() - except: - self.failOnException("close") + f.close() + f.close() # How to test the mode and bufsize parameters? def test_mode_and_encoding(self): @@ -983,10 +935,7 @@ def do_create(self, dir=None, pre="", suf="", recurse=1): if dir is None: dir = tempfile.gettempdir() - try: - tmp = tempfile.TemporaryDirectory(dir=dir, prefix=pre, suffix=suf) - except: - self.failOnException("TemporaryDirectory") + tmp = tempfile.TemporaryDirectory(dir=dir, prefix=pre, suffix=suf) self.nameCheck(tmp.name, dir, pre, suf) # Create a subdirectory and some files if recurse: @@ -1110,11 +1059,8 @@ # Can be cleaned-up many times without error d = self.do_create() d.cleanup() - try: - d.cleanup() - d.cleanup() - except: - self.failOnException("cleanup") + d.cleanup() + d.cleanup() def test_context_manager(self): # Can be used as a context manager -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 16:39:12 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 10 Mar 2012 16:39:12 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_PEP8-ize_test_names?= Message-ID: http://hg.python.org/cpython/rev/b7121ab1107c changeset: 75516:b7121ab1107c user: Antoine Pitrou date: Sat Mar 10 16:34:40 2012 +0100 summary: PEP8-ize test names files: Lib/test/test_tempfile.py | 150 ++++++++++--------------- 1 files changed, 61 insertions(+), 89 deletions(-) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -31,7 +31,7 @@ # threads is not done here. # Common functionality. -class TC(unittest.TestCase): +class BaseTestCase(unittest.TestCase): str_check = re.compile(r"[a-zA-Z0-9_-]{6}$") @@ -63,9 +63,8 @@ "random string '%s' does not match /^[a-zA-Z0-9_-]{6}$/" % nbase) -test_classes = [] -class test_exports(TC): +class TestExports(BaseTestCase): def test_exports(self): # There are no surprising symbols in the tempfile module dict = tempfile.__dict__ @@ -92,10 +91,8 @@ self.assertTrue(len(unexp) == 0, "unexpected keys: %s" % unexp) -test_classes.append(test_exports) - -class test__RandomNameSequence(TC): +class TestRandomNameSequence(BaseTestCase): """Test the internal iterator object _RandomNameSequence.""" def setUp(self): @@ -159,10 +156,8 @@ self.assertNotEqual(child_value, parent_value) -test_classes.append(test__RandomNameSequence) - -class test__candidate_tempdir_list(TC): +class TestCandidateTempdirList(BaseTestCase): """Test the internal function _candidate_tempdir_list.""" def test_nonempty_list(self): @@ -201,13 +196,11 @@ # Not practical to try to verify the presence of OS-specific # paths in this list. -test_classes.append(test__candidate_tempdir_list) - # We test _get_default_tempdir by testing gettempdir. -class test__get_candidate_names(TC): +class TestGetCandidateNames(BaseTestCase): """Test the internal function _get_candidate_names.""" def test_retval(self): @@ -222,10 +215,8 @@ self.assertTrue(a is b) -test_classes.append(test__get_candidate_names) - -class test__mkstemp_inner(TC): +class TestMkstempInner(BaseTestCase): """Test the internal function _mkstemp_inner.""" class mkstemped: @@ -342,10 +333,8 @@ os.lseek(f.fd, 0, os.SEEK_SET) self.assertEqual(os.read(f.fd, 20), b"blat") -test_classes.append(test__mkstemp_inner) - -class test_gettempprefix(TC): +class TestGetTempPrefix(BaseTestCase): """Test gettempprefix().""" def test_sane_template(self): @@ -371,10 +360,8 @@ finally: os.rmdir(d) -test_classes.append(test_gettempprefix) - -class test_gettempdir(TC): +class TestGetTempDir(BaseTestCase): """Test gettempdir().""" def test_directory_exists(self): @@ -403,10 +390,8 @@ self.assertTrue(a is b) -test_classes.append(test_gettempdir) - -class test_mkstemp(TC): +class TestMkstemp(BaseTestCase): """Test mkstemp().""" def do_create(self, dir=None, pre="", suf=""): @@ -441,10 +426,8 @@ finally: os.rmdir(dir) -test_classes.append(test_mkstemp) - -class test_mkdtemp(TC): +class TestMkdtemp(BaseTestCase): """Test mkdtemp().""" def do_create(self, dir=None, pre="", suf=""): @@ -505,10 +488,8 @@ finally: os.rmdir(dir) -test_classes.append(test_mkdtemp) - -class test_mktemp(TC): +class TestMktemp(BaseTestCase): """Test mktemp().""" # For safety, all use of mktemp must occur in a private directory. @@ -564,13 +545,11 @@ ## self.assertRaises(RuntimeWarning, ## tempfile.mktemp, dir=self.dir) -test_classes.append(test_mktemp) - # We test _TemporaryFileWrapper by testing NamedTemporaryFile. -class test_NamedTemporaryFile(TC): +class TestNamedTemporaryFile(BaseTestCase): """Test NamedTemporaryFile().""" def do_create(self, dir=None, pre="", suf="", delete=True): @@ -645,9 +624,8 @@ # How to test the mode and bufsize parameters? -test_classes.append(test_NamedTemporaryFile) -class test_SpooledTemporaryFile(TC): +class TestSpooledTemporaryFile(BaseTestCase): """Test SpooledTemporaryFile().""" def do_create(self, max_size=0, dir=None, pre="", suf=""): @@ -859,58 +837,54 @@ if has_stat: self.assertEqual(os.fstat(f.fileno()).st_size, 20) -test_classes.append(test_SpooledTemporaryFile) - - -class test_TemporaryFile(TC): - """Test TemporaryFile().""" - - def test_basic(self): - # TemporaryFile can create files - # No point in testing the name params - the file has no name. - tempfile.TemporaryFile() - - def test_has_no_name(self): - # TemporaryFile creates files with no names (on this system) - dir = tempfile.mkdtemp() - f = tempfile.TemporaryFile(dir=dir) - f.write(b'blat') - - # Sneaky: because this file has no name, it should not prevent - # us from removing the directory it was created in. - try: - os.rmdir(dir) - except: - # cleanup - f.close() - os.rmdir(dir) - raise - - def test_multiple_close(self): - # A TemporaryFile can be closed many times without error - f = tempfile.TemporaryFile() - f.write(b'abc\n') - f.close() - f.close() - f.close() - - # How to test the mode and bufsize parameters? - def test_mode_and_encoding(self): - - def roundtrip(input, *args, **kwargs): - with tempfile.TemporaryFile(*args, **kwargs) as fileobj: - fileobj.write(input) - fileobj.seek(0) - self.assertEqual(input, fileobj.read()) - - roundtrip(b"1234", "w+b") - roundtrip("abdc\n", "w+") - roundtrip("\u039B", "w+", encoding="utf-16") - roundtrip("foo\r\n", "w+", newline="") - if tempfile.NamedTemporaryFile is not tempfile.TemporaryFile: - test_classes.append(test_TemporaryFile) + + class TestTemporaryFile(BaseTestCase): + """Test TemporaryFile().""" + + def test_basic(self): + # TemporaryFile can create files + # No point in testing the name params - the file has no name. + tempfile.TemporaryFile() + + def test_has_no_name(self): + # TemporaryFile creates files with no names (on this system) + dir = tempfile.mkdtemp() + f = tempfile.TemporaryFile(dir=dir) + f.write(b'blat') + + # Sneaky: because this file has no name, it should not prevent + # us from removing the directory it was created in. + try: + os.rmdir(dir) + except: + # cleanup + f.close() + os.rmdir(dir) + raise + + def test_multiple_close(self): + # A TemporaryFile can be closed many times without error + f = tempfile.TemporaryFile() + f.write(b'abc\n') + f.close() + f.close() + f.close() + + # How to test the mode and bufsize parameters? + def test_mode_and_encoding(self): + + def roundtrip(input, *args, **kwargs): + with tempfile.TemporaryFile(*args, **kwargs) as fileobj: + fileobj.write(input) + fileobj.seek(0) + self.assertEqual(input, fileobj.read()) + + roundtrip(b"1234", "w+b") + roundtrip("abdc\n", "w+") + roundtrip("\u039B", "w+", encoding="utf-16") + roundtrip("foo\r\n", "w+", newline="") # Helper for test_del_on_shutdown @@ -929,7 +903,7 @@ d.clear() d.update(c) -class test_TemporaryDirectory(TC): +class TestTemporaryDirectory(BaseTestCase): """Test TemporaryDirectory().""" def do_create(self, dir=None, pre="", suf="", recurse=1): @@ -1071,10 +1045,8 @@ self.assertFalse(os.path.exists(name)) -test_classes.append(test_TemporaryDirectory) - def test_main(): - support.run_unittest(*test_classes) + support.run_unittest(__name__) if __name__ == "__main__": test_main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 17:15:38 2012 From: python-checkins at python.org (mark.dickinson) Date: Sat, 10 Mar 2012 17:15:38 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogQ2xvc2VzICM5NTc0?= =?utf8?q?=3A_Note_that_complex_constructor_doesn=27t_allow_whitespace_aro?= =?utf8?q?und?= Message-ID: http://hg.python.org/cpython/rev/5a3c89337b50 changeset: 75517:5a3c89337b50 branch: 2.7 parent: 75500:f8efcca7e90f user: Mark Dickinson date: Sat Mar 10 16:09:35 2012 +0000 summary: Closes #9574: Note that complex constructor doesn't allow whitespace around central operator. files: Doc/library/functions.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -247,6 +247,13 @@ the function serves as a numeric conversion function like :func:`int`, :func:`long` and :func:`float`. If both arguments are omitted, returns ``0j``. + .. note:: + + When converting from a string, the string must not contain whitespace + around the central ``+`` or ``-`` operator. For example, + ``complex('1+2j')`` is fine, but ``complex('1 + 2j')`` raises + :exc:`ValueError`. + The complex type is described in :ref:`typesnumeric`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 17:15:40 2012 From: python-checkins at python.org (mark.dickinson) Date: Sat, 10 Mar 2012 17:15:40 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogQ2xvc2VzICM5NTc0?= =?utf8?q?=3A_Note_that_complex_constructor_doesn=27t_allow_whitespace_aro?= =?utf8?q?und?= Message-ID: http://hg.python.org/cpython/rev/a5b073b1cfea changeset: 75518:a5b073b1cfea branch: 3.2 parent: 75513:b96251d9f36a user: Mark Dickinson date: Sat Mar 10 16:09:35 2012 +0000 summary: Closes #9574: Note that complex constructor doesn't allow whitespace around central operator. files: Doc/library/functions.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -247,6 +247,13 @@ the function serves as a numeric conversion function like :func:`int` and :func:`float`. If both arguments are omitted, returns ``0j``. + .. note:: + + When converting from a string, the string must not contain whitespace + around the central ``+`` or ``-`` operator. For example, + ``complex('1+2j')`` is fine, but ``complex('1 + 2j')`` raises + :exc:`ValueError`. + The complex type is described in :ref:`typesnumeric`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 17:15:41 2012 From: python-checkins at python.org (mark.dickinson) Date: Sat, 10 Mar 2012 17:15:41 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiBtZXJnZSAzLjIgKCM5NTc0KQ==?= Message-ID: http://hg.python.org/cpython/rev/2f48415e917c changeset: 75519:2f48415e917c parent: 75516:b7121ab1107c parent: 75518:a5b073b1cfea user: Mark Dickinson date: Sat Mar 10 16:11:49 2012 +0000 summary: merge 3.2 (#9574) files: Doc/library/functions.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -243,6 +243,13 @@ the function serves as a numeric conversion function like :func:`int` and :func:`float`. If both arguments are omitted, returns ``0j``. + .. note:: + + When converting from a string, the string must not contain whitespace + around the central ``+`` or ``-`` operator. For example, + ``complex('1+2j')`` is fine, but ``complex('1 + 2j')`` raises + :exc:`ValueError`. + The complex type is described in :ref:`typesnumeric`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 19:54:16 2012 From: python-checkins at python.org (lukasz.langa) Date: Sat, 10 Mar 2012 19:54:16 +0100 Subject: [Python-checkins] =?utf8?q?devguide=3A_added_asterisk_to_my_name_?= =?utf8?q?to_indicate_I_can_be_assigned_to_configparser_issues?= Message-ID: http://hg.python.org/devguide/rev/8c9d51fcf1a0 changeset: 493:8c9d51fcf1a0 user: ?ukasz Langa date: Sat Mar 10 19:54:10 2012 +0100 summary: added asterisk to my name to indicate I can be assigned to configparser issues files: experts.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -80,7 +80,7 @@ colorsys compileall concurrent.futures bquinlan -configparser lukasz.langa +configparser lukasz.langa* contextlib ncoghlan copy alexandre.vassalotti copyreg alexandre.vassalotti -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Mar 10 20:52:21 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 10 Mar 2012 20:52:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_=2314248=3A_fix_typo?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/9afbb3af1693 changeset: 75520:9afbb3af1693 user: Georg Brandl date: Sat Mar 10 20:52:16 2012 +0100 summary: Close #14248: fix typo. files: Doc/whatsnew/3.3.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -475,7 +475,7 @@ (:issue:`12170`) * A dict lookup now raises a :exc:`RuntimeError` if the dict is modified during - the lookup. If you implement your own comparaison function for objects used + the lookup. If you implement your own comparison function for objects used as dict keys and the dict is shared by multiple threads, access to the dict should be protected by a lock. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 22:36:53 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 10 Mar 2012 22:36:53 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_=2314210=3A_add_comma?= =?utf8?q?nd_argument_completion_to_pdb=3A_complete_file_names=2C?= Message-ID: http://hg.python.org/cpython/rev/01a25f638c83 changeset: 75521:01a25f638c83 user: Georg Brandl date: Sat Mar 10 22:36:48 2012 +0100 summary: Close #14210: add command argument completion to pdb: complete file names, global/local variables, aliases files: Doc/library/pdb.rst | 5 + Doc/whatsnew/3.3.rst | 8 ++ Lib/pdb.py | 95 ++++++++++++++++++++++++++++++++ Misc/NEWS | 3 + 4 files changed, 111 insertions(+), 0 deletions(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -38,6 +38,11 @@ > (1)?() (Pdb) +.. versionchanged:: 3.3 + Tab-completion via the :mod:`readline` module is available for commands and + command arguments, e.g. the current global and local names are offered as + arguments of the ``print`` command. + :file:`pdb.py` can also be invoked as a script to debug other scripts. For example:: diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -777,6 +777,14 @@ .. TODO add examples and howto to the packaging docs and link to them +pdb +--- + +* Tab-completion is now available not only for command names, but also their + arguments. For example, for the ``break`` command, function and file names + are completed. (Contributed by Georg Brandl in :issue:`14210`) + + pydoc ----- diff --git a/Lib/pdb.py b/Lib/pdb.py --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -73,6 +73,7 @@ import bdb import dis import code +import glob import pprint import signal import inspect @@ -155,6 +156,8 @@ # Try to load readline if it exists try: import readline + # remove some common file name delimiters + readline.set_completer_delims(' \t\n`@#$%^&*()=+[{]}\\|;:\'",<>?') except ImportError: pass self.allow_kbdint = False @@ -445,6 +448,61 @@ def error(self, msg): print('***', msg, file=self.stdout) + # Generic completion functions. Individual complete_foo methods can be + # assigned below to one of these functions. + + def _complete_location(self, text, line, begidx, endidx): + # Complete a file/module/function location for break/tbreak/clear. + if line.strip().endswith((':', ',')): + # Here comes a line number or a condition which we can't complete. + return [] + # First, try to find matching functions (i.e. expressions). + try: + ret = self._complete_expression(text, line, begidx, endidx) + except Exception: + ret = [] + # Then, try to complete file names as well. + globs = glob.glob(text + '*') + for fn in globs: + if os.path.isdir(fn): + ret.append(fn + '/') + elif os.path.isfile(fn) and fn.lower().endswith(('.py', '.pyw')): + ret.append(fn + ':') + return ret + + def _complete_bpnumber(self, text, line, begidx, endidx): + # Complete a breakpoint number. (This would be more helpful if we could + # display additional info along with the completions, such as file/line + # of the breakpoint.) + return [str(i) for i, bp in enumerate(bdb.Breakpoint.bpbynumber) + if bp is not None and str(i).startswith(text)] + + def _complete_expression(self, text, line, begidx, endidx): + # Complete an arbitrary expression. + if not self.curframe: + return [] + # Collect globals and locals. It is usually not really sensible to also + # complete builtins, and they clutter the namespace quite heavily, so we + # leave them out. + ns = self.curframe.f_globals.copy() + ns.update(self.curframe_locals) + if '.' in text: + # Walk an attribute chain up to the last part, similar to what + # rlcompleter does. This will bail if any of the parts are not + # simple attribute access, which is what we want. + dotted = text.split('.') + try: + obj = ns[dotted[0]] + for part in dotted[1:-1]: + obj = getattr(obj, part) + except (KeyError, AttributeError): + return [] + prefix = '.'.join(dotted[:-1]) + '.' + return [prefix + n for n in dir(obj) if n.startswith(dotted[-1])] + else: + # Complete a simple name. + return [n for n in ns.keys() if n.startswith(text)] + # Command definitions, called by cmdloop() # The argument is the remaining string on the command line # Return true to exit from the command loop @@ -526,6 +584,8 @@ self.commands_defining = False self.prompt = prompt_back + complete_commands = _complete_bpnumber + def do_break(self, arg, temporary = 0): """b(reak) [ ([filename:]lineno | function) [, condition] ] Without argument, list all breaks. @@ -628,6 +688,9 @@ do_b = do_break + complete_break = _complete_location + complete_b = _complete_location + def do_tbreak(self, arg): """tbreak [ ([filename:]lineno | function) [, condition] ] Same arguments as break, but sets a temporary breakpoint: it @@ -635,6 +698,8 @@ """ self.do_break(arg, 1) + complete_tbreak = _complete_location + def lineinfo(self, identifier): failed = (None, None, None) # Input is identifier, may be in single quotes @@ -704,6 +769,8 @@ bp.enable() self.message('Enabled %s' % bp) + complete_enable = _complete_bpnumber + def do_disable(self, arg): """disable bpnumber [bpnumber ...] Disables the breakpoints given as a space separated list of @@ -722,6 +789,8 @@ bp.disable() self.message('Disabled %s' % bp) + complete_disable = _complete_bpnumber + def do_condition(self, arg): """condition bpnumber [condition] Set a new condition for the breakpoint, an expression which @@ -745,6 +814,8 @@ else: self.message('New condition set for breakpoint %d.' % bp.number) + complete_condition = _complete_bpnumber + def do_ignore(self, arg): """ignore bpnumber [count] Set the ignore count for the given breakpoint number. If @@ -776,6 +847,8 @@ self.message('Will stop next time breakpoint %d is reached.' % bp.number) + complete_ignore = _complete_bpnumber + def do_clear(self, arg): """cl(ear) filename:lineno\ncl(ear) [bpnumber [bpnumber...]] With a space separated list of breakpoint numbers, clear @@ -824,6 +897,9 @@ self.message('Deleted %s' % bp) do_cl = do_clear # 'c' is already an abbreviation for 'continue' + complete_clear = _complete_location + complete_cl = _complete_location + def do_where(self, arg): """w(here) Print a stack trace, with the most recent frame at the bottom. @@ -1007,6 +1083,8 @@ sys.settrace(self.trace_dispatch) self.lastcmd = p.lastcmd + complete_debug = _complete_expression + def do_quit(self, arg): """q(uit)\nexit Quit from the debugger. The program being executed is aborted. @@ -1093,6 +1171,10 @@ except: pass + complete_print = _complete_expression + complete_p = _complete_expression + complete_pp = _complete_expression + def do_list(self, arg): """l(ist) [first [,last] | .] @@ -1173,6 +1255,8 @@ return self._print_lines(lines, lineno) + complete_source = _complete_expression + def _print_lines(self, lines, start, breaks=(), frame=None): """Print a range of lines.""" if frame: @@ -1227,6 +1311,8 @@ # None of the above... self.message(type(value)) + complete_whatis = _complete_expression + def do_display(self, arg): """display [expression] @@ -1244,6 +1330,8 @@ self.displaying.setdefault(self.curframe, {})[arg] = val self.message('display %s: %r' % (arg, val)) + complete_display = _complete_expression + def do_undisplay(self, arg): """undisplay [expression] @@ -1259,6 +1347,10 @@ else: self.displaying.pop(self.curframe, None) + def complete_undisplay(self, text, line, begidx, endidx): + return [e for e in self.displaying.get(self.curframe, {}) + if e.startswith(text)] + def do_interact(self, arg): """interact @@ -1313,6 +1405,9 @@ if args[0] in self.aliases: del self.aliases[args[0]] + def complete_unalias(self, text, line, begidx, endidx): + return [a for a in self.aliases if a.startswith(text)] + # List of all the commands making the program resume execution. commands_resuming = ['do_continue', 'do_step', 'do_next', 'do_return', 'do_quit', 'do_jump'] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,9 @@ data or close method) for the Python implementation as well. Drop the no-op TreeBuilder().xml() method from the C implementation. +- Issue #14210: pdb now has tab-completion not only for command names, but + also for their arguments, wherever possible. + Extension Modules ----------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 10 23:11:14 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 10 Mar 2012 23:11:14 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_add_bugfix_releases?= Message-ID: http://hg.python.org/peps/rev/d168f7ada371 changeset: 4125:d168f7ada371 user: Benjamin Peterson date: Sat Mar 10 14:11:10 2012 -0800 summary: add bugfix releases files: pep-0373.txt | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/pep-0373.txt b/pep-0373.txt --- a/pep-0373.txt +++ b/pep-0373.txt @@ -46,6 +46,13 @@ - 2.7 rc2 2010-06-19 - 2.7 final 2010-07-03 +Maintenance releases +==================== + +- 2.7.1 2010-11-27 +- 2.7.2 2011-07-21 +- 2.7.3rc1 2012-02-23 + Possible features for 2.7 ========================= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 10 23:48:46 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 10 Mar 2012 23:48:46 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_regression_after_c8d1df?= =?utf8?q?9ac987?= Message-ID: http://hg.python.org/cpython/rev/713db33a4ebc changeset: 75522:713db33a4ebc user: Antoine Pitrou date: Sat Mar 10 23:43:12 2012 +0100 summary: Fix regression after c8d1df9ac987 (PPC buildbot) files: Include/genobject.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Include/genobject.h b/Include/genobject.h --- a/Include/genobject.h +++ b/Include/genobject.h @@ -18,7 +18,7 @@ struct _frame *gi_frame; /* True if generator is being executed. */ - int gi_running; + char gi_running; /* The code object backing the generator */ PyObject *gi_code; -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Mar 11 05:38:27 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 11 Mar 2012 05:38:27 +0100 Subject: [Python-checkins] Daily reference leaks (713db33a4ebc): sum=0 Message-ID: results for 713db33a4ebc on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog2BbA0F', '-x'] From python-checkins at python.org Sun Mar 11 18:23:18 2012 From: python-checkins at python.org (ross.lagerwall) Date: Sun, 11 Mar 2012 18:23:18 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Modify_patchcheck=2Epy_to_c?= =?utf8?q?heck_for_changes_to_configure=2Ein=2E?= Message-ID: http://hg.python.org/cpython/rev/8ecd1a1c7dfc changeset: 75523:8ecd1a1c7dfc user: Ross Lagerwall date: Sun Mar 11 19:21:07 2012 +0200 summary: Modify patchcheck.py to check for changes to configure.in. It now reports if configure and pyconfig.h.in weren't regenerated but configure.in was changed. files: Tools/scripts/patchcheck.py | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+), 0 deletions(-) diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py --- a/Tools/scripts/patchcheck.py +++ b/Tools/scripts/patchcheck.py @@ -132,6 +132,21 @@ """Check if Misc/NEWS has been changed.""" return 'Misc/NEWS' in file_paths + at status("configure regenerated", modal=True, info=str) +def regenerated_configure(file_paths): + """Check if configure has been regenerated.""" + if 'configure.in' in file_paths: + return "yes" if 'configure' in file_paths else "no" + else: + return "not needed" + + at status("pyconfig.h.in regenerated", modal=True, info=str) +def regenerated_pyconfig_h_in(file_paths): + """Check if pyconfig.h.in has been regenerated.""" + if 'configure.in' in file_paths: + return "yes" if 'pyconfig.h.in' in file_paths else "no" + else: + return "not needed" def main(): file_paths = changed_files() @@ -151,6 +166,10 @@ credit_given(special_files) # Misc/NEWS changed. reported_news(special_files) + # Regenerated configure, if necessary. + regenerated_configure(file_paths) + # Regenerated pyconfig.h.in, if necessary. + regenerated_pyconfig_h_in(file_paths) # Test suite run and passed. if python_files or c_files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 11 18:24:09 2012 From: python-checkins at python.org (ross.lagerwall) Date: Sun, 11 Mar 2012 18:24:09 +0100 Subject: [Python-checkins] =?utf8?q?devguide=3A_Issue_7997=3A_Explain_how_?= =?utf8?q?to_regenerate_configure_using_Autoconf=2E?= Message-ID: http://hg.python.org/devguide/rev/5432be4d4e1a changeset: 494:5432be4d4e1a user: Ross Lagerwall date: Sun Mar 11 19:22:40 2012 +0200 summary: Issue 7997: Explain how to regenerate configure using Autoconf. Based on info written by David Malcolm. files: committing.rst | 2 + patch.rst | 56 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 0 deletions(-) diff --git a/committing.rst b/committing.rst --- a/committing.rst +++ b/committing.rst @@ -32,6 +32,8 @@ * Has the test suite been updated? * Has ``Misc/NEWS`` been updated? * Has ``Misc/ACKS`` been updated? +* Has ``configure`` been regenerated, if necessary? +* Has ``pyconfig.h.in`` been regenerated, if necessary? * Has the test suite been run? Note that the automated patch check can't actually *answer* all of these diff --git a/patch.rst b/patch.rst --- a/patch.rst +++ b/patch.rst @@ -137,6 +137,62 @@ Also, please make sure your patch is whitespace normalized. ``patchcheck`` will check this for you. +Autoconf +'''''''' + +If a change is made to Python which relies on some POSIX system-specific +functionality (such as using a new system call), it is necessary to update the +``configure`` script to test for availability of the functionality. + +Python's ``configure`` script is generated from ``configure.in`` using Autoconf. +Instead of editing ``configure``, edit ``configure.in`` and then run +``autoreconf`` to regenerate ``configure`` and a number of other files (such as +``pyconfig.h``. + +When submitting a patch with changes made to ``configure.in``, it is preferred +to leave out the generated files as differences between Autoconf versions +frequently results in many spurious changes cluttering the patch. Instead, +remind any potential reviewers on the tracker to run ``autoreconf``. + +Note that running ``autoreconf`` is not the same as running ``autoconf``. For +example, ``autoconf`` by itself will not regenerate ``pyconfig.h.in``. +``autoreconf`` runs ``autoconf`` and a number of other tools repeatedly as is +appropriate. + +Python's ``configure.in`` script typically requires a specific version of +Autoconf. At the moment, this reads: ``version_required(2.65)`` + +If the system copy of Autoconf does not match this version, you will need to +install your own copy of Autoconf: + +1. Go to http://ftp.gnu.org/gnu/autoconf/ and download the version of Autoconf + matching the one in ``configure.in``:: + + wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.65.tar.bz2 + +2. Unpack the tarball:: + + tar -jxf autoconf-2.65.tar.bz2 + +3. Build the specified version of Autoconf and install it to a writable location + (e.g. within your home directory):: + + pushd autoconf-2.65.tar.bz2 + ./configure --prefix=$HOME/autoconf-2.65 + make + make install + + This installs a copy of the appropriate version of Autoconf into + ~/autoconf-2.65. + +4. Go back to the Python source and rerun ``autoreconf``, pointing ``PATH`` at + the newly installed copy of Autoconf:: + + popd + PATH=~/autoconf-2.65/bin:$PATH autoreconf + +5. Autoconf should now have updated your local copy of ``configure`` to reflect + your changes. Submitting ---------- -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Mar 11 19:37:52 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 11 Mar 2012 19:37:52 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MjUy?= =?utf8?q?=3A_Fix_subprocess=2EPopen=2Eterminate=28=29_to_not_raise_an_err?= =?utf8?q?or_under?= Message-ID: http://hg.python.org/cpython/rev/41b1fe5a75a6 changeset: 75524:41b1fe5a75a6 branch: 3.2 parent: 75518:a5b073b1cfea user: Antoine Pitrou date: Sun Mar 11 19:29:12 2012 +0100 summary: Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under Windows when the child process has already exited. files: Lib/subprocess.py | 12 ++++- Lib/test/test_subprocess.py | 67 +++++++++++++++++++++++++ Misc/NEWS | 3 + PC/_subprocess.c | 1 + 4 files changed, 82 insertions(+), 1 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1075,7 +1075,17 @@ def terminate(self): """Terminates the process """ - _subprocess.TerminateProcess(self._handle, 1) + try: + _subprocess.TerminateProcess(self._handle, 1) + except OSError as e: + # ERROR_ACCESS_DENIED (winerror 5) is received when the + # process already died. + if e.winerror != 5: + raise + rc = _subprocess.GetExitCodeProcess(self._handle) + if rc == _subprocess.STILL_ACTIVE: + raise + self.returncode = rc kill = terminate diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -989,6 +989,27 @@ getattr(p, method)(*args) return p + def _kill_dead_process(self, method, *args): + # Do not inherit file handles from the parent. + # It should fix failures on some platforms. + p = subprocess.Popen([sys.executable, "-c", """if 1: + import sys, time + sys.stdout.write('x\\n') + sys.stdout.flush() + """], + close_fds=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + # Wait for the interpreter to be completely initialized before + # sending any signal. + p.stdout.read(1) + # The process should end after this + time.sleep(1) + # This shouldn't raise even though the child is now dead + getattr(p, method)(*args) + p.communicate() + def test_send_signal(self): p = self._kill_process('send_signal', signal.SIGINT) _, stderr = p.communicate() @@ -1007,6 +1028,18 @@ self.assertStderrEqual(stderr, b'') self.assertEqual(p.wait(), -signal.SIGTERM) + def test_send_signal_dead(self): + # Sending a signal to a dead process + self._kill_dead_process('send_signal', signal.SIGINT) + + def test_kill_dead(self): + # Killing a dead process + self._kill_dead_process('kill') + + def test_terminate_dead(self): + # Terminating a dead process + self._kill_dead_process('terminate') + def check_close_std_fds(self, fds): # Issue #9905: test that subprocess pipes still work properly with # some standard fds closed @@ -1568,6 +1601,31 @@ returncode = p.wait() self.assertNotEqual(returncode, 0) + def _kill_dead_process(self, method, *args): + p = subprocess.Popen([sys.executable, "-c", """if 1: + import sys, time + sys.stdout.write('x\\n') + sys.stdout.flush() + sys.exit(42) + """], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + self.addCleanup(p.stdout.close) + self.addCleanup(p.stderr.close) + self.addCleanup(p.stdin.close) + # Wait for the interpreter to be completely initialized before + # sending any signal. + p.stdout.read(1) + # The process should end after this + time.sleep(1) + # This shouldn't raise even though the child is now dead + getattr(p, method)(*args) + _, stderr = p.communicate() + self.assertStderrEqual(stderr, b'') + rc = p.wait() + self.assertEqual(rc, 42) + def test_send_signal(self): self._kill_process('send_signal', signal.SIGTERM) @@ -1577,6 +1635,15 @@ def test_terminate(self): self._kill_process('terminate') + def test_send_signal_dead(self): + self._kill_dead_process('send_signal', signal.SIGTERM) + + def test_kill_dead(self): + self._kill_dead_process('kill') + + def test_terminate_dead(self): + self._kill_dead_process('terminate') + # The module says: # "NB This only works (and is only relevant) for UNIX." diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,9 @@ Library ------- +- Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under + Windows when the child process has already exited. + - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been fixed. diff --git a/PC/_subprocess.c b/PC/_subprocess.c --- a/PC/_subprocess.c +++ b/PC/_subprocess.c @@ -684,6 +684,7 @@ defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0); defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE); defint(d, "CREATE_NEW_PROCESS_GROUP", CREATE_NEW_PROCESS_GROUP); + defint(d, "STILL_ACTIVE", STILL_ACTIVE); return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 11 19:37:53 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 11 Mar 2012 19:37:53 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314252=3A_Fix_subprocess=2EPopen=2Eterminate=28=29_t?= =?utf8?q?o_not_raise_an_error_under?= Message-ID: http://hg.python.org/cpython/rev/f452d7d5470d changeset: 75525:f452d7d5470d parent: 75523:8ecd1a1c7dfc parent: 75524:41b1fe5a75a6 user: Antoine Pitrou date: Sun Mar 11 19:33:29 2012 +0100 summary: Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under Windows when the child process has already exited. files: Lib/subprocess.py | 10 +++- Lib/test/test_subprocess.py | 67 +++++++++++++++++++++++++ Misc/NEWS | 3 + PC/_subprocess.c | 1 + 4 files changed, 80 insertions(+), 1 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1162,7 +1162,15 @@ def terminate(self): """Terminates the process """ - _subprocess.TerminateProcess(self._handle, 1) + try: + _subprocess.TerminateProcess(self._handle, 1) + except PermissionError: + # ERROR_ACCESS_DENIED (winerror 5) is received when the + # process already died. + rc = _subprocess.GetExitCodeProcess(self._handle) + if rc == _subprocess.STILL_ACTIVE: + raise + self.returncode = rc kill = terminate diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1078,6 +1078,27 @@ getattr(p, method)(*args) return p + def _kill_dead_process(self, method, *args): + # Do not inherit file handles from the parent. + # It should fix failures on some platforms. + p = subprocess.Popen([sys.executable, "-c", """if 1: + import sys, time + sys.stdout.write('x\\n') + sys.stdout.flush() + """], + close_fds=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + # Wait for the interpreter to be completely initialized before + # sending any signal. + p.stdout.read(1) + # The process should end after this + time.sleep(1) + # This shouldn't raise even though the child is now dead + getattr(p, method)(*args) + p.communicate() + def test_send_signal(self): p = self._kill_process('send_signal', signal.SIGINT) _, stderr = p.communicate() @@ -1096,6 +1117,18 @@ self.assertStderrEqual(stderr, b'') self.assertEqual(p.wait(), -signal.SIGTERM) + def test_send_signal_dead(self): + # Sending a signal to a dead process + self._kill_dead_process('send_signal', signal.SIGINT) + + def test_kill_dead(self): + # Killing a dead process + self._kill_dead_process('kill') + + def test_terminate_dead(self): + # Terminating a dead process + self._kill_dead_process('terminate') + def check_close_std_fds(self, fds): # Issue #9905: test that subprocess pipes still work properly with # some standard fds closed @@ -1662,6 +1695,31 @@ returncode = p.wait() self.assertNotEqual(returncode, 0) + def _kill_dead_process(self, method, *args): + p = subprocess.Popen([sys.executable, "-c", """if 1: + import sys, time + sys.stdout.write('x\\n') + sys.stdout.flush() + sys.exit(42) + """], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + self.addCleanup(p.stdout.close) + self.addCleanup(p.stderr.close) + self.addCleanup(p.stdin.close) + # Wait for the interpreter to be completely initialized before + # sending any signal. + p.stdout.read(1) + # The process should end after this + time.sleep(1) + # This shouldn't raise even though the child is now dead + getattr(p, method)(*args) + _, stderr = p.communicate() + self.assertStderrEqual(stderr, b'') + rc = p.wait() + self.assertEqual(rc, 42) + def test_send_signal(self): self._kill_process('send_signal', signal.SIGTERM) @@ -1671,6 +1729,15 @@ def test_terminate(self): self._kill_process('terminate') + def test_send_signal_dead(self): + self._kill_dead_process('send_signal', signal.SIGTERM) + + def test_kill_dead(self): + self._kill_dead_process('kill') + + def test_terminate_dead(self): + self._kill_dead_process('terminate') + # The module says: # "NB This only works (and is only relevant) for UNIX." diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,9 @@ Library ------- +- Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under + Windows when the child process has already exited. + - Issue #14223: curses.addch() is no more limited to the range 0-255 when the Python curses is not linked to libncursesw. It was a regression introduced in Python 3.3a1. diff --git a/PC/_subprocess.c b/PC/_subprocess.c --- a/PC/_subprocess.c +++ b/PC/_subprocess.c @@ -691,6 +691,7 @@ defint(d, "WAIT_TIMEOUT", WAIT_TIMEOUT); defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE); defint(d, "CREATE_NEW_PROCESS_GROUP", CREATE_NEW_PROCESS_GROUP); + defint(d, "STILL_ACTIVE", STILL_ACTIVE); return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 11 19:45:18 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 11 Mar 2012 19:45:18 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0MjUy?= =?utf8?q?=3A_Fix_subprocess=2EPopen=2Eterminate=28=29_to_not_raise_an_err?= =?utf8?q?or_under?= Message-ID: http://hg.python.org/cpython/rev/b6ec3b717f7e changeset: 75526:b6ec3b717f7e branch: 2.7 parent: 75517:5a3c89337b50 user: Antoine Pitrou date: Sun Mar 11 19:29:12 2012 +0100 summary: Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under Windows when the child process has already exited. files: Lib/subprocess.py | 12 ++++- Lib/test/test_subprocess.py | 67 +++++++++++++++++++++++++ Misc/NEWS | 3 + PC/_subprocess.c | 1 + 4 files changed, 82 insertions(+), 1 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1016,7 +1016,17 @@ def terminate(self): """Terminates the process """ - _subprocess.TerminateProcess(self._handle, 1) + try: + _subprocess.TerminateProcess(self._handle, 1) + except OSError as e: + # ERROR_ACCESS_DENIED (winerror 5) is received when the + # process already died. + if e.winerror != 5: + raise + rc = _subprocess.GetExitCodeProcess(self._handle) + if rc == _subprocess.STILL_ACTIVE: + raise + self.returncode = rc kill = terminate diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -812,6 +812,27 @@ getattr(p, method)(*args) return p + def _kill_dead_process(self, method, *args): + # Do not inherit file handles from the parent. + # It should fix failures on some platforms. + p = subprocess.Popen([sys.executable, "-c", """if 1: + import sys, time + sys.stdout.write('x\\n') + sys.stdout.flush() + """], + close_fds=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + # Wait for the interpreter to be completely initialized before + # sending any signal. + p.stdout.read(1) + # The process should end after this + time.sleep(1) + # This shouldn't raise even though the child is now dead + getattr(p, method)(*args) + p.communicate() + def test_send_signal(self): p = self._kill_process('send_signal', signal.SIGINT) _, stderr = p.communicate() @@ -830,6 +851,18 @@ self.assertStderrEqual(stderr, '') self.assertEqual(p.wait(), -signal.SIGTERM) + def test_send_signal_dead(self): + # Sending a signal to a dead process + self._kill_dead_process('send_signal', signal.SIGINT) + + def test_kill_dead(self): + # Killing a dead process + self._kill_dead_process('kill') + + def test_terminate_dead(self): + # Terminating a dead process + self._kill_dead_process('terminate') + def check_close_std_fds(self, fds): # Issue #9905: test that subprocess pipes still work properly with # some standard fds closed @@ -1126,6 +1159,31 @@ returncode = p.wait() self.assertNotEqual(returncode, 0) + def _kill_dead_process(self, method, *args): + p = subprocess.Popen([sys.executable, "-c", """if 1: + import sys, time + sys.stdout.write('x\\n') + sys.stdout.flush() + sys.exit(42) + """], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + self.addCleanup(p.stdout.close) + self.addCleanup(p.stderr.close) + self.addCleanup(p.stdin.close) + # Wait for the interpreter to be completely initialized before + # sending any signal. + p.stdout.read(1) + # The process should end after this + time.sleep(1) + # This shouldn't raise even though the child is now dead + getattr(p, method)(*args) + _, stderr = p.communicate() + self.assertStderrEqual(stderr, b'') + rc = p.wait() + self.assertEqual(rc, 42) + def test_send_signal(self): self._kill_process('send_signal', signal.SIGTERM) @@ -1135,6 +1193,15 @@ def test_terminate(self): self._kill_process('terminate') + def test_send_signal_dead(self): + self._kill_dead_process('send_signal', signal.SIGTERM) + + def test_kill_dead(self): + self._kill_dead_process('kill') + + def test_terminate_dead(self): + self._kill_dead_process('terminate') + @unittest.skipUnless(getattr(subprocess, '_has_poll', False), "poll system call not supported") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under + Windows when the child process has already exited. + - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been fixed. diff --git a/PC/_subprocess.c b/PC/_subprocess.c --- a/PC/_subprocess.c +++ b/PC/_subprocess.c @@ -670,4 +670,5 @@ defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0); defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE); defint(d, "CREATE_NEW_PROCESS_GROUP", CREATE_NEW_PROCESS_GROUP); + defint(d, "STILL_ACTIVE", STILL_ACTIVE); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 00:17:17 2012 From: python-checkins at python.org (ezio.melotti) Date: Mon, 12 Mar 2012 00:17:17 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzE0MTYxOiBmaXgg?= =?utf8?q?the_=5F=5Frepr=5F=5F_of_file_objects_to_escape_the_file_name=2E?= Message-ID: http://hg.python.org/cpython/rev/6c1964dee98b changeset: 75527:6c1964dee98b branch: 2.7 user: Ezio Melotti date: Mon Mar 12 01:17:02 2012 +0200 summary: #14161: fix the __repr__ of file objects to escape the file name. files: Lib/test/test_file2k.py | 7 +++++++ Misc/NEWS | 2 ++ Objects/fileobject.c | 14 ++++++++++---- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_file2k.py b/Lib/test/test_file2k.py --- a/Lib/test/test_file2k.py +++ b/Lib/test/test_file2k.py @@ -89,6 +89,13 @@ def testRepr(self): # verify repr works self.assertTrue(repr(self.f).startswith("f_name)) { #ifdef Py_USING_UNICODE - PyObject *ret = NULL; - PyObject *name = PyUnicode_AsUnicodeEscapeString(f->f_name); + name = PyUnicode_AsUnicodeEscapeString(f->f_name); const char *name_str = name ? PyString_AsString(name) : "?"; ret = PyString_FromFormat("<%s file u'%s', mode '%s' at %p>", f->f_fp == NULL ? "closed" : "open", @@ -649,11 +650,16 @@ return ret; #endif } else { - return PyString_FromFormat("<%s file '%s', mode '%s' at %p>", + name = PyObject_Repr(f->f_name); + if (name == NULL) + return NULL; + ret = PyString_FromFormat("<%s file %s, mode '%s' at %p>", f->f_fp == NULL ? "closed" : "open", - PyString_AsString(f->f_name), + PyString_AsString(name), PyString_AsString(f->f_mode), f); + Py_XDECREF(name); + return ret; } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 00:29:02 2012 From: python-checkins at python.org (ezio.melotti) Date: Mon, 12 Mar 2012 00:29:02 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzE0MTYxOiBmaXgg?= =?utf8?q?compile_error_under_Windows=2E?= Message-ID: http://hg.python.org/cpython/rev/86c749151660 changeset: 75528:86c749151660 branch: 2.7 user: Ezio Melotti date: Mon Mar 12 01:28:45 2012 +0200 summary: #14161: fix compile error under Windows. files: Objects/fileobject.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Objects/fileobject.c b/Objects/fileobject.c --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -639,8 +639,9 @@ PyObject *name = NULL; if (PyUnicode_Check(f->f_name)) { #ifdef Py_USING_UNICODE + const char *name_str; name = PyUnicode_AsUnicodeEscapeString(f->f_name); - const char *name_str = name ? PyString_AsString(name) : "?"; + name_str = name ? PyString_AsString(name) : "?"; ret = PyString_FromFormat("<%s file u'%s', mode '%s' at %p>", f->f_fp == NULL ? "closed" : "open", name_str, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 01:09:16 2012 From: python-checkins at python.org (ezio.melotti) Date: Mon, 12 Mar 2012 01:09:16 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzE0MTYxOiBmaXgg?= =?utf8?q?test_failures_on_Windows=2E?= Message-ID: http://hg.python.org/cpython/rev/6b1fad34d893 changeset: 75529:6b1fad34d893 branch: 2.7 user: Ezio Melotti date: Mon Mar 12 02:09:02 2012 +0200 summary: #14161: fix test failures on Windows. files: Lib/test/test_repr.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_repr.py b/Lib/test/test_repr.py --- a/Lib/test/test_repr.py +++ b/Lib/test/test_repr.py @@ -130,10 +130,10 @@ def test_file(self): fp = open(unittest.__file__) self.assertTrue(repr(fp).startswith( - " http://hg.python.org/cpython/rev/2d2a972b7523 changeset: 75530:2d2a972b7523 branch: 2.7 user: Senthil Kumaran date: Sun Mar 11 20:37:39 2012 -0700 summary: Fix closes issue14258 - added clarification to \W and \S flags files: Doc/library/re.rst | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -361,12 +361,12 @@ character properties database. ``\S`` - When the :const:`LOCALE` and :const:`UNICODE` flags are not specified, matches - any non-whitespace character; this is equivalent to the set ``[^ \t\n\r\f\v]`` - With :const:`LOCALE`, it will match any character not in this set, and not - defined as space in the current locale. If :const:`UNICODE` is set, this will - match anything other than ``[ \t\n\r\f\v]`` and characters marked as space in - the Unicode character properties database. + When the :const:`LOCALE` and :const:`UNICODE` flags are not specified, + matches any non-whitespace character; this is equivalent to the set ``[^ + \t\n\r\f\v]`` With :const:`LOCALE`, it will match the above set plus any + non-space character in the current locale. If :const:`UNICODE` is set, the + above set ``[^ \t\n\r\f\v]`` plus the characters not marked as space in the + Unicode character properties database. ``\w`` When the :const:`LOCALE` and :const:`UNICODE` flags are not specified, matches @@ -381,12 +381,16 @@ any non-alphanumeric character; this is equivalent to the set ``[^a-zA-Z0-9_]``. With :const:`LOCALE`, it will match any character not in the set ``[0-9_]``, and not defined as alphanumeric for the current locale. If :const:`UNICODE` is set, - this will match anything other than ``[0-9_]`` and characters marked as - alphanumeric in the Unicode character properties database. + this will match anything other than ``[0-9_]`` plus characters classied as + not alphanumeric in the Unicode character properties database. ``\Z`` Matches only at the end of the string. +If both :const:`LOCALE` and :const:`UNICODE` flags are included for a +particular sequence, then :const:`LOCALE` flag takes effect first followed by +the :const:`UNICODE`. + Most of the standard escapes supported by Python string literals are also accepted by the regular expression parser:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 05:06:14 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 12 Mar 2012 05:06:14 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_closes_issue142?= =?utf8?q?57_minor_error_in_glossary_wording_regarding_=5F=5Fhash=5F=5F?= Message-ID: http://hg.python.org/cpython/rev/f0a5f39615c8 changeset: 75531:f0a5f39615c8 branch: 2.7 user: Senthil Kumaran date: Sun Mar 11 21:04:05 2012 -0700 summary: closes issue14257 minor error in glossary wording regarding __hash__ files: Doc/glossary.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -153,7 +153,7 @@ dictionary An associative array, where arbitrary keys are mapped to values. The keys - can be any object with :meth:`__hash__` function and :meth:`__eq__` + can be any object with :meth:`__hash__` method and :meth:`__eq__` methods. Called a hash in Perl. docstring -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 05:06:16 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 12 Mar 2012 05:06:16 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_closes_issue142?= =?utf8?q?57_-_3=2E2_minor_error_in_glossary_wording_regarding_=5F=5Fhash?= =?utf8?b?X18=?= Message-ID: http://hg.python.org/cpython/rev/3f15c069454d changeset: 75532:3f15c069454d branch: 3.2 parent: 75524:41b1fe5a75a6 user: Senthil Kumaran date: Sun Mar 11 21:04:56 2012 -0700 summary: closes issue14257 - 3.2 minor error in glossary wording regarding __hash__ files: Doc/glossary.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -147,7 +147,7 @@ dictionary An associative array, where arbitrary keys are mapped to values. The keys - can be any object with :meth:`__hash__` function and :meth:`__eq__` + can be any object with :meth:`__hash__` method and :meth:`__eq__` methods. Called a hash in Perl. docstring -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 05:06:17 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 12 Mar 2012 05:06:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_closes_issue14257_-_cpython_-_minor_error_in_glossary_wordin?= =?utf8?q?g_regarding_=5F=5Fhash=5F=5F?= Message-ID: http://hg.python.org/cpython/rev/2b7c39db2150 changeset: 75533:2b7c39db2150 parent: 75525:f452d7d5470d parent: 75532:3f15c069454d user: Senthil Kumaran date: Sun Mar 11 21:06:03 2012 -0700 summary: closes issue14257 - cpython - minor error in glossary wording regarding __hash__ files: Doc/glossary.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -147,7 +147,7 @@ dictionary An associative array, where arbitrary keys are mapped to values. The keys - can be any object with :meth:`__hash__` function and :meth:`__eq__` + can be any object with :meth:`__hash__` method and :meth:`__eq__` methods. Called a hash in Perl. docstring -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Mar 12 05:35:38 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 12 Mar 2012 05:35:38 +0100 Subject: [Python-checkins] Daily reference leaks (f452d7d5470d): sum=0 Message-ID: results for f452d7d5470d on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogBQLBN4', '-x'] From python-checkins at python.org Mon Mar 12 06:47:34 2012 From: python-checkins at python.org (eric.smith) Date: Mon, 12 Mar 2012 06:47:34 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Make_test=5Flogging_no_long?= =?utf8?q?er_fail_if_zlib_not_present=2E_Closes_=2314256=2E_Patch_by?= Message-ID: http://hg.python.org/cpython/rev/4b54a686541f changeset: 75534:4b54a686541f parent: 75525:f452d7d5470d user: Eric V. Smith date: Sun Mar 11 22:46:04 2012 -0700 summary: Make test_logging no longer fail if zlib not present. Closes #14256. Patch by Pedro Kroger. files: Lib/test/test_logging.py | 10 +++++++--- Misc/ACKS | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -39,14 +39,13 @@ import struct import sys import tempfile -from test.support import captured_stdout, run_with_locale, run_unittest, patch -from test.support import TestHandler, Matcher +from test.support import (captured_stdout, run_with_locale, run_unittest, + patch, requires_zlib, TestHandler, Matcher) import textwrap import time import unittest import warnings import weakref -import zlib try: import threading # The following imports are needed only for tests which @@ -70,6 +69,10 @@ except ImportError: win32evtlogutil = None win32evtlog = None +try: + import zlib +except ImportError: + pass class BaseTest(unittest.TestCase): @@ -3602,6 +3605,7 @@ self.assertFalse(os.path.exists(namer(self.fn + ".3"))) rh.close() + @requires_zlib def test_rotator(self): def namer(name): return name + ".gz" diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -559,6 +559,7 @@ Michael Kremer Fabian Kreutz C?dric Krier +Pedro Kroger Hannu Krosing Andrej Krpic Ivan Krsti? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 06:47:38 2012 From: python-checkins at python.org (eric.smith) Date: Mon, 12 Mar 2012 06:47:38 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?b?KTogTWVyZ2Uu?= Message-ID: http://hg.python.org/cpython/rev/b8a14f95453a changeset: 75535:b8a14f95453a parent: 75533:2b7c39db2150 parent: 75534:4b54a686541f user: Eric V. Smith date: Sun Mar 11 22:47:07 2012 -0700 summary: Merge. files: Lib/test/test_logging.py | 10 +++++++--- Misc/ACKS | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -39,14 +39,13 @@ import struct import sys import tempfile -from test.support import captured_stdout, run_with_locale, run_unittest, patch -from test.support import TestHandler, Matcher +from test.support import (captured_stdout, run_with_locale, run_unittest, + patch, requires_zlib, TestHandler, Matcher) import textwrap import time import unittest import warnings import weakref -import zlib try: import threading # The following imports are needed only for tests which @@ -70,6 +69,10 @@ except ImportError: win32evtlogutil = None win32evtlog = None +try: + import zlib +except ImportError: + pass class BaseTest(unittest.TestCase): @@ -3602,6 +3605,7 @@ self.assertFalse(os.path.exists(namer(self.fn + ".3"))) rh.close() + @requires_zlib def test_rotator(self): def namer(name): return name + ".gz" diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -559,6 +559,7 @@ Michael Kremer Fabian Kreutz C?dric Krier +Pedro Kroger Hannu Krosing Andrej Krpic Ivan Krsti? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 17:56:04 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 17:56:04 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_every_other_ast?= =?utf8?q?_object_has_a_dict=2C_so_I_think_AST_should=2C_too?= Message-ID: http://hg.python.org/cpython/rev/15550b5777b9 changeset: 75536:15550b5777b9 branch: 3.2 parent: 75524:41b1fe5a75a6 user: Benjamin Peterson date: Mon Mar 12 09:27:36 2012 -0700 summary: every other ast object has a dict, so I think AST should, too files: Lib/test/test_ast.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -196,9 +196,6 @@ x.vararg with self.assertRaises(AttributeError): - x.foobar = 21 - - with self.assertRaises(AttributeError): ast.AST(lineno=2) with self.assertRaises(TypeError): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 17:56:06 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 17:56:06 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/13f251824b6b changeset: 75537:13f251824b6b branch: 3.2 parent: 75536:15550b5777b9 parent: 75532:3f15c069454d user: Benjamin Peterson date: Mon Mar 12 09:28:26 2012 -0700 summary: merge heads files: Doc/glossary.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -147,7 +147,7 @@ dictionary An associative array, where arbitrary keys are mapped to values. The keys - can be any object with :meth:`__hash__` function and :meth:`__eq__` + can be any object with :meth:`__hash__` method and :meth:`__eq__` methods. Called a hash in Perl. docstring -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 17:56:06 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 17:56:06 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/fd60aab46733 changeset: 75538:fd60aab46733 parent: 75525:f452d7d5470d parent: 75537:13f251824b6b user: Benjamin Peterson date: Mon Mar 12 09:28:36 2012 -0700 summary: merge 3.2 files: Doc/glossary.rst | 2 +- Lib/test/test_ast.py | 3 --- 2 files changed, 1 insertions(+), 4 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -147,7 +147,7 @@ dictionary An associative array, where arbitrary keys are mapped to values. The keys - can be any object with :meth:`__hash__` function and :meth:`__eq__` + can be any object with :meth:`__hash__` method and :meth:`__eq__` methods. Called a hash in Perl. docstring diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -201,9 +201,6 @@ x.vararg with self.assertRaises(AttributeError): - x.foobar = 21 - - with self.assertRaises(AttributeError): ast.AST(lineno=2) with self.assertRaises(TypeError): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 17:56:07 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 17:56:07 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/a4aa5ac6f425 changeset: 75539:a4aa5ac6f425 parent: 75538:fd60aab46733 parent: 75535:b8a14f95453a user: Benjamin Peterson date: Mon Mar 12 09:28:51 2012 -0700 summary: merge heads files: Lib/test/test_logging.py | 10 +++++++--- Misc/ACKS | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -39,14 +39,13 @@ import struct import sys import tempfile -from test.support import captured_stdout, run_with_locale, run_unittest, patch -from test.support import TestHandler, Matcher +from test.support import (captured_stdout, run_with_locale, run_unittest, + patch, requires_zlib, TestHandler, Matcher) import textwrap import time import unittest import warnings import weakref -import zlib try: import threading # The following imports are needed only for tests which @@ -70,6 +69,10 @@ except ImportError: win32evtlogutil = None win32evtlog = None +try: + import zlib +except ImportError: + pass class BaseTest(unittest.TestCase): @@ -3602,6 +3605,7 @@ self.assertFalse(os.path.exists(namer(self.fn + ".3"))) rh.close() + @requires_zlib def test_rotator(self): def namer(name): return name + ".gz" diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -559,6 +559,7 @@ Michael Kremer Fabian Kreutz C?dric Krier +Pedro Kroger Hannu Krosing Andrej Krpic Ivan Krsti? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 17:56:08 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 17:56:08 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_allow_AST_objec?= =?utf8?q?ts_to_be_like_its_subclasses?= Message-ID: http://hg.python.org/cpython/rev/5ed1a3f19ac6 changeset: 75540:5ed1a3f19ac6 branch: 3.2 parent: 75537:13f251824b6b user: Benjamin Peterson date: Mon Mar 12 09:43:09 2012 -0700 summary: allow AST objects to be like its subclasses files: Lib/test/test_ast.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -195,9 +195,6 @@ with self.assertRaises(AttributeError): x.vararg - with self.assertRaises(AttributeError): - ast.AST(lineno=2) - with self.assertRaises(TypeError): # "_ast.AST constructor takes 0 positional arguments" ast.AST(2) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 17:56:09 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 17:56:09 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/8a5742b7a14d changeset: 75541:8a5742b7a14d parent: 75539:a4aa5ac6f425 parent: 75540:5ed1a3f19ac6 user: Benjamin Peterson date: Mon Mar 12 09:43:27 2012 -0700 summary: merge 3.2 files: Lib/test/test_ast.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -200,9 +200,6 @@ with self.assertRaises(AttributeError): x.vararg - with self.assertRaises(AttributeError): - ast.AST(lineno=2) - with self.assertRaises(TypeError): # "_ast.AST constructor takes 0 positional arguments" ast.AST(2) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 17:56:10 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 17:56:10 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_give_the_AST_class_a_=5F=5F?= =?utf8?b?ZGljdF9f?= Message-ID: http://hg.python.org/cpython/rev/3877bf2e3235 changeset: 75542:3877bf2e3235 user: Benjamin Peterson date: Mon Mar 12 09:46:44 2012 -0700 summary: give the AST class a __dict__ files: Lib/test/test_ast.py | 3 +++ Misc/NEWS | 2 ++ Parser/asdl_c.py | 18 +++++++++++++++--- Python/Python-ast.c | 18 +++++++++++++++--- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -196,6 +196,9 @@ def test_AST_objects(self): x = ast.AST() self.assertEqual(x._fields, ()) + x.foobar = 42 + self.assertEqual(x.foobar, 42) + self.assertEqual(x.__dict__["foobar"], 42) with self.assertRaises(AttributeError): x.vararg diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Give the ast.AST class a __dict__. + - Issue #1469629: Allow cycles through an object's __dict__ slot to be collected. (For example if ``x.__dict__ is x``). diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -603,6 +603,11 @@ def visitModule(self, mod): self.emit(""" +typedef struct { + PyObject_HEAD; + PyObject *dict; +} AST_object; + static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { @@ -681,10 +686,15 @@ {NULL} }; +static PyGetSetDef ast_type_getsets[] = { + {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, + {NULL} +}; + static PyTypeObject AST_type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "_ast.AST", - sizeof(PyObject), + sizeof(AST_object), 0, 0, /* tp_dealloc */ 0, /* tp_print */ @@ -711,12 +721,12 @@ 0, /* tp_iternext */ ast_type_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + ast_type_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ + offsetof(AST_object, dict),/* tp_dictoffset */ (initproc)ast_type_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ @@ -1185,6 +1195,8 @@ p = os.path.join(SRC_DIR, str(mod.name) + "-ast.c") f = open(p, "w") f.write(auto_gen_msg) + f.write('#include \n') + f.write('\n') f.write('#include "Python.h"\n') f.write('#include "%s-ast.h"\n' % mod.name) f.write('\n') diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -1,5 +1,7 @@ /* File automatically generated by Parser/asdl_c.py. */ +#include + #include "Python.h" #include "Python-ast.h" @@ -453,6 +455,11 @@ }; +typedef struct { + PyObject_HEAD; + PyObject *dict; +} AST_object; + static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { @@ -531,10 +538,15 @@ {NULL} }; +static PyGetSetDef ast_type_getsets[] = { + {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, + {NULL} +}; + static PyTypeObject AST_type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "_ast.AST", - sizeof(PyObject), + sizeof(AST_object), 0, 0, /* tp_dealloc */ 0, /* tp_print */ @@ -561,12 +573,12 @@ 0, /* tp_iternext */ ast_type_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + ast_type_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ + offsetof(AST_object, dict),/* tp_dictoffset */ (initproc)ast_type_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 19:18:56 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 19:18:56 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_use_correct_nam?= =?utf8?q?ing_convention?= Message-ID: http://hg.python.org/cpython/rev/fe0b2681a42f changeset: 75543:fe0b2681a42f branch: 3.2 parent: 75540:5ed1a3f19ac6 user: Benjamin Peterson date: Mon Mar 12 11:00:41 2012 -0700 summary: use correct naming convention files: Python/ast.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -645,7 +645,7 @@ } static arg_ty -compiler_arg(struct compiling *c, const node *n) +ast_for_arg(struct compiling *c, const node *n) { identifier name; expr_ty annotation = NULL; @@ -859,7 +859,7 @@ "non-default argument follows default argument"); return NULL; } - arg = compiler_arg(c, ch); + arg = ast_for_arg(c, ch); if (!arg) return NULL; asdl_seq_SET(posargs, k++, arg); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 19:18:57 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 19:18:57 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/e00f6b8b83e8 changeset: 75544:e00f6b8b83e8 parent: 75542:3877bf2e3235 parent: 75543:fe0b2681a42f user: Benjamin Peterson date: Mon Mar 12 11:02:10 2012 -0700 summary: merge 3.2 files: Python/ast.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -1153,7 +1153,7 @@ } static arg_ty -compiler_arg(struct compiling *c, const node *n) +ast_for_arg(struct compiling *c, const node *n) { identifier name; expr_ty annotation = NULL; @@ -1367,7 +1367,7 @@ "non-default argument follows default argument"); return NULL; } - arg = compiler_arg(c, ch); + arg = ast_for_arg(c, ch); if (!arg) return NULL; asdl_seq_SET(posargs, k++, arg); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 19:18:58 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 19:18:58 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_kill_this_disab?= =?utf8?q?led_code?= Message-ID: http://hg.python.org/cpython/rev/5fe780c9638a changeset: 75545:5fe780c9638a branch: 3.2 parent: 75543:fe0b2681a42f user: Benjamin Peterson date: Mon Mar 12 11:15:48 2012 -0700 summary: kill this disabled code files: Python/ast.c | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -666,12 +666,6 @@ } return arg(name, annotation, c->c_arena); -#if 0 - result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena); - if (!set_context(c, result, Store, n)) - return NULL; - return result; -#endif } /* returns -1 if failed to handle keyword only arguments -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 19:18:59 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 19:18:59 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/6d992dea9391 changeset: 75546:6d992dea9391 parent: 75544:e00f6b8b83e8 parent: 75545:5fe780c9638a user: Benjamin Peterson date: Mon Mar 12 11:16:03 2012 -0700 summary: merge 3.2 files: Python/ast.c | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -1174,12 +1174,6 @@ } return arg(name, annotation, c->c_arena); -#if 0 - result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena); - if (!set_context(c, result, Store, n)) - return NULL; - return result; -#endif } /* returns -1 if failed to handle keyword only arguments -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 19:37:33 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 12 Mar 2012 19:37:33 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_adjust_for_change_in_AST_ty?= =?utf8?q?pe?= Message-ID: http://hg.python.org/cpython/rev/2687e8a9bb6c changeset: 75547:2687e8a9bb6c user: Benjamin Peterson date: Mon Mar 12 11:19:19 2012 -0700 summary: adjust for change in AST type files: Lib/test/test_sys.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -882,7 +882,7 @@ check = self.check_sizeof # _ast.AST import _ast - check(_ast.AST(), size(h + '')) + check(_ast.AST(), size(h + 'P')) # imp.NullImporter import imp check(imp.NullImporter(self.file.name), size(h + '')) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 20:00:03 2012 From: python-checkins at python.org (lukasz.langa) Date: Mon, 12 Mar 2012 20:00:03 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fixes_=2313842=3A_cannot_pi?= =?utf8?q?ckle_Ellipsis_or_NotImplemented=2E?= Message-ID: http://hg.python.org/cpython/rev/5832d3622473 changeset: 75548:5832d3622473 parent: 75535:b8a14f95453a user: ?ukasz Langa date: Mon Mar 12 19:46:12 2012 +0100 summary: Fixes #13842: cannot pickle Ellipsis or NotImplemented. Thanks for James Sanders for the bug report and the patch. files: Lib/pickle.py | 8 ++++++++ Lib/test/pickletester.py | 12 ++++++++++++ Misc/ACKS | 1 + Modules/_pickle.c | 21 +++++++++++++++++++++ 4 files changed, 42 insertions(+), 0 deletions(-) diff --git a/Lib/pickle.py b/Lib/pickle.py --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -438,6 +438,14 @@ self.write(NONE) dispatch[type(None)] = save_none + def save_ellipsis(self, obj): + self.save_global(Ellipsis, 'Ellipsis') + dispatch[type(Ellipsis)] = save_ellipsis + + def save_notimplemented(self, obj): + self.save_global(NotImplemented, 'NotImplemented') + dispatch[type(NotImplemented)] = save_notimplemented + def save_bool(self, obj): if self.proto >= 2: self.write(obj and NEWTRUE or NEWFALSE) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -743,6 +743,18 @@ u = self.loads(s) self.assertEqual(t, u) + def test_ellipsis(self): + for proto in protocols: + s = self.dumps(..., proto) + u = self.loads(s) + self.assertEqual(..., u) + + def test_notimplemented(self): + for proto in protocols: + s = self.dumps(NotImplemented, proto) + u = self.loads(s) + self.assertEqual(NotImplemented, u) + # Tests for protocol 2 def test_proto(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -883,6 +883,7 @@ Rich Salz Kevin Samborn Adrian Sampson +James Sanders Ilya Sandler Mark Sapiro Ty Sarna diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2812,6 +2812,19 @@ } static int +save_ellipsis(PicklerObject *self, PyObject *obj) +{ + return save_global(self, Py_Ellipsis, PyUnicode_FromString("Ellipsis")); +} + +static int +save_notimplemented(PicklerObject *self, PyObject *obj) +{ + return save_global(self, Py_NotImplemented, + PyUnicode_FromString("NotImplemented")); +} + +static int save_pers(PicklerObject *self, PyObject *obj, PyObject *func) { PyObject *pid = NULL; @@ -3114,6 +3127,14 @@ status = save_none(self, obj); goto done; } + else if (obj == Py_Ellipsis) { + status = save_ellipsis(self, obj); + goto done; + } + else if (obj == Py_NotImplemented) { + status = save_notimplemented(self, obj); + goto done; + } else if (obj == Py_False || obj == Py_True) { status = save_bool(self, obj); goto done; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 20:00:05 2012 From: python-checkins at python.org (lukasz.langa) Date: Mon, 12 Mar 2012 20:00:05 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Head_merge=2E?= Message-ID: http://hg.python.org/cpython/rev/8538eeb71698 changeset: 75549:8538eeb71698 parent: 75547:2687e8a9bb6c parent: 75548:5832d3622473 user: ?ukasz Langa date: Mon Mar 12 19:59:48 2012 +0100 summary: Head merge. files: Lib/pickle.py | 8 ++++++++ Lib/test/pickletester.py | 12 ++++++++++++ Misc/ACKS | 1 + Modules/_pickle.c | 21 +++++++++++++++++++++ 4 files changed, 42 insertions(+), 0 deletions(-) diff --git a/Lib/pickle.py b/Lib/pickle.py --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -438,6 +438,14 @@ self.write(NONE) dispatch[type(None)] = save_none + def save_ellipsis(self, obj): + self.save_global(Ellipsis, 'Ellipsis') + dispatch[type(Ellipsis)] = save_ellipsis + + def save_notimplemented(self, obj): + self.save_global(NotImplemented, 'NotImplemented') + dispatch[type(NotImplemented)] = save_notimplemented + def save_bool(self, obj): if self.proto >= 2: self.write(obj and NEWTRUE or NEWFALSE) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -743,6 +743,18 @@ u = self.loads(s) self.assertEqual(t, u) + def test_ellipsis(self): + for proto in protocols: + s = self.dumps(..., proto) + u = self.loads(s) + self.assertEqual(..., u) + + def test_notimplemented(self): + for proto in protocols: + s = self.dumps(NotImplemented, proto) + u = self.loads(s) + self.assertEqual(NotImplemented, u) + # Tests for protocol 2 def test_proto(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -883,6 +883,7 @@ Rich Salz Kevin Samborn Adrian Sampson +James Sanders Ilya Sandler Mark Sapiro Ty Sarna diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2812,6 +2812,19 @@ } static int +save_ellipsis(PicklerObject *self, PyObject *obj) +{ + return save_global(self, Py_Ellipsis, PyUnicode_FromString("Ellipsis")); +} + +static int +save_notimplemented(PicklerObject *self, PyObject *obj) +{ + return save_global(self, Py_NotImplemented, + PyUnicode_FromString("NotImplemented")); +} + +static int save_pers(PicklerObject *self, PyObject *obj, PyObject *func) { PyObject *pid = NULL; @@ -3114,6 +3127,14 @@ status = save_none(self, obj); goto done; } + else if (obj == Py_Ellipsis) { + status = save_ellipsis(self, obj); + goto done; + } + else if (obj == Py_NotImplemented) { + status = save_notimplemented(self, obj); + goto done; + } else if (obj == Py_False || obj == Py_True) { status = save_bool(self, obj); goto done; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 20:53:47 2012 From: python-checkins at python.org (tarek.ziade) Date: Mon, 12 Mar 2012 20:53:47 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Fixed_a_function_name_lo?= =?utf8?q?okup_in_distutils2=2Epypi=2Ewrapper_=28=2314263=29?= Message-ID: http://hg.python.org/distutils2/rev/32a95541829c changeset: 1292:32a95541829c parent: 1290:c82c97b2eae1 user: Tarek Ziade date: Mon Mar 12 12:51:33 2012 -0700 summary: Fixed a function name lookup in distutils2.pypi.wrapper (#14263) files: distutils2/pypi/wrapper.py | 5 +- distutils2/tests/test_pypi_wrapper.py | 37 +++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/distutils2/pypi/wrapper.py b/distutils2/pypi/wrapper.py --- a/distutils2/pypi/wrapper.py +++ b/distutils2/pypi/wrapper.py @@ -25,8 +25,9 @@ exception = None methods = [func] for f in wrapper._indexes.values(): - if f != func.im_self and hasattr(f, func.f_name): - methods.append(getattr(f, func.f_name)) + func_name = func.im_func.func_name + if f != func.im_self and hasattr(f, func_name): + methods.append(getattr(f, func_name)) for method in methods: try: response = method(*args, **kwargs) diff --git a/distutils2/tests/test_pypi_wrapper.py b/distutils2/tests/test_pypi_wrapper.py new file mode 100644 --- /dev/null +++ b/distutils2/tests/test_pypi_wrapper.py @@ -0,0 +1,37 @@ +"""Tests for the distutils2.pypi.wrapper module.""" + + +from distutils2.tests import unittest +from distutils2.pypi.wrapper import switch_index_if_fails + + +class Index1(object): + def test(self): + raise Exception("boo") + + +class Index2(object): + def test(self): + return 'OK' + + +class Indexes(object): + _indexes = {'one': Index1(), 'two': Index2()} + + +class TestPyPIWrapper(unittest.TestCase): + + def test_wrapper(self): + index = Indexes._indexes['one'] + func = switch_index_if_fails(getattr(index, 'test'), Indexes) + self.assertEqual(func(), 'OK') + + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestPyPIWrapper)) + return suite + + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Mon Mar 12 21:54:52 2012 From: python-checkins at python.org (michael.foord) Date: Mon, 12 Mar 2012 21:54:52 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Refactor_unittest_command_l?= =?utf8?q?ine_handling_to_always_use_optparse?= Message-ID: http://hg.python.org/cpython/rev/06628ec43732 changeset: 75550:06628ec43732 parent: 75546:6d992dea9391 user: Michael Foord date: Mon Mar 12 13:53:04 2012 -0700 summary: Refactor unittest command line handling to always use optparse files: Lib/unittest/main.py | 74 ++++++++---------- Lib/unittest/test/test_program.py | 17 ---- 2 files changed, 32 insertions(+), 59 deletions(-) diff --git a/Lib/unittest/main.py b/Lib/unittest/main.py --- a/Lib/unittest/main.py +++ b/Lib/unittest/main.py @@ -1,6 +1,7 @@ """Unittest main program""" import sys +import optparse import os from . import loader, runner @@ -76,6 +77,7 @@ def _convert_names(names): return [_convert_name(name) for name in names] + class TestProgram(object): """A command-line program that runs a set of tests; this is primarily for making test modules conveniently executable. @@ -142,33 +144,9 @@ self._do_discovery(argv[2:]) return - import getopt - long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer'] - try: - options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts) - except getopt.error as msg: - self.usageExit(msg) - return - - for opt, value in options: - if opt in ('-h','-H','--help'): - self.usageExit() - if opt in ('-q','--quiet'): - self.verbosity = 0 - if opt in ('-v','--verbose'): - self.verbosity = 2 - if opt in ('-f','--failfast'): - if self.failfast is None: - self.failfast = True - # Should this raise an exception if -f is not valid? - if opt in ('-c','--catch'): - if self.catchbreak is None: - self.catchbreak = True - # Should this raise an exception if -c is not valid? - if opt in ('-b','--buffer'): - if self.buffer is None: - self.buffer = True - # Should this raise an exception if -b is not valid? + parser = self._getOptParser() + options, args = parser.parse_args(argv[1:]) + self._setAttributesFromOptions(options) if len(args) == 0 and self.module is None: # this allows "python -m unittest -v" to still work for @@ -196,14 +174,14 @@ self.test = self.testLoader.loadTestsFromNames(self.testNames, self.module) - def _do_discovery(self, argv, Loader=loader.TestLoader): - # handle command line args for test discovery - self.progName = '%s discover' % self.progName - import optparse + def _getOptParser(self): parser = optparse.OptionParser() parser.prog = self.progName parser.add_option('-v', '--verbose', dest='verbose', default=False, help='Verbose output', action='store_true') + parser.add_option('-q', '--quiet', dest='quiet', default=False, + help='Quiet output', action='store_true') + if self.failfast != False: parser.add_option('-f', '--failfast', dest='failfast', default=False, help='Stop on first fail or error', @@ -216,6 +194,28 @@ parser.add_option('-b', '--buffer', dest='buffer', default=False, help='Buffer stdout and stderr during tests', action='store_true') + return parser + + def _setAttributesFromOptions(self, options): + # only set options from the parsing here + # if they weren't set explicitly in the constructor + if self.failfast is None: + self.failfast = options.failfast + if self.catchbreak is None: + self.catchbreak = options.catchbreak + if self.buffer is None: + self.buffer = options.buffer + + if options.verbose: + self.verbosity = 2 + elif options.quiet: + self.verbosity = 0 + + + def _do_discovery(self, argv, Loader=loader.TestLoader): + # handle command line args for test discovery + self.progName = '%s discover' % self.progName + parser = self._getOptParser() parser.add_option('-s', '--start-directory', dest='start', default='.', help="Directory to start discovery ('.' default)") parser.add_option('-p', '--pattern', dest='pattern', default='test*.py', @@ -230,17 +230,7 @@ for name, value in zip(('start', 'pattern', 'top'), args): setattr(options, name, value) - # only set options from the parsing here - # if they weren't set explicitly in the constructor - if self.failfast is None: - self.failfast = options.failfast - if self.catchbreak is None: - self.catchbreak = options.catchbreak - if self.buffer is None: - self.buffer = options.buffer - - if options.verbose: - self.verbosity = 2 + self._setAttributesFromOptions(options) start_dir = options.start pattern = options.pattern diff --git a/Lib/unittest/test/test_program.py b/Lib/unittest/test/test_program.py --- a/Lib/unittest/test/test_program.py +++ b/Lib/unittest/test/test_program.py @@ -131,23 +131,6 @@ FakeRunner.test = None FakeRunner.raiseError = False - def testHelpAndUnknown(self): - program = self.program - def usageExit(msg=None): - program.msg = msg - program.exit = True - program.usageExit = usageExit - - for opt in '-h', '-H', '--help': - program.exit = False - program.parseArgs([None, opt]) - self.assertTrue(program.exit) - self.assertIsNone(program.msg) - - program.parseArgs([None, '-$']) - self.assertTrue(program.exit) - self.assertIsNotNone(program.msg) - def testVerbosity(self): program = self.program -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 21:54:53 2012 From: python-checkins at python.org (michael.foord) Date: Mon, 12 Mar 2012 21:54:53 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merge?= Message-ID: http://hg.python.org/cpython/rev/b154ab2cdb1e changeset: 75551:b154ab2cdb1e parent: 75550:06628ec43732 parent: 75549:8538eeb71698 user: Michael Foord date: Mon Mar 12 13:54:03 2012 -0700 summary: Merge files: Lib/pickle.py | 8 ++++++++ Lib/test/pickletester.py | 12 ++++++++++++ Lib/test/test_sys.py | 2 +- Misc/ACKS | 1 + Modules/_pickle.c | 21 +++++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletions(-) diff --git a/Lib/pickle.py b/Lib/pickle.py --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -438,6 +438,14 @@ self.write(NONE) dispatch[type(None)] = save_none + def save_ellipsis(self, obj): + self.save_global(Ellipsis, 'Ellipsis') + dispatch[type(Ellipsis)] = save_ellipsis + + def save_notimplemented(self, obj): + self.save_global(NotImplemented, 'NotImplemented') + dispatch[type(NotImplemented)] = save_notimplemented + def save_bool(self, obj): if self.proto >= 2: self.write(obj and NEWTRUE or NEWFALSE) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -743,6 +743,18 @@ u = self.loads(s) self.assertEqual(t, u) + def test_ellipsis(self): + for proto in protocols: + s = self.dumps(..., proto) + u = self.loads(s) + self.assertEqual(..., u) + + def test_notimplemented(self): + for proto in protocols: + s = self.dumps(NotImplemented, proto) + u = self.loads(s) + self.assertEqual(NotImplemented, u) + # Tests for protocol 2 def test_proto(self): diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -882,7 +882,7 @@ check = self.check_sizeof # _ast.AST import _ast - check(_ast.AST(), size(h + '')) + check(_ast.AST(), size(h + 'P')) # imp.NullImporter import imp check(imp.NullImporter(self.file.name), size(h + '')) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -883,6 +883,7 @@ Rich Salz Kevin Samborn Adrian Sampson +James Sanders Ilya Sandler Mark Sapiro Ty Sarna diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2812,6 +2812,19 @@ } static int +save_ellipsis(PicklerObject *self, PyObject *obj) +{ + return save_global(self, Py_Ellipsis, PyUnicode_FromString("Ellipsis")); +} + +static int +save_notimplemented(PicklerObject *self, PyObject *obj) +{ + return save_global(self, Py_NotImplemented, + PyUnicode_FromString("NotImplemented")); +} + +static int save_pers(PicklerObject *self, PyObject *obj, PyObject *func) { PyObject *pid = NULL; @@ -3114,6 +3127,14 @@ status = save_none(self, obj); goto done; } + else if (obj == Py_Ellipsis) { + status = save_ellipsis(self, obj); + goto done; + } + else if (obj == Py_NotImplemented) { + status = save_notimplemented(self, obj); + goto done; + } else if (obj == Py_False || obj == Py_True) { status = save_bool(self, obj); goto done; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 22:07:13 2012 From: python-checkins at python.org (tarek.ziade) Date: Mon, 12 Mar 2012 22:07:13 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Removed_the_trailing_zer?= =?utf8?q?o_wiping_=28=2314264=29?= Message-ID: http://hg.python.org/distutils2/rev/1e0ca4594a2a changeset: 1293:1e0ca4594a2a user: Tarek Ziade date: Mon Mar 12 14:06:59 2012 -0700 summary: Removed the trailing zero wiping (#14264) files: distutils2/pypi/simple.py | 4 ++-- distutils2/tests/test_version.py | 10 ++++++++-- distutils2/version.py | 18 ++++++++++-------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/distutils2/pypi/simple.py b/distutils2/pypi/simple.py --- a/distutils2/pypi/simple.py +++ b/distutils2/pypi/simple.py @@ -198,8 +198,8 @@ def get_release(self, requirements, prefer_final=None): """Return only one release that fulfill the given requirements""" predicate = get_version_predicate(requirements) - release = self.get_releases(predicate, prefer_final)\ - .get_last(predicate) + releases = self.get_releases(predicate, prefer_final) + release = releases.get_last(predicate) if not release: raise ReleaseNotFound("No release matches the given criterias") return release diff --git a/distutils2/tests/test_version.py b/distutils2/tests/test_version.py --- a/distutils2/tests/test_version.py +++ b/distutils2/tests/test_version.py @@ -18,8 +18,8 @@ (V('1.2c4'), '1.2c4'), (V('4.17rc2'), '4.17rc2'), (V('1.2.3.4'), '1.2.3.4'), - (V('1.2.3.4.0b3'), '1.2.3.4b3'), - (V('1.2.0.0.0'), '1.2'), + (V('1.2.3.4.0b3', drop_trailing_zeros=True), '1.2.3.4b3'), + (V('1.2.0.0.0', drop_trailing_zeros=True), '1.2'), (V('1.0.dev345'), '1.0.dev345'), (V('1.0.post456.dev623'), '1.0.post456.dev623')) @@ -249,6 +249,12 @@ for version in other_versions: self.assertFalse(V(version).is_final) + def test_micro_predicate(self): + self.assertNotEqual(V('3.4.0'), V('3.4')) + predicate = VersionPredicate('zope.event (3.4.0)') + self.assertTrue(predicate.match('3.4.0')) + self.assertFalse(predicate.match('3.4.1')) + class VersionWhiteBoxTestCase(unittest.TestCase): diff --git a/distutils2/version.py b/distutils2/version.py --- a/distutils2/version.py +++ b/distutils2/version.py @@ -57,7 +57,8 @@ 1.2a # release level must have a release serial 1.2.3b """ - def __init__(self, s, error_on_huge_major_num=True): + def __init__(self, s, error_on_huge_major_num=True, + drop_trailing_zeros=False): """Create a NormalizedVersion instance from a version string. @param s {str} The version string. @@ -74,8 +75,12 @@ and, e.g. downstream Linux package managers, will forever remove the possibility of using a version number like "1.0" (i.e. where the major number is less than that huge major number). + @param drop_trailing_zeros {bool} Whether to drop trailing zeros + + from the returned list. Default True. """ self.is_final = True # by default, consider a version as final. + self.drop_trailing_zeros = drop_trailing_zeros self._parse(s, error_on_huge_major_num) @classmethod @@ -93,7 +98,7 @@ parts = [] # main version - block = self._parse_numdots(groups['version'], s, False, 2) + block = self._parse_numdots(groups['version'], s, 2) extraversion = groups.get('extraversion') if extraversion not in ('', None): block += self._parse_numdots(extraversion[1:], s) @@ -130,16 +135,13 @@ raise HugeMajorVersionNumError("huge major version number, %r, " "which might cause future problems: %r" % (self.parts[0][0], s)) - def _parse_numdots(self, s, full_ver_str, drop_trailing_zeros=True, - pad_zeros_length=0): + def _parse_numdots(self, s, full_ver_str, pad_zeros_length=0): """Parse 'N.N.N' sequences, return a list of ints. @param s {str} 'N.N.N...' sequence to be parsed @param full_ver_str {str} The full version string from which this comes. Used for error strings. - @param drop_trailing_zeros {bool} Whether to drop trailing zeros - from the returned list. Default True. - @param pad_zeros_length {int} The length to which to pad the + @param pad_zeros_length {int} The length to which to pad the returned list with zeros, if necessary. Default 0. """ nums = [] @@ -148,7 +150,7 @@ raise IrrationalVersionError("cannot have leading zero in " "version number segment: '%s' in %r" % (n, full_ver_str)) nums.append(int(n)) - if drop_trailing_zeros: + if self.drop_trailing_zeros: while nums and nums[-1] == 0: nums.pop() while len(nums) < pad_zeros_length: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Mon Mar 12 22:46:02 2012 From: python-checkins at python.org (tarek.ziade) Date: Mon, 12 Mar 2012 22:46:02 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_removed_2=2E4_and_2=2E5?= Message-ID: http://hg.python.org/distutils2/rev/485ff56573bf changeset: 1294:485ff56573bf user: Tarek Ziade date: Mon Mar 12 14:19:36 2012 -0700 summary: removed 2.4 and 2.5 files: tests.sh | 21 --------------------- 1 files changed, 0 insertions(+), 21 deletions(-) diff --git a/tests.sh b/tests.sh --- a/tests.sh +++ b/tests.sh @@ -1,25 +1,4 @@ #!/bin/sh -echo -n "Running tests with Python 2.4... " -python2.4 setup.py build_ext -f -q 2> /dev/null > /dev/null -python2.4 -Wd runtests.py -q -if [ $? -ne 0 ];then - echo Failed, re-running - python2.4 -Wd runtests.py - exit $? -else - echo Success -fi - -echo -n "Running tests with Python 2.5... " -python2.5 -Wd runtests.py -q -if [ $? -ne 0 ];then - echo Failed, re-running - python2.5 -Wd runtests.py - exit $? -else - echo Success -fi - echo -n "Running tests with Python 2.6... " python2.6 -Wd runtests.py -q if [ $? -ne 0 ];then -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Mon Mar 12 22:46:02 2012 From: python-checkins at python.org (tarek.ziade) Date: Mon, 12 Mar 2012 22:46:02 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_fixed_a_test_mock_issue_?= =?utf8?b?KCMxNDI2OCk=?= Message-ID: http://hg.python.org/distutils2/rev/c0a9ba08ebe3 changeset: 1295:c0a9ba08ebe3 user: Tarek Ziade date: Mon Mar 12 14:45:50 2012 -0700 summary: fixed a test mock issue (#14268) files: distutils2/install.py | 3 ++- distutils2/tests/test_install.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -244,7 +244,8 @@ temp_dir = tempfile.mkdtemp() for dist in remove: files = dist.list_installed_files() - temp_files[dist] = _move_files(files, temp_dir) + paths = [path for path, md5, size in files] + temp_files[dist] = _move_files(paths, temp_dir) try: if install: install_dists(install, install_path, paths) diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -57,7 +57,7 @@ def list_installed_files(self, **args): if self._files: - return self._real_files + return [(path, 'md5', 0) for path in self._real_files] def get_install(self, **args): return self.list_installed_files() @@ -312,7 +312,7 @@ # assert that the files have been removed for dist in dists: - for f in dist.list_installed_files(): + for f, md5, size in dist.list_installed_files(): self.assertFalse(os.path.exists(f)) finally: install.install_dists = old_install_dists @@ -338,7 +338,7 @@ # assert that the files are in the same place # assert that the files have been removed for dist in remove: - for f in dist.list_installed_files(): + for f, md5, size in dist.list_installed_files(): self.assertTrue(os.path.exists(f)) dist._unlink_installed_files() finally: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Mon Mar 12 22:57:36 2012 From: python-checkins at python.org (ezio.melotti) Date: Mon, 12 Mar 2012 22:57:36 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzEzMzk0OiBhZGQg?= =?utf8?q?more_tests_for_the_aifc_module=2E__Patch_by_Oleg_Plakhotnyuk=2E?= Message-ID: http://hg.python.org/cpython/rev/fc3a63ed1f67 changeset: 75552:fc3a63ed1f67 branch: 3.2 parent: 75545:5fe780c9638a user: Ezio Melotti date: Mon Mar 12 23:52:40 2012 +0200 summary: #13394: add more tests for the aifc module. Patch by Oleg Plakhotnyuk. files: Lib/test/test_aifc.py | 163 ++++++++++++++++++++++++++++- 1 files changed, 154 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -1,7 +1,8 @@ -from test.support import findfile, run_unittest, TESTFN +from test.support import findfile, run_unittest, TESTFN, captured_stdout, unlink import unittest import os import io +import struct import aifc @@ -20,10 +21,8 @@ self.fout.close() except (aifc.Error, AttributeError): pass - try: - os.remove(TESTFN) - except OSError: - pass + unlink(TESTFN) + unlink(TESTFN + '.aiff') def test_skipunknown(self): #Issue 2245 @@ -32,6 +31,7 @@ def test_params(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.getfp().name, self.sndfilepath) self.assertEqual(f.getnchannels(), 2) self.assertEqual(f.getsampwidth(), 2) self.assertEqual(f.getframerate(), 48000) @@ -45,6 +45,7 @@ def test_read(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.readframes(0), b'') self.assertEqual(f.tell(), 0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') f.rewind() @@ -58,6 +59,10 @@ self.assertEqual(f.readframes(2), b'\x17t\x17t"\xad"\xad') f.setpos(pos0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') + with self.assertRaises(aifc.Error): + f.setpos(-1) + with self.assertRaises(aifc.Error): + f.setpos(f.getnframes() + 1) def test_write(self): f = self.f = aifc.open(self.sndfilepath) @@ -92,8 +97,6 @@ self.assertEqual(f.getparams()[0:3], fout.getparams()[0:3]) self.assertEqual(fout.getcomptype(), b'ULAW') self.assertEqual(fout.getcompname(), b'foo') - # XXX: this test fails, not sure if it should succeed or not - # self.assertEqual(f.readframes(5), fout.readframes(5)) def test_close(self): class Wrapfile(object): @@ -112,7 +115,7 @@ def test_write_header_comptype_sampwidth(self): for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') fout.setnchannels(1) fout.setframerate(1) fout.setcomptype(comptype, b'') @@ -121,7 +124,7 @@ fout.initfp(None) def test_write_markers_values(self): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') self.assertEqual(fout.getmarkers(), None) fout.setmark(1, 0, b'foo1') fout.setmark(1, 1, b'foo2') @@ -179,6 +182,148 @@ with self.assertRaises(ValueError): aifc._write_string(f, b'too long' * 255) + def test_wrong_open_mode(self): + with self.assertRaises(aifc.Error): + aifc.open(TESTFN, 'wrong_mode') + + def test_read_wrong_form(self): + b1 = io.BytesIO(b'WRNG' + struct.pack('>L', 0)) + b2 = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'WRNG') + self.assertRaises(aifc.Error, aifc.open, b1) + self.assertRaises(aifc.Error, aifc.open, b2) + + def test_read_no_comm_chunk(self): + b = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'AIFF') + self.assertRaises(aifc.Error, aifc.open, b) + + def test_read_wrong_compression_type(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0) + b += b'WRNG' + struct.pack('B', 0) + self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b)) + + def test_read_wrong_marks(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFF' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + b += b'MARK' + struct.pack('>LhB', 3, 1, 1) + with captured_stdout() as s: + f = aifc.open(io.BytesIO(b)) + self.assertEqual( + s.getvalue(), + 'Warning: MARK chunk contains only 0 markers instead of 1\n') + self.assertEqual(f.getmarkers(), None) + + def test_read_comm_kludge_compname_even(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with captured_stdout() as s: + f = aifc.open(io.BytesIO(b)) + self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n') + self.assertEqual(f.getcompname(), b'even') + + def test_read_comm_kludge_compname_odd(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 3) + b'odd' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with captured_stdout() as s: + f = aifc.open(io.BytesIO(b)) + self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n') + self.assertEqual(f.getcompname(), b'odd') + + def test_write_params_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + wrong_params = (0, 0, 0, 0, b'WRNG', '') + self.assertRaises(aifc.Error, fout.setparams, wrong_params) + self.assertRaises(aifc.Error, fout.getparams) + self.assertRaises(aifc.Error, fout.setnchannels, 0) + self.assertRaises(aifc.Error, fout.getnchannels) + self.assertRaises(aifc.Error, fout.setsampwidth, 0) + self.assertRaises(aifc.Error, fout.getsampwidth) + self.assertRaises(aifc.Error, fout.setframerate, 0) + self.assertRaises(aifc.Error, fout.getframerate) + self.assertRaises(aifc.Error, fout.setcomptype, b'WRNG', '') + fout.aiff() + fout.setnchannels(1) + fout.setsampwidth(1) + fout.setframerate(1) + fout.setnframes(1) + fout.writeframes(b'\x00') + self.assertRaises(aifc.Error, fout.setparams, (1, 1, 1, 1, 1, 1)) + self.assertRaises(aifc.Error, fout.setnchannels, 1) + self.assertRaises(aifc.Error, fout.setsampwidth, 1) + self.assertRaises(aifc.Error, fout.setframerate, 1) + self.assertRaises(aifc.Error, fout.setnframes, 1) + self.assertRaises(aifc.Error, fout.setcomptype, b'NONE', '') + self.assertRaises(aifc.Error, fout.aiff) + self.assertRaises(aifc.Error, fout.aifc) + + def test_write_params_singles(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + fout.setnchannels(1) + fout.setsampwidth(2) + fout.setframerate(3) + fout.setnframes(4) + fout.setcomptype(b'NONE', b'name') + self.assertEqual(fout.getnchannels(), 1) + self.assertEqual(fout.getsampwidth(), 2) + self.assertEqual(fout.getframerate(), 3) + self.assertEqual(fout.getnframes(), 0) + self.assertEqual(fout.tell(), 0) + self.assertEqual(fout.getcomptype(), b'NONE') + self.assertEqual(fout.getcompname(), b'name') + fout.writeframes(b'\x00' * 4 * fout.getsampwidth() * fout.getnchannels()) + self.assertEqual(fout.getnframes(), 4) + self.assertEqual(fout.tell(), 4) + + def test_write_params_bunch(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + p = (1, 2, 3, 4, b'NONE', b'name') + fout.setparams(p) + self.assertEqual(fout.getparams(), p) + fout.initfp(None) + + def test_write_header_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.close) + fout.setnchannels(1) + self.assertRaises(aifc.Error, fout.close) + fout.setsampwidth(1) + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_header_comptype_raises(self): + for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): + fout = aifc.open(io.BytesIO(), 'wb') + fout.setsampwidth(1) + fout.setcomptype(comptype, b'') + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_markers_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.setmark, 0, 0, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, -1, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, 0, None) + self.assertRaises(aifc.Error, fout.getmark, 1) + fout.initfp(None) + + def test_write_aiff_by_extension(self): + sampwidth = 2 + fout = self.fout = aifc.open(TESTFN + '.aiff', 'wb') + fout.setparams((1, sampwidth, 1, 1, b'ULAW', b'')) + frames = b'\x00' * fout.getnchannels() * sampwidth + fout.writeframes(frames) + fout.close() + f = self.f = aifc.open(TESTFN + '.aiff', 'rb') + self.assertEqual(f.getcomptype(), b'NONE') + f.close() + def test_main(): run_unittest(AIFCTest) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 22:57:37 2012 From: python-checkins at python.org (ezio.melotti) Date: Mon, 12 Mar 2012 22:57:37 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=2313394=3A_add_more_tests_for_the_aifc_module_and_use_warni?= =?utf8?q?ngs=2Ewarn_instead_of?= Message-ID: http://hg.python.org/cpython/rev/512d3ad81fb9 changeset: 75553:512d3ad81fb9 parent: 75551:b154ab2cdb1e parent: 75552:fc3a63ed1f67 user: Ezio Melotti date: Mon Mar 12 23:57:18 2012 +0200 summary: #13394: add more tests for the aifc module and use warnings.warn instead of print. Patch by Oleg Plakhotnyuk. files: Lib/aifc.py | 12 +- Lib/test/test_aifc.py | 158 ++++++++++++++++++++++++++++- Misc/NEWS | 2 + 3 files changed, 157 insertions(+), 15 deletions(-) diff --git a/Lib/aifc.py b/Lib/aifc.py --- a/Lib/aifc.py +++ b/Lib/aifc.py @@ -136,6 +136,7 @@ import struct import builtins +import warnings __all__ = ["Error", "open", "openfp"] @@ -440,7 +441,7 @@ kludge = 0 if chunk.chunksize == 18: kludge = 1 - print('Warning: bad COMM chunk size') + warnings.warn('Warning: bad COMM chunk size') chunk.chunksize = 23 #DEBUG end self._comptype = chunk.read(4) @@ -484,11 +485,10 @@ # a position 0 and name '' self._markers.append((id, pos, name)) except EOFError: - print('Warning: MARK chunk contains only', end=' ') - print(len(self._markers), end=' ') - if len(self._markers) == 1: print('marker', end=' ') - else: print('markers', end=' ') - print('instead of', nmarkers) + w = ('Warning: MARK chunk contains only %s marker%s instead of %s' % + (len(self._markers), '' if len(self._markers) == 1 else 's', + nmarkers)) + warnings.warn(w) class Aifc_write: # Variables used in this class: diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -1,7 +1,8 @@ -from test.support import findfile, run_unittest, TESTFN +from test.support import findfile, run_unittest, TESTFN, unlink import unittest import os import io +import struct import aifc @@ -20,10 +21,8 @@ self.fout.close() except (aifc.Error, AttributeError): pass - try: - os.remove(TESTFN) - except OSError: - pass + unlink(TESTFN) + unlink(TESTFN + '.aiff') def test_skipunknown(self): #Issue 2245 @@ -32,6 +31,7 @@ def test_params(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.getfp().name, self.sndfilepath) self.assertEqual(f.getnchannels(), 2) self.assertEqual(f.getsampwidth(), 2) self.assertEqual(f.getframerate(), 48000) @@ -45,6 +45,7 @@ def test_read(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.readframes(0), b'') self.assertEqual(f.tell(), 0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') f.rewind() @@ -58,6 +59,10 @@ self.assertEqual(f.readframes(2), b'\x17t\x17t"\xad"\xad') f.setpos(pos0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') + with self.assertRaises(aifc.Error): + f.setpos(-1) + with self.assertRaises(aifc.Error): + f.setpos(f.getnframes() + 1) def test_write(self): f = self.f = aifc.open(self.sndfilepath) @@ -92,8 +97,6 @@ self.assertEqual(f.getparams()[0:3], fout.getparams()[0:3]) self.assertEqual(fout.getcomptype(), b'ULAW') self.assertEqual(fout.getcompname(), b'foo') - # XXX: this test fails, not sure if it should succeed or not - # self.assertEqual(f.readframes(5), fout.readframes(5)) def test_close(self): class Wrapfile(object): @@ -112,7 +115,7 @@ def test_write_header_comptype_sampwidth(self): for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') fout.setnchannels(1) fout.setframerate(1) fout.setcomptype(comptype, b'') @@ -121,7 +124,7 @@ fout.initfp(None) def test_write_markers_values(self): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') self.assertEqual(fout.getmarkers(), None) fout.setmark(1, 0, b'foo1') fout.setmark(1, 1, b'foo2') @@ -179,6 +182,143 @@ with self.assertRaises(ValueError): aifc._write_string(f, b'too long' * 255) + def test_wrong_open_mode(self): + with self.assertRaises(aifc.Error): + aifc.open(TESTFN, 'wrong_mode') + + def test_read_wrong_form(self): + b1 = io.BytesIO(b'WRNG' + struct.pack('>L', 0)) + b2 = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'WRNG') + self.assertRaises(aifc.Error, aifc.open, b1) + self.assertRaises(aifc.Error, aifc.open, b2) + + def test_read_no_comm_chunk(self): + b = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'AIFF') + self.assertRaises(aifc.Error, aifc.open, b) + + def test_read_wrong_compression_type(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0) + b += b'WRNG' + struct.pack('B', 0) + self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b)) + + def test_read_wrong_marks(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFF' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + b += b'MARK' + struct.pack('>LhB', 3, 1, 1) + with self.assertWarns(UserWarning): + f = aifc.open(io.BytesIO(b)) + self.assertEqual(f.getmarkers(), None) + + def test_read_comm_kludge_compname_even(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with self.assertWarns(UserWarning): + f = aifc.open(io.BytesIO(b)) + self.assertEqual(f.getcompname(), b'even') + + def test_read_comm_kludge_compname_odd(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 3) + b'odd' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with self.assertWarns(UserWarning): + f = aifc.open(io.BytesIO(b)) + self.assertEqual(f.getcompname(), b'odd') + + def test_write_params_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + wrong_params = (0, 0, 0, 0, b'WRNG', '') + self.assertRaises(aifc.Error, fout.setparams, wrong_params) + self.assertRaises(aifc.Error, fout.getparams) + self.assertRaises(aifc.Error, fout.setnchannels, 0) + self.assertRaises(aifc.Error, fout.getnchannels) + self.assertRaises(aifc.Error, fout.setsampwidth, 0) + self.assertRaises(aifc.Error, fout.getsampwidth) + self.assertRaises(aifc.Error, fout.setframerate, 0) + self.assertRaises(aifc.Error, fout.getframerate) + self.assertRaises(aifc.Error, fout.setcomptype, b'WRNG', '') + fout.aiff() + fout.setnchannels(1) + fout.setsampwidth(1) + fout.setframerate(1) + fout.setnframes(1) + fout.writeframes(b'\x00') + self.assertRaises(aifc.Error, fout.setparams, (1, 1, 1, 1, 1, 1)) + self.assertRaises(aifc.Error, fout.setnchannels, 1) + self.assertRaises(aifc.Error, fout.setsampwidth, 1) + self.assertRaises(aifc.Error, fout.setframerate, 1) + self.assertRaises(aifc.Error, fout.setnframes, 1) + self.assertRaises(aifc.Error, fout.setcomptype, b'NONE', '') + self.assertRaises(aifc.Error, fout.aiff) + self.assertRaises(aifc.Error, fout.aifc) + + def test_write_params_singles(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + fout.setnchannels(1) + fout.setsampwidth(2) + fout.setframerate(3) + fout.setnframes(4) + fout.setcomptype(b'NONE', b'name') + self.assertEqual(fout.getnchannels(), 1) + self.assertEqual(fout.getsampwidth(), 2) + self.assertEqual(fout.getframerate(), 3) + self.assertEqual(fout.getnframes(), 0) + self.assertEqual(fout.tell(), 0) + self.assertEqual(fout.getcomptype(), b'NONE') + self.assertEqual(fout.getcompname(), b'name') + fout.writeframes(b'\x00' * 4 * fout.getsampwidth() * fout.getnchannels()) + self.assertEqual(fout.getnframes(), 4) + self.assertEqual(fout.tell(), 4) + + def test_write_params_bunch(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + p = (1, 2, 3, 4, b'NONE', b'name') + fout.setparams(p) + self.assertEqual(fout.getparams(), p) + fout.initfp(None) + + def test_write_header_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.close) + fout.setnchannels(1) + self.assertRaises(aifc.Error, fout.close) + fout.setsampwidth(1) + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_header_comptype_raises(self): + for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): + fout = aifc.open(io.BytesIO(), 'wb') + fout.setsampwidth(1) + fout.setcomptype(comptype, b'') + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_markers_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.setmark, 0, 0, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, -1, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, 0, None) + self.assertRaises(aifc.Error, fout.getmark, 1) + fout.initfp(None) + + def test_write_aiff_by_extension(self): + sampwidth = 2 + fout = self.fout = aifc.open(TESTFN + '.aiff', 'wb') + fout.setparams((1, sampwidth, 1, 1, b'ULAW', b'')) + frames = b'\x00' * fout.getnchannels() * sampwidth + fout.writeframes(frames) + fout.close() + f = self.f = aifc.open(TESTFN + '.aiff', 'rb') + self.assertEqual(f.getcomptype(), b'NONE') + f.close() + def test_main(): run_unittest(AIFCTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #13394: the aifc module now uses warnings.warn() to signal warnings. + - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under Windows when the child process has already exited. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 22:59:54 2012 From: python-checkins at python.org (lukasz.langa) Date: Mon, 12 Mar 2012 22:59:54 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=2313842=3A_check_whether_P?= =?utf8?q?yUnicode=5FFromString_succeeded?= Message-ID: http://hg.python.org/cpython/rev/5353357382e2 changeset: 75554:5353357382e2 parent: 75551:b154ab2cdb1e user: ?ukasz Langa date: Mon Mar 12 22:59:11 2012 +0100 summary: #13842: check whether PyUnicode_FromString succeeded files: Modules/_pickle.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2814,14 +2814,19 @@ static int save_ellipsis(PicklerObject *self, PyObject *obj) { - return save_global(self, Py_Ellipsis, PyUnicode_FromString("Ellipsis")); + PyObject *str = PyUnicode_FromString("Ellipsis"); + if (str == NULL) + return -1; + return save_global(self, Py_Ellipsis, str); } static int save_notimplemented(PicklerObject *self, PyObject *obj) { - return save_global(self, Py_NotImplemented, - PyUnicode_FromString("NotImplemented")); + PyObject *str = PyUnicode_FromString("NotImplemented"); + if (str == NULL) + return -1; + return save_global(self, Py_NotImplemented, str); } static int -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 22:59:55 2012 From: python-checkins at python.org (lukasz.langa) Date: Mon, 12 Mar 2012 22:59:55 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Head_merge?= Message-ID: http://hg.python.org/cpython/rev/9cccfaa6b534 changeset: 75555:9cccfaa6b534 parent: 75553:512d3ad81fb9 parent: 75554:5353357382e2 user: ?ukasz Langa date: Mon Mar 12 22:59:49 2012 +0100 summary: Head merge files: Modules/_pickle.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2814,14 +2814,19 @@ static int save_ellipsis(PicklerObject *self, PyObject *obj) { - return save_global(self, Py_Ellipsis, PyUnicode_FromString("Ellipsis")); + PyObject *str = PyUnicode_FromString("Ellipsis"); + if (str == NULL) + return -1; + return save_global(self, Py_Ellipsis, str); } static int save_notimplemented(PicklerObject *self, PyObject *obj) { - return save_global(self, Py_NotImplemented, - PyUnicode_FromString("NotImplemented")); + PyObject *str = PyUnicode_FromString("NotImplemented"); + if (str == NULL) + return -1; + return save_global(self, Py_NotImplemented, str); } static int -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 23:01:49 2012 From: python-checkins at python.org (michael.foord) Date: Mon, 12 Mar 2012 23:01:49 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Adding_PEP_417_=27Adding_mock_?= =?utf8?q?to_the_standard_library=27?= Message-ID: http://hg.python.org/peps/rev/ef8a076004d6 changeset: 4126:ef8a076004d6 user: Michael Foord date: Mon Mar 12 15:00:48 2012 -0700 summary: Adding PEP 417 'Adding mock to the standard library' files: pep-0417.txt | 71 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 71 insertions(+), 0 deletions(-) diff --git a/pep-0417.txt b/pep-0417.txt new file mode 100644 --- /dev/null +++ b/pep-0417.txt @@ -0,0 +1,71 @@ +PEP: 417 +Title: Including mock in the Standard Library +Version: $Revision$ +Last-Modified: $Date$ +Author: Michael Foord +Status: Draft +Type: Standards Track +Content-Type: text/plain +Created: 12-Mar-2012 +Python-Version: 3.3 +Post-History: 12-Mar-2012 + + +Abstract + + This PEP proposes adding the mock [1]_ testing library + to the Python standard library as ``unittest.mock``. + + +Rationale + + Creating mock objects for testing is a common need in Python. + Many developers create ad-hoc mocks, as needed, in their test + suites. This is currently what we do in the Python test suite, + where a standardised mock object library would be helpful. + + There are many mock object libraries available for Python [2]_. + Of these, mock is overwhelmingly the most popular, with as many + downloads on PyPI as the other mocking libraries combined. + + An advantage of mock is that it is a mocking library and not a + framework. It provides a configurable and flexible mock object, + without being opinionated about how you write your tests. The + mock api is now well battle-tested and stable. + + mock also handles safely monkeypatching and unmonkeypatching + objects during the scope of a test. This is hard to do safely + and many developers / projects mimic this functionality + (often incorrectly). A standardised way to do this, handling + the complexity of patching in the presence of the descriptor + protocol (etc) is useful. People are asking for a "patch" [3]_ + feature to unittest. Doing this via mock.patch is preferable + to re-implementing part of this functionality in unittest. + + +Background + Addition of mock to the Python standard library was discussed + and agreed to at the Python Language Summit 2012. + + +References + + [1] `mock library on PyPI`_ + [2] http://pypi.python.org/pypi?%3Aaction=search&term=mock&submit=search + [3] http://bugs.python.org/issue11664 + + + +Copyright + + This document has been placed in the public domain. + + + +Local Variables: +mode: indented-text +indent-tabs-mode: nil +sentence-end-double-space: t +fill-column: 70 +coding: utf-8 +End: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Mar 12 23:13:53 2012 From: python-checkins at python.org (michael.foord) Date: Mon, 12 Mar 2012 23:13:53 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Addition_of_=27open_issues=27_?= =?utf8?q?to_PEP_417?= Message-ID: http://hg.python.org/peps/rev/dece9beaf6c0 changeset: 4127:dece9beaf6c0 user: Michael Foord date: Mon Mar 12 15:13:48 2012 -0700 summary: Addition of 'open issues' to PEP 417 files: pep-0417.txt | 20 ++++++++++++++++---- 1 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pep-0417.txt b/pep-0417.txt --- a/pep-0417.txt +++ b/pep-0417.txt @@ -13,7 +13,7 @@ Abstract - This PEP proposes adding the mock [1]_ testing library + This PEP proposes adding the mock [1] testing library to the Python standard library as ``unittest.mock``. @@ -24,7 +24,7 @@ suites. This is currently what we do in the Python test suite, where a standardised mock object library would be helpful. - There are many mock object libraries available for Python [2]_. + There are many mock object libraries available for Python [2]. Of these, mock is overwhelmingly the most popular, with as many downloads on PyPI as the other mocking libraries combined. @@ -38,7 +38,7 @@ and many developers / projects mimic this functionality (often incorrectly). A standardised way to do this, handling the complexity of patching in the presence of the descriptor - protocol (etc) is useful. People are asking for a "patch" [3]_ + protocol (etc) is useful. People are asking for a "patch" [3] feature to unittest. Doing this via mock.patch is preferable to re-implementing part of this functionality in unittest. @@ -46,11 +46,23 @@ Background Addition of mock to the Python standard library was discussed and agreed to at the Python Language Summit 2012. + + +Open Issues + As of release 0.8, which is current at the time of writing, + mock is compatible with Python 2.4-3.2. Moving into the Python + standard library will allow for the removal of some Python 2 + specific "compatibility hacks". + + mock 0.8 introduced a new feature, "auto-speccing", obsoletes + an older mock feature called "mocksignature". The + "mocksignature" functionality can be removed from mock + altogether prior to inclusion. References - [1] `mock library on PyPI`_ + [1] `mock library on PyPI `_ [2] http://pypi.python.org/pypi?%3Aaction=search&term=mock&submit=search [3] http://bugs.python.org/issue11664 -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Mar 12 23:25:21 2012 From: python-checkins at python.org (michael.foord) Date: Mon, 12 Mar 2012 23:25:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Move_adding_unittest_test_d?= =?utf8?q?iscovery_command_line_options_into_their_own_method=2E?= Message-ID: http://hg.python.org/cpython/rev/8c5506468ecb changeset: 75556:8c5506468ecb parent: 75551:b154ab2cdb1e user: Michael Foord date: Mon Mar 12 15:24:46 2012 -0700 summary: Move adding unittest test discovery command line options into their own method. files: Lib/unittest/main.py | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/unittest/main.py b/Lib/unittest/main.py --- a/Lib/unittest/main.py +++ b/Lib/unittest/main.py @@ -211,11 +211,7 @@ elif options.quiet: self.verbosity = 0 - - def _do_discovery(self, argv, Loader=loader.TestLoader): - # handle command line args for test discovery - self.progName = '%s discover' % self.progName - parser = self._getOptParser() + def _addDiscoveryOptions(self, parser): parser.add_option('-s', '--start-directory', dest='start', default='.', help="Directory to start discovery ('.' default)") parser.add_option('-p', '--pattern', dest='pattern', default='test*.py', @@ -223,6 +219,12 @@ parser.add_option('-t', '--top-level-directory', dest='top', default=None, help='Top level directory of project (defaults to start directory)') + def _do_discovery(self, argv, Loader=loader.TestLoader): + # handle command line args for test discovery + self.progName = '%s discover' % self.progName + parser = self._getOptParser() + self._addDiscoveryOptions(parser) + options, args = parser.parse_args(argv) if len(args) > 3: self.usageExit() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 23:25:22 2012 From: python-checkins at python.org (michael.foord) Date: Mon, 12 Mar 2012 23:25:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merge?= Message-ID: http://hg.python.org/cpython/rev/e04750e0ffd6 changeset: 75557:e04750e0ffd6 parent: 75556:8c5506468ecb parent: 75555:9cccfaa6b534 user: Michael Foord date: Mon Mar 12 15:25:12 2012 -0700 summary: Merge files: Lib/aifc.py | 12 +- Lib/test/test_aifc.py | 158 ++++++++++++++++++++++++++++- Misc/NEWS | 2 + Modules/_pickle.c | 11 +- 4 files changed, 165 insertions(+), 18 deletions(-) diff --git a/Lib/aifc.py b/Lib/aifc.py --- a/Lib/aifc.py +++ b/Lib/aifc.py @@ -136,6 +136,7 @@ import struct import builtins +import warnings __all__ = ["Error", "open", "openfp"] @@ -440,7 +441,7 @@ kludge = 0 if chunk.chunksize == 18: kludge = 1 - print('Warning: bad COMM chunk size') + warnings.warn('Warning: bad COMM chunk size') chunk.chunksize = 23 #DEBUG end self._comptype = chunk.read(4) @@ -484,11 +485,10 @@ # a position 0 and name '' self._markers.append((id, pos, name)) except EOFError: - print('Warning: MARK chunk contains only', end=' ') - print(len(self._markers), end=' ') - if len(self._markers) == 1: print('marker', end=' ') - else: print('markers', end=' ') - print('instead of', nmarkers) + w = ('Warning: MARK chunk contains only %s marker%s instead of %s' % + (len(self._markers), '' if len(self._markers) == 1 else 's', + nmarkers)) + warnings.warn(w) class Aifc_write: # Variables used in this class: diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -1,7 +1,8 @@ -from test.support import findfile, run_unittest, TESTFN +from test.support import findfile, run_unittest, TESTFN, unlink import unittest import os import io +import struct import aifc @@ -20,10 +21,8 @@ self.fout.close() except (aifc.Error, AttributeError): pass - try: - os.remove(TESTFN) - except OSError: - pass + unlink(TESTFN) + unlink(TESTFN + '.aiff') def test_skipunknown(self): #Issue 2245 @@ -32,6 +31,7 @@ def test_params(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.getfp().name, self.sndfilepath) self.assertEqual(f.getnchannels(), 2) self.assertEqual(f.getsampwidth(), 2) self.assertEqual(f.getframerate(), 48000) @@ -45,6 +45,7 @@ def test_read(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.readframes(0), b'') self.assertEqual(f.tell(), 0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') f.rewind() @@ -58,6 +59,10 @@ self.assertEqual(f.readframes(2), b'\x17t\x17t"\xad"\xad') f.setpos(pos0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') + with self.assertRaises(aifc.Error): + f.setpos(-1) + with self.assertRaises(aifc.Error): + f.setpos(f.getnframes() + 1) def test_write(self): f = self.f = aifc.open(self.sndfilepath) @@ -92,8 +97,6 @@ self.assertEqual(f.getparams()[0:3], fout.getparams()[0:3]) self.assertEqual(fout.getcomptype(), b'ULAW') self.assertEqual(fout.getcompname(), b'foo') - # XXX: this test fails, not sure if it should succeed or not - # self.assertEqual(f.readframes(5), fout.readframes(5)) def test_close(self): class Wrapfile(object): @@ -112,7 +115,7 @@ def test_write_header_comptype_sampwidth(self): for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') fout.setnchannels(1) fout.setframerate(1) fout.setcomptype(comptype, b'') @@ -121,7 +124,7 @@ fout.initfp(None) def test_write_markers_values(self): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') self.assertEqual(fout.getmarkers(), None) fout.setmark(1, 0, b'foo1') fout.setmark(1, 1, b'foo2') @@ -179,6 +182,143 @@ with self.assertRaises(ValueError): aifc._write_string(f, b'too long' * 255) + def test_wrong_open_mode(self): + with self.assertRaises(aifc.Error): + aifc.open(TESTFN, 'wrong_mode') + + def test_read_wrong_form(self): + b1 = io.BytesIO(b'WRNG' + struct.pack('>L', 0)) + b2 = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'WRNG') + self.assertRaises(aifc.Error, aifc.open, b1) + self.assertRaises(aifc.Error, aifc.open, b2) + + def test_read_no_comm_chunk(self): + b = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'AIFF') + self.assertRaises(aifc.Error, aifc.open, b) + + def test_read_wrong_compression_type(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0) + b += b'WRNG' + struct.pack('B', 0) + self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b)) + + def test_read_wrong_marks(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFF' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + b += b'MARK' + struct.pack('>LhB', 3, 1, 1) + with self.assertWarns(UserWarning): + f = aifc.open(io.BytesIO(b)) + self.assertEqual(f.getmarkers(), None) + + def test_read_comm_kludge_compname_even(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with self.assertWarns(UserWarning): + f = aifc.open(io.BytesIO(b)) + self.assertEqual(f.getcompname(), b'even') + + def test_read_comm_kludge_compname_odd(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 3) + b'odd' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with self.assertWarns(UserWarning): + f = aifc.open(io.BytesIO(b)) + self.assertEqual(f.getcompname(), b'odd') + + def test_write_params_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + wrong_params = (0, 0, 0, 0, b'WRNG', '') + self.assertRaises(aifc.Error, fout.setparams, wrong_params) + self.assertRaises(aifc.Error, fout.getparams) + self.assertRaises(aifc.Error, fout.setnchannels, 0) + self.assertRaises(aifc.Error, fout.getnchannels) + self.assertRaises(aifc.Error, fout.setsampwidth, 0) + self.assertRaises(aifc.Error, fout.getsampwidth) + self.assertRaises(aifc.Error, fout.setframerate, 0) + self.assertRaises(aifc.Error, fout.getframerate) + self.assertRaises(aifc.Error, fout.setcomptype, b'WRNG', '') + fout.aiff() + fout.setnchannels(1) + fout.setsampwidth(1) + fout.setframerate(1) + fout.setnframes(1) + fout.writeframes(b'\x00') + self.assertRaises(aifc.Error, fout.setparams, (1, 1, 1, 1, 1, 1)) + self.assertRaises(aifc.Error, fout.setnchannels, 1) + self.assertRaises(aifc.Error, fout.setsampwidth, 1) + self.assertRaises(aifc.Error, fout.setframerate, 1) + self.assertRaises(aifc.Error, fout.setnframes, 1) + self.assertRaises(aifc.Error, fout.setcomptype, b'NONE', '') + self.assertRaises(aifc.Error, fout.aiff) + self.assertRaises(aifc.Error, fout.aifc) + + def test_write_params_singles(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + fout.setnchannels(1) + fout.setsampwidth(2) + fout.setframerate(3) + fout.setnframes(4) + fout.setcomptype(b'NONE', b'name') + self.assertEqual(fout.getnchannels(), 1) + self.assertEqual(fout.getsampwidth(), 2) + self.assertEqual(fout.getframerate(), 3) + self.assertEqual(fout.getnframes(), 0) + self.assertEqual(fout.tell(), 0) + self.assertEqual(fout.getcomptype(), b'NONE') + self.assertEqual(fout.getcompname(), b'name') + fout.writeframes(b'\x00' * 4 * fout.getsampwidth() * fout.getnchannels()) + self.assertEqual(fout.getnframes(), 4) + self.assertEqual(fout.tell(), 4) + + def test_write_params_bunch(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + p = (1, 2, 3, 4, b'NONE', b'name') + fout.setparams(p) + self.assertEqual(fout.getparams(), p) + fout.initfp(None) + + def test_write_header_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.close) + fout.setnchannels(1) + self.assertRaises(aifc.Error, fout.close) + fout.setsampwidth(1) + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_header_comptype_raises(self): + for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): + fout = aifc.open(io.BytesIO(), 'wb') + fout.setsampwidth(1) + fout.setcomptype(comptype, b'') + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_markers_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.setmark, 0, 0, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, -1, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, 0, None) + self.assertRaises(aifc.Error, fout.getmark, 1) + fout.initfp(None) + + def test_write_aiff_by_extension(self): + sampwidth = 2 + fout = self.fout = aifc.open(TESTFN + '.aiff', 'wb') + fout.setparams((1, sampwidth, 1, 1, b'ULAW', b'')) + frames = b'\x00' * fout.getnchannels() * sampwidth + fout.writeframes(frames) + fout.close() + f = self.f = aifc.open(TESTFN + '.aiff', 'rb') + self.assertEqual(f.getcomptype(), b'NONE') + f.close() + def test_main(): run_unittest(AIFCTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #13394: the aifc module now uses warnings.warn() to signal warnings. + - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under Windows when the child process has already exited. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2814,14 +2814,19 @@ static int save_ellipsis(PicklerObject *self, PyObject *obj) { - return save_global(self, Py_Ellipsis, PyUnicode_FromString("Ellipsis")); + PyObject *str = PyUnicode_FromString("Ellipsis"); + if (str == NULL) + return -1; + return save_global(self, Py_Ellipsis, str); } static int save_notimplemented(PicklerObject *self, PyObject *obj) { - return save_global(self, Py_NotImplemented, - PyUnicode_FromString("NotImplemented")); + PyObject *str = PyUnicode_FromString("NotImplemented"); + if (str == NULL) + return -1; + return save_global(self, Py_NotImplemented, str); } static int -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 23:29:18 2012 From: python-checkins at python.org (eric.smith) Date: Mon, 12 Mar 2012 23:29:18 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogc3RyLmZvcm1hdF9t?= =?utf8?q?ap_tests_don=27t_do_what_they_say=3A_fix_to_actually_implement_t?= =?utf8?q?he?= Message-ID: http://hg.python.org/cpython/rev/995cddd15313 changeset: 75558:995cddd15313 branch: 3.2 parent: 75532:3f15c069454d user: Eric V. Smith date: Mon Mar 12 15:16:22 2012 -0700 summary: str.format_map tests don't do what they say: fix to actually implement the intent of the test. Closes #13450. files: Lib/test/test_unicode.py | 15 +++++++++------ Misc/ACKS | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -891,12 +891,15 @@ self.assertEqual('{foo._x}'.format_map({'foo': C(20)}), '20') # test various errors - self.assertRaises(TypeError, '{'.format_map) - self.assertRaises(TypeError, '}'.format_map) - self.assertRaises(TypeError, 'a{'.format_map) - self.assertRaises(TypeError, 'a}'.format_map) - self.assertRaises(TypeError, '{a'.format_map) - self.assertRaises(TypeError, '}a'.format_map) + self.assertRaises(TypeError, ''.format_map) + self.assertRaises(TypeError, 'a'.format_map) + + self.assertRaises(ValueError, '{'.format_map, {}) + self.assertRaises(ValueError, '}'.format_map, {}) + self.assertRaises(ValueError, 'a{'.format_map, {}) + self.assertRaises(ValueError, 'a}'.format_map, {}) + self.assertRaises(ValueError, '{a'.format_map, {}) + self.assertRaises(ValueError, '}a'.format_map, {}) # issue #12579: can't supply positional params to format_map self.assertRaises(ValueError, '{}'.format_map, {'a' : 2}) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -552,6 +552,7 @@ Christopher Tur Lesniewski-Laas Mark Levinson William Lewis +Akira Li Xuanji Li Robert van Liere Ross Light -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 23:29:19 2012 From: python-checkins at python.org (eric.smith) Date: Mon, 12 Mar 2012 23:29:19 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_Merge_heads=2E?= Message-ID: http://hg.python.org/cpython/rev/368a5d7d8a15 changeset: 75559:368a5d7d8a15 branch: 3.2 parent: 75558:995cddd15313 parent: 75552:fc3a63ed1f67 user: Eric V. Smith date: Mon Mar 12 15:18:30 2012 -0700 summary: Merge heads. files: Lib/test/test_aifc.py | 163 ++++++++++++++++++++++++++++- Lib/test/test_ast.py | 6 - Python/ast.c | 10 +- 3 files changed, 156 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -1,7 +1,8 @@ -from test.support import findfile, run_unittest, TESTFN +from test.support import findfile, run_unittest, TESTFN, captured_stdout, unlink import unittest import os import io +import struct import aifc @@ -20,10 +21,8 @@ self.fout.close() except (aifc.Error, AttributeError): pass - try: - os.remove(TESTFN) - except OSError: - pass + unlink(TESTFN) + unlink(TESTFN + '.aiff') def test_skipunknown(self): #Issue 2245 @@ -32,6 +31,7 @@ def test_params(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.getfp().name, self.sndfilepath) self.assertEqual(f.getnchannels(), 2) self.assertEqual(f.getsampwidth(), 2) self.assertEqual(f.getframerate(), 48000) @@ -45,6 +45,7 @@ def test_read(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.readframes(0), b'') self.assertEqual(f.tell(), 0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') f.rewind() @@ -58,6 +59,10 @@ self.assertEqual(f.readframes(2), b'\x17t\x17t"\xad"\xad') f.setpos(pos0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') + with self.assertRaises(aifc.Error): + f.setpos(-1) + with self.assertRaises(aifc.Error): + f.setpos(f.getnframes() + 1) def test_write(self): f = self.f = aifc.open(self.sndfilepath) @@ -92,8 +97,6 @@ self.assertEqual(f.getparams()[0:3], fout.getparams()[0:3]) self.assertEqual(fout.getcomptype(), b'ULAW') self.assertEqual(fout.getcompname(), b'foo') - # XXX: this test fails, not sure if it should succeed or not - # self.assertEqual(f.readframes(5), fout.readframes(5)) def test_close(self): class Wrapfile(object): @@ -112,7 +115,7 @@ def test_write_header_comptype_sampwidth(self): for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') fout.setnchannels(1) fout.setframerate(1) fout.setcomptype(comptype, b'') @@ -121,7 +124,7 @@ fout.initfp(None) def test_write_markers_values(self): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') self.assertEqual(fout.getmarkers(), None) fout.setmark(1, 0, b'foo1') fout.setmark(1, 1, b'foo2') @@ -179,6 +182,148 @@ with self.assertRaises(ValueError): aifc._write_string(f, b'too long' * 255) + def test_wrong_open_mode(self): + with self.assertRaises(aifc.Error): + aifc.open(TESTFN, 'wrong_mode') + + def test_read_wrong_form(self): + b1 = io.BytesIO(b'WRNG' + struct.pack('>L', 0)) + b2 = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'WRNG') + self.assertRaises(aifc.Error, aifc.open, b1) + self.assertRaises(aifc.Error, aifc.open, b2) + + def test_read_no_comm_chunk(self): + b = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'AIFF') + self.assertRaises(aifc.Error, aifc.open, b) + + def test_read_wrong_compression_type(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0) + b += b'WRNG' + struct.pack('B', 0) + self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b)) + + def test_read_wrong_marks(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFF' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + b += b'MARK' + struct.pack('>LhB', 3, 1, 1) + with captured_stdout() as s: + f = aifc.open(io.BytesIO(b)) + self.assertEqual( + s.getvalue(), + 'Warning: MARK chunk contains only 0 markers instead of 1\n') + self.assertEqual(f.getmarkers(), None) + + def test_read_comm_kludge_compname_even(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with captured_stdout() as s: + f = aifc.open(io.BytesIO(b)) + self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n') + self.assertEqual(f.getcompname(), b'even') + + def test_read_comm_kludge_compname_odd(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 3) + b'odd' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with captured_stdout() as s: + f = aifc.open(io.BytesIO(b)) + self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n') + self.assertEqual(f.getcompname(), b'odd') + + def test_write_params_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + wrong_params = (0, 0, 0, 0, b'WRNG', '') + self.assertRaises(aifc.Error, fout.setparams, wrong_params) + self.assertRaises(aifc.Error, fout.getparams) + self.assertRaises(aifc.Error, fout.setnchannels, 0) + self.assertRaises(aifc.Error, fout.getnchannels) + self.assertRaises(aifc.Error, fout.setsampwidth, 0) + self.assertRaises(aifc.Error, fout.getsampwidth) + self.assertRaises(aifc.Error, fout.setframerate, 0) + self.assertRaises(aifc.Error, fout.getframerate) + self.assertRaises(aifc.Error, fout.setcomptype, b'WRNG', '') + fout.aiff() + fout.setnchannels(1) + fout.setsampwidth(1) + fout.setframerate(1) + fout.setnframes(1) + fout.writeframes(b'\x00') + self.assertRaises(aifc.Error, fout.setparams, (1, 1, 1, 1, 1, 1)) + self.assertRaises(aifc.Error, fout.setnchannels, 1) + self.assertRaises(aifc.Error, fout.setsampwidth, 1) + self.assertRaises(aifc.Error, fout.setframerate, 1) + self.assertRaises(aifc.Error, fout.setnframes, 1) + self.assertRaises(aifc.Error, fout.setcomptype, b'NONE', '') + self.assertRaises(aifc.Error, fout.aiff) + self.assertRaises(aifc.Error, fout.aifc) + + def test_write_params_singles(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + fout.setnchannels(1) + fout.setsampwidth(2) + fout.setframerate(3) + fout.setnframes(4) + fout.setcomptype(b'NONE', b'name') + self.assertEqual(fout.getnchannels(), 1) + self.assertEqual(fout.getsampwidth(), 2) + self.assertEqual(fout.getframerate(), 3) + self.assertEqual(fout.getnframes(), 0) + self.assertEqual(fout.tell(), 0) + self.assertEqual(fout.getcomptype(), b'NONE') + self.assertEqual(fout.getcompname(), b'name') + fout.writeframes(b'\x00' * 4 * fout.getsampwidth() * fout.getnchannels()) + self.assertEqual(fout.getnframes(), 4) + self.assertEqual(fout.tell(), 4) + + def test_write_params_bunch(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + p = (1, 2, 3, 4, b'NONE', b'name') + fout.setparams(p) + self.assertEqual(fout.getparams(), p) + fout.initfp(None) + + def test_write_header_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.close) + fout.setnchannels(1) + self.assertRaises(aifc.Error, fout.close) + fout.setsampwidth(1) + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_header_comptype_raises(self): + for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): + fout = aifc.open(io.BytesIO(), 'wb') + fout.setsampwidth(1) + fout.setcomptype(comptype, b'') + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_markers_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.setmark, 0, 0, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, -1, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, 0, None) + self.assertRaises(aifc.Error, fout.getmark, 1) + fout.initfp(None) + + def test_write_aiff_by_extension(self): + sampwidth = 2 + fout = self.fout = aifc.open(TESTFN + '.aiff', 'wb') + fout.setparams((1, sampwidth, 1, 1, b'ULAW', b'')) + frames = b'\x00' * fout.getnchannels() * sampwidth + fout.writeframes(frames) + fout.close() + f = self.f = aifc.open(TESTFN + '.aiff', 'rb') + self.assertEqual(f.getcomptype(), b'NONE') + f.close() + def test_main(): run_unittest(AIFCTest) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -195,12 +195,6 @@ with self.assertRaises(AttributeError): x.vararg - with self.assertRaises(AttributeError): - x.foobar = 21 - - with self.assertRaises(AttributeError): - ast.AST(lineno=2) - with self.assertRaises(TypeError): # "_ast.AST constructor takes 0 positional arguments" ast.AST(2) diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -645,7 +645,7 @@ } static arg_ty -compiler_arg(struct compiling *c, const node *n) +ast_for_arg(struct compiling *c, const node *n) { identifier name; expr_ty annotation = NULL; @@ -666,12 +666,6 @@ } return arg(name, annotation, c->c_arena); -#if 0 - result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena); - if (!set_context(c, result, Store, n)) - return NULL; - return result; -#endif } /* returns -1 if failed to handle keyword only arguments @@ -859,7 +853,7 @@ "non-default argument follows default argument"); return NULL; } - arg = compiler_arg(c, ch); + arg = ast_for_arg(c, ch); if (!arg) return NULL; asdl_seq_SET(posargs, k++, arg); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 23:29:21 2012 From: python-checkins at python.org (eric.smith) Date: Mon, 12 Mar 2012 23:29:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_str=2Eformat=5Fmap_tests_don=27t_do_what_they_say=3A_fix_to_?= =?utf8?q?actually_implement_the?= Message-ID: http://hg.python.org/cpython/rev/0df295d590a8 changeset: 75560:0df295d590a8 parent: 75555:9cccfaa6b534 parent: 75559:368a5d7d8a15 user: Eric V. Smith date: Mon Mar 12 15:26:21 2012 -0700 summary: str.format_map tests don't do what they say: fix to actually implement the intent of the test. Closes #13450. Patch by Akira Li. files: Lib/test/test_unicode.py | 15 +++++++++------ Misc/ACKS | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -957,12 +957,15 @@ self.assertEqual('{foo._x}'.format_map({'foo': C(20)}), '20') # test various errors - self.assertRaises(TypeError, '{'.format_map) - self.assertRaises(TypeError, '}'.format_map) - self.assertRaises(TypeError, 'a{'.format_map) - self.assertRaises(TypeError, 'a}'.format_map) - self.assertRaises(TypeError, '{a'.format_map) - self.assertRaises(TypeError, '}a'.format_map) + self.assertRaises(TypeError, ''.format_map) + self.assertRaises(TypeError, 'a'.format_map) + + self.assertRaises(ValueError, '{'.format_map, {}) + self.assertRaises(ValueError, '}'.format_map, {}) + self.assertRaises(ValueError, 'a{'.format_map, {}) + self.assertRaises(ValueError, 'a}'.format_map, {}) + self.assertRaises(ValueError, '{a'.format_map, {}) + self.assertRaises(ValueError, '}a'.format_map, {}) # issue #12579: can't supply positional params to format_map self.assertRaises(ValueError, '{}'.format_map, {'a' : 2}) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -602,6 +602,7 @@ Alain Leufroy Mark Levinson William Lewis +Akira Li Xuanji Li Robert van Liere Ross Light -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 23:29:21 2012 From: python-checkins at python.org (eric.smith) Date: Mon, 12 Mar 2012 23:29:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?b?KTogTWVyZ2UgaGVhZHMu?= Message-ID: http://hg.python.org/cpython/rev/6b8dd7724ec0 changeset: 75561:6b8dd7724ec0 parent: 75557:e04750e0ffd6 parent: 75560:0df295d590a8 user: Eric V. Smith date: Mon Mar 12 15:29:06 2012 -0700 summary: Merge heads. files: Lib/test/test_unicode.py | 15 +++++++++------ Misc/ACKS | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -957,12 +957,15 @@ self.assertEqual('{foo._x}'.format_map({'foo': C(20)}), '20') # test various errors - self.assertRaises(TypeError, '{'.format_map) - self.assertRaises(TypeError, '}'.format_map) - self.assertRaises(TypeError, 'a{'.format_map) - self.assertRaises(TypeError, 'a}'.format_map) - self.assertRaises(TypeError, '{a'.format_map) - self.assertRaises(TypeError, '}a'.format_map) + self.assertRaises(TypeError, ''.format_map) + self.assertRaises(TypeError, 'a'.format_map) + + self.assertRaises(ValueError, '{'.format_map, {}) + self.assertRaises(ValueError, '}'.format_map, {}) + self.assertRaises(ValueError, 'a{'.format_map, {}) + self.assertRaises(ValueError, 'a}'.format_map, {}) + self.assertRaises(ValueError, '{a'.format_map, {}) + self.assertRaises(ValueError, '}a'.format_map, {}) # issue #12579: can't supply positional params to format_map self.assertRaises(ValueError, '{}'.format_map, {'a' : 2}) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -602,6 +602,7 @@ Alain Leufroy Mark Levinson William Lewis +Akira Li Xuanji Li Robert van Liere Ross Light -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 12 23:33:23 2012 From: python-checkins at python.org (ezio.melotti) Date: Mon, 12 Mar 2012 23:33:23 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Convert_PEP_417_to_rst=2E?= Message-ID: http://hg.python.org/peps/rev/165ef1bcbce4 changeset: 4128:165ef1bcbce4 user: Ezio Melotti date: Tue Mar 13 00:33:12 2012 +0200 summary: Convert PEP 417 to rst. files: pep-0417.txt | 104 +++++++++++++++++++++------------------ 1 files changed, 56 insertions(+), 48 deletions(-) diff --git a/pep-0417.txt b/pep-0417.txt --- a/pep-0417.txt +++ b/pep-0417.txt @@ -5,79 +5,87 @@ Author: Michael Foord Status: Draft Type: Standards Track -Content-Type: text/plain +Content-Type: text/x-rst Created: 12-Mar-2012 Python-Version: 3.3 Post-History: 12-Mar-2012 Abstract +======== - This PEP proposes adding the mock [1] testing library - to the Python standard library as ``unittest.mock``. +This PEP proposes adding the mock [1]_ testing library +to the Python standard library as ``unittest.mock``. Rationale +========= - Creating mock objects for testing is a common need in Python. - Many developers create ad-hoc mocks, as needed, in their test - suites. This is currently what we do in the Python test suite, - where a standardised mock object library would be helpful. - - There are many mock object libraries available for Python [2]. - Of these, mock is overwhelmingly the most popular, with as many - downloads on PyPI as the other mocking libraries combined. - - An advantage of mock is that it is a mocking library and not a - framework. It provides a configurable and flexible mock object, - without being opinionated about how you write your tests. The - mock api is now well battle-tested and stable. - - mock also handles safely monkeypatching and unmonkeypatching - objects during the scope of a test. This is hard to do safely - and many developers / projects mimic this functionality - (often incorrectly). A standardised way to do this, handling - the complexity of patching in the presence of the descriptor - protocol (etc) is useful. People are asking for a "patch" [3] - feature to unittest. Doing this via mock.patch is preferable - to re-implementing part of this functionality in unittest. +Creating mock objects for testing is a common need in Python. +Many developers create ad-hoc mocks, as needed, in their test +suites. This is currently what we do in the Python test suite, +where a standardised mock object library would be helpful. + +There are many mock object libraries available for Python [2]_. +Of these, mock is overwhelmingly the most popular, with as many +downloads on PyPI as the other mocking libraries combined. + +An advantage of mock is that it is a mocking library and not a +framework. It provides a configurable and flexible mock object, +without being opinionated about how you write your tests. The +mock api is now well battle-tested and stable. + +mock also handles safely monkeypatching and unmonkeypatching +objects during the scope of a test. This is hard to do safely +and many developers / projects mimic this functionality +(often incorrectly). A standardised way to do this, handling +the complexity of patching in the presence of the descriptor +protocol (etc) is useful. People are asking for a "patch" [3]_ +feature to unittest. Doing this via mock.patch is preferable +to re-implementing part of this functionality in unittest. Background - Addition of mock to the Python standard library was discussed - and agreed to at the Python Language Summit 2012. +========== + +Addition of mock to the Python standard library was discussed +and agreed to at the Python Language Summit 2012. Open Issues - As of release 0.8, which is current at the time of writing, - mock is compatible with Python 2.4-3.2. Moving into the Python - standard library will allow for the removal of some Python 2 - specific "compatibility hacks". - - mock 0.8 introduced a new feature, "auto-speccing", obsoletes - an older mock feature called "mocksignature". The - "mocksignature" functionality can be removed from mock - altogether prior to inclusion. +=========== + +As of release 0.8, which is current at the time of writing, +mock is compatible with Python 2.4-3.2. Moving into the Python +standard library will allow for the removal of some Python 2 +specific "compatibility hacks". + +mock 0.8 introduced a new feature, "auto-speccing", obsoletes +an older mock feature called "mocksignature". The +"mocksignature" functionality can be removed from mock +altogether prior to inclusion. References +========== - [1] `mock library on PyPI `_ - [2] http://pypi.python.org/pypi?%3Aaction=search&term=mock&submit=search - [3] http://bugs.python.org/issue11664 - +.. [1] `mock library on PyPI `_ +.. [2] http://pypi.python.org/pypi?%3Aaction=search&term=mock&submit=search +.. [3] http://bugs.python.org/issue11664 Copyright +========= - This document has been placed in the public domain. +This document has been placed in the public domain. -Local Variables: -mode: indented-text -indent-tabs-mode: nil -sentence-end-double-space: t -fill-column: 70 -coding: utf-8 -End: +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Mar 12 23:42:00 2012 From: python-checkins at python.org (lukasz.langa) Date: Mon, 12 Mar 2012 23:42:00 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_minor_PEP7-related_fix?= Message-ID: http://hg.python.org/cpython/rev/fa0d86b4a656 changeset: 75562:fa0d86b4a656 user: ?ukasz Langa date: Mon Mar 12 23:41:07 2012 +0100 summary: minor PEP7-related fix files: Modules/_pickle.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2816,7 +2816,7 @@ { PyObject *str = PyUnicode_FromString("Ellipsis"); if (str == NULL) - return -1; + return -1; return save_global(self, Py_Ellipsis, str); } @@ -2825,7 +2825,7 @@ { PyObject *str = PyUnicode_FromString("NotImplemented"); if (str == NULL) - return -1; + return -1; return save_global(self, Py_NotImplemented, str); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 00:22:41 2012 From: python-checkins at python.org (brett.cannon) Date: Tue, 13 Mar 2012 00:22:41 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Be_explicit_about_using_the_lo?= =?utf8?q?west_PEP_number_=28e=2Eg=2E_in_the_400s=29_instead_of_the?= Message-ID: http://hg.python.org/peps/rev/7a9fb7faa02f changeset: 4129:7a9fb7faa02f user: Brett Cannon date: Mon Mar 12 19:22:35 2012 -0400 summary: Be explicit about using the lowest PEP number (e.g. in the 400s) instead of the next number (e.g. in the 3100s). files: pep-0001.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0001.txt b/pep-0001.txt --- a/pep-0001.txt +++ b/pep-0001.txt @@ -413,8 +413,8 @@ Once the PEP is ready for the repository, the PEP editor will: -* Assign a PEP number (almost always just the next available number, - but sometimes it's a special/joke number, like 666 or 3141). +* Assign a PEP number (almost always just the next available *lowest* + number, but sometimes it's a special/joke number, like 666 or 3141). * List the PEP in PEP 0 (in two places: the categorized list, and the numeric list). -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 13 00:25:57 2012 From: python-checkins at python.org (ezio.melotti) Date: Tue, 13 Mar 2012 00:25:57 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzE0MTc5OiBhZGQg?= =?utf8?q?tests_for_re=2Ecompile=2E__Patch_by_Florian_Mladitsch=2E?= Message-ID: http://hg.python.org/cpython/rev/cc48eef234dd changeset: 75563:cc48eef234dd branch: 2.7 parent: 75531:f0a5f39615c8 user: Ezio Melotti date: Tue Mar 13 01:25:40 2012 +0200 summary: #14179: add tests for re.compile. Patch by Florian Mladitsch. files: Lib/test/test_re.py | 10 ++++++++++ Misc/ACKS | 1 + 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -783,6 +783,16 @@ self.assertRaises(TypeError, re.finditer, "a", {}) self.assertRaises(OverflowError, _sre.compile, "abc", 0, [long_overflow]) + def test_compile(self): + # Test return value when given string and pattern as parameter + pattern = re.compile('random pattern') + self.assertIsInstance(pattern, re._pattern_type) + same_pattern = re.compile(pattern) + self.assertIsInstance(same_pattern, re._pattern_type) + self.assertIs(same_pattern, pattern) + # Test behaviour when not given a string or pattern as parameter + self.assertRaises(TypeError, re.compile, 0) + def run_re_tests(): from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR if verbose: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -577,6 +577,7 @@ Andrii V. Mishkovskyi Dustin J. Mitchell Dom Mitchell +Florian Mladitsch Doug Moen The Dragon De Monsyne Skip Montanaro -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 00:27:08 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 13 Mar 2012 00:27:08 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314104=3A_Implement?= =?utf8?q?_time=2Emonotonic=28=29_on_Mac_OS_X=2C?= Message-ID: http://hg.python.org/cpython/rev/3c875719e46d changeset: 75564:3c875719e46d parent: 75562:fa0d86b4a656 user: Victor Stinner date: Tue Mar 13 00:25:42 2012 +0100 summary: Issue #14104: Implement time.monotonic() on Mac OS X, patch written by Nicholas Riley. files: Misc/NEWS | 3 +++ Modules/timemodule.c | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #14104: Implement time.monotonic() on Mac OS X, patch written by + Nicholas Riley. + - Issue #13394: the aifc module now uses warnings.warn() to signal warnings. - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -40,6 +40,10 @@ #include #endif +#if defined(__APPLE__) +#include +#endif + /* Forward declarations */ static int floatsleep(double); static double floattime(void); @@ -816,7 +820,8 @@ calls is valid."); #if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) \ - || (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)) + || (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)) \ + || (defined(__APPLE__)) # define HAVE_PYTIME_MONOTONIC #endif @@ -826,6 +831,17 @@ { #if defined(MS_WINDOWS) && !defined(__BORLANDC__) return win32_clock(0); +#elif defined(__APPLE__) + uint64_t time = mach_absolute_time(); + double secs; + + static mach_timebase_info_data_t timebase; + if (timebase.denom == 0) + mach_timebase_info(&timebase); + + secs = (double)time * timebase.numer / timebase.denom * 1e-9; + + return PyFloat_FromDouble(secs); #else static int clk_index = 0; clockid_t clk_ids[] = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 00:33:50 2012 From: python-checkins at python.org (ezio.melotti) Date: Tue, 13 Mar 2012 00:33:50 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzE0MTc5OiBhZGQg?= =?utf8?q?tests_for_re=2Ecompile=2E__Patch_by_Florian_Mladitsch=2E?= Message-ID: http://hg.python.org/cpython/rev/fafe12f2a030 changeset: 75565:fafe12f2a030 branch: 3.2 parent: 75559:368a5d7d8a15 user: Ezio Melotti date: Tue Mar 13 01:29:48 2012 +0200 summary: #14179: add tests for re.compile. Patch by Florian Mladitsch. files: Lib/test/test_re.py | 10 ++++++++++ Misc/ACKS | 1 + 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -818,6 +818,16 @@ self.assertRaises(OverflowError, _sre.compile, "abc", 0, [long_overflow]) self.assertRaises(TypeError, _sre.compile, {}, 0, []) + def test_compile(self): + # Test return value when given string and pattern as parameter + pattern = re.compile('random pattern') + self.assertIsInstance(pattern, re._pattern_type) + same_pattern = re.compile(pattern) + self.assertIsInstance(same_pattern, re._pattern_type) + self.assertIs(same_pattern, pattern) + # Test behaviour when not given a string or pattern as parameter + self.assertRaises(TypeError, re.compile, 0) + def run_re_tests(): from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR if verbose: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -629,6 +629,7 @@ Andrii V. Mishkovskyi Dustin J. Mitchell Dom Mitchell +Florian Mladitsch Doug Moen The Dragon De Monsyne Skip Montanaro -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 00:33:51 2012 From: python-checkins at python.org (ezio.melotti) Date: Tue, 13 Mar 2012 00:33:51 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=2314179=3A_merge_with_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/4a5eafcdde11 changeset: 75566:4a5eafcdde11 parent: 75564:3c875719e46d parent: 75565:fafe12f2a030 user: Ezio Melotti date: Tue Mar 13 01:33:30 2012 +0200 summary: #14179: merge with 3.2. files: Lib/test/test_re.py | 10 ++++++++++ Misc/ACKS | 1 + 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -825,6 +825,16 @@ self.assertIsNotNone(re.search("123.*-", '123\U0010ffff-')) self.assertIsNotNone(re.search("123.*-", '123\xe9\u20ac\U0010ffff-')) + def test_compile(self): + # Test return value when given string and pattern as parameter + pattern = re.compile('random pattern') + self.assertIsInstance(pattern, re._pattern_type) + same_pattern = re.compile(pattern) + self.assertIsInstance(same_pattern, re._pattern_type) + self.assertIs(same_pattern, pattern) + # Test behaviour when not given a string or pattern as parameter + self.assertRaises(TypeError, re.compile, 0) + def run_re_tests(): from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR if verbose: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -687,6 +687,7 @@ Dom Mitchell Dustin J. Mitchell Zubin Mithra +Florian Mladitsch Doug Moen The Dragon De Monsyne Skip Montanaro -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 00:50:36 2012 From: python-checkins at python.org (michael.foord) Date: Tue, 13 Mar 2012 00:50:36 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Accepting_PEP_417?= Message-ID: http://hg.python.org/peps/rev/b8863d30b3ee changeset: 4130:b8863d30b3ee user: Michael Foord date: Mon Mar 12 16:50:28 2012 -0700 summary: Accepting PEP 417 files: pep-0417.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0417.txt b/pep-0417.txt --- a/pep-0417.txt +++ b/pep-0417.txt @@ -3,12 +3,13 @@ Version: $Revision$ Last-Modified: $Date$ Author: Michael Foord -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 12-Mar-2012 Python-Version: 3.3 Post-History: 12-Mar-2012 +Resolution: http://mail.python.org/pipermail/python-dev/2012-March/117507.html Abstract -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 13 00:59:43 2012 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 13 Mar 2012 00:59:43 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Ignore_*=7E_files=2E?= Message-ID: http://hg.python.org/peps/rev/ab8103e13233 changeset: 4131:ab8103e13233 parent: 4129:7a9fb7faa02f user: Guido van Rossum date: Mon Mar 12 16:52:25 2012 -0700 summary: Ignore *~ files. files: .hgignore | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -3,3 +3,4 @@ pep-????.html *.pyc *.pyo +*~ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 13 00:59:44 2012 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 13 Mar 2012 00:59:44 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Reject_PEP_382=2C_PEP_402=2C_a?= =?utf8?q?ccept_PEP_335=2E?= Message-ID: http://hg.python.org/peps/rev/5b93aa6c1322 changeset: 4132:5b93aa6c1322 user: Guido van Rossum date: Mon Mar 12 16:58:36 2012 -0700 summary: Reject PEP 382, PEP 402, accept PEP 335. files: pep-0335.txt | 7 ++++++- pep-0382.txt | 13 ++++++++++++- pep-0402.txt | 13 ++++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/pep-0335.txt b/pep-0335.txt --- a/pep-0335.txt +++ b/pep-0335.txt @@ -3,13 +3,18 @@ Version: $Revision$ Last-Modified: $Date$ Author: Gregory Ewing -Status: Draft +Status: Rejected Type: Standards Track Content-Type: text/x-rst Created: 29-Aug-2004 Python-Version: 3.3 Post-History: 05-Sep-2004, 30-Sep-2011, 25-Oct-2011 +Rejection Notice +================ + +This PEP was rejected. +See http://mail.python.org/pipermail/python-dev/2012-March/117510.html Abstract ======== diff --git a/pep-0382.txt b/pep-0382.txt --- a/pep-0382.txt +++ b/pep-0382.txt @@ -3,13 +3,21 @@ Version: $Revision$ Last-Modified: $Date$ Author: Martin v. L?wis -Status: Draft +Status: Rejected Type: Standards Track Content-Type: text/x-rst Created: 02-Apr-2009 Python-Version: 3.2 Post-History: +Rejection Notice +================ + +On the first day of sprints at US PyCon 2012 we had a long and +fruitful discussion about PEP 382 and PEP 402. We ended up rejecting +both but a new PEP will be written to carry on in the spirit of PEP +402. Martin von L?wis wrote up a summary: [2]_. + Abstract ======== @@ -200,6 +208,9 @@ .. [1] PEP 382 branch (http://hg.python.org/features/pep-382-2#pep-382) +.. [2] Namespace Packages resolution + (http://mail.python.org/pipermail/import-sig/2012-March/000421.html) + Copyright ========= diff --git a/pep-0402.txt b/pep-0402.txt --- a/pep-0402.txt +++ b/pep-0402.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: P.J. Eby -Status: Draft +Status: Rejected Type: Standards Track Content-Type: text/x-rst Created: 12-Jul-2011 @@ -11,6 +11,14 @@ Post-History: 20-Jul-2011 Replaces: 382 +Rejection Notice +================ + +On the first day of sprints at US PyCon 2012 we had a long and +fruitful discussion about PEP 382 and PEP 402. We ended up rejecting +both but a new PEP will be written to carry on in the spirit of PEP +402. Martin von L?wis wrote up a summary: [3]_. + Abstract ======== @@ -647,6 +655,9 @@ .. [2] "Dropping __init__.py requirement for subpackages" (http://mail.python.org/pipermail/python-dev/2006-April/064400.html) +.. [3] Namespace Packages resolution + (http://mail.python.org/pipermail/import-sig/2012-March/000421.html) + Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 13 00:59:45 2012 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 13 Mar 2012 00:59:45 +0100 Subject: [Python-checkins] =?utf8?q?peps_=28merge_default_-=3E_default=29?= =?utf8?q?=3A_Merge?= Message-ID: http://hg.python.org/peps/rev/920bba6d5916 changeset: 4133:920bba6d5916 parent: 4132:5b93aa6c1322 parent: 4130:b8863d30b3ee user: Guido van Rossum date: Mon Mar 12 16:59:06 2012 -0700 summary: Merge files: pep-0417.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0417.txt b/pep-0417.txt --- a/pep-0417.txt +++ b/pep-0417.txt @@ -3,12 +3,13 @@ Version: $Revision$ Last-Modified: $Date$ Author: Michael Foord -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 12-Mar-2012 Python-Version: 3.3 Post-History: 12-Mar-2012 +Resolution: http://mail.python.org/pipermail/python-dev/2012-March/117507.html Abstract -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 13 01:06:50 2012 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 13 Mar 2012 01:06:50 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Clarify_numbering_scheme_a_bit?= =?utf8?q?_more=2E?= Message-ID: http://hg.python.org/peps/rev/64946958be78 changeset: 4134:64946958be78 user: Guido van Rossum date: Mon Mar 12 17:06:44 2012 -0700 summary: Clarify numbering scheme a bit more. files: pep-0001.txt | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pep-0001.txt b/pep-0001.txt --- a/pep-0001.txt +++ b/pep-0001.txt @@ -413,8 +413,12 @@ Once the PEP is ready for the repository, the PEP editor will: -* Assign a PEP number (almost always just the next available *lowest* - number, but sometimes it's a special/joke number, like 666 or 3141). +* Assign a PEP number (almost always just the next available number, + but sometimes it's a special/joke number, like 666 or 3141). + (Clarification: For Python 3, we used numbers in the 3000s for + Py3k-specific proposals. But now that all new features go into + Python 3 only, we're back to using numbers in the 100s again. + Remember that numbers below 100 are meta-PEPs.) * List the PEP in PEP 0 (in two places: the categorized list, and the numeric list). -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 13 01:17:17 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 13 Mar 2012 01:17:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Try_to_fix_compilation_of_P?= =?utf8?q?ython-ast=2Ec_on_Visual_Studio_2008?= Message-ID: http://hg.python.org/cpython/rev/6bee4eea1efa changeset: 75567:6bee4eea1efa user: Victor Stinner date: Tue Mar 13 01:17:31 2012 +0100 summary: Try to fix compilation of Python-ast.c on Visual Studio 2008 files: Parser/asdl_c.py | 2 +- Python/Python-ast.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -604,7 +604,7 @@ def visitModule(self, mod): self.emit(""" typedef struct { - PyObject_HEAD; + PyObject_HEAD PyObject *dict; } AST_object; diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -456,7 +456,7 @@ typedef struct { - PyObject_HEAD; + PyObject_HEAD PyObject *dict; } AST_object; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 01:22:54 2012 From: python-checkins at python.org (sean.reifschneider) Date: Tue, 13 Mar 2012 01:22:54 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_closes_=2314259_re=2Efindit?= =?utf8?q?er=28=29_now_takes_keyword_arguments=3A_pos=2C_endpos=2E?= Message-ID: http://hg.python.org/cpython/rev/1adb114343f9 changeset: 75568:1adb114343f9 user: Sean Reifschneider date: Mon Mar 12 18:22:38 2012 -0600 summary: closes #14259 re.finditer() now takes keyword arguments: pos, endpos. Contrary to the documentation, finditer() did not take pos and endpos keyword arguments. files: Lib/test/test_re.py | 20 ++++++++++++++++++++ Misc/NEWS | 3 +++ Modules/_sre.c | 16 +++++++++------- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -652,6 +652,26 @@ self.assertEqual([item.group(0) for item in iter], [":", "::", ":::"]) + pat = re.compile(r":+") + iter = pat.finditer("a:b::c:::d", 1, 10) + self.assertEqual([item.group(0) for item in iter], + [":", "::", ":::"]) + + pat = re.compile(r":+") + iter = pat.finditer("a:b::c:::d", pos=1, endpos=10) + self.assertEqual([item.group(0) for item in iter], + [":", "::", ":::"]) + + pat = re.compile(r":+") + iter = pat.finditer("a:b::c:::d", endpos=10, pos=1) + self.assertEqual([item.group(0) for item in iter], + [":", "::", ":::"]) + + pat = re.compile(r":+") + iter = pat.finditer("a:b::c:::d", pos=3, endpos=8) + self.assertEqual([item.group(0) for item in iter], + ["::", "::"]) + def test_bug_926075(self): self.assertTrue(re.compile('bug_926075') is not re.compile(b'bug_926075')) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -56,6 +56,9 @@ - Issue #14212: The re module didn't retain a reference to buffers it was scanning, resulting in segfaults. +- Issue #14259: The finditer() method of re objects did not take any + keyword arguments, contrary to the documentation. + What's New in Python 3.3.0 Alpha 1? =================================== diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -1596,7 +1596,7 @@ /* see sre.h for object declarations */ static PyObject*pattern_new_match(PatternObject*, SRE_STATE*, int); -static PyObject*pattern_scanner(PatternObject*, PyObject*); +static PyObject*pattern_scanner(PatternObject*, PyObject*, PyObject* kw); static int sre_literal_template(int charsize, char* ptr, Py_ssize_t len) @@ -2132,13 +2132,13 @@ #if PY_VERSION_HEX >= 0x02020000 static PyObject* -pattern_finditer(PatternObject* pattern, PyObject* args) +pattern_finditer(PatternObject* pattern, PyObject* args, PyObject* kw) { PyObject* scanner; PyObject* search; PyObject* iterator; - scanner = pattern_scanner(pattern, args); + scanner = pattern_scanner(pattern, args, kw); if (!scanner) return NULL; @@ -2576,10 +2576,10 @@ {"findall", (PyCFunction) pattern_findall, METH_VARARGS|METH_KEYWORDS, pattern_findall_doc}, #if PY_VERSION_HEX >= 0x02020000 - {"finditer", (PyCFunction) pattern_finditer, METH_VARARGS, + {"finditer", (PyCFunction) pattern_finditer, METH_VARARGS|METH_KEYWORDS, pattern_finditer_doc}, #endif - {"scanner", (PyCFunction) pattern_scanner, METH_VARARGS}, + {"scanner", (PyCFunction) pattern_scanner, METH_VARARGS|METH_KEYWORDS}, {"__copy__", (PyCFunction) pattern_copy, METH_NOARGS}, {"__deepcopy__", (PyCFunction) pattern_deepcopy, METH_O}, {NULL, NULL} @@ -3822,7 +3822,7 @@ }; static PyObject* -pattern_scanner(PatternObject* pattern, PyObject* args) +pattern_scanner(PatternObject* pattern, PyObject* args, PyObject* kw) { /* create search state object */ @@ -3831,7 +3831,9 @@ PyObject* string; Py_ssize_t start = 0; Py_ssize_t end = PY_SSIZE_T_MAX; - if (!PyArg_ParseTuple(args, "O|nn:scanner", &string, &start, &end)) + static char* kwlist[] = { "source", "pos", "endpos", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|nn:scanner", kwlist, + &string, &start, &end)) return NULL; /* create scanner object */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 01:47:47 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 13 Mar 2012 01:47:47 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=231178863=3A_Separat?= =?utf8?q?e_initialisation_from_setting_when_initializing?= Message-ID: http://hg.python.org/cpython/rev/79bb99ec2464 changeset: 75569:79bb99ec2464 user: Martin v. L?wis date: Mon Mar 12 17:47:35 2012 -0700 summary: Issue #1178863: Separate initialisation from setting when initializing Tkinter.Variables; harmonize exceptions to ValueError; only delete variables that have not been deleted; assert that variable names are strings Patch by Andrew Svetlov. files: Lib/tkinter/__init__.py | 36 +- Lib/tkinter/test/test_tkinter/test_variables.py | 165 ++++++++++ Misc/NEWS | 4 + 3 files changed, 193 insertions(+), 12 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -155,6 +155,7 @@ Subclasses StringVar, IntVar, DoubleVar, BooleanVar are specializations that constrain the type of the value returned from get().""" _default = "" + _tk = None def __init__(self, master=None, value=None, name=None): """Construct a variable @@ -165,6 +166,11 @@ If NAME matches an existing variable and VALUE is omitted then the existing value is retained. """ + # check for type of NAME parameter to override weird error message + # raised from Modules/_tkinter.c:SetVar like: + # TypeError: setvar() takes exactly 3 arguments (2 given) + if name is not None and not isinstance(name, str): + raise TypeError("name must be a string") global _varnum if not master: master = _default_root @@ -176,18 +182,21 @@ self._name = 'PY_VAR' + repr(_varnum) _varnum += 1 if value is not None: - self.set(value) + self.initialize(value) elif not self._tk.call("info", "exists", self._name): - self.set(self._default) + self.initialize(self._default) def __del__(self): """Unset the variable in Tcl.""" - self._tk.globalunsetvar(self._name) + if (self._tk is not None and self._tk.call("info", "exists", + self._name)): + self._tk.globalunsetvar(self._name) def __str__(self): """Return the name of the variable in Tcl.""" return self._name def set(self, value): """Set the variable to VALUE.""" return self._tk.globalsetvar(self._name, value) + initialize = set def get(self): """Return value of variable.""" return self._tk.globalgetvar(self._name) @@ -262,12 +271,6 @@ """ Variable.__init__(self, master, value, name) - def set(self, value): - """Set the variable to value, converting booleans to integers.""" - if isinstance(value, bool): - value = int(value) - return Variable.set(self, value) - def get(self): """Return the value of the variable as an integer.""" return getint(self._tk.globalgetvar(self._name)) @@ -308,7 +311,10 @@ def get(self): """Return the value of the variable as a bool.""" - return self._tk.getboolean(self._tk.globalgetvar(self._name)) + try: + return self._tk.getboolean(self._tk.globalgetvar(self._name)) + except TclError: + raise ValueError("invalid literal for getboolean()") def mainloop(n=0): """Run the main loop of Tcl.""" @@ -320,7 +326,10 @@ def getboolean(s): """Convert true and false to integer values 1 and 0.""" - return _default_root.tk.getboolean(s) + try: + return _default_root.tk.getboolean(s) + except TclError: + raise ValueError("invalid literal for getboolean()") # Methods defined on both toplevel and interior widgets class Misc: @@ -410,7 +419,10 @@ getdouble = float def getboolean(self, s): """Return a boolean value for Tcl boolean values true and false given as parameter.""" - return self.tk.getboolean(s) + try: + return self.tk.getboolean(s) + except TclError: + raise ValueError("invalid literal for getboolean()") def focus_set(self): """Direct input focus to this widget. diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py new file mode 100644 --- /dev/null +++ b/Lib/tkinter/test/test_tkinter/test_variables.py @@ -0,0 +1,165 @@ +import unittest + +from tkinter import Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tk + + +class Var(Variable): + + _default = "default" + side_effect = False + + def set(self, value): + self.side_effect = True + super().set(value) + + +class TestBase(unittest.TestCase): + + def setUp(self): + self.root = Tk() + + def tearDown(self): + self.root.destroy() + + +class TestVariable(TestBase): + + def test_default(self): + v = Variable(self.root) + self.assertEqual("", v.get()) + self.assertRegex(str(v), r"^PY_VAR(\d+)$") + + def test_name_and_value(self): + v = Variable(self.root, "sample string", "varname") + self.assertEqual("sample string", v.get()) + self.assertEqual("varname", str(v)) + + def test___del__(self): + self.assertFalse(self.root.call("info", "exists", "varname")) + v = Variable(self.root, "sample string", "varname") + self.assertTrue(self.root.call("info", "exists", "varname")) + del v + self.assertFalse(self.root.call("info", "exists", "varname")) + + def test_dont_unset_not_existing(self): + self.assertFalse(self.root.call("info", "exists", "varname")) + v1 = Variable(self.root, name="name") + v2 = Variable(self.root, name="name") + del v1 + self.assertFalse(self.root.call("info", "exists", "name")) + # shouldn't raise exception + del v2 + self.assertFalse(self.root.call("info", "exists", "name")) + + def test___eq__(self): + # values doesn't matter, only class and name are checked + v1 = Variable(self.root, name="abc") + v2 = Variable(self.root, name="abc") + self.assertEqual(v1, v2) + + v3 = Variable(self.root, name="abc") + v4 = StringVar(self.root, name="abc") + self.assertNotEqual(v3, v4) + + def test_invalid_name(self): + with self.assertRaises(TypeError): + Variable(self.root, name=123) + + def test_initialize(self): + v = Var() + self.assertFalse(v.side_effect) + v.set("value") + self.assertTrue(v.side_effect) + + +class TestStringVar(TestBase): + + def test_default(self): + v = StringVar(self.root) + self.assertEqual("", v.get()) + + def test_get(self): + v = StringVar(self.root, "abc", "name") + self.assertEqual("abc", v.get()) + self.root.globalsetvar("name", True) + self.assertEqual("1", v.get()) + + +class TestIntVar(TestBase): + + def test_default(self): + v = IntVar(self.root) + self.assertEqual(0, v.get()) + + def test_get(self): + v = IntVar(self.root, 123, "name") + self.assertEqual(123, v.get()) + self.root.globalsetvar("name", "345") + self.assertEqual(345, v.get()) + + def test_invalid_value(self): + v = IntVar(self.root, name="name") + self.root.globalsetvar("name", "value") + with self.assertRaises(ValueError): + v.get() + self.root.globalsetvar("name", "345.0") + with self.assertRaises(ValueError): + v.get() + + +class TestDoubleVar(TestBase): + + def test_default(self): + v = DoubleVar(self.root) + self.assertEqual(0.0, v.get()) + + def test_get(self): + v = DoubleVar(self.root, 1.23, "name") + self.assertAlmostEqual(1.23, v.get()) + self.root.globalsetvar("name", "3.45") + self.assertAlmostEqual(3.45, v.get()) + + def test_get_from_int(self): + v = DoubleVar(self.root, 1.23, "name") + self.assertAlmostEqual(1.23, v.get()) + self.root.globalsetvar("name", "3.45") + self.assertAlmostEqual(3.45, v.get()) + self.root.globalsetvar("name", "456") + self.assertAlmostEqual(456, v.get()) + + def test_invalid_value(self): + v = DoubleVar(self.root, name="name") + self.root.globalsetvar("name", "value") + with self.assertRaises(ValueError): + v.get() + + +class TestBooleanVar(TestBase): + + def test_default(self): + v = BooleanVar(self.root) + self.assertEqual(False, v.get()) + + def test_get(self): + v = BooleanVar(self.root, True, "name") + self.assertAlmostEqual(True, v.get()) + self.root.globalsetvar("name", "0") + self.assertAlmostEqual(False, v.get()) + + def test_invalid_value_domain(self): + v = BooleanVar(self.root, name="name") + self.root.globalsetvar("name", "value") + with self.assertRaises(ValueError): + v.get() + self.root.globalsetvar("name", "1.0") + with self.assertRaises(ValueError): + v.get() + + +tests_gui = (TestVariable, TestStringVar, TestIntVar, + TestDoubleVar, TestBooleanVar) + + +if __name__ == "__main__": + from test.support import run_unittest + run_unittest(*tests_gui) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,10 @@ Library ------- +- Issue #1178863: Separate initialisation from setting when initializing + Tkinter.Variables; harmonize exceptions to ValueError; only delete variables + that have not been deleted; assert that variable names are strings. + - Issue #14104: Implement time.monotonic() on Mac OS X, patch written by Nicholas Riley. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 02:17:11 2012 From: python-checkins at python.org (r.david.murray) Date: Tue, 13 Mar 2012 02:17:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=238942=3A_add_test_for_=5F?= =?utf8?q?=5Fpath=5F=5F_contents_in_zipimport_tests?= Message-ID: http://hg.python.org/cpython/rev/7e576ad85663 changeset: 75570:7e576ad85663 user: R David Murray date: Mon Mar 12 21:16:33 2012 -0400 summary: #8942: add test for __path__ contents in zipimport tests Patch by Tatiana Al-Chueyr. files: Lib/test/test_zipimport.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -205,6 +205,10 @@ mod = zi.load_module(TESTPACK) self.assertEqual(zi.get_filename(TESTPACK), mod.__file__) + existing_pack_path = __import__(TESTPACK).__path__[0] + expected_path_path = os.path.join(TEMP_ZIP, TESTPACK) + self.assertEqual(existing_pack_path, expected_path_path) + self.assertEqual(zi.is_package(packdir + '__init__'), False) self.assertEqual(zi.is_package(packdir + TESTPACK2), True) self.assertEqual(zi.is_package(packdir2 + TESTMOD), False) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 04:25:44 2012 From: python-checkins at python.org (tarek.ziade) Date: Tue, 13 Mar 2012 04:25:44 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_changed_the_metadata_beh?= =?utf8?q?avior_so_the_version_does_not_get_set_all_the_time?= Message-ID: http://hg.python.org/distutils2/rev/812ba38e2f63 changeset: 1296:812ba38e2f63 user: Tarek Ziade date: Mon Mar 12 20:25:35 2012 -0700 summary: changed the metadata behavior so the version does not get set all the time files: distutils2/database.py | 3 +- distutils2/metadata.py | 29 +++++++++--------- distutils2/tests/test_metadata.py | 25 ++++++++++++--- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/distutils2/database.py b/distutils2/database.py --- a/distutils2/database.py +++ b/distutils2/database.py @@ -380,7 +380,8 @@ if self.metadata['Metadata-Version'] == '1.1': # we can't have 1.1 metadata *and* Setuptools requires for field in ('Obsoletes', 'Requires', 'Provides'): - del self.metadata[field] + if field in self.metadata: + del self.metadata[field] reqs = [] diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -49,7 +49,7 @@ # preferred version. Hopefully will be changed # to 1.2 once PEP 345 is supported everywhere -PKG_INFO_PREFERRED_VERSION = '1.0' +PKG_INFO_PREFERRED_VERSION = '1.1' _LINE_PREFIX = re.compile('\n \|') _241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', @@ -102,7 +102,12 @@ return True return False - keys = list(fields) + keys = [] + for key, value in fields.items(): + if value in ([], 'UNKNOWN', None): + continue + keys.append(key) + possible_versions = ['1.0', '1.1', '1.2'] # first let's try to see if a field is not part of one of the version @@ -215,8 +220,9 @@ self.read_file(fileobj) elif mapping is not None: self.update(mapping) + self.set_metadata_version() - def _set_best_version(self): + def set_metadata_version(self): self._fields['Metadata-Version'] = _best_version(self._fields) def _write_field(self, file, name, value): @@ -234,7 +240,6 @@ del self._fields[field_name] except KeyError: raise KeyError(name) - self._set_best_version() def __contains__(self, name): return (name in self._fields or @@ -336,6 +341,7 @@ value = msg[field] if value is not None and value != 'UNKNOWN': self.set(field, value) + self.set_metadata_version() def write(self, filepath): """Write the metadata fields to filepath.""" @@ -347,7 +353,8 @@ def write_file(self, fileobject): """Write the PKG-INFO format data to a file object.""" - self._set_best_version() + self.set_metadata_version() + for field in _version2fieldlist(self['Metadata-Version']): values = self.get(field) if field in _ELEMENTSFIELD: @@ -374,14 +381,6 @@ Keys that don't match a metadata field or that have an empty value are dropped. """ - # XXX the code should just use self.set, which does tbe same checks and - # conversions already, but that would break packaging.pypi: it uses the - # update method, which does not call _set_best_version (which set - # does), and thus allows having a Metadata object (as long as you don't - # modify or write it) with extra fields from PyPI that are not fields - # defined in Metadata PEPs. to solve it, the best_version system - # should be reworked so that it's called only for writing, or in a new - # strict mode, or with a new, more lax Metadata subclass in p7g.pypi def _set(key, value): if key in _ATTR2FIELD and value: self.set(self._convert_name(key), value) @@ -442,7 +441,6 @@ value = self._remove_line_prefix(value) self._fields[name] = value - self._set_best_version() def get(self, name, default=_MISSING): """Get a metadata field.""" @@ -484,6 +482,8 @@ def check(self, strict=False, restructuredtext=False): """Check if the metadata is compliant. If strict is False then raise if no Name or Version are provided""" + self.set_metadata_version() + # XXX should check the versions (if the file was loaded) missing, warnings = [], [] @@ -528,6 +528,7 @@ Field names will be converted to use the underscore-lowercase style instead of hyphen-mixed case (i.e. home_page instead of Home-page). """ + self.set_metadata_version() data = { 'metadata_version': self['Metadata-Version'], 'name': self['Name'], diff --git a/distutils2/tests/test_metadata.py b/distutils2/tests/test_metadata.py --- a/distutils2/tests/test_metadata.py +++ b/distutils2/tests/test_metadata.py @@ -54,7 +54,7 @@ self.assertEqual(len(m.items()), 22) m = Metadata(mapping=dict(name='Test', version='1.0')) - self.assertEqual(len(m.items()), 11) + self.assertEqual(len(m.items()), 17) d = dict(m.items()) self.assertRaises(TypeError, Metadata, @@ -266,27 +266,32 @@ self.assertNotIn('Obsoletes', metadata) metadata['Classifier'] = ['ok'] + metadata.set_metadata_version() self.assertEqual(metadata['Metadata-Version'], '1.1') metadata = Metadata() metadata['Download-URL'] = 'ok' + metadata.set_metadata_version() self.assertEqual(metadata['Metadata-Version'], '1.1') metadata = Metadata() metadata['Obsoletes'] = 'ok' + metadata.set_metadata_version() self.assertEqual(metadata['Metadata-Version'], '1.1') del metadata['Obsoletes'] metadata['Obsoletes-Dist'] = 'ok' + metadata.set_metadata_version() self.assertEqual(metadata['Metadata-Version'], '1.2') - - self.assertRaises(MetadataConflictError, metadata.set, - 'Obsoletes', 'ok') + metadata.set('Obsoletes', 'ok') + self.assertRaises(MetadataConflictError, + metadata.set_metadata_version) del metadata['Obsoletes'] del metadata['Obsoletes-Dist'] + metadata.set_metadata_version() metadata['Version'] = '1' - self.assertEqual(metadata['Metadata-Version'], '1.0') + self.assertEqual(metadata['Metadata-Version'], '1.1') # make sure the _best_version function works okay with # non-conflicting fields from 1.1 and 1.2 (i.e. we want only the @@ -295,18 +300,25 @@ metadata = Metadata() metadata['Requires-Python'] = '3' metadata['Classifier'] = ['Programming language :: Python :: 3'] + metadata.set_metadata_version() self.assertEqual(metadata['Metadata-Version'], '1.2') PKG_INFO = os.path.join(os.path.dirname(__file__), 'SETUPTOOLS-PKG-INFO') metadata = Metadata(PKG_INFO) - self.assertEqual(metadata['Metadata-Version'], '1.0') + self.assertEqual(metadata['Metadata-Version'], '1.1') PKG_INFO = os.path.join(os.path.dirname(__file__), 'SETUPTOOLS-PKG-INFO2') metadata = Metadata(PKG_INFO) self.assertEqual(metadata['Metadata-Version'], '1.1') + # make sure an empty list for Obsoletes and Requires-dist gets ignored + metadata['Obsoletes'] = [] + metadata['Requires-dist'] = [] + metadata.set_metadata_version() + self.assertEqual(metadata['Metadata-Version'], '1.1') + # Update the _fields dict directly to prevent 'Metadata-Version' # from being updated by the _set_best_version() method. metadata._fields['Metadata-Version'] = '1.618' @@ -371,6 +383,7 @@ metadata = Metadata() metadata['Project-URL'] = [('one', 'http://ok')] self.assertEqual(metadata['Project-URL'], [('one', 'http://ok')]) + metadata.set_metadata_version() self.assertEqual(metadata['Metadata-Version'], '1.2') # make sure this particular field is handled properly when written -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Tue Mar 13 08:10:06 2012 From: python-checkins at python.org (michael.foord) Date: Tue, 13 Mar 2012 08:10:06 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_unittest_te?= =?utf8?q?st_discovery_for_Jython?= Message-ID: http://hg.python.org/cpython/rev/0f1619e539fb changeset: 75571:0f1619e539fb branch: 3.2 parent: 75565:fafe12f2a030 user: Michael Foord date: Tue Mar 13 00:09:54 2012 -0700 summary: Fix unittest test discovery for Jython files: Lib/unittest/loader.py | 13 +++++++++---- Misc/NEWS | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -34,6 +34,11 @@ TestClass = type(classname, (case.TestCase,), attrs) return suiteClass((TestClass(methodname),)) +def _jython_aware_splitext(path): + if path.lower().endswith('$py.class'): + return path[:-9] + return os.path.splitext(path)[0] + class TestLoader(object): """ @@ -221,7 +226,7 @@ return os.path.dirname(full_path) def _get_name_from_path(self, path): - path = os.path.splitext(os.path.normpath(path))[0] + path = _jython_aware_splitext(os.path.normpath(path)) _relpath = os.path.relpath(path, self._top_level_dir) assert not os.path.isabs(_relpath), "Path must be within the project" @@ -258,11 +263,11 @@ yield _make_failed_import_test(name, self.suiteClass) else: mod_file = os.path.abspath(getattr(module, '__file__', full_path)) - realpath = os.path.splitext(mod_file)[0] - fullpath_noext = os.path.splitext(full_path)[0] + realpath = _jython_aware_splitext(mod_file) + fullpath_noext = _jython_aware_splitext(full_path) if realpath.lower() != fullpath_noext.lower(): module_dir = os.path.dirname(realpath) - mod_name = os.path.splitext(os.path.basename(full_path))[0] + mod_name = _jython_aware_splitext(os.path.basename(full_path)) expected_dir = os.path.dirname(full_path) msg = ("%r module incorrectly imported from %r. Expected %r. " "Is this module globally installed?") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,8 @@ Library ------- +- Issue #10543: Fix unittest test discovery with Jython bytecode files. + - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under Windows when the child process has already exited. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 08:14:43 2012 From: python-checkins at python.org (michael.foord) Date: Tue, 13 Mar 2012 08:14:43 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge?= Message-ID: http://hg.python.org/cpython/rev/cb0174117487 changeset: 75572:cb0174117487 parent: 75570:7e576ad85663 parent: 75571:0f1619e539fb user: Michael Foord date: Tue Mar 13 00:14:19 2012 -0700 summary: Merge files: Lib/unittest/loader.py | 13 +++++++++---- Misc/NEWS | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -34,6 +34,11 @@ TestClass = type(classname, (case.TestCase,), attrs) return suiteClass((TestClass(methodname),)) +def _jython_aware_splitext(path): + if path.lower().endswith('$py.class'): + return path[:-9] + return os.path.splitext(path)[0] + class TestLoader(object): """ @@ -221,7 +226,7 @@ return os.path.dirname(full_path) def _get_name_from_path(self, path): - path = os.path.splitext(os.path.normpath(path))[0] + path = _jython_aware_splitext(os.path.normpath(path)) _relpath = os.path.relpath(path, self._top_level_dir) assert not os.path.isabs(_relpath), "Path must be within the project" @@ -258,11 +263,11 @@ yield _make_failed_import_test(name, self.suiteClass) else: mod_file = os.path.abspath(getattr(module, '__file__', full_path)) - realpath = os.path.splitext(mod_file)[0] - fullpath_noext = os.path.splitext(full_path)[0] + realpath = _jython_aware_splitext(mod_file) + fullpath_noext = _jython_aware_splitext(full_path) if realpath.lower() != fullpath_noext.lower(): module_dir = os.path.dirname(realpath) - mod_name = os.path.splitext(os.path.basename(full_path))[0] + mod_name = _jython_aware_splitext(os.path.basename(full_path)) expected_dir = os.path.dirname(full_path) msg = ("%r module incorrectly imported from %r. Expected %r. " "Is this module globally installed?") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #10543: Fix unittest test discovery with Jython bytecode files. + - Issue #1178863: Separate initialisation from setting when initializing Tkinter.Variables; harmonize exceptions to ValueError; only delete variables that have not been deleted; assert that variable names are strings. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 08:17:22 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 08:17:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_closes_issue142?= =?utf8?q?57_-_Grammatical_fix?= Message-ID: http://hg.python.org/cpython/rev/0f146020d8e9 changeset: 75573:0f146020d8e9 branch: 3.2 parent: 75532:3f15c069454d user: Senthil Kumaran date: Mon Mar 12 10:05:34 2012 -0700 summary: closes issue14257 - Grammatical fix files: Doc/glossary.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -146,9 +146,9 @@ For more information about descriptors' methods, see :ref:`descriptors`. dictionary - An associative array, where arbitrary keys are mapped to values. The keys - can be any object with :meth:`__hash__` method and :meth:`__eq__` - methods. Called a hash in Perl. + An associative array, where arbitrary keys are mapped to values. The + keys can be any object with :meth:`__hash__` and :meth:`__eq__` methods. + Called a hash in Perl. docstring A string literal which appears as the first expression in a class, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 08:17:25 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 08:17:25 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_closes_issue14257_-_Grammatical_fix?= Message-ID: http://hg.python.org/cpython/rev/c5833f277258 changeset: 75574:c5833f277258 parent: 75535:b8a14f95453a parent: 75573:0f146020d8e9 user: Senthil Kumaran date: Mon Mar 12 10:05:58 2012 -0700 summary: closes issue14257 - Grammatical fix files: Doc/glossary.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -146,9 +146,9 @@ For more information about descriptors' methods, see :ref:`descriptors`. dictionary - An associative array, where arbitrary keys are mapped to values. The keys - can be any object with :meth:`__hash__` method and :meth:`__eq__` - methods. Called a hash in Perl. + An associative array, where arbitrary keys are mapped to values. The + keys can be any object with :meth:`__hash__` and :meth:`__eq__` methods. + Called a hash in Perl. docstring A string literal which appears as the first expression in a class, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 08:17:28 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 08:17:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/3184e2d52ac5 changeset: 75575:3184e2d52ac5 parent: 75574:c5833f277258 parent: 75570:7e576ad85663 user: Senthil Kumaran date: Tue Mar 13 00:14:25 2012 -0700 summary: merge heads files: Lib/aifc.py | 12 +- Lib/pickle.py | 8 + Lib/test/pickletester.py | 12 + Lib/test/test_aifc.py | 158 +++++++++- Lib/test/test_ast.py | 9 +- Lib/test/test_re.py | 30 + Lib/test/test_sys.py | 2 +- Lib/test/test_unicode.py | 15 +- Lib/test/test_zipimport.py | 4 + Lib/tkinter/__init__.py | 36 +- Lib/tkinter/test/test_tkinter/test_variables.py | 165 ++++++++++ Lib/unittest/main.py | 80 ++-- Lib/unittest/test/test_program.py | 17 - Misc/ACKS | 3 + Misc/NEWS | 14 + Modules/_pickle.c | 26 + Modules/_sre.c | 16 +- Modules/timemodule.c | 18 +- Parser/asdl_c.py | 18 +- Python/Python-ast.c | 18 +- Python/ast.c | 10 +- 21 files changed, 548 insertions(+), 123 deletions(-) diff --git a/Lib/aifc.py b/Lib/aifc.py --- a/Lib/aifc.py +++ b/Lib/aifc.py @@ -136,6 +136,7 @@ import struct import builtins +import warnings __all__ = ["Error", "open", "openfp"] @@ -440,7 +441,7 @@ kludge = 0 if chunk.chunksize == 18: kludge = 1 - print('Warning: bad COMM chunk size') + warnings.warn('Warning: bad COMM chunk size') chunk.chunksize = 23 #DEBUG end self._comptype = chunk.read(4) @@ -484,11 +485,10 @@ # a position 0 and name '' self._markers.append((id, pos, name)) except EOFError: - print('Warning: MARK chunk contains only', end=' ') - print(len(self._markers), end=' ') - if len(self._markers) == 1: print('marker', end=' ') - else: print('markers', end=' ') - print('instead of', nmarkers) + w = ('Warning: MARK chunk contains only %s marker%s instead of %s' % + (len(self._markers), '' if len(self._markers) == 1 else 's', + nmarkers)) + warnings.warn(w) class Aifc_write: # Variables used in this class: diff --git a/Lib/pickle.py b/Lib/pickle.py --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -438,6 +438,14 @@ self.write(NONE) dispatch[type(None)] = save_none + def save_ellipsis(self, obj): + self.save_global(Ellipsis, 'Ellipsis') + dispatch[type(Ellipsis)] = save_ellipsis + + def save_notimplemented(self, obj): + self.save_global(NotImplemented, 'NotImplemented') + dispatch[type(NotImplemented)] = save_notimplemented + def save_bool(self, obj): if self.proto >= 2: self.write(obj and NEWTRUE or NEWFALSE) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -743,6 +743,18 @@ u = self.loads(s) self.assertEqual(t, u) + def test_ellipsis(self): + for proto in protocols: + s = self.dumps(..., proto) + u = self.loads(s) + self.assertEqual(..., u) + + def test_notimplemented(self): + for proto in protocols: + s = self.dumps(NotImplemented, proto) + u = self.loads(s) + self.assertEqual(NotImplemented, u) + # Tests for protocol 2 def test_proto(self): diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -1,7 +1,8 @@ -from test.support import findfile, run_unittest, TESTFN +from test.support import findfile, run_unittest, TESTFN, unlink import unittest import os import io +import struct import aifc @@ -20,10 +21,8 @@ self.fout.close() except (aifc.Error, AttributeError): pass - try: - os.remove(TESTFN) - except OSError: - pass + unlink(TESTFN) + unlink(TESTFN + '.aiff') def test_skipunknown(self): #Issue 2245 @@ -32,6 +31,7 @@ def test_params(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.getfp().name, self.sndfilepath) self.assertEqual(f.getnchannels(), 2) self.assertEqual(f.getsampwidth(), 2) self.assertEqual(f.getframerate(), 48000) @@ -45,6 +45,7 @@ def test_read(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.readframes(0), b'') self.assertEqual(f.tell(), 0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') f.rewind() @@ -58,6 +59,10 @@ self.assertEqual(f.readframes(2), b'\x17t\x17t"\xad"\xad') f.setpos(pos0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') + with self.assertRaises(aifc.Error): + f.setpos(-1) + with self.assertRaises(aifc.Error): + f.setpos(f.getnframes() + 1) def test_write(self): f = self.f = aifc.open(self.sndfilepath) @@ -92,8 +97,6 @@ self.assertEqual(f.getparams()[0:3], fout.getparams()[0:3]) self.assertEqual(fout.getcomptype(), b'ULAW') self.assertEqual(fout.getcompname(), b'foo') - # XXX: this test fails, not sure if it should succeed or not - # self.assertEqual(f.readframes(5), fout.readframes(5)) def test_close(self): class Wrapfile(object): @@ -112,7 +115,7 @@ def test_write_header_comptype_sampwidth(self): for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') fout.setnchannels(1) fout.setframerate(1) fout.setcomptype(comptype, b'') @@ -121,7 +124,7 @@ fout.initfp(None) def test_write_markers_values(self): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') self.assertEqual(fout.getmarkers(), None) fout.setmark(1, 0, b'foo1') fout.setmark(1, 1, b'foo2') @@ -179,6 +182,143 @@ with self.assertRaises(ValueError): aifc._write_string(f, b'too long' * 255) + def test_wrong_open_mode(self): + with self.assertRaises(aifc.Error): + aifc.open(TESTFN, 'wrong_mode') + + def test_read_wrong_form(self): + b1 = io.BytesIO(b'WRNG' + struct.pack('>L', 0)) + b2 = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'WRNG') + self.assertRaises(aifc.Error, aifc.open, b1) + self.assertRaises(aifc.Error, aifc.open, b2) + + def test_read_no_comm_chunk(self): + b = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'AIFF') + self.assertRaises(aifc.Error, aifc.open, b) + + def test_read_wrong_compression_type(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0) + b += b'WRNG' + struct.pack('B', 0) + self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b)) + + def test_read_wrong_marks(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFF' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + b += b'MARK' + struct.pack('>LhB', 3, 1, 1) + with self.assertWarns(UserWarning): + f = aifc.open(io.BytesIO(b)) + self.assertEqual(f.getmarkers(), None) + + def test_read_comm_kludge_compname_even(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with self.assertWarns(UserWarning): + f = aifc.open(io.BytesIO(b)) + self.assertEqual(f.getcompname(), b'even') + + def test_read_comm_kludge_compname_odd(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 3) + b'odd' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with self.assertWarns(UserWarning): + f = aifc.open(io.BytesIO(b)) + self.assertEqual(f.getcompname(), b'odd') + + def test_write_params_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + wrong_params = (0, 0, 0, 0, b'WRNG', '') + self.assertRaises(aifc.Error, fout.setparams, wrong_params) + self.assertRaises(aifc.Error, fout.getparams) + self.assertRaises(aifc.Error, fout.setnchannels, 0) + self.assertRaises(aifc.Error, fout.getnchannels) + self.assertRaises(aifc.Error, fout.setsampwidth, 0) + self.assertRaises(aifc.Error, fout.getsampwidth) + self.assertRaises(aifc.Error, fout.setframerate, 0) + self.assertRaises(aifc.Error, fout.getframerate) + self.assertRaises(aifc.Error, fout.setcomptype, b'WRNG', '') + fout.aiff() + fout.setnchannels(1) + fout.setsampwidth(1) + fout.setframerate(1) + fout.setnframes(1) + fout.writeframes(b'\x00') + self.assertRaises(aifc.Error, fout.setparams, (1, 1, 1, 1, 1, 1)) + self.assertRaises(aifc.Error, fout.setnchannels, 1) + self.assertRaises(aifc.Error, fout.setsampwidth, 1) + self.assertRaises(aifc.Error, fout.setframerate, 1) + self.assertRaises(aifc.Error, fout.setnframes, 1) + self.assertRaises(aifc.Error, fout.setcomptype, b'NONE', '') + self.assertRaises(aifc.Error, fout.aiff) + self.assertRaises(aifc.Error, fout.aifc) + + def test_write_params_singles(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + fout.setnchannels(1) + fout.setsampwidth(2) + fout.setframerate(3) + fout.setnframes(4) + fout.setcomptype(b'NONE', b'name') + self.assertEqual(fout.getnchannels(), 1) + self.assertEqual(fout.getsampwidth(), 2) + self.assertEqual(fout.getframerate(), 3) + self.assertEqual(fout.getnframes(), 0) + self.assertEqual(fout.tell(), 0) + self.assertEqual(fout.getcomptype(), b'NONE') + self.assertEqual(fout.getcompname(), b'name') + fout.writeframes(b'\x00' * 4 * fout.getsampwidth() * fout.getnchannels()) + self.assertEqual(fout.getnframes(), 4) + self.assertEqual(fout.tell(), 4) + + def test_write_params_bunch(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + p = (1, 2, 3, 4, b'NONE', b'name') + fout.setparams(p) + self.assertEqual(fout.getparams(), p) + fout.initfp(None) + + def test_write_header_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.close) + fout.setnchannels(1) + self.assertRaises(aifc.Error, fout.close) + fout.setsampwidth(1) + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_header_comptype_raises(self): + for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): + fout = aifc.open(io.BytesIO(), 'wb') + fout.setsampwidth(1) + fout.setcomptype(comptype, b'') + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_markers_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.setmark, 0, 0, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, -1, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, 0, None) + self.assertRaises(aifc.Error, fout.getmark, 1) + fout.initfp(None) + + def test_write_aiff_by_extension(self): + sampwidth = 2 + fout = self.fout = aifc.open(TESTFN + '.aiff', 'wb') + fout.setparams((1, sampwidth, 1, 1, b'ULAW', b'')) + frames = b'\x00' * fout.getnchannels() * sampwidth + fout.writeframes(frames) + fout.close() + f = self.f = aifc.open(TESTFN + '.aiff', 'rb') + self.assertEqual(f.getcomptype(), b'NONE') + f.close() + def test_main(): run_unittest(AIFCTest) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -196,16 +196,13 @@ def test_AST_objects(self): x = ast.AST() self.assertEqual(x._fields, ()) + x.foobar = 42 + self.assertEqual(x.foobar, 42) + self.assertEqual(x.__dict__["foobar"], 42) with self.assertRaises(AttributeError): x.vararg - with self.assertRaises(AttributeError): - x.foobar = 21 - - with self.assertRaises(AttributeError): - ast.AST(lineno=2) - with self.assertRaises(TypeError): # "_ast.AST constructor takes 0 positional arguments" ast.AST(2) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -652,6 +652,26 @@ self.assertEqual([item.group(0) for item in iter], [":", "::", ":::"]) + pat = re.compile(r":+") + iter = pat.finditer("a:b::c:::d", 1, 10) + self.assertEqual([item.group(0) for item in iter], + [":", "::", ":::"]) + + pat = re.compile(r":+") + iter = pat.finditer("a:b::c:::d", pos=1, endpos=10) + self.assertEqual([item.group(0) for item in iter], + [":", "::", ":::"]) + + pat = re.compile(r":+") + iter = pat.finditer("a:b::c:::d", endpos=10, pos=1) + self.assertEqual([item.group(0) for item in iter], + [":", "::", ":::"]) + + pat = re.compile(r":+") + iter = pat.finditer("a:b::c:::d", pos=3, endpos=8) + self.assertEqual([item.group(0) for item in iter], + ["::", "::"]) + def test_bug_926075(self): self.assertTrue(re.compile('bug_926075') is not re.compile(b'bug_926075')) @@ -825,6 +845,16 @@ self.assertIsNotNone(re.search("123.*-", '123\U0010ffff-')) self.assertIsNotNone(re.search("123.*-", '123\xe9\u20ac\U0010ffff-')) + def test_compile(self): + # Test return value when given string and pattern as parameter + pattern = re.compile('random pattern') + self.assertIsInstance(pattern, re._pattern_type) + same_pattern = re.compile(pattern) + self.assertIsInstance(same_pattern, re._pattern_type) + self.assertIs(same_pattern, pattern) + # Test behaviour when not given a string or pattern as parameter + self.assertRaises(TypeError, re.compile, 0) + def run_re_tests(): from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR if verbose: diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -882,7 +882,7 @@ check = self.check_sizeof # _ast.AST import _ast - check(_ast.AST(), size(h + '')) + check(_ast.AST(), size(h + 'P')) # imp.NullImporter import imp check(imp.NullImporter(self.file.name), size(h + '')) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -957,12 +957,15 @@ self.assertEqual('{foo._x}'.format_map({'foo': C(20)}), '20') # test various errors - self.assertRaises(TypeError, '{'.format_map) - self.assertRaises(TypeError, '}'.format_map) - self.assertRaises(TypeError, 'a{'.format_map) - self.assertRaises(TypeError, 'a}'.format_map) - self.assertRaises(TypeError, '{a'.format_map) - self.assertRaises(TypeError, '}a'.format_map) + self.assertRaises(TypeError, ''.format_map) + self.assertRaises(TypeError, 'a'.format_map) + + self.assertRaises(ValueError, '{'.format_map, {}) + self.assertRaises(ValueError, '}'.format_map, {}) + self.assertRaises(ValueError, 'a{'.format_map, {}) + self.assertRaises(ValueError, 'a}'.format_map, {}) + self.assertRaises(ValueError, '{a'.format_map, {}) + self.assertRaises(ValueError, '}a'.format_map, {}) # issue #12579: can't supply positional params to format_map self.assertRaises(ValueError, '{}'.format_map, {'a' : 2}) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -205,6 +205,10 @@ mod = zi.load_module(TESTPACK) self.assertEqual(zi.get_filename(TESTPACK), mod.__file__) + existing_pack_path = __import__(TESTPACK).__path__[0] + expected_path_path = os.path.join(TEMP_ZIP, TESTPACK) + self.assertEqual(existing_pack_path, expected_path_path) + self.assertEqual(zi.is_package(packdir + '__init__'), False) self.assertEqual(zi.is_package(packdir + TESTPACK2), True) self.assertEqual(zi.is_package(packdir2 + TESTMOD), False) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -155,6 +155,7 @@ Subclasses StringVar, IntVar, DoubleVar, BooleanVar are specializations that constrain the type of the value returned from get().""" _default = "" + _tk = None def __init__(self, master=None, value=None, name=None): """Construct a variable @@ -165,6 +166,11 @@ If NAME matches an existing variable and VALUE is omitted then the existing value is retained. """ + # check for type of NAME parameter to override weird error message + # raised from Modules/_tkinter.c:SetVar like: + # TypeError: setvar() takes exactly 3 arguments (2 given) + if name is not None and not isinstance(name, str): + raise TypeError("name must be a string") global _varnum if not master: master = _default_root @@ -176,18 +182,21 @@ self._name = 'PY_VAR' + repr(_varnum) _varnum += 1 if value is not None: - self.set(value) + self.initialize(value) elif not self._tk.call("info", "exists", self._name): - self.set(self._default) + self.initialize(self._default) def __del__(self): """Unset the variable in Tcl.""" - self._tk.globalunsetvar(self._name) + if (self._tk is not None and self._tk.call("info", "exists", + self._name)): + self._tk.globalunsetvar(self._name) def __str__(self): """Return the name of the variable in Tcl.""" return self._name def set(self, value): """Set the variable to VALUE.""" return self._tk.globalsetvar(self._name, value) + initialize = set def get(self): """Return value of variable.""" return self._tk.globalgetvar(self._name) @@ -262,12 +271,6 @@ """ Variable.__init__(self, master, value, name) - def set(self, value): - """Set the variable to value, converting booleans to integers.""" - if isinstance(value, bool): - value = int(value) - return Variable.set(self, value) - def get(self): """Return the value of the variable as an integer.""" return getint(self._tk.globalgetvar(self._name)) @@ -308,7 +311,10 @@ def get(self): """Return the value of the variable as a bool.""" - return self._tk.getboolean(self._tk.globalgetvar(self._name)) + try: + return self._tk.getboolean(self._tk.globalgetvar(self._name)) + except TclError: + raise ValueError("invalid literal for getboolean()") def mainloop(n=0): """Run the main loop of Tcl.""" @@ -320,7 +326,10 @@ def getboolean(s): """Convert true and false to integer values 1 and 0.""" - return _default_root.tk.getboolean(s) + try: + return _default_root.tk.getboolean(s) + except TclError: + raise ValueError("invalid literal for getboolean()") # Methods defined on both toplevel and interior widgets class Misc: @@ -410,7 +419,10 @@ getdouble = float def getboolean(self, s): """Return a boolean value for Tcl boolean values true and false given as parameter.""" - return self.tk.getboolean(s) + try: + return self.tk.getboolean(s) + except TclError: + raise ValueError("invalid literal for getboolean()") def focus_set(self): """Direct input focus to this widget. diff --git a/Lib/tkinter/test/test_tkinter/test_variables.py b/Lib/tkinter/test/test_tkinter/test_variables.py new file mode 100644 --- /dev/null +++ b/Lib/tkinter/test/test_tkinter/test_variables.py @@ -0,0 +1,165 @@ +import unittest + +from tkinter import Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tk + + +class Var(Variable): + + _default = "default" + side_effect = False + + def set(self, value): + self.side_effect = True + super().set(value) + + +class TestBase(unittest.TestCase): + + def setUp(self): + self.root = Tk() + + def tearDown(self): + self.root.destroy() + + +class TestVariable(TestBase): + + def test_default(self): + v = Variable(self.root) + self.assertEqual("", v.get()) + self.assertRegex(str(v), r"^PY_VAR(\d+)$") + + def test_name_and_value(self): + v = Variable(self.root, "sample string", "varname") + self.assertEqual("sample string", v.get()) + self.assertEqual("varname", str(v)) + + def test___del__(self): + self.assertFalse(self.root.call("info", "exists", "varname")) + v = Variable(self.root, "sample string", "varname") + self.assertTrue(self.root.call("info", "exists", "varname")) + del v + self.assertFalse(self.root.call("info", "exists", "varname")) + + def test_dont_unset_not_existing(self): + self.assertFalse(self.root.call("info", "exists", "varname")) + v1 = Variable(self.root, name="name") + v2 = Variable(self.root, name="name") + del v1 + self.assertFalse(self.root.call("info", "exists", "name")) + # shouldn't raise exception + del v2 + self.assertFalse(self.root.call("info", "exists", "name")) + + def test___eq__(self): + # values doesn't matter, only class and name are checked + v1 = Variable(self.root, name="abc") + v2 = Variable(self.root, name="abc") + self.assertEqual(v1, v2) + + v3 = Variable(self.root, name="abc") + v4 = StringVar(self.root, name="abc") + self.assertNotEqual(v3, v4) + + def test_invalid_name(self): + with self.assertRaises(TypeError): + Variable(self.root, name=123) + + def test_initialize(self): + v = Var() + self.assertFalse(v.side_effect) + v.set("value") + self.assertTrue(v.side_effect) + + +class TestStringVar(TestBase): + + def test_default(self): + v = StringVar(self.root) + self.assertEqual("", v.get()) + + def test_get(self): + v = StringVar(self.root, "abc", "name") + self.assertEqual("abc", v.get()) + self.root.globalsetvar("name", True) + self.assertEqual("1", v.get()) + + +class TestIntVar(TestBase): + + def test_default(self): + v = IntVar(self.root) + self.assertEqual(0, v.get()) + + def test_get(self): + v = IntVar(self.root, 123, "name") + self.assertEqual(123, v.get()) + self.root.globalsetvar("name", "345") + self.assertEqual(345, v.get()) + + def test_invalid_value(self): + v = IntVar(self.root, name="name") + self.root.globalsetvar("name", "value") + with self.assertRaises(ValueError): + v.get() + self.root.globalsetvar("name", "345.0") + with self.assertRaises(ValueError): + v.get() + + +class TestDoubleVar(TestBase): + + def test_default(self): + v = DoubleVar(self.root) + self.assertEqual(0.0, v.get()) + + def test_get(self): + v = DoubleVar(self.root, 1.23, "name") + self.assertAlmostEqual(1.23, v.get()) + self.root.globalsetvar("name", "3.45") + self.assertAlmostEqual(3.45, v.get()) + + def test_get_from_int(self): + v = DoubleVar(self.root, 1.23, "name") + self.assertAlmostEqual(1.23, v.get()) + self.root.globalsetvar("name", "3.45") + self.assertAlmostEqual(3.45, v.get()) + self.root.globalsetvar("name", "456") + self.assertAlmostEqual(456, v.get()) + + def test_invalid_value(self): + v = DoubleVar(self.root, name="name") + self.root.globalsetvar("name", "value") + with self.assertRaises(ValueError): + v.get() + + +class TestBooleanVar(TestBase): + + def test_default(self): + v = BooleanVar(self.root) + self.assertEqual(False, v.get()) + + def test_get(self): + v = BooleanVar(self.root, True, "name") + self.assertAlmostEqual(True, v.get()) + self.root.globalsetvar("name", "0") + self.assertAlmostEqual(False, v.get()) + + def test_invalid_value_domain(self): + v = BooleanVar(self.root, name="name") + self.root.globalsetvar("name", "value") + with self.assertRaises(ValueError): + v.get() + self.root.globalsetvar("name", "1.0") + with self.assertRaises(ValueError): + v.get() + + +tests_gui = (TestVariable, TestStringVar, TestIntVar, + TestDoubleVar, TestBooleanVar) + + +if __name__ == "__main__": + from test.support import run_unittest + run_unittest(*tests_gui) diff --git a/Lib/unittest/main.py b/Lib/unittest/main.py --- a/Lib/unittest/main.py +++ b/Lib/unittest/main.py @@ -1,6 +1,7 @@ """Unittest main program""" import sys +import optparse import os from . import loader, runner @@ -76,6 +77,7 @@ def _convert_names(names): return [_convert_name(name) for name in names] + class TestProgram(object): """A command-line program that runs a set of tests; this is primarily for making test modules conveniently executable. @@ -142,33 +144,9 @@ self._do_discovery(argv[2:]) return - import getopt - long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer'] - try: - options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts) - except getopt.error as msg: - self.usageExit(msg) - return - - for opt, value in options: - if opt in ('-h','-H','--help'): - self.usageExit() - if opt in ('-q','--quiet'): - self.verbosity = 0 - if opt in ('-v','--verbose'): - self.verbosity = 2 - if opt in ('-f','--failfast'): - if self.failfast is None: - self.failfast = True - # Should this raise an exception if -f is not valid? - if opt in ('-c','--catch'): - if self.catchbreak is None: - self.catchbreak = True - # Should this raise an exception if -c is not valid? - if opt in ('-b','--buffer'): - if self.buffer is None: - self.buffer = True - # Should this raise an exception if -b is not valid? + parser = self._getOptParser() + options, args = parser.parse_args(argv[1:]) + self._setAttributesFromOptions(options) if len(args) == 0 and self.module is None: # this allows "python -m unittest -v" to still work for @@ -196,14 +174,14 @@ self.test = self.testLoader.loadTestsFromNames(self.testNames, self.module) - def _do_discovery(self, argv, Loader=loader.TestLoader): - # handle command line args for test discovery - self.progName = '%s discover' % self.progName - import optparse + def _getOptParser(self): parser = optparse.OptionParser() parser.prog = self.progName parser.add_option('-v', '--verbose', dest='verbose', default=False, help='Verbose output', action='store_true') + parser.add_option('-q', '--quiet', dest='quiet', default=False, + help='Quiet output', action='store_true') + if self.failfast != False: parser.add_option('-f', '--failfast', dest='failfast', default=False, help='Stop on first fail or error', @@ -216,20 +194,9 @@ parser.add_option('-b', '--buffer', dest='buffer', default=False, help='Buffer stdout and stderr during tests', action='store_true') - parser.add_option('-s', '--start-directory', dest='start', default='.', - help="Directory to start discovery ('.' default)") - parser.add_option('-p', '--pattern', dest='pattern', default='test*.py', - help="Pattern to match tests ('test*.py' default)") - parser.add_option('-t', '--top-level-directory', dest='top', default=None, - help='Top level directory of project (defaults to start directory)') + return parser - options, args = parser.parse_args(argv) - if len(args) > 3: - self.usageExit() - - for name, value in zip(('start', 'pattern', 'top'), args): - setattr(options, name, value) - + def _setAttributesFromOptions(self, options): # only set options from the parsing here # if they weren't set explicitly in the constructor if self.failfast is None: @@ -241,6 +208,31 @@ if options.verbose: self.verbosity = 2 + elif options.quiet: + self.verbosity = 0 + + def _addDiscoveryOptions(self, parser): + parser.add_option('-s', '--start-directory', dest='start', default='.', + help="Directory to start discovery ('.' default)") + parser.add_option('-p', '--pattern', dest='pattern', default='test*.py', + help="Pattern to match tests ('test*.py' default)") + parser.add_option('-t', '--top-level-directory', dest='top', default=None, + help='Top level directory of project (defaults to start directory)') + + def _do_discovery(self, argv, Loader=loader.TestLoader): + # handle command line args for test discovery + self.progName = '%s discover' % self.progName + parser = self._getOptParser() + self._addDiscoveryOptions(parser) + + options, args = parser.parse_args(argv) + if len(args) > 3: + self.usageExit() + + for name, value in zip(('start', 'pattern', 'top'), args): + setattr(options, name, value) + + self._setAttributesFromOptions(options) start_dir = options.start pattern = options.pattern diff --git a/Lib/unittest/test/test_program.py b/Lib/unittest/test/test_program.py --- a/Lib/unittest/test/test_program.py +++ b/Lib/unittest/test/test_program.py @@ -131,23 +131,6 @@ FakeRunner.test = None FakeRunner.raiseError = False - def testHelpAndUnknown(self): - program = self.program - def usageExit(msg=None): - program.msg = msg - program.exit = True - program.usageExit = usageExit - - for opt in '-h', '-H', '--help': - program.exit = False - program.parseArgs([None, opt]) - self.assertTrue(program.exit) - self.assertIsNone(program.msg) - - program.parseArgs([None, '-$']) - self.assertTrue(program.exit) - self.assertIsNotNone(program.msg) - def testVerbosity(self): program = self.program diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -602,6 +602,7 @@ Alain Leufroy Mark Levinson William Lewis +Akira Li Xuanji Li Robert van Liere Ross Light @@ -686,6 +687,7 @@ Dom Mitchell Dustin J. Mitchell Zubin Mithra +Florian Mladitsch Doug Moen The Dragon De Monsyne Skip Montanaro @@ -883,6 +885,7 @@ Rich Salz Kevin Samborn Adrian Sampson +James Sanders Ilya Sandler Mark Sapiro Ty Sarna diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Give the ast.AST class a __dict__. + - Issue #1469629: Allow cycles through an object's __dict__ slot to be collected. (For example if ``x.__dict__ is x``). @@ -22,6 +24,15 @@ Library ------- +- Issue #1178863: Separate initialisation from setting when initializing + Tkinter.Variables; harmonize exceptions to ValueError; only delete variables + that have not been deleted; assert that variable names are strings. + +- Issue #14104: Implement time.monotonic() on Mac OS X, patch written by + Nicholas Riley. + +- Issue #13394: the aifc module now uses warnings.warn() to signal warnings. + - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under Windows when the child process has already exited. @@ -49,6 +60,9 @@ - Issue #14212: The re module didn't retain a reference to buffers it was scanning, resulting in segfaults. +- Issue #14259: The finditer() method of re objects did not take any + keyword arguments, contrary to the documentation. + What's New in Python 3.3.0 Alpha 1? =================================== diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2812,6 +2812,24 @@ } static int +save_ellipsis(PicklerObject *self, PyObject *obj) +{ + PyObject *str = PyUnicode_FromString("Ellipsis"); + if (str == NULL) + return -1; + return save_global(self, Py_Ellipsis, str); +} + +static int +save_notimplemented(PicklerObject *self, PyObject *obj) +{ + PyObject *str = PyUnicode_FromString("NotImplemented"); + if (str == NULL) + return -1; + return save_global(self, Py_NotImplemented, str); +} + +static int save_pers(PicklerObject *self, PyObject *obj, PyObject *func) { PyObject *pid = NULL; @@ -3114,6 +3132,14 @@ status = save_none(self, obj); goto done; } + else if (obj == Py_Ellipsis) { + status = save_ellipsis(self, obj); + goto done; + } + else if (obj == Py_NotImplemented) { + status = save_notimplemented(self, obj); + goto done; + } else if (obj == Py_False || obj == Py_True) { status = save_bool(self, obj); goto done; diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -1596,7 +1596,7 @@ /* see sre.h for object declarations */ static PyObject*pattern_new_match(PatternObject*, SRE_STATE*, int); -static PyObject*pattern_scanner(PatternObject*, PyObject*); +static PyObject*pattern_scanner(PatternObject*, PyObject*, PyObject* kw); static int sre_literal_template(int charsize, char* ptr, Py_ssize_t len) @@ -2132,13 +2132,13 @@ #if PY_VERSION_HEX >= 0x02020000 static PyObject* -pattern_finditer(PatternObject* pattern, PyObject* args) +pattern_finditer(PatternObject* pattern, PyObject* args, PyObject* kw) { PyObject* scanner; PyObject* search; PyObject* iterator; - scanner = pattern_scanner(pattern, args); + scanner = pattern_scanner(pattern, args, kw); if (!scanner) return NULL; @@ -2576,10 +2576,10 @@ {"findall", (PyCFunction) pattern_findall, METH_VARARGS|METH_KEYWORDS, pattern_findall_doc}, #if PY_VERSION_HEX >= 0x02020000 - {"finditer", (PyCFunction) pattern_finditer, METH_VARARGS, + {"finditer", (PyCFunction) pattern_finditer, METH_VARARGS|METH_KEYWORDS, pattern_finditer_doc}, #endif - {"scanner", (PyCFunction) pattern_scanner, METH_VARARGS}, + {"scanner", (PyCFunction) pattern_scanner, METH_VARARGS|METH_KEYWORDS}, {"__copy__", (PyCFunction) pattern_copy, METH_NOARGS}, {"__deepcopy__", (PyCFunction) pattern_deepcopy, METH_O}, {NULL, NULL} @@ -3822,7 +3822,7 @@ }; static PyObject* -pattern_scanner(PatternObject* pattern, PyObject* args) +pattern_scanner(PatternObject* pattern, PyObject* args, PyObject* kw) { /* create search state object */ @@ -3831,7 +3831,9 @@ PyObject* string; Py_ssize_t start = 0; Py_ssize_t end = PY_SSIZE_T_MAX; - if (!PyArg_ParseTuple(args, "O|nn:scanner", &string, &start, &end)) + static char* kwlist[] = { "source", "pos", "endpos", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|nn:scanner", kwlist, + &string, &start, &end)) return NULL; /* create scanner object */ diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -40,6 +40,10 @@ #include #endif +#if defined(__APPLE__) +#include +#endif + /* Forward declarations */ static int floatsleep(double); static double floattime(void); @@ -816,7 +820,8 @@ calls is valid."); #if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) \ - || (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)) + || (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)) \ + || (defined(__APPLE__)) # define HAVE_PYTIME_MONOTONIC #endif @@ -826,6 +831,17 @@ { #if defined(MS_WINDOWS) && !defined(__BORLANDC__) return win32_clock(0); +#elif defined(__APPLE__) + uint64_t time = mach_absolute_time(); + double secs; + + static mach_timebase_info_data_t timebase; + if (timebase.denom == 0) + mach_timebase_info(&timebase); + + secs = (double)time * timebase.numer / timebase.denom * 1e-9; + + return PyFloat_FromDouble(secs); #else static int clk_index = 0; clockid_t clk_ids[] = { diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -603,6 +603,11 @@ def visitModule(self, mod): self.emit(""" +typedef struct { + PyObject_HEAD + PyObject *dict; +} AST_object; + static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { @@ -681,10 +686,15 @@ {NULL} }; +static PyGetSetDef ast_type_getsets[] = { + {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, + {NULL} +}; + static PyTypeObject AST_type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "_ast.AST", - sizeof(PyObject), + sizeof(AST_object), 0, 0, /* tp_dealloc */ 0, /* tp_print */ @@ -711,12 +721,12 @@ 0, /* tp_iternext */ ast_type_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + ast_type_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ + offsetof(AST_object, dict),/* tp_dictoffset */ (initproc)ast_type_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ @@ -1185,6 +1195,8 @@ p = os.path.join(SRC_DIR, str(mod.name) + "-ast.c") f = open(p, "w") f.write(auto_gen_msg) + f.write('#include \n') + f.write('\n') f.write('#include "Python.h"\n') f.write('#include "%s-ast.h"\n' % mod.name) f.write('\n') diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -1,5 +1,7 @@ /* File automatically generated by Parser/asdl_c.py. */ +#include + #include "Python.h" #include "Python-ast.h" @@ -453,6 +455,11 @@ }; +typedef struct { + PyObject_HEAD + PyObject *dict; +} AST_object; + static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { @@ -531,10 +538,15 @@ {NULL} }; +static PyGetSetDef ast_type_getsets[] = { + {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, + {NULL} +}; + static PyTypeObject AST_type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "_ast.AST", - sizeof(PyObject), + sizeof(AST_object), 0, 0, /* tp_dealloc */ 0, /* tp_print */ @@ -561,12 +573,12 @@ 0, /* tp_iternext */ ast_type_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + ast_type_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ + offsetof(AST_object, dict),/* tp_dictoffset */ (initproc)ast_type_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -1153,7 +1153,7 @@ } static arg_ty -compiler_arg(struct compiling *c, const node *n) +ast_for_arg(struct compiling *c, const node *n) { identifier name; expr_ty annotation = NULL; @@ -1174,12 +1174,6 @@ } return arg(name, annotation, c->c_arena); -#if 0 - result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena); - if (!set_context(c, result, Store, n)) - return NULL; - return result; -#endif } /* returns -1 if failed to handle keyword only arguments @@ -1367,7 +1361,7 @@ "non-default argument follows default argument"); return NULL; } - arg = compiler_arg(c, ch); + arg = ast_for_arg(c, ch); if (!arg) return NULL; asdl_seq_SET(posargs, k++, arg); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 08:17:29 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 08:17:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_closes_issue142?= =?utf8?q?57_-_Grammatical_fix?= Message-ID: http://hg.python.org/cpython/rev/f3c8bdbe2cf3 changeset: 75576:f3c8bdbe2cf3 branch: 2.7 parent: 75531:f0a5f39615c8 user: Senthil Kumaran date: Mon Mar 12 10:05:04 2012 -0700 summary: closes issue14257 - Grammatical fix files: Doc/glossary.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -152,9 +152,9 @@ For more information about descriptors' methods, see :ref:`descriptors`. dictionary - An associative array, where arbitrary keys are mapped to values. The keys - can be any object with :meth:`__hash__` method and :meth:`__eq__` - methods. Called a hash in Perl. + An associative array, where arbitrary keys are mapped to values. The + keys can be any object with :meth:`__hash__` and :meth:`__eq__` methods. + Called a hash in Perl. docstring A string literal which appears as the first expression in a class, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 08:17:29 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 08:17:29 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/755a5f18ccf3 changeset: 75577:755a5f18ccf3 branch: 2.7 parent: 75576:f3c8bdbe2cf3 parent: 75563:cc48eef234dd user: Senthil Kumaran date: Tue Mar 13 00:15:15 2012 -0700 summary: merge heads files: Lib/test/test_re.py | 10 ++++++++++ Misc/ACKS | 1 + 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -783,6 +783,16 @@ self.assertRaises(TypeError, re.finditer, "a", {}) self.assertRaises(OverflowError, _sre.compile, "abc", 0, [long_overflow]) + def test_compile(self): + # Test return value when given string and pattern as parameter + pattern = re.compile('random pattern') + self.assertIsInstance(pattern, re._pattern_type) + same_pattern = re.compile(pattern) + self.assertIsInstance(same_pattern, re._pattern_type) + self.assertIs(same_pattern, pattern) + # Test behaviour when not given a string or pattern as parameter + self.assertRaises(TypeError, re.compile, 0) + def run_re_tests(): from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR if verbose: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -577,6 +577,7 @@ Andrii V. Mishkovskyi Dustin J. Mitchell Dom Mitchell +Florian Mladitsch Doug Moen The Dragon De Monsyne Skip Montanaro -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 08:17:31 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 08:17:31 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/744a8256489f changeset: 75578:744a8256489f branch: 3.2 parent: 75573:0f146020d8e9 parent: 75565:fafe12f2a030 user: Senthil Kumaran date: Tue Mar 13 00:14:59 2012 -0700 summary: merge heads files: Lib/test/test_aifc.py | 163 +++++++++++++++++++++++++- Lib/test/test_ast.py | 6 - Lib/test/test_re.py | 10 + Lib/test/test_unicode.py | 15 +- Misc/ACKS | 2 + Python/ast.c | 10 +- 6 files changed, 177 insertions(+), 29 deletions(-) diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -1,7 +1,8 @@ -from test.support import findfile, run_unittest, TESTFN +from test.support import findfile, run_unittest, TESTFN, captured_stdout, unlink import unittest import os import io +import struct import aifc @@ -20,10 +21,8 @@ self.fout.close() except (aifc.Error, AttributeError): pass - try: - os.remove(TESTFN) - except OSError: - pass + unlink(TESTFN) + unlink(TESTFN + '.aiff') def test_skipunknown(self): #Issue 2245 @@ -32,6 +31,7 @@ def test_params(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.getfp().name, self.sndfilepath) self.assertEqual(f.getnchannels(), 2) self.assertEqual(f.getsampwidth(), 2) self.assertEqual(f.getframerate(), 48000) @@ -45,6 +45,7 @@ def test_read(self): f = self.f = aifc.open(self.sndfilepath) + self.assertEqual(f.readframes(0), b'') self.assertEqual(f.tell(), 0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') f.rewind() @@ -58,6 +59,10 @@ self.assertEqual(f.readframes(2), b'\x17t\x17t"\xad"\xad') f.setpos(pos0) self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4') + with self.assertRaises(aifc.Error): + f.setpos(-1) + with self.assertRaises(aifc.Error): + f.setpos(f.getnframes() + 1) def test_write(self): f = self.f = aifc.open(self.sndfilepath) @@ -92,8 +97,6 @@ self.assertEqual(f.getparams()[0:3], fout.getparams()[0:3]) self.assertEqual(fout.getcomptype(), b'ULAW') self.assertEqual(fout.getcompname(), b'foo') - # XXX: this test fails, not sure if it should succeed or not - # self.assertEqual(f.readframes(5), fout.readframes(5)) def test_close(self): class Wrapfile(object): @@ -112,7 +115,7 @@ def test_write_header_comptype_sampwidth(self): for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') fout.setnchannels(1) fout.setframerate(1) fout.setcomptype(comptype, b'') @@ -121,7 +124,7 @@ fout.initfp(None) def test_write_markers_values(self): - fout = self.fout = aifc.open(io.BytesIO(), 'wb') + fout = aifc.open(io.BytesIO(), 'wb') self.assertEqual(fout.getmarkers(), None) fout.setmark(1, 0, b'foo1') fout.setmark(1, 1, b'foo2') @@ -179,6 +182,148 @@ with self.assertRaises(ValueError): aifc._write_string(f, b'too long' * 255) + def test_wrong_open_mode(self): + with self.assertRaises(aifc.Error): + aifc.open(TESTFN, 'wrong_mode') + + def test_read_wrong_form(self): + b1 = io.BytesIO(b'WRNG' + struct.pack('>L', 0)) + b2 = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'WRNG') + self.assertRaises(aifc.Error, aifc.open, b1) + self.assertRaises(aifc.Error, aifc.open, b2) + + def test_read_no_comm_chunk(self): + b = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'AIFF') + self.assertRaises(aifc.Error, aifc.open, b) + + def test_read_wrong_compression_type(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0) + b += b'WRNG' + struct.pack('B', 0) + self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b)) + + def test_read_wrong_marks(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFF' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + b += b'MARK' + struct.pack('>LhB', 3, 1, 1) + with captured_stdout() as s: + f = aifc.open(io.BytesIO(b)) + self.assertEqual( + s.getvalue(), + 'Warning: MARK chunk contains only 0 markers instead of 1\n') + self.assertEqual(f.getmarkers(), None) + + def test_read_comm_kludge_compname_even(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with captured_stdout() as s: + f = aifc.open(io.BytesIO(b)) + self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n') + self.assertEqual(f.getcompname(), b'even') + + def test_read_comm_kludge_compname_odd(self): + b = b'FORM' + struct.pack('>L', 4) + b'AIFC' + b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0) + b += b'NONE' + struct.pack('B', 3) + b'odd' + b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8 + with captured_stdout() as s: + f = aifc.open(io.BytesIO(b)) + self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n') + self.assertEqual(f.getcompname(), b'odd') + + def test_write_params_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + wrong_params = (0, 0, 0, 0, b'WRNG', '') + self.assertRaises(aifc.Error, fout.setparams, wrong_params) + self.assertRaises(aifc.Error, fout.getparams) + self.assertRaises(aifc.Error, fout.setnchannels, 0) + self.assertRaises(aifc.Error, fout.getnchannels) + self.assertRaises(aifc.Error, fout.setsampwidth, 0) + self.assertRaises(aifc.Error, fout.getsampwidth) + self.assertRaises(aifc.Error, fout.setframerate, 0) + self.assertRaises(aifc.Error, fout.getframerate) + self.assertRaises(aifc.Error, fout.setcomptype, b'WRNG', '') + fout.aiff() + fout.setnchannels(1) + fout.setsampwidth(1) + fout.setframerate(1) + fout.setnframes(1) + fout.writeframes(b'\x00') + self.assertRaises(aifc.Error, fout.setparams, (1, 1, 1, 1, 1, 1)) + self.assertRaises(aifc.Error, fout.setnchannels, 1) + self.assertRaises(aifc.Error, fout.setsampwidth, 1) + self.assertRaises(aifc.Error, fout.setframerate, 1) + self.assertRaises(aifc.Error, fout.setnframes, 1) + self.assertRaises(aifc.Error, fout.setcomptype, b'NONE', '') + self.assertRaises(aifc.Error, fout.aiff) + self.assertRaises(aifc.Error, fout.aifc) + + def test_write_params_singles(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + fout.setnchannels(1) + fout.setsampwidth(2) + fout.setframerate(3) + fout.setnframes(4) + fout.setcomptype(b'NONE', b'name') + self.assertEqual(fout.getnchannels(), 1) + self.assertEqual(fout.getsampwidth(), 2) + self.assertEqual(fout.getframerate(), 3) + self.assertEqual(fout.getnframes(), 0) + self.assertEqual(fout.tell(), 0) + self.assertEqual(fout.getcomptype(), b'NONE') + self.assertEqual(fout.getcompname(), b'name') + fout.writeframes(b'\x00' * 4 * fout.getsampwidth() * fout.getnchannels()) + self.assertEqual(fout.getnframes(), 4) + self.assertEqual(fout.tell(), 4) + + def test_write_params_bunch(self): + fout = aifc.open(io.BytesIO(), 'wb') + fout.aifc() + p = (1, 2, 3, 4, b'NONE', b'name') + fout.setparams(p) + self.assertEqual(fout.getparams(), p) + fout.initfp(None) + + def test_write_header_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.close) + fout.setnchannels(1) + self.assertRaises(aifc.Error, fout.close) + fout.setsampwidth(1) + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_header_comptype_raises(self): + for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'): + fout = aifc.open(io.BytesIO(), 'wb') + fout.setsampwidth(1) + fout.setcomptype(comptype, b'') + self.assertRaises(aifc.Error, fout.close) + fout.initfp(None) + + def test_write_markers_raises(self): + fout = aifc.open(io.BytesIO(), 'wb') + self.assertRaises(aifc.Error, fout.setmark, 0, 0, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, -1, b'') + self.assertRaises(aifc.Error, fout.setmark, 1, 0, None) + self.assertRaises(aifc.Error, fout.getmark, 1) + fout.initfp(None) + + def test_write_aiff_by_extension(self): + sampwidth = 2 + fout = self.fout = aifc.open(TESTFN + '.aiff', 'wb') + fout.setparams((1, sampwidth, 1, 1, b'ULAW', b'')) + frames = b'\x00' * fout.getnchannels() * sampwidth + fout.writeframes(frames) + fout.close() + f = self.f = aifc.open(TESTFN + '.aiff', 'rb') + self.assertEqual(f.getcomptype(), b'NONE') + f.close() + def test_main(): run_unittest(AIFCTest) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -195,12 +195,6 @@ with self.assertRaises(AttributeError): x.vararg - with self.assertRaises(AttributeError): - x.foobar = 21 - - with self.assertRaises(AttributeError): - ast.AST(lineno=2) - with self.assertRaises(TypeError): # "_ast.AST constructor takes 0 positional arguments" ast.AST(2) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -818,6 +818,16 @@ self.assertRaises(OverflowError, _sre.compile, "abc", 0, [long_overflow]) self.assertRaises(TypeError, _sre.compile, {}, 0, []) + def test_compile(self): + # Test return value when given string and pattern as parameter + pattern = re.compile('random pattern') + self.assertIsInstance(pattern, re._pattern_type) + same_pattern = re.compile(pattern) + self.assertIsInstance(same_pattern, re._pattern_type) + self.assertIs(same_pattern, pattern) + # Test behaviour when not given a string or pattern as parameter + self.assertRaises(TypeError, re.compile, 0) + def run_re_tests(): from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR if verbose: diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -891,12 +891,15 @@ self.assertEqual('{foo._x}'.format_map({'foo': C(20)}), '20') # test various errors - self.assertRaises(TypeError, '{'.format_map) - self.assertRaises(TypeError, '}'.format_map) - self.assertRaises(TypeError, 'a{'.format_map) - self.assertRaises(TypeError, 'a}'.format_map) - self.assertRaises(TypeError, '{a'.format_map) - self.assertRaises(TypeError, '}a'.format_map) + self.assertRaises(TypeError, ''.format_map) + self.assertRaises(TypeError, 'a'.format_map) + + self.assertRaises(ValueError, '{'.format_map, {}) + self.assertRaises(ValueError, '}'.format_map, {}) + self.assertRaises(ValueError, 'a{'.format_map, {}) + self.assertRaises(ValueError, 'a}'.format_map, {}) + self.assertRaises(ValueError, '{a'.format_map, {}) + self.assertRaises(ValueError, '}a'.format_map, {}) # issue #12579: can't supply positional params to format_map self.assertRaises(ValueError, '{}'.format_map, {'a' : 2}) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -552,6 +552,7 @@ Christopher Tur Lesniewski-Laas Mark Levinson William Lewis +Akira Li Xuanji Li Robert van Liere Ross Light @@ -628,6 +629,7 @@ Andrii V. Mishkovskyi Dustin J. Mitchell Dom Mitchell +Florian Mladitsch Doug Moen The Dragon De Monsyne Skip Montanaro diff --git a/Python/ast.c b/Python/ast.c --- a/Python/ast.c +++ b/Python/ast.c @@ -645,7 +645,7 @@ } static arg_ty -compiler_arg(struct compiling *c, const node *n) +ast_for_arg(struct compiling *c, const node *n) { identifier name; expr_ty annotation = NULL; @@ -666,12 +666,6 @@ } return arg(name, annotation, c->c_arena); -#if 0 - result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena); - if (!set_context(c, result, Store, n)) - return NULL; - return result; -#endif } /* returns -1 if failed to handle keyword only arguments @@ -859,7 +853,7 @@ "non-default argument follows default argument"); return NULL; } - arg = compiler_arg(c, ch); + arg = ast_for_arg(c, ch); if (!arg) return NULL; asdl_seq_SET(posargs, k++, arg); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 08:17:35 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 08:17:35 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/e063f1b724d7 changeset: 75579:e063f1b724d7 parent: 75575:3184e2d52ac5 parent: 75572:cb0174117487 user: Senthil Kumaran date: Tue Mar 13 00:16:17 2012 -0700 summary: merge heads files: Lib/unittest/loader.py | 13 +++++++++---- Misc/NEWS | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -34,6 +34,11 @@ TestClass = type(classname, (case.TestCase,), attrs) return suiteClass((TestClass(methodname),)) +def _jython_aware_splitext(path): + if path.lower().endswith('$py.class'): + return path[:-9] + return os.path.splitext(path)[0] + class TestLoader(object): """ @@ -221,7 +226,7 @@ return os.path.dirname(full_path) def _get_name_from_path(self, path): - path = os.path.splitext(os.path.normpath(path))[0] + path = _jython_aware_splitext(os.path.normpath(path)) _relpath = os.path.relpath(path, self._top_level_dir) assert not os.path.isabs(_relpath), "Path must be within the project" @@ -258,11 +263,11 @@ yield _make_failed_import_test(name, self.suiteClass) else: mod_file = os.path.abspath(getattr(module, '__file__', full_path)) - realpath = os.path.splitext(mod_file)[0] - fullpath_noext = os.path.splitext(full_path)[0] + realpath = _jython_aware_splitext(mod_file) + fullpath_noext = _jython_aware_splitext(full_path) if realpath.lower() != fullpath_noext.lower(): module_dir = os.path.dirname(realpath) - mod_name = os.path.splitext(os.path.basename(full_path))[0] + mod_name = _jython_aware_splitext(os.path.basename(full_path)) expected_dir = os.path.dirname(full_path) msg = ("%r module incorrectly imported from %r. Expected %r. " "Is this module globally installed?") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #10543: Fix unittest test discovery with Jython bytecode files. + - Issue #1178863: Separate initialisation from setting when initializing Tkinter.Variables; harmonize exceptions to ValueError; only delete variables that have not been deleted; assert that variable names are strings. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 08:17:37 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 08:17:37 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/0b3e5503a6ee changeset: 75580:0b3e5503a6ee branch: 3.2 parent: 75578:744a8256489f parent: 75571:0f1619e539fb user: Senthil Kumaran date: Tue Mar 13 00:16:58 2012 -0700 summary: merge heads files: Lib/unittest/loader.py | 13 +++++++++---- Misc/NEWS | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -34,6 +34,11 @@ TestClass = type(classname, (case.TestCase,), attrs) return suiteClass((TestClass(methodname),)) +def _jython_aware_splitext(path): + if path.lower().endswith('$py.class'): + return path[:-9] + return os.path.splitext(path)[0] + class TestLoader(object): """ @@ -221,7 +226,7 @@ return os.path.dirname(full_path) def _get_name_from_path(self, path): - path = os.path.splitext(os.path.normpath(path))[0] + path = _jython_aware_splitext(os.path.normpath(path)) _relpath = os.path.relpath(path, self._top_level_dir) assert not os.path.isabs(_relpath), "Path must be within the project" @@ -258,11 +263,11 @@ yield _make_failed_import_test(name, self.suiteClass) else: mod_file = os.path.abspath(getattr(module, '__file__', full_path)) - realpath = os.path.splitext(mod_file)[0] - fullpath_noext = os.path.splitext(full_path)[0] + realpath = _jython_aware_splitext(mod_file) + fullpath_noext = _jython_aware_splitext(full_path) if realpath.lower() != fullpath_noext.lower(): module_dir = os.path.dirname(realpath) - mod_name = os.path.splitext(os.path.basename(full_path))[0] + mod_name = _jython_aware_splitext(os.path.basename(full_path)) expected_dir = os.path.dirname(full_path) msg = ("%r module incorrectly imported from %r. Expected %r. " "Is this module globally installed?") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,8 @@ Library ------- +- Issue #10543: Fix unittest test discovery with Jython bytecode files. + - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under Windows when the child process has already exited. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 09:51:32 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 09:51:32 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_closes_Issu?= =?utf8?q?e14281_-_Test_for_cgi=2Eescape_by_Brian_Landers?= Message-ID: http://hg.python.org/cpython/rev/757afb3af762 changeset: 75581:757afb3af762 branch: 2.7 parent: 75577:755a5f18ccf3 user: Senthil Kumaran date: Tue Mar 13 01:48:41 2012 -0700 summary: Fix closes Issue14281 - Test for cgi.escape by Brian Landers files: Lib/test/test_cgi.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -120,6 +120,11 @@ class CgiTests(unittest.TestCase): + def test_escape(self): + self.assertEqual("test & string", cgi.escape("test & string")) + self.assertEqual("<test string>", cgi.escape("")) + self.assertEqual(""test string"", cgi.escape('"test string"', True)) + def test_strict(self): for orig, expect in parse_strict_test_cases: # Test basic parsing -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 09:51:33 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 09:51:33 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_3=2E2_-_Fix_clo?= =?utf8?q?ses_Issue14281_-_Test_for_cgi=2Eescape_by_Brian_Landers?= Message-ID: http://hg.python.org/cpython/rev/13922f6d87f2 changeset: 75582:13922f6d87f2 branch: 3.2 parent: 75580:0b3e5503a6ee user: Senthil Kumaran date: Tue Mar 13 01:50:27 2012 -0700 summary: 3.2 - Fix closes Issue14281 - Test for cgi.escape by Brian Landers files: Lib/test/test_cgi.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -118,6 +118,11 @@ class CgiTests(unittest.TestCase): + def test_escape(self): + self.assertEqual("test & string", cgi.escape("test & string")) + self.assertEqual("<test string>", cgi.escape("")) + self.assertEqual(""test string"", cgi.escape('"test string"', True)) + def test_strict(self): for orig, expect in parse_strict_test_cases: # Test basic parsing -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 09:51:34 2012 From: python-checkins at python.org (senthil.kumaran) Date: Tue, 13 Mar 2012 09:51:34 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_to_3=2E3_-_Fix_closes_Issue14281_-_Test_for_cgi=2Eesca?= =?utf8?q?pe_by_Brian_Landers?= Message-ID: http://hg.python.org/cpython/rev/70712a806bdb changeset: 75583:70712a806bdb parent: 75579:e063f1b724d7 parent: 75582:13922f6d87f2 user: Senthil Kumaran date: Tue Mar 13 01:51:20 2012 -0700 summary: merge to 3.3 - Fix closes Issue14281 - Test for cgi.escape by Brian Landers files: Lib/test/test_cgi.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -118,6 +118,11 @@ class CgiTests(unittest.TestCase): + def test_escape(self): + self.assertEqual("test & string", cgi.escape("test & string")) + self.assertEqual("<test string>", cgi.escape("")) + self.assertEqual(""test string"", cgi.escape('"test string"', True)) + def test_strict(self): for orig, expect in parse_strict_test_cases: # Test basic parsing -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 13:19:42 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 13 Mar 2012 13:19:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314267?= =?utf8?q?=3A_Corrected_computation_of_rollover_filename=2E?= Message-ID: http://hg.python.org/cpython/rev/a5c4b8ccca8b changeset: 75584:a5c4b8ccca8b branch: 2.7 parent: 75577:755a5f18ccf3 user: Vinay Sajip date: Tue Mar 13 12:06:35 2012 +0000 summary: Closes #14267: Corrected computation of rollover filename. files: Lib/logging/handlers.py | 21 +++++++++++++++------ 1 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -272,9 +272,10 @@ dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour - newRolloverAt = newRolloverAt - 3600 + addend = -3600 else: # DST bows out before next rollover, so we need to add an hour - newRolloverAt = newRolloverAt + 3600 + addend = 3600 + newRolloverAt += addend result = newRolloverAt return result @@ -326,11 +327,20 @@ self.stream.close() self.stream = None # get the time that this sequence started at and make it a TimeTuple + currentTime = int(time.time()) + dstNow = time.localtime(currentTime)[-1] t = self.rolloverAt - self.interval if self.utc: timeTuple = time.gmtime(t) else: timeTuple = time.localtime(t) + dstThen = timeTuple[-1] + if dstNow != dstThen: + if dstNow: + addend = 3600 + else: + addend = -3600 + timeTuple = time.localtime(t + addend) dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple) if os.path.exists(dfn): os.remove(dfn) @@ -346,19 +356,18 @@ #print "%s -> %s" % (self.baseFilename, dfn) self.mode = 'w' self.stream = self._open() - currentTime = int(time.time()) newRolloverAt = self.computeRollover(currentTime) while newRolloverAt <= currentTime: newRolloverAt = newRolloverAt + self.interval #If DST changes and midnight or weekly rollover, adjust for this. if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc: - dstNow = time.localtime(currentTime)[-1] dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour - newRolloverAt = newRolloverAt - 3600 + addend = -3600 else: # DST bows out before next rollover, so we need to add an hour - newRolloverAt = newRolloverAt + 3600 + addend = 3600 + newRolloverAt += addend self.rolloverAt = newRolloverAt class WatchedFileHandler(logging.FileHandler): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 13:19:42 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 13 Mar 2012 13:19:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314267?= =?utf8?q?=3A_Corrected_computation_of_rollover_filename=2E?= Message-ID: http://hg.python.org/cpython/rev/a1d9466441ff changeset: 75585:a1d9466441ff branch: 3.2 parent: 75580:0b3e5503a6ee user: Vinay Sajip date: Tue Mar 13 12:10:33 2012 +0000 summary: Closes #14267: Corrected computation of rollover filename. files: Lib/logging/handlers.py | 21 +++++++++++++++------ 1 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -270,9 +270,10 @@ dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour - newRolloverAt = newRolloverAt - 3600 + addend = -3600 else: # DST bows out before next rollover, so we need to add an hour - newRolloverAt = newRolloverAt + 3600 + addend = 3600 + newRolloverAt += addend result = newRolloverAt return result @@ -323,11 +324,20 @@ self.stream.close() self.stream = None # get the time that this sequence started at and make it a TimeTuple + currentTime = int(time.time()) + dstNow = time.localtime(currentTime)[-1] t = self.rolloverAt - self.interval if self.utc: timeTuple = time.gmtime(t) else: timeTuple = time.localtime(t) + dstThen = timeTuple[-1] + if dstNow != dstThen: + if dstNow: + addend = 3600 + else: + addend = -3600 + timeTuple = time.localtime(t + addend) dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple) if os.path.exists(dfn): os.remove(dfn) @@ -337,19 +347,18 @@ os.remove(s) self.mode = 'w' self.stream = self._open() - currentTime = int(time.time()) newRolloverAt = self.computeRollover(currentTime) while newRolloverAt <= currentTime: newRolloverAt = newRolloverAt + self.interval #If DST changes and midnight or weekly rollover, adjust for this. if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc: - dstNow = time.localtime(currentTime)[-1] dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour - newRolloverAt = newRolloverAt - 3600 + addend = -3600 else: # DST bows out before next rollover, so we need to add an hour - newRolloverAt = newRolloverAt + 3600 + addend = 3600 + newRolloverAt += addend self.rolloverAt = newRolloverAt class WatchedFileHandler(logging.FileHandler): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 13:19:44 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 13 Mar 2012 13:19:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Closes_=2314267=3A_Merged_fix_from_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/30fe8a62046e changeset: 75586:30fe8a62046e parent: 75579:e063f1b724d7 parent: 75585:a1d9466441ff user: Vinay Sajip date: Tue Mar 13 12:15:09 2012 +0000 summary: Closes #14267: Merged fix from 3.2. files: Lib/logging/handlers.py | 21 +++++++++++++++------ 1 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -305,9 +305,10 @@ dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour - newRolloverAt = newRolloverAt - 3600 + addend = -3600 else: # DST bows out before next rollover, so we need to add an hour - newRolloverAt = newRolloverAt + 3600 + addend = 3600 + newRolloverAt += addend result = newRolloverAt return result @@ -358,11 +359,20 @@ self.stream.close() self.stream = None # get the time that this sequence started at and make it a TimeTuple + currentTime = int(time.time()) + dstNow = time.localtime(currentTime)[-1] t = self.rolloverAt - self.interval if self.utc: timeTuple = time.gmtime(t) else: timeTuple = time.localtime(t) + dstThen = timeTuple[-1] + if dstNow != dstThen: + if dstNow: + addend = 3600 + else: + addend = -3600 + timeTuple = time.localtime(t + addend) dfn = self.rotation_filename(self.baseFilename + "." + time.strftime(self.suffix, timeTuple)) if os.path.exists(dfn): @@ -373,19 +383,18 @@ os.remove(s) self.mode = 'w' self.stream = self._open() - currentTime = int(time.time()) newRolloverAt = self.computeRollover(currentTime) while newRolloverAt <= currentTime: newRolloverAt = newRolloverAt + self.interval #If DST changes and midnight or weekly rollover, adjust for this. if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc: - dstNow = time.localtime(currentTime)[-1] dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour - newRolloverAt = newRolloverAt - 3600 + addend = -3600 else: # DST bows out before next rollover, so we need to add an hour - newRolloverAt = newRolloverAt + 3600 + addend = 3600 + newRolloverAt += addend self.rolloverAt = newRolloverAt class WatchedFileHandler(logging.FileHandler): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 13:19:44 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 13 Mar 2012 13:19:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merged_upstream_change=2E?= Message-ID: http://hg.python.org/cpython/rev/8df496684d99 changeset: 75587:8df496684d99 parent: 75586:30fe8a62046e parent: 75583:70712a806bdb user: Vinay Sajip date: Tue Mar 13 12:15:46 2012 +0000 summary: Merged upstream change. files: Lib/test/test_cgi.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -118,6 +118,11 @@ class CgiTests(unittest.TestCase): + def test_escape(self): + self.assertEqual("test & string", cgi.escape("test & string")) + self.assertEqual("<test string>", cgi.escape("")) + self.assertEqual(""test string"", cgi.escape('"test string"', True)) + def test_strict(self): for orig, expect in parse_strict_test_cases: # Test basic parsing -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 13:19:45 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 13 Mar 2012 13:19:45 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_Merged_upstream_change=2E?= Message-ID: http://hg.python.org/cpython/rev/397215db7be1 changeset: 75588:397215db7be1 branch: 3.2 parent: 75585:a1d9466441ff parent: 75582:13922f6d87f2 user: Vinay Sajip date: Tue Mar 13 12:18:19 2012 +0000 summary: Merged upstream change. files: Lib/test/test_cgi.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -118,6 +118,11 @@ class CgiTests(unittest.TestCase): + def test_escape(self): + self.assertEqual("test & string", cgi.escape("test & string")) + self.assertEqual("<test string>", cgi.escape("")) + self.assertEqual(""test string"", cgi.escape('"test string"', True)) + def test_strict(self): for orig, expect in parse_strict_test_cases: # Test basic parsing -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 13:19:46 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 13 Mar 2012 13:19:46 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_Merged_upstream_change=2E?= Message-ID: http://hg.python.org/cpython/rev/48e6d66f708f changeset: 75589:48e6d66f708f branch: 2.7 parent: 75584:a5c4b8ccca8b parent: 75581:757afb3af762 user: Vinay Sajip date: Tue Mar 13 12:18:55 2012 +0000 summary: Merged upstream change. files: Lib/test/test_cgi.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -120,6 +120,11 @@ class CgiTests(unittest.TestCase): + def test_escape(self): + self.assertEqual("test & string", cgi.escape("test & string")) + self.assertEqual("<test string>", cgi.escape("")) + self.assertEqual(""test string"", cgi.escape('"test string"', True)) + def test_strict(self): for orig, expect in parse_strict_test_cases: # Test basic parsing -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 13:38:42 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 13 Mar 2012 13:38:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Close_=2314180=3A_Factorize?= =?utf8?q?_code_to_convert_a_number_of_seconds_to_time=5Ft=2C_timeval?= Message-ID: http://hg.python.org/cpython/rev/1e9cc1a03365 changeset: 75590:1e9cc1a03365 parent: 75587:8df496684d99 user: Victor Stinner date: Tue Mar 13 13:35:55 2012 +0100 summary: Close #14180: Factorize code to convert a number of seconds to time_t, timeval or timespec time.ctime(), gmtime(), time.localtime(), datetime.date.fromtimestamp(), datetime.datetime.fromtimestamp() and datetime.datetime.utcfromtimestamp() now raises an OverflowError, instead of a ValueError, if the timestamp does not fit in time_t. datetime.datetime.fromtimestamp() and datetime.datetime.utcfromtimestamp() now round microseconds towards zero instead of rounding to nearest with ties going away from zero. files: Doc/library/datetime.rst | 17 +++- Include/pytime.h | 17 +++- Include/timefuncs.h | 25 ------ Lib/datetime.py | 4 +- Lib/test/datetimetester.py | 34 ++++++- Lib/test/test_time.py | 57 ++++++++++++- Misc/NEWS | 9 ++ Modules/_datetimemodule.c | 47 +++-------- Modules/_testcapimodule.c | 45 +++++++++- Modules/_time.c | 28 ------ Modules/_time.h | 3 - Modules/posixmodule.c | 65 ++++----------- Modules/selectmodule.c | 39 +------- Modules/timemodule.c | 7 +- Python/pytime.c | 101 +++++++++++++++++++----- setup.py | 4 +- 16 files changed, 279 insertions(+), 223 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -395,12 +395,17 @@ .. classmethod:: date.fromtimestamp(timestamp) Return the local date corresponding to the POSIX timestamp, such as is returned - by :func:`time.time`. This may raise :exc:`ValueError`, if the timestamp is out + by :func:`time.time`. This may raise :exc:`OverflowError`, if the timestamp is out of the range of values supported by the platform C :c:func:`localtime` function. It's common for this to be restricted to years from 1970 through 2038. Note that on non-POSIX systems that include leap seconds in their notion of a timestamp, leap seconds are ignored by :meth:`fromtimestamp`. + .. versionchanged:: 3.3 + Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp + is out of the range of values supported by the platform C + :c:func:`localtime` function. + .. classmethod:: date.fromordinal(ordinal) @@ -712,6 +717,11 @@ and then it's possible to have two timestamps differing by a second that yield identical :class:`.datetime` objects. See also :meth:`utcfromtimestamp`. + .. versionchanged:: 3.3 + Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp + is out of the range of values supported by the platform C + :c:func:`localtime` or :c:func:`gmtime` functions + .. classmethod:: datetime.utcfromtimestamp(timestamp) @@ -737,6 +747,11 @@ timestamp = (dt - datetime(1970, 1, 1, tzinfo=timezone.utc)) / timedelta(seconds=1) + .. versionchanged:: 3.3 + Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp + is out of the range of values supported by the platform C + :c:func:`gmtime` function. + .. classmethod:: datetime.fromordinal(ordinal) diff --git a/Include/pytime.h b/Include/pytime.h --- a/Include/pytime.h +++ b/Include/pytime.h @@ -39,9 +39,22 @@ (tv_end.tv_usec - tv_start.tv_usec) * 0.000001) #ifndef Py_LIMITED_API +/* Convert a number of seconds, int or float, to time_t. */ +PyAPI_FUNC(int) _PyTime_ObjectToTime_t( + PyObject *obj, + time_t *sec); + +/* Convert a number of seconds, int or float, to a timeval structure. + usec is in the range [0; 999999] and rounded towards zero. + For example, -1.2 is converted to (-2, 800000). */ +PyAPI_FUNC(int) _PyTime_ObjectToTimeval( + PyObject *obj, + time_t *sec, + long *usec); + /* Convert a number of seconds, int or float, to a timespec structure. - nsec is always in the range [0; 999999999]. For example, -1.2 is converted - to (-2, 800000000). */ + nsec is in the range [0; 999999999] and rounded towards zero. + For example, -1.2 is converted to (-2, 800000000). */ PyAPI_FUNC(int) _PyTime_ObjectToTimespec( PyObject *obj, time_t *sec, diff --git a/Include/timefuncs.h b/Include/timefuncs.h deleted file mode 100644 --- a/Include/timefuncs.h +++ /dev/null @@ -1,25 +0,0 @@ -/* timefuncs.h - */ - -/* Utility function related to timemodule.c. */ - -#ifndef TIMEFUNCS_H -#define TIMEFUNCS_H -#ifdef __cplusplus -extern "C" { -#endif - - -/* Cast double x to time_t, but raise ValueError if x is too large - * to fit in a time_t. ValueError is set on return iff the return - * value is (time_t)-1 and PyErr_Occurred(). - */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(time_t) _PyTime_DoubleToTimet(double x); -#endif - - -#ifdef __cplusplus -} -#endif -#endif /* TIMEFUNCS_H */ diff --git a/Lib/datetime.py b/Lib/datetime.py --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -1360,7 +1360,7 @@ converter = _time.localtime if tz is None else _time.gmtime t, frac = divmod(t, 1.0) - us = round(frac * 1e6) + us = int(frac * 1e6) # If timestamp is less than one microsecond smaller than a # full second, us can be rounded up to 1000000. In this case, @@ -1380,7 +1380,7 @@ def utcfromtimestamp(cls, t): "Construct a UTC datetime from a POSIX timestamp (like time.time())." t, frac = divmod(t, 1.0) - us = round(frac * 1e6) + us = int(frac * 1e6) # If timestamp is less than one microsecond smaller than a # full second, us can be rounded up to 1000000. In this case, diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -977,7 +977,7 @@ # exempt such platforms (provided they return reasonable # results!). for insane in -1e200, 1e200: - self.assertRaises(ValueError, self.theclass.fromtimestamp, + self.assertRaises(OverflowError, self.theclass.fromtimestamp, insane) def test_today(self): @@ -1736,12 +1736,32 @@ self.verify_field_equality(expected, got) def test_microsecond_rounding(self): - # Test whether fromtimestamp "rounds up" floats that are less - # than 1/2 microsecond smaller than an integer. for fts in [self.theclass.fromtimestamp, self.theclass.utcfromtimestamp]: - self.assertEqual(fts(0.9999999), fts(1)) - self.assertEqual(fts(0.99999949).microsecond, 999999) + zero = fts(0) + self.assertEqual(zero.second, 0) + self.assertEqual(zero.microsecond, 0) + minus_one = fts(-1e-6) + self.assertEqual(minus_one.second, 59) + self.assertEqual(minus_one.microsecond, 999999) + + t = fts(-1e-8) + self.assertEqual(t, minus_one) + t = fts(-9e-7) + self.assertEqual(t, minus_one) + t = fts(-1e-7) + self.assertEqual(t, minus_one) + + t = fts(1e-7) + self.assertEqual(t, zero) + t = fts(9e-7) + self.assertEqual(t, zero) + t = fts(0.99999949) + self.assertEqual(t.second, 0) + self.assertEqual(t.microsecond, 999999) + t = fts(0.9999999) + self.assertEqual(t.second, 0) + self.assertEqual(t.microsecond, 999999) def test_insane_fromtimestamp(self): # It's possible that some platform maps time_t to double, @@ -1749,7 +1769,7 @@ # exempt such platforms (provided they return reasonable # results!). for insane in -1e200, 1e200: - self.assertRaises(ValueError, self.theclass.fromtimestamp, + self.assertRaises(OverflowError, self.theclass.fromtimestamp, insane) def test_insane_utcfromtimestamp(self): @@ -1758,7 +1778,7 @@ # exempt such platforms (provided they return reasonable # results!). for insane in -1e200, 1e200: - self.assertRaises(ValueError, self.theclass.utcfromtimestamp, + self.assertRaises(OverflowError, self.theclass.utcfromtimestamp, insane) @unittest.skipIf(sys.platform == "win32", "Windows doesn't accept negative timestamps") def test_negative_float_fromtimestamp(self): diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -281,7 +281,7 @@ # results!). for func in time.ctime, time.gmtime, time.localtime: for unreasonable in -1e200, 1e200: - self.assertRaises(ValueError, func, unreasonable) + self.assertRaises(OverflowError, func, unreasonable) def test_ctime_without_arg(self): # Not sure how to check the values, since the clock could tick @@ -365,11 +365,8 @@ for time_t in (-1, 2**30, 2**33, 2**60): try: time.localtime(time_t) - except ValueError as err: - if str(err) == "timestamp out of range for platform time_t": - self.skipTest("need 64-bit time_t") - else: - raise + except OverflowError: + self.skipTest("need 64-bit time_t") except OSError: invalid_time_t = time_t break @@ -498,19 +495,63 @@ class TestPytime(unittest.TestCase): + def setUp(self): + self.invalid_values = ( + -(2 ** 100), 2 ** 100, + -(2.0 ** 100.0), 2.0 ** 100.0, + ) + + def test_time_t(self): + from _testcapi import pytime_object_to_time_t + for obj, time_t in ( + (0, 0), + (-1, -1), + (-1.0, -1), + (-1.9, -1), + (1.0, 1), + (1.9, 1), + ): + self.assertEqual(pytime_object_to_time_t(obj), time_t) + + for invalid in self.invalid_values: + self.assertRaises(OverflowError, pytime_object_to_time_t, invalid) + + def test_timeval(self): + from _testcapi import pytime_object_to_timeval + for obj, timeval in ( + (0, (0, 0)), + (-1, (-1, 0)), + (-1.0, (-1, 0)), + (1e-6, (0, 1)), + (-1e-6, (-1, 999999)), + (-1.2, (-2, 800000)), + (1.1234560, (1, 123456)), + (1.1234569, (1, 123456)), + (-1.1234560, (-2, 876544)), + (-1.1234561, (-2, 876543)), + ): + self.assertEqual(pytime_object_to_timeval(obj), timeval) + + for invalid in self.invalid_values: + self.assertRaises(OverflowError, pytime_object_to_timeval, invalid) + def test_timespec(self): from _testcapi import pytime_object_to_timespec for obj, timespec in ( (0, (0, 0)), (-1, (-1, 0)), (-1.0, (-1, 0)), + (1e-9, (0, 1)), (-1e-9, (-1, 999999999)), (-1.2, (-2, 800000000)), - (1.123456789, (1, 123456789)), + (1.1234567890, (1, 123456789)), + (1.1234567899, (1, 123456789)), + (-1.1234567890, (-2, 876543211)), + (-1.1234567891, (-2, 876543210)), ): self.assertEqual(pytime_object_to_timespec(obj), timespec) - for invalid in (-(2 ** 100), -(2.0 ** 100.0), 2 ** 100, 2.0 ** 100.0): + for invalid in self.invalid_values: self.assertRaises(OverflowError, pytime_object_to_timespec, invalid) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,15 @@ Library ------- +- Issue #14180: time.ctime(), gmtime(), time.localtime(), + datetime.date.fromtimestamp(), datetime.datetime.fromtimestamp() and + datetime.datetime.utcfromtimestamp() now raises an OverflowError, instead of + a ValueError, if the timestamp does not fit in time_t. + +- Issue #14180: datetime.datetime.fromtimestamp() and + datetime.datetime.utcfromtimestamp() now round microseconds towards zero + instead of rounding to nearest with ties going away from zero. + - Issue #10543: Fix unittest test discovery with Jython bytecode files. - Issue #1178863: Separate initialisation from setting when initializing diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -7,8 +7,6 @@ #include -#include "_time.h" - /* Differentiate between building the core module and building extension * modules. */ @@ -2441,15 +2439,15 @@ /* Return new date from localtime(t). */ static PyObject * -date_local_from_time_t(PyObject *cls, double ts) +date_local_from_object(PyObject *cls, PyObject *obj) { struct tm *tm; time_t t; PyObject *result = NULL; - t = _PyTime_DoubleToTimet(ts); - if (t == (time_t)-1 && PyErr_Occurred()) + if (_PyTime_ObjectToTime_t(obj, &t) == -1) return NULL; + tm = localtime(&t); if (tm) result = PyObject_CallFunction(cls, "iii", @@ -2494,11 +2492,11 @@ static PyObject * date_fromtimestamp(PyObject *cls, PyObject *args) { - double timestamp; + PyObject *timestamp; PyObject *result = NULL; - if (PyArg_ParseTuple(args, "d:fromtimestamp", ×tamp)) - result = date_local_from_time_t(cls, timestamp); + if (PyArg_ParseTuple(args, "O:fromtimestamp", ×tamp)) + result = date_local_from_object(cls, timestamp); return result; } @@ -4096,31 +4094,14 @@ * to get that much precision (e.g., C time() isn't good enough). */ static PyObject * -datetime_from_timestamp(PyObject *cls, TM_FUNC f, double timestamp, +datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp, PyObject *tzinfo) { time_t timet; - double fraction; - int us; - - timet = _PyTime_DoubleToTimet(timestamp); - if (timet == (time_t)-1 && PyErr_Occurred()) + long us; + + if (_PyTime_ObjectToTimeval(timestamp, &timet, &us) == -1) return NULL; - fraction = timestamp - (double)timet; - us = (int)round_to_long(fraction * 1e6); - if (us < 0) { - /* Truncation towards zero is not what we wanted - for negative numbers (Python's mod semantics) */ - timet -= 1; - us += 1000000; - } - /* If timestamp is less than one microsecond smaller than a - * full second, round up. Otherwise, ValueErrors are raised - * for some floats. */ - if (us == 1000000) { - timet += 1; - us = 0; - } return datetime_from_timet_and_us(cls, f, timet, us, tzinfo); } @@ -4181,11 +4162,11 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) { PyObject *self; - double timestamp; + PyObject *timestamp; PyObject *tzinfo = Py_None; static char *keywords[] = {"timestamp", "tz", NULL}; - if (! PyArg_ParseTupleAndKeywords(args, kw, "d|O:fromtimestamp", + if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp", keywords, ×tamp, &tzinfo)) return NULL; if (check_tzinfo_subclass(tzinfo) < 0) @@ -4210,10 +4191,10 @@ static PyObject * datetime_utcfromtimestamp(PyObject *cls, PyObject *args) { - double timestamp; + PyObject *timestamp; PyObject *result = NULL; - if (PyArg_ParseTuple(args, "d:utcfromtimestamp", ×tamp)) + if (PyArg_ParseTuple(args, "O:utcfromtimestamp", ×tamp)) result = datetime_from_timestamp(cls, gmtime, timestamp, Py_None); return result; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2323,6 +2323,42 @@ return PyLong_FromLong(r); } +static PyObject* +_PyLong_FromTime_t(time_t value) +{ +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + return PyLong_FromLongLong(value); +#else + assert(sizeof(time_t) <= sizeof(long)); + return PyLong_FromLong(value); +#endif +} + +static PyObject * +test_pytime_object_to_time_t(PyObject *self, PyObject *args) +{ + PyObject *obj; + time_t sec; + if (!PyArg_ParseTuple(args, "O:pytime_object_to_time_t", &obj)) + return NULL; + if (_PyTime_ObjectToTime_t(obj, &sec) == -1) + return NULL; + return _PyLong_FromTime_t(sec); +} + +static PyObject * +test_pytime_object_to_timeval(PyObject *self, PyObject *args) +{ + PyObject *obj; + time_t sec; + long usec; + if (!PyArg_ParseTuple(args, "O:pytime_object_to_timeval", &obj)) + return NULL; + if (_PyTime_ObjectToTimeval(obj, &sec, &usec) == -1) + return NULL; + return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), usec); +} + static PyObject * test_pytime_object_to_timespec(PyObject *self, PyObject *args) { @@ -2333,12 +2369,7 @@ return NULL; if (_PyTime_ObjectToTimespec(obj, &sec, &nsec) == -1) return NULL; -#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG - return Py_BuildValue("Ll", (PY_LONG_LONG)sec, nsec); -#else - assert(sizeof(time_t) <= sizeof(long)); - return Py_BuildValue("ll", (long)sec, nsec); -#endif + return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); } @@ -2430,6 +2461,8 @@ METH_NOARGS}, {"crash_no_current_thread", (PyCFunction)crash_no_current_thread, METH_NOARGS}, {"run_in_subinterp", run_in_subinterp, METH_VARARGS}, + {"pytime_object_to_time_t", test_pytime_object_to_time_t, METH_VARARGS}, + {"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS}, {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_time.c b/Modules/_time.c deleted file mode 100644 --- a/Modules/_time.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "Python.h" -#include "_time.h" - -/* Exposed in timefuncs.h. */ -time_t -_PyTime_DoubleToTimet(double x) -{ - time_t result; - double diff; - - result = (time_t)x; - /* How much info did we lose? time_t may be an integral or - * floating type, and we don't know which. If it's integral, - * we don't know whether C truncates, rounds, returns the floor, - * etc. If we lost a second or more, the C rounding is - * unreasonable, or the input just doesn't fit in a time_t; - * call it an error regardless. Note that the original cast to - * time_t can cause a C error too, but nothing we can do to - * work around that. - */ - diff = x - (double)result; - if (diff <= -1.0 || diff >= 1.0) { - PyErr_SetString(PyExc_ValueError, - "timestamp out of range for platform time_t"); - result = (time_t)-1; - } - return result; -} diff --git a/Modules/_time.h b/Modules/_time.h deleted file mode 100644 --- a/Modules/_time.h +++ /dev/null @@ -1,3 +0,0 @@ -/* XXX: It is probably best to move timefuncs.h content in here, and - remove it but user code may rely on it. */ -#include "timefuncs.h" diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3540,31 +3540,6 @@ #endif /* HAVE_UNAME */ -static int -extract_time(PyObject *t, time_t* sec, long* nsec) -{ - time_t intval; - if (PyFloat_Check(t)) { - double d = PyFloat_AsDouble(t); - double mod; - *sec = (time_t)d; - mod = fmod(d, 1.0); - mod *= 1e9; - *nsec = (long)mod; - return 0; - } -#if SIZEOF_TIME_T > SIZEOF_LONG - intval = PyLong_AsUnsignedLongLongMask(t); -#else - intval = PyLong_AsLong(t); -#endif - if (intval == -1 && PyErr_Occurred()) - return -1; - *sec = intval; - *nsec = 0; - return 0; -} - PyDoc_STRVAR(posix_utime__doc__, "utime(path[, (atime, mtime)])\n\ Set the access and modified time of the file to the given values.\n\ @@ -3633,12 +3608,12 @@ goto done; } else { - if (extract_time(PyTuple_GET_ITEM(arg, 0), - &atimesec, &ansec) == -1) + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 0), + &atimesec, &ansec) == -1) goto done; time_t_to_FILE_TIME(atimesec, ansec, &atime); - if (extract_time(PyTuple_GET_ITEM(arg, 1), - &mtimesec, &mnsec) == -1) + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 1), + &mtimesec, &mnsec) == -1) goto done; time_t_to_FILE_TIME(mtimesec, mnsec, &mtime); } @@ -3681,13 +3656,13 @@ return NULL; } else { - if (extract_time(PyTuple_GET_ITEM(arg, 0), - &atime, &ansec) == -1) { + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 0), + &atime, &ansec) == -1) { Py_DECREF(opath); return NULL; } - if (extract_time(PyTuple_GET_ITEM(arg, 1), - &mtime, &mnsec) == -1) { + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 1), + &mtime, &mnsec) == -1) { Py_DECREF(opath); return NULL; } @@ -3763,12 +3738,12 @@ return NULL; } else { - if (extract_time(PyTuple_GET_ITEM(arg, 0), - &atime, &ansec) == -1) { + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 0), + &atime, &ansec) == -1) { return NULL; } - if (extract_time(PyTuple_GET_ITEM(arg, 1), - &mtime, &mnsec) == -1) { + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 1), + &mtime, &mnsec) == -1) { return NULL; } Py_BEGIN_ALLOW_THREADS @@ -3829,13 +3804,13 @@ return NULL; } else { - if (extract_time(PyTuple_GET_ITEM(arg, 0), - &atime, &ansec) == -1) { + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 0), + &atime, &ansec) == -1) { Py_DECREF(opath); return NULL; } - if (extract_time(PyTuple_GET_ITEM(arg, 1), - &mtime, &mnsec) == -1) { + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 1), + &mtime, &mnsec) == -1) { Py_DECREF(opath); return NULL; } @@ -9610,13 +9585,13 @@ return NULL; } else { - if (extract_time(PyTuple_GET_ITEM(arg, 0), - &atime, &ansec) == -1) { + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 0), + &atime, &ansec) == -1) { Py_DECREF(opath); return NULL; } - if (extract_time(PyTuple_GET_ITEM(arg, 1), - &mtime, &mnsec) == -1) { + if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(arg, 1), + &mtime, &mnsec) == -1) { Py_DECREF(opath); return NULL; } diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -206,9 +206,7 @@ PyObject *ret = NULL; PyObject *tout = Py_None; fd_set ifdset, ofdset, efdset; - double timeout; struct timeval tv, *tvp; - long seconds; int imax, omax, emax, max; int n; @@ -225,23 +223,12 @@ return NULL; } else { - timeout = PyFloat_AsDouble(tout); - if (timeout == -1 && PyErr_Occurred()) + if (_PyTime_ObjectToTimeval(tout, &tv.tv_sec, &tv.tv_usec) == -1) return NULL; - if (timeout > (double)LONG_MAX) { - PyErr_SetString(PyExc_OverflowError, - "timeout period too long"); + if (tv.tv_sec < 0) { + PyErr_SetString(PyExc_ValueError, "timeout must be non-negative"); return NULL; } - if (timeout < 0) { - PyErr_SetString(PyExc_ValueError, - "timeout must be non-negative"); - return NULL; - } - seconds = (long)timeout; - timeout = timeout - (double)seconds; - tv.tv_sec = seconds; - tv.tv_usec = (long)(timeout * 1E6); tvp = &tv; } @@ -1870,27 +1857,15 @@ ptimeoutspec = NULL; } else if (PyNumber_Check(otimeout)) { - double timeout; - long seconds; + if (_PyTime_ObjectToTimespec(otimeout, + &timeout.tv_sec, &timeout.tv_nsec) == -1) + return NULL; - timeout = PyFloat_AsDouble(otimeout); - if (timeout == -1 && PyErr_Occurred()) - return NULL; - if (timeout > (double)LONG_MAX) { - PyErr_SetString(PyExc_OverflowError, - "timeout period too long"); - return NULL; - } - if (timeout < 0) { + if (timeout.tv_sec < 0) { PyErr_SetString(PyExc_ValueError, "timeout must be positive or None"); return NULL; } - - seconds = (long)timeout; - timeout = timeout - (double)seconds; - timeoutspec.tv_sec = seconds; - timeoutspec.tv_nsec = (long)(timeout * 1E9); ptimeoutspec = &timeoutspec; } else { diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1,7 +1,6 @@ /* Time module */ #include "Python.h" -#include "_time.h" #include @@ -288,11 +287,7 @@ whent = time(NULL); } else { - double d = PyFloat_AsDouble(ot); - if (PyErr_Occurred()) - return 0; - whent = _PyTime_DoubleToTimet(d); - if (whent == (time_t)-1 && PyErr_Occurred()) + if (_PyTime_ObjectToTime_t(ot, &whent) == -1) return 0; } *pwhen = whent; diff --git a/Python/pytime.c b/Python/pytime.c --- a/Python/pytime.c +++ b/Python/pytime.c @@ -70,9 +70,37 @@ #endif /* MS_WINDOWS */ } -int -_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec) +static void +error_time_t_overflow(void) { + PyErr_SetString(PyExc_OverflowError, + "timestamp out of range for platform time_t"); +} + +static time_t +_PyLong_AsTime_t(PyObject *obj) +{ +#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG + PY_LONG_LONG val; + val = PyLong_AsLongLong(obj); +#else + long val; + assert(sizeof(time_t) <= sizeof(long)); + val = PyLong_AsLong(obj); +#endif + if (val == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + error_time_t_overflow(); + return -1; + } + return (time_t)val; +} + +static int +_PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator, + double denominator) +{ + assert(denominator <= LONG_MAX); if (PyFloat_Check(obj)) { double d, intpart, floatpart, err; @@ -85,34 +113,61 @@ *sec = (time_t)intpart; err = intpart - (double)*sec; - if (err <= -1.0 || err >= 1.0) - goto overflow; + if (err <= -1.0 || err >= 1.0) { + error_time_t_overflow(); + return -1; + } - floatpart *= 1e9; - *nsec = (long)floatpart; + floatpart *= denominator; + *numerator = (long)floatpart; return 0; } else { -#if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG - *sec = PyLong_AsLongLong(obj); -#else - assert(sizeof(time_t) <= sizeof(long)); - *sec = PyLong_AsLong(obj); -#endif - if (*sec == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - goto overflow; - else - return -1; - } - *nsec = 0; + *sec = _PyLong_AsTime_t(obj); + if (*sec == (time_t)-1 && PyErr_Occurred()) + return -1; + *numerator = 0; return 0; } +} -overflow: - PyErr_SetString(PyExc_OverflowError, - "timestamp out of range for platform time_t"); - return -1; +int +_PyTime_ObjectToTime_t(PyObject *obj, time_t *sec) +{ + if (PyFloat_Check(obj)) { + double d, intpart, err; + + /*whent = _PyTime_DoubleToTimet(d);*/ + + d = PyFloat_AsDouble(obj); + (void)modf(d, &intpart); + + *sec = (time_t)intpart; + err = intpart - (double)*sec; + if (err <= -1.0 || err >= 1.0) { + error_time_t_overflow(); + return -1; + } + return 0; + } + else { + *sec = _PyLong_AsTime_t(obj); + if (*sec == (time_t)-1 && PyErr_Occurred()) + return -1; + return 0; + } +} + +int +_PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec) +{ + return _PyTime_ObjectToDenominator(obj, sec, nsec, 1e9); +} + +int +_PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec) +{ + return _PyTime_ObjectToDenominator(obj, sec, usec, 1e6); } void diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -512,9 +512,9 @@ time_libs.append(lib) # time operations and variables - exts.append( Extension('time', ['timemodule.c', '_time.c'], + exts.append( Extension('time', ['timemodule.c'], libraries=time_libs) ) - exts.append( Extension('_datetime', ['_datetimemodule.c', '_time.c']) ) + exts.append( Extension('_datetime', ['_datetimemodule.c']) ) # random number generator implemented in C exts.append( Extension("_random", ["_randommodule.c"]) ) # bisect -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 13:50:39 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 13 Mar 2012 13:50:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314180=3A_Remove_co?= =?utf8?q?mmented_code?= Message-ID: http://hg.python.org/cpython/rev/ed73006bac42 changeset: 75591:ed73006bac42 user: Victor Stinner date: Tue Mar 13 13:50:34 2012 +0100 summary: Issue #14180: Remove commented code files: Python/pytime.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Python/pytime.c b/Python/pytime.c --- a/Python/pytime.c +++ b/Python/pytime.c @@ -137,8 +137,6 @@ if (PyFloat_Check(obj)) { double d, intpart, err; - /*whent = _PyTime_DoubleToTimet(d);*/ - d = PyFloat_AsDouble(obj); (void)modf(d, &intpart); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 15:30:59 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 13 Mar 2012 15:30:59 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314180=3A_Fix_selec?= =?utf8?q?t=2Eselect=28=29_compilation_on_BSD_and_a_typo_in?= Message-ID: http://hg.python.org/cpython/rev/1eaf6e899f02 changeset: 75592:1eaf6e899f02 user: Victor Stinner date: Tue Mar 13 15:29:08 2012 +0100 summary: Issue #14180: Fix select.select() compilation on BSD and a typo in kqueue_queue_control() files: Modules/selectmodule.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -223,8 +223,10 @@ return NULL; } else { - if (_PyTime_ObjectToTimeval(tout, &tv.tv_sec, &tv.tv_usec) == -1) + long usec; + if (_PyTime_ObjectToTimeval(tout, &tv.tv_sec, &usec) == -1) return NULL; + tv.tv_usec = usec; if (tv.tv_sec < 0) { PyErr_SetString(PyExc_ValueError, "timeout must be non-negative"); return NULL; @@ -1837,7 +1839,7 @@ PyObject *result = NULL; struct kevent *evl = NULL; struct kevent *chl = NULL; - struct timespec timeoutspec; + struct timespec timeout; struct timespec *ptimeoutspec; if (self->kqfd < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 16:07:00 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 13 Mar 2012 16:07:00 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Add_missing_CHANGES_entr?= =?utf8?q?ies_and_remove_more_2=2E4_support_code?= Message-ID: http://hg.python.org/distutils2/rev/55f80f3d59ef changeset: 1297:55f80f3d59ef user: ?ric Araujo date: Tue Mar 13 16:05:55 2012 +0100 summary: Add missing CHANGES entries and remove more 2.4 support code files: CHANGES.txt | 4 + DEVNOTES.txt | 8 +- PC/build_ssl.py | 282 ------------------------------------ README.txt | 2 +- setup.cfg | 5 + setup.py | 135 +---------------- tests.sh | 10 + tox.ini | 9 +- 8 files changed, 25 insertions(+), 430 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt --- a/CHANGES.txt +++ b/CHANGES.txt @@ -169,6 +169,10 @@ - #13974: add test for util.set_platform [tshepang] - #6884: Fix MANIFEST.in parsing bugs on Windows [?ric, nadeem] - #11841: Fix comparison bug with 'rc' versions [filip] +- #14263: Fix function name lookup in d2.pypi.wrapper [tarek] +- #14264: Stop removing trailing zeroes in versions [tarek] +- #14268: Fix small error in a test [tarek] +- Drop support for Python 2.4 [tarek, ?ric] 1.0a3 - 2010-10-08 diff --git a/DEVNOTES.txt b/DEVNOTES.txt --- a/DEVNOTES.txt +++ b/DEVNOTES.txt @@ -11,7 +11,7 @@ Repo: http://hg.python.org/cpython (default branch) More info: http://wiki.python.org/moin/Distutils/Contributing -- Distutils2 runs on Python from 2.4 to 2.7, so make sure you don't use code +- Distutils2 runs on Python from 2.5 to 2.7, so make sure you don't use code that doesn't work under one of these Python versions. The version in the "python3" branch is compatible with all version from 3.1 to 3.3. @@ -21,12 +21,8 @@ have a look or use a diff tool with the same file in distutils or packaging from Python 3.3. If you can't run tests, let someone else do the merge. -- For 2.4, you need to run "python2.4 setup.py build" before you can try out - pysetup or run tests (unless you use the runtests.py script which will call - "setup.py build" automatically). - - Always run tests.sh before you commit a change. This implies that you have - all Python versions installed from 2.4 to 2.7, as well as 3.1-.3.3 if you + all Python versions installed from 2.5 to 2.7, as well as 3.1-.3.3 if you merge into the python3 branch. Be sure to also have docutils installed on all Python versions to avoid skipping tests. diff --git a/PC/build_ssl.py b/PC/build_ssl.py deleted file mode 100644 --- a/PC/build_ssl.py +++ /dev/null @@ -1,282 +0,0 @@ -# Script for building the _ssl and _hashlib modules for Windows. -# Uses Perl to setup the OpenSSL environment correctly -# and build OpenSSL, then invokes a simple nmake session -# for the actual _ssl.pyd and _hashlib.pyd DLLs. - -# THEORETICALLY, you can: -# * Unpack the latest SSL release one level above your main Python source -# directory. It is likely you will already find the zlib library and -# any other external packages there. -# * Install ActivePerl and ensure it is somewhere on your path. -# * Run this script from the PCBuild directory. -# -# it should configure and build SSL, then build the _ssl and _hashlib -# Python extensions without intervention. - -# Modified by Christian Heimes -# Now this script supports pre-generated makefiles and assembly files. -# Developers don't need an installation of Perl anymore to build Python. A svn -# checkout from our svn repository is enough. -# -# In Order to create the files in the case of an update you still need Perl. -# Run build_ssl in this order: -# python.exe build_ssl.py Release x64 -# python.exe build_ssl.py Release Win32 - -import os, sys, re, shutil - -# Find all "foo.exe" files on the PATH. -def find_all_on_path(filename, extras = None): - entries = os.environ["PATH"].split(os.pathsep) - ret = [] - for p in entries: - fname = os.path.abspath(os.path.join(p, filename)) - if os.path.isfile(fname) and fname not in ret: - ret.append(fname) - if extras: - for p in extras: - fname = os.path.abspath(os.path.join(p, filename)) - if os.path.isfile(fname) and fname not in ret: - ret.append(fname) - return ret - -# Find a suitable Perl installation for OpenSSL. -# cygwin perl does *not* work. ActivePerl does. -# Being a Perl dummy, the simplest way I can check is if the "Win32" package -# is available. -def find_working_perl(perls): - for perl in perls: - fh = os.popen('"%s" -e "use Win32;"' % perl) - fh.read() - rc = fh.close() - if rc: - continue - return perl - print("Can not find a suitable PERL:") - if perls: - print(" the following perl interpreters were found:") - for p in perls: - print(" ", p) - print(" None of these versions appear suitable for building OpenSSL") - else: - print(" NO perl interpreters were found on this machine at all!") - print(" Please install ActivePerl and ensure it appears on your path") - return None - -# Locate the best SSL directory given a few roots to look into. -def find_best_ssl_dir(sources): - candidates = [] - for s in sources: - try: - # note: do not abspath s; the build will fail if any - # higher up directory name has spaces in it. - fnames = os.listdir(s) - except os.error: - fnames = [] - for fname in fnames: - fqn = os.path.join(s, fname) - if os.path.isdir(fqn) and fname.startswith("openssl-"): - candidates.append(fqn) - # Now we have all the candidates, locate the best. - best_parts = [] - best_name = None - for c in candidates: - parts = re.split("[.-]", os.path.basename(c))[1:] - # eg - openssl-0.9.7-beta1 - ignore all "beta" or any other qualifiers - if len(parts) >= 4: - continue - if parts > best_parts: - best_parts = parts - best_name = c - if best_name is not None: - print("Found an SSL directory at '%s'" % (best_name,)) - else: - print("Could not find an SSL directory in '%s'" % (sources,)) - sys.stdout.flush() - return best_name - -def create_makefile64(makefile, m32): - """Create and fix makefile for 64bit - - Replace 32 with 64bit directories - """ - if not os.path.isfile(m32): - return - with open(m32) as fin: - with open(makefile, 'w') as fout: - for line in fin: - line = line.replace("=tmp32", "=tmp64") - line = line.replace("=out32", "=out64") - line = line.replace("=inc32", "=inc64") - # force 64 bit machine - line = line.replace("MKLIB=lib", "MKLIB=lib /MACHINE:X64") - line = line.replace("LFLAGS=", "LFLAGS=/MACHINE:X64 ") - # don't link against the lib on 64bit systems - line = line.replace("bufferoverflowu.lib", "") - fout.write(line) - os.unlink(m32) - -def fix_makefile(makefile): - """Fix some stuff in all makefiles - """ - if not os.path.isfile(makefile): - return - with open(makefile) as fin: - lines = fin.readlines() - with open(makefile, 'w') as fout: - for line in lines: - if line.startswith("PERL="): - continue - if line.startswith("CP="): - line = "CP=copy\n" - if line.startswith("MKDIR="): - line = "MKDIR=mkdir\n" - if line.startswith("CFLAG="): - line = line.strip() - for algo in ("RC5", "MDC2", "IDEA"): - noalgo = " -DOPENSSL_NO_%s" % algo - if noalgo not in line: - line = line + noalgo - line = line + '\n' - fout.write(line) - -def run_configure(configure, do_script): - print("perl Configure "+configure+" no-idea no-mdc2") - os.system("perl Configure "+configure+" no-idea no-mdc2") - print(do_script) - os.system(do_script) - -def cmp(f1, f2): - bufsize = 1024 * 8 - with open(f1, 'rb') as fp1, open(f2, 'rb') as fp2: - while True: - b1 = fp1.read(bufsize) - b2 = fp2.read(bufsize) - if b1 != b2: - return False - if not b1: - return True - -def copy(src, dst): - if os.path.isfile(dst) and cmp(src, dst): - return - shutil.copy(src, dst) - -def main(): - build_all = "-a" in sys.argv - # Default to 'Release' configuration on for the 'Win32' platform - try: - configuration, platform = sys.argv[1:3] - except ValueError: - configuration, platform = 'Release', 'Win32' - if configuration == "Release": - debug = False - elif configuration == "Debug": - debug = True - else: - raise ValueError(str(sys.argv)) - - if platform == "Win32": - arch = "x86" - configure = "VC-WIN32" - do_script = "ms\\do_nasm" - makefile="ms\\nt.mak" - m32 = makefile - dirsuffix = "32" - elif platform == "x64": - arch="amd64" - configure = "VC-WIN64A" - do_script = "ms\\do_win64a" - makefile = "ms\\nt64.mak" - m32 = makefile.replace('64', '') - dirsuffix = "64" - #os.environ["VSEXTCOMP_USECL"] = "MS_OPTERON" - else: - raise ValueError(str(sys.argv)) - - make_flags = "" - if build_all: - make_flags = "-a" - # perl should be on the path, but we also look in "\perl" and "c:\\perl" - # as "well known" locations - perls = find_all_on_path("perl.exe", ["\\perl\\bin", "C:\\perl\\bin"]) - perl = find_working_perl(perls) - if perl: - print("Found a working perl at '%s'" % (perl,)) - else: - print("No Perl installation was found. Existing Makefiles are used.") - sys.stdout.flush() - # Look for SSL 2 levels up from pcbuild - ie, same place zlib etc all live. - ssl_dir = find_best_ssl_dir(("..\\..",)) - if ssl_dir is None: - sys.exit(1) - - old_cd = os.getcwd() - try: - os.chdir(ssl_dir) - # rebuild makefile when we do the role over from 32 to 64 build - if arch == "amd64" and os.path.isfile(m32) and not os.path.isfile(makefile): - os.unlink(m32) - - # If the ssl makefiles do not exist, we invoke Perl to generate them. - # Due to a bug in this script, the makefile sometimes ended up empty - # Force a regeneration if it is. - if not os.path.isfile(makefile) or os.path.getsize(makefile)==0: - if perl is None: - print("Perl is required to build the makefiles!") - sys.exit(1) - - print("Creating the makefiles...") - sys.stdout.flush() - # Put our working Perl at the front of our path - os.environ["PATH"] = os.path.dirname(perl) + \ - os.pathsep + \ - os.environ["PATH"] - run_configure(configure, do_script) - if debug: - print("OpenSSL debug builds aren't supported.") - #if arch=="x86" and debug: - # # the do_masm script in openssl doesn't generate a debug - # # build makefile so we generate it here: - # os.system("perl util\mk1mf.pl debug "+configure+" >"+makefile) - - if arch == "amd64": - create_makefile64(makefile, m32) - fix_makefile(makefile) - copy(r"crypto\buildinf.h", r"crypto\buildinf_%s.h" % arch) - copy(r"crypto\opensslconf.h", r"crypto\opensslconf_%s.h" % arch) - - # If the assembler files don't exist in tmpXX, copy them there - if perl is None and os.path.exists("asm"+dirsuffix): - if not os.path.exists("tmp"+dirsuffix): - os.mkdir("tmp"+dirsuffix) - for f in os.listdir("asm"+dirsuffix): - if not f.endswith(".asm"): continue - if os.path.isfile(r"tmp%s\%s" % (dirsuffix, f)): continue - shutil.copy(r"asm%s\%s" % (dirsuffix, f), "tmp"+dirsuffix) - - # Now run make. - if arch == "amd64": - rc = os.system("ml64 -c -Foms\\uptable.obj ms\\uptable.asm") - if rc: - print("ml64 assembler has failed.") - sys.exit(rc) - - copy(r"crypto\buildinf_%s.h" % arch, r"crypto\buildinf.h") - copy(r"crypto\opensslconf_%s.h" % arch, r"crypto\opensslconf.h") - - #makeCommand = "nmake /nologo PERL=\"%s\" -f \"%s\"" %(perl, makefile) - makeCommand = "nmake /nologo -f \"%s\"" % makefile - print("Executing ssl makefiles: " + makeCommand) - sys.stdout.flush() - rc = os.system(makeCommand) - if rc: - print("Executing "+makefile+" failed") - print(rc) - sys.exit(rc) - finally: - os.chdir(old_cd) - sys.exit(rc) - -if __name__=='__main__': - main() diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -10,7 +10,7 @@ - Developers of packaging-related tools who need a support library to build on -Authors will have to write a :file:`setup.cfg` file and run a few +Authors will have to write a ``setup.cfg`` file and run a few commands to package and distribute their code. End users will be able to search for, install and remove Python projects with the included ``pysetup`` program. Last, developers will be able to reuse classes and diff --git a/setup.cfg b/setup.cfg --- a/setup.cfg +++ b/setup.cfg @@ -16,6 +16,11 @@ License :: OSI Approved :: Python Software Foundation License Operating System :: OS Independent Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 2.5 + Programming Language :: Python :: 2.6 + Programming Language :: Python :: 2.7 + Programming Language :: Python :: Implementation :: CPython Topic :: Software Development :: Libraries :: Python Modules Topic :: System :: Archiving :: Packaging Topic :: System :: Systems Administration diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -1,12 +1,7 @@ #!/usr/bin/env python # -*- encoding: utf-8 -*- -import os -import re -import sys import codecs -from distutils import sysconfig -from distutils.core import setup, Extension -from distutils.ccompiler import new_compiler +from distutils.core import setup from ConfigParser import RawConfigParser @@ -22,7 +17,7 @@ def cfg_to_args(path='setup.cfg'): - opts_to_args = { + opts_to_args = { 'metadata': ( ('name', 'name', None), ('version', 'version', None), @@ -83,131 +78,5 @@ kwargs['package_data'] = package_data return kwargs -# (from Python's setup.py, in PyBuildExt.detect_modules()) -def prepare_hashlib_extensions(): - """Decide which C extensions to build and create the appropriate - Extension objects to build them. Return a list of Extensions. - """ - ssl_libs = None - ssl_inc_dir = None - ssl_lib_dirs = [] - ssl_inc_dirs = [] - if os.name == 'posix': - # (from Python's setup.py, in PyBuildExt.detect_modules()) - # lib_dirs and inc_dirs are used to search for files; - # if a file is found in one of those directories, it can - # be assumed that no additional -I,-L directives are needed. - lib_dirs = [] - inc_dirs = [] - if os.path.normpath(sys.prefix) != '/usr': - lib_dirs.append(sysconfig.get_config_var('LIBDIR')) - inc_dirs.append(sysconfig.get_config_var('INCLUDEDIR')) - # Ensure that /usr/local is always used - lib_dirs.append('/usr/local/lib') - inc_dirs.append('/usr/local/include') - # Add the compiler defaults; this compiler object is only used - # to locate the OpenSSL files. - compiler = new_compiler() - lib_dirs.extend(compiler.library_dirs) - inc_dirs.extend(compiler.include_dirs) - # Now the platform defaults - lib_dirs.extend(['/lib64', '/usr/lib64', '/lib', '/usr/lib']) - inc_dirs.extend(['/usr/include']) - # Find the SSL library directory - ssl_libs = ['ssl', 'crypto'] - ssl_lib = compiler.find_library_file(lib_dirs, 'ssl') - if ssl_lib is None: - ssl_lib_dirs = ['/usr/local/ssl/lib', '/usr/contrib/ssl/lib'] - ssl_lib = compiler.find_library_file(ssl_lib_dirs, 'ssl') - if ssl_lib is not None: - ssl_lib_dirs.append(os.path.dirname(ssl_lib)) - else: - ssl_libs = None - # Locate the SSL headers - for ssl_inc_dir in inc_dirs + ['/usr/local/ssl/include', - '/usr/contrib/ssl/include']: - ssl_h = os.path.join(ssl_inc_dir, 'openssl', 'ssl.h') - if os.path.exists(ssl_h): - if ssl_inc_dir not in inc_dirs: - ssl_inc_dirs.append(ssl_inc_dir) - break - elif os.name == 'nt': - # (from Python's PCbuild/build_ssl.py, in find_best_ssl_dir()) - # Look for SSL 1 level up from here. That is, the same place the - # other externals for Python core live. - # note: do not abspath src_dir; the build will fail if any - # higher up directory name has spaces in it. - src_dir = '..' - try: - fnames = os.listdir(src_dir) - except OSError: - fnames = [] - ssl_dir = None - best_parts = [] - for fname in fnames: - fqn = os.path.join(src_dir, fname) - if os.path.isdir(fqn) and fname.startswith("openssl-"): - # We have a candidate, determine the best - parts = re.split("[.-]", fname)[1:] - # Ignore all "beta" or any other qualifiers; - # eg - openssl-0.9.7-beta1 - if len(parts) < 4 and parts > best_parts: - best_parts = parts - ssl_dir = fqn - if ssl_dir is not None: - ssl_libs = ['gdi32', 'user32', 'advapi32', - os.path.join(ssl_dir, 'out32', 'libeay32')] - ssl_inc_dir = os.path.join(ssl_dir, 'inc32') - ssl_inc_dirs.append(ssl_inc_dir) - - # Find out which version of OpenSSL we have - openssl_ver = 0 - openssl_ver_re = re.compile( - '^\s*#\s*define\s+OPENSSL_VERSION_NUMBER\s+(0x[0-9a-fA-F]+)' ) - if ssl_inc_dir is not None: - opensslv_h = os.path.join(ssl_inc_dir, 'openssl', 'opensslv.h') - try: - incfile = open(opensslv_h, 'r') - for line in incfile: - m = openssl_ver_re.match(line) - if m: - openssl_ver = int(m.group(1), 16) - except IOError: - e = str(sys.last_value) - print("IOError while reading %s: %s" % (opensslv_h, e)) - - # Now we can determine which extension modules need to be built. - exts = [] - if ssl_libs is not None and openssl_ver >= 0x907000: - # The _hashlib module wraps optimized implementations - # of hash functions from the OpenSSL library. - exts.append(Extension('distutils2._backport._hashlib', - ['distutils2/_backport/_hashopenssl.c'], - include_dirs=ssl_inc_dirs, - library_dirs=ssl_lib_dirs, - libraries=ssl_libs)) - else: - # no openssl at all, use our own md5 and sha1 - exts.append(Extension('distutils2._backport._sha', - ['distutils2/_backport/shamodule.c'])) - exts.append(Extension('distutils2._backport._md5', - sources=['distutils2/_backport/md5module.c', - 'distutils2/_backport/md5.c'], - depends=['distutils2/_backport/md5.h']) ) - # XXX always compile sha256 and sha512 to have a working hashlib (maybe - # I (merwok) can't compile _ssl and thus _hashlib for 2.4, maybe because of - # Debian multiarch, even though I set all needed build vars (and can - # compile _ssl for 2.6 for example) - if True: - #if openssl_ver < 0x908000: - # # OpenSSL doesn't do these until 0.9.8 so we'll bring our own - exts.append(Extension('distutils2._backport._sha256', - ['distutils2/_backport/sha256module.c'])) - exts.append(Extension('distutils2._backport._sha512', - ['distutils2/_backport/sha512module.c'])) - return exts - setup_kwargs = cfg_to_args('setup.cfg') -if sys.version_info[:2] < (2, 5): - setup_kwargs['ext_modules'] = prepare_hashlib_extensions() setup(**setup_kwargs) diff --git a/tests.sh b/tests.sh --- a/tests.sh +++ b/tests.sh @@ -1,4 +1,14 @@ #!/bin/sh +echo -n "Running tests with Python 2.5... " +python2.5 -Wd runtests.py -q +if [ $? -ne 0 ];then + echo Failed, re-running + python2.5 -Wd runtests.py + exit $? +else + echo Success +fi + echo -n "Running tests with Python 2.6... " python2.6 -Wd runtests.py -q if [ $? -ne 0 ];then diff --git a/tox.ini b/tox.ini --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] #distshare={homedir}/.tox/distshare -envlist=py24,py25,py26,py26-s,py27 +envlist=py25,py26,py26-s,py27 [tox:hudson] #distshare={toxworkdir}/distshare @@ -20,10 +20,3 @@ basepython=python2.7 commands= nosetests --with-xunit distutils2/tests - -[testenv:py24] -basepython=python2.4 -commands= - rm -f distutils2/_backport/_hashlib.so - python setup.py build_ext -f - nosetests --with-xunit distutils2/tests -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Tue Mar 13 16:25:44 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 13 Mar 2012 16:25:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314180=3A_Fix_anoth?= =?utf8?q?er_typo_in_kqueue=5Fqueue=5Fcontrol=28=29?= Message-ID: http://hg.python.org/cpython/rev/cb1c877a27f2 changeset: 75593:cb1c877a27f2 user: Victor Stinner date: Tue Mar 13 16:25:35 2012 +0100 summary: Issue #14180: Fix another typo in kqueue_queue_control() files: Modules/selectmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1868,7 +1868,7 @@ "timeout must be positive or None"); return NULL; } - ptimeoutspec = &timeoutspec; + ptimeoutspec = &timeout; } else { PyErr_Format(PyExc_TypeError, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 17:03:35 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 13 Mar 2012 17:03:35 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Release_1=2E0a4_=5Co/?= Message-ID: http://hg.python.org/distutils2/rev/1e4d52d83e95 changeset: 1299:1e4d52d83e95 tag: 1.0a4 user: ?ric Araujo date: Tue Mar 13 16:55:34 2012 +0100 summary: Release 1.0a4 \o/ files: CHANGES.txt | 2 +- setup.cfg | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,7 +9,7 @@ CONTRIBUTORS.txt for full names. Bug numbers refer to http://bugs.python.org/. -1.0a4 - 2012-02-?? +1.0a4 - 2012-03-13 ------------------ - Remove type check for commands in favor of minimal duck type check [tarek] diff --git a/setup.cfg b/setup.cfg --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,10 @@ [metadata] name = Distutils2 -version = 1.0a3 +version = 1.0a4 summary = Python Packaging Library description-file = README.txt -home-page = http://bitbucket.org/tarek/distutils2/wiki/Home +home-page = http://wiki.python.org/moin/Distutils2 +download-url = http://pypi.python.org/pypi/Distutils2 author = The Fellowship of the Packaging author-email = the-fellowship-of-the-packaging at googlegroups.com # we set a custom license field in addition to the classifier below @@ -42,8 +43,20 @@ distutils2.tests = xxmodule.c scripts = pysetup +extra_files = + README.txt + LICENSE.txt + CHANGES.txt + CONTRIBUTORS.txt + DEVNOTES.txt + setup.py + Makefile + runtests.py + check.sh + tests.sh + tox.ini + scan_pypi_versions.py -# TODO build hashlib for Python < 2.4 # TODO add all test data files # FIXME cfg_to_args should support comments in multi-line fields -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Tue Mar 13 17:03:35 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 13 Mar 2012 17:03:35 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Added_tag_1=2E0a4_for_ch?= =?utf8?q?angeset_1e4d52d83e95?= Message-ID: http://hg.python.org/distutils2/rev/27910fcea9ed changeset: 1300:27910fcea9ed user: ?ric Araujo date: Tue Mar 13 16:55:50 2012 +0100 summary: Added tag 1.0a4 for changeset 1e4d52d83e95 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -5,3 +5,4 @@ 7c8e61aa51f4748286964bc1405bd4169c270f46 1.0a3 7c8e61aa51f4748286964bc1405bd4169c270f46 1.0a3 d930ae6caab58bec92683235aa88d06bbc07ae36 1.0a3 +1e4d52d83e95c14e3f0bd2179a81ac1023ef32e9 1.0a4 -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Tue Mar 13 17:03:35 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 13 Mar 2012 17:03:35 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Added_signature_for_chan?= =?utf8?q?geset_27910fcea9ed?= Message-ID: http://hg.python.org/distutils2/rev/efdfd98bd217 changeset: 1301:efdfd98bd217 user: ?ric Araujo date: Tue Mar 13 16:56:22 2012 +0100 summary: Added signature for changeset 27910fcea9ed files: .hgsigs | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgsigs b/.hgsigs new file mode 100644 --- /dev/null +++ b/.hgsigs @@ -0,0 +1,1 @@ +27910fcea9ed851af1f932caa58fdc0f811b748f 0 iEYEABECAAYFAk9fbhkACgkQ8s4Pc9+KtnaVdACfTNegvVs1BXtKgM+oAq/9gsuZtGwAnA04B7Zc/ICRkbpejyS4xzPTv8jw -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Tue Mar 13 17:03:35 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 13 Mar 2012 17:03:35 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Remove_out-of-date_docum?= =?utf8?q?entation=2E?= Message-ID: http://hg.python.org/distutils2/rev/21b8e29bcd5c changeset: 1298:21b8e29bcd5c user: ?ric Araujo date: Tue Mar 13 16:40:09 2012 +0100 summary: Remove out-of-date documentation. Tarek and I agreed that maintaining doc in two places was wasteful, so I?m going to point people to the packaging docs in Python 3.3. Most of them apply as is to distutils2, except for the module name and a few other things that I?ll fix later (like the logger name or the HTTP user agent string). I will put up a simple page with links on packages.python.org to replace the old doc. files: CHANGES.txt | 6 +- MANIFEST.in | 1 - docs/Makefile | 89 - docs/design/configfile.rst | 131 - docs/design/pep-0376.txt | 687 --- docs/design/wiki.rst | 620 --- docs/make.bat | 113 - docs/source/_static/depgraph_big.png | Bin docs/source/conf.py | 199 - docs/source/contributing.rst | 25 - docs/source/devresources.rst | 49 - docs/source/distutils/apiref.rst | 2010 ---------- docs/source/distutils/builtdist.rst | 452 -- docs/source/distutils/commandhooks.rst | 31 - docs/source/distutils/commandref.rst | 58 - docs/source/distutils/configfile.rst | 130 - docs/source/distutils/examples.rst | 332 - docs/source/distutils/extending.rst | 95 - docs/source/distutils/index.rst | 33 - docs/source/distutils/introduction.rst | 193 - docs/source/distutils/newcommands.rst | 144 - docs/source/distutils/packageindex.rst | 104 - docs/source/distutils/setupscript.rst | 681 --- docs/source/distutils/sourcedist.rst | 270 - docs/source/distutils/uploading.rst | 80 - docs/source/images/depgraph_output.png | Bin docs/source/index.rst | 89 - docs/source/install/index.rst | 988 ---- docs/source/library/distutils2.depgraph.rst | 122 - docs/source/library/distutils2.index.client.rst | 20 - docs/source/library/distutils2.index.dist.rst | 106 - docs/source/library/distutils2.index.rst | 31 - docs/source/library/distutils2.index.simple.rst | 141 - docs/source/library/distutils2.index.xmlrpc.rst | 124 - docs/source/library/distutils2.install.rst | 23 - docs/source/library/distutils2.metadata.rst | 93 - docs/source/library/distutils2.rst | 44 - docs/source/library/distutils2.tests.pypi_server.rst | 89 - docs/source/library/distutils2.version.rst | 69 - docs/source/library/pkgutil.rst | 330 - docs/source/setupcfg-spec.rst | 308 - docs/source/setupcfg.rst | 544 -- docs/source/tutorial.rst | 129 - setup.cfg | 3 - 44 files changed, 4 insertions(+), 9782 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt --- a/CHANGES.txt +++ b/CHANGES.txt @@ -111,8 +111,8 @@ guillermoo, ?ric] - Add 'pysetup generate-setup' to expose util.generate_setup_py [tarek] - #11092: Make sdist always include setup.cfg [?ric] -- #12246: Don?t try to install something when running from an uninstalled Python - built in its checkout [tschepang, ?ric] +- #12246: Don't try to install something when running from an uninstalled Python + built in its checkout [tshepang, ?ric] - Add packaging.util.split_multiline [julien m, erik] - #11595: Fix assorted bugs in packaging.util.cfg_to_args [erik, ?ric] - #12240: Allow multiple setup hooks [erik, ?ric] @@ -173,6 +173,8 @@ - #14264: Stop removing trailing zeroes in versions [tarek] - #14268: Fix small error in a test [tarek] - Drop support for Python 2.4 [tarek, ?ric] +- Out-of-date documentation removed, people should look at + http://docs.python.org/dev/packaging [?ric] 1.0a3 - 2010-10-08 diff --git a/MANIFEST.in b/MANIFEST.in --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,1 @@ -recursive-include docs *.bat *.rst *.py *.png Makefile *.txt recursive-include distutils2/_backport *.c *.h *.cfg diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 --- a/docs/Makefile +++ /dev/null @@ -1,89 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Distutils2.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Distutils2.qhc" - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ - "run these through (pdf)latex." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/design/configfile.rst b/docs/design/configfile.rst deleted file mode 100644 --- a/docs/design/configfile.rst +++ /dev/null @@ -1,132 +0,0 @@ -.. _setup-config: - -************************************ -Writing the Setup Configuration File -************************************ - -Often, it's not possible to write down everything needed to build a distribution -*a priori*: you may need to get some information from the user, or from the -user's system, in order to proceed. As long as that information is fairly -simple---a list of directories to search for C header files or libraries, for -example---then providing a configuration file, :file:`setup.cfg`, for users to -edit is a cheap and easy way to solicit it. Configuration files also let you -provide default values for any command option, which the installer can then -override either on the command line or by editing the config file. - -The setup configuration file is a useful middle-ground between the setup script ----which, ideally, would be opaque to installers [#]_---and the command line to -the setup script, which is outside of your control and entirely up to the -installer. In fact, :file:`setup.cfg` (and any other Distutils configuration -files present on the target system) are processed after the contents of the -setup script, but before the command line. This has several useful -consequences: - -.. If you have more advanced needs, such as determining which extensions to - build based on what capabilities are present on the target system, then you - need the Distutils auto-configuration facility. This started to appear in - Distutils 0.9 but, as of this writing, isn't mature or stable enough yet - for real-world use. - -* installers can override some of what you put in :file:`setup.py` by editing - :file:`setup.cfg` - -* you can provide non-standard defaults for options that are not easily set in - :file:`setup.py` - -* installers can override anything in :file:`setup.cfg` using the command-line - options to :file:`setup.py` - -The basic syntax of the configuration file is simple:: - - [command] - option=value - ... - -where *command* is one of the Distutils commands (e.g. :command:`build_py`, -:command:`install`), and *option* is one of the options that command supports. -Any number of options can be supplied for each command, and any number of -command sections can be included in the file. Blank lines are ignored, as are -comments, which run from a ``'#'`` character until the end of the line. Long -option values can be split across multiple lines simply by indenting the -continuation lines. - -You can find out the list of options supported by a particular command with the -universal :option:`--help` option, e.g. :: - - > python setup.py --help build_ext - [...] - Options for 'build_ext' command: - --build-lib (-b) directory for compiled extension modules - --build-temp (-t) directory for temporary files (build by-products) - --inplace (-i) ignore build-lib and put compiled extensions into the - source directory alongside your pure Python modules - --include-dirs (-I) list of directories to search for header files - --define (-D) C preprocessor macros to define - --undef (-U) C preprocessor macros to undefine - --swig-opts list of SWIG command-line options - [...] - -.. XXX do we want to support ``setup.py --help metadata``? - -Note that an option spelled :option:`--foo-bar` on the command line is spelled -:option:`foo_bar` in configuration files. - -For example, say you want your extensions to be built "in-place"---that is, you -have an extension :mod:`pkg.ext`, and you want the compiled extension file -(:file:`ext.so` on Unix, say) to be put in the same source directory as your -pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the -:option:`--inplace` option on the command line to ensure this:: - - python setup.py build_ext --inplace - -But this requires that you always specify the :command:`build_ext` command -explicitly, and remember to provide :option:`--inplace`. An easier way is to -"set and forget" this option, by encoding it in :file:`setup.cfg`, the -configuration file for this distribution:: - - [build_ext] - inplace=1 - -This will affect all builds of this module distribution, whether or not you -explicitly specify :command:`build_ext`. If you include :file:`setup.cfg` in -your source distribution, it will also affect end-user builds---which is -probably a bad idea for this option, since always building extensions in-place -would break installation of the module distribution. In certain peculiar cases, -though, modules are built right in their installation directory, so this is -conceivably a useful ability. (Distributing extensions that expect to be built -in their installation directory is almost always a bad idea, though.) - -Another example: certain commands take a lot of options that don't change from -run to run; for example, :command:`bdist_rpm` needs to know everything required -to generate a "spec" file for creating an RPM distribution. Some of this -information comes from the setup script, and some is automatically generated by -the Distutils (such as the list of files installed). But some of it has to be -supplied as options to :command:`bdist_rpm`, which would be very tedious to do -on the command line for every run. Hence, here is a snippet from the Distutils' -own :file:`setup.cfg`:: - - [bdist_rpm] - release = 1 - packager = Greg Ward - doc_files = CHANGES.txt - README.txt - USAGE.txt - doc/ - examples/ - -Note that the :option:`doc_files` option is simply a whitespace-separated string -split across multiple lines for readability. - - -.. seealso:: - - :ref:`inst-config-syntax` in "Installing Python Modules" - More information on the configuration files is available in the manual for - system administrators. - - -.. rubric:: Footnotes - -.. [#] This ideal probably won't be achieved until auto-configuration is fully - supported by the Distutils. - diff --git a/docs/design/pep-0376.txt b/docs/design/pep-0376.txt deleted file mode 100644 --- a/docs/design/pep-0376.txt +++ /dev/null @@ -1,698 +0,0 @@ -PEP: 376 -Title: Changing the .egg-info structure -Version: $Revision: 75414 $ -Last-Modified: $Date: 2009-10-14 14:39:17 -0400 (Wed, 14 Oct 2009) $ -Author: Tarek Ziad? -Status: Draft -Type: Standards Track -Content-Type: text/x-rst -Created: 22-Feb-2009 -Python-Version: 2.7, 3.2 -Post-History: - - -Abstract -======== - -This PEP proposes various enhancements for Distutils: - -- A new format for the .egg-info structure. -- Some APIs to read the metadata of a distribution. -- A replacement PEP 262. -- An uninstall feature. - -Definitions -=========== - -A **distribution** is a collection of files, which can be Python modules, -extensions, or data. A distribution is managed by a special module called -`setup.py` which contains a call to the `distutils.core.setup` function. -The arguments passed to that function describe the distribution, like -its `name`, its `version`, and so on. - -Distutils provides, among other things, **commands** that can be called -through the shell using the `setup.py` script. An `sdist` command is provided -for instance to create a source distribution archive. An `install` command -is also provided to perform an installation of the distribution in the Python -installation the script is invoked with:: - - $ python setup.py install - -See the Distutils [#distutils]_ documentation for more information. - -Once installed, the elements are located in various places in the system, like: - -- In Python's site-packages (Python modules, Python modules organized into - packages, Extensions, etc.) -- In Python's `include` directory. -- In Python's `bin` or `Script` directory. -- Etc. - -Rationale -========= - -There are two problems right now in the way distributions are installed in -Python: - -- There are too many ways to do it. -- There is no API to get the metadata of installed distributions. - -How distributions are installed -------------------------------- - -Right now, when a distribution is installed in Python, the elements it -contains are installed in various directories. - -The pure Python code, for instance, is installed in the `purelib` directory -which is located in the Python installation at ``lib/python2.6/site-packages`` -for example under Unix-like systems or Mac OS X, and in ``Lib\site-packages`` -under Windows. This is done with the Distutils `install` command, which calls -various subcommands. - -The `install_egg_info` subcommand is called during this process in order to -create an `.egg-info` file in the `purelib` directory. - -For example, for the `docutils` distribution, which contains one package an -extra module and executable scripts, three elements are installed in -`site-packages`: - -- `docutils`: The ``docutils`` package. -- `roman.py`: An extra module used by `docutils`. -- `docutils-0.5-py2.6.egg-info`: A file containing the distribution metadata - as described in PEP 314 [#pep314]_. This file corresponds to the file - called `PKG-INFO`, built by the `sdist` command. - -Some executable scripts, such as `rst2html.py`, are also be added in the -`bin` directory of the Python installation. - -Another project called `setuptools` [#setuptools]_ has two other formats -to install distributions, called `EggFormats` [#eggformats]_: - -- a self-contained `.egg` directory, that contains all the distribution files - and the distribution metadata in a file called `PKG-INFO` in a subdirectory - called `EGG-INFO`. `setuptools` creates other fils in that directory that can - be considered as complementary metadata. - -- a `.egg-info` directory installed in `site-packages`, that contains the same - files `EGG-INFO` has in the `.egg` format. - -The first format is automatically used when you install a distribution that -uses the ``setuptools.setup`` function in its setup.py file, instead of -the ``distutils.core.setup`` one. - -The `setuptools` project also provides an executable script called -`easy_install` [#easyinstall]_ that installs all distributions, including -distutils-based ones in self-contained `.egg` directories. - -If you want to have a standalone `.egg.info` directory distributions, e.g. -the second `setuptools` format, you have to force it when you work -with a setuptools-based distribution or with the `easy_install` script. -You can force it by using the `-?single-version-externally-managed` option -**or** the `--root` option. - -This option is used by : - -- the `pip` [#pip]_ installer -- the Fedora packagers [#fedora]_. -- the Debian packagers [#debian]_. - -Uninstall information ---------------------- - -Distutils doesn't provide an `uninstall` command. If you want to uninstall -a distribution, you have to be a power user and remove the various elements -that were installed, and then look over the `.pth` file to clean them if -necessary. - -And the process differs depending on the tools you have used to install the -distribution and if the distribution's `setup.py` uses Distutils or -Setuptools. - -Under some circumstances, you might not be able to know for sure that you -have removed everything, or that you didn't break another distribution by -removing a file that is shared among several distributions. - -But there's a common behavior: when you install a distribution, files are -copied in your system. And it's possible to keep track of these files for -later removal. - -What this PEP proposes ----------------------- - -To address those issues, this PEP proposes a few changes: - -- A new `.egg-info` structure using a directory, based on one format of - the `EggFormats` standard from `setuptools`. -- New APIs in `pkgutil` to be able to query the information of installed - distributions. -- A de-facto replacement for PEP 262 -- An uninstall function and an uninstall script in Distutils. - - -.egg-info becomes a directory -============================= - -As explained earlier, the `EggFormats` standard from `setuptools` proposes two -formats to install the metadata information of a distribution: - -- A self-contained directory that can be zipped or left unzipped and contains - the distribution files *and* an `.egg-info` directory containing the - metadata. - -- A distinct `.egg-info` directory located in the site-packages directory, - with the metadata inside. - -This PEP proposes to keep just one format and make it the standard way to -install the metadata of a distribution : a distinct `.egg-info` directory -located in the site-packages directory, containing the metadata. - -This `.egg-info` directory contains a `PKG-INFO` file built by the -`write_pkg_file` method of the `Distribution` class in Distutils. - -This change does not impact Python itself because the metadata files are not -used anywhere yet in the standard library besides Distutils. - -It does impact the `setuptools` and `pip` projects, but given the fact that -they already work with a directory that contains a `PKG-INFO` file, the change -will have no deep consequences. - -Let's take an example of the new format with the `docutils` distribution. -The elements installed in `site-packages` are:: - - - docutils/ - - roman.py - - docutils-0.5.egg-info/ - PKG-INFO - -The syntax of the egg-info directory name is as follows:: - - name + '-' + version + '.egg-info' - -The egg-info directory name is created using a new function called -``egginfo_dirname(name, version)`` added to ``pkgutil``. ``name`` is -converted to a standard distribution name by replacing any runs of -non-alphanumeric characters with a single '-'. ``version`` is converted -to a standard version string. Spaces become dots, and all other -non-alphanumeric characters (except dots) become dashes, with runs of -multiple dashes condensed to a single dash. Both attributes are then -converted into their filename-escaped form, i.e. any '-' characters are -replaced with '_' other than the one in 'egg-info' and the one -separating the name from the version number. - -Examples:: - - >>> egginfo_dirname('docutils', '0.5') - 'docutils-0.5.egg-info' - - >>> egginfo_dirname('python-ldap', '2.5') - 'python_ldap-2.5.egg-info' - - >>> egginfo_dirname('python-ldap', '2.5 a---5') - 'python_ldap-2.5.a_5.egg-info' - -Adding a RECORD file in the .egg-info directory -=============================================== - -A `RECORD` file is added inside the `.egg-info` directory at installation -time when installing a source distribution using the `install` command. -Notice that when installing a binary distribution created with `bdist` command -or a `bdist`-based command, the `RECORD` file will be installed as well since -these commands use the `install` command to create a binary distributions. - -The `RECORD` file holds the list of installed files. These correspond -to the files listed by the `record` option of the `install` command, and will -be generated by default. This allows the implementation of an uninstallation -feature, as explained later in this PEP. The `install` command also provides -an option to prevent the `RECORD` file from being written and this option -should be used when creating system packages. - -Third-party installation tools also should not overwrite or delete files -that are not in a RECORD file without prompting or warning. - -This RECORD file is inspired from PEP 262 FILES [#pep262]_. - -The RECORD format ------------------ - -The `RECORD` file is a CSV file, composed of records, one line per -installed file. The ``csv`` module is used to read the file, with -these options: - -- field delimiter : `,` -- quoting char : `"`. -- line terminator : ``os.linesep`` (so ``\r\n`` or ``\n``) - -Each record is composed of three elements. - -- the file's full **path** - - - if the installed file is located in the directory where the `.egg-info` - directory of the package is located, it's a '/'-separated relative - path, no matter what the target system is. This makes this information - cross-compatible and allows simple installations to be relocatable. - - - if the installed file is located under ``sys.prefix`` or - `sys.exec_prefix``, it's a it's a '/'-separated relative path prefixed - by the `$PREFIX` or the `$EXEC_PREFIX` string. The `install` command - decides which prefix to use depending on the files. For instance if - it's an executable script defined in the `scripts` option of the - setup script, `$EXEC_PREFIX` will be used. If `install` doesn't know - which prefix to use, `$PREFIX` is preferred. - -- the **MD5** hash of the file, encoded in hex. Notice that `pyc` and `pyo` - generated files don't have any hash because they are automatically produced - from `py` files. So checking the hash of the corresponding `py` file is - enough to decide if the file and its associated `pyc` or `pyo` files have - changed. - -- the file's size in bytes - -The ``csv`` module is used to generate this file, so the field separator is -",". Any "," characters found within a field is escaped automatically by ``csv``. - -When the file is read, the `U` option is used so the universal newline -support (see PEP 278 [#pep278]_) is activated, avoiding any trouble -reading a file produced on a platform that uses a different new line -terminator. - -Example -------- - -Back to our `docutils` example, we now have:: - - - docutils/ - - roman.py - - docutils-0.5.egg-info/ - PKG-INFO - RECORD - -And the RECORD file contains (extract):: - - docutils/__init__.py,b690274f621402dda63bf11ba5373bf2,9544 - docutils/core.py,9c4b84aff68aa55f2e9bf70481b94333,66188 - roman.py,a4b84aff68aa55f2e9bf70481b943D3,234 - $EXEC_PREFIX/bin/rst2html.py,a4b84aff68aa55f2e9bf70481b943D3,234 - docutils-0.5.egg-info/PKG-INFO,6fe57de576d749536082d8e205b77748,195 - docutils-0.5.egg-info/RECORD - -Notice that: - -- the `RECORD` file can't contain a hash of itself and is just mentioned here -- `docutils` and `docutils-0.5.egg-info` are located in `site-packages` so the file - paths are relative to it. - -Adding an INSTALLER file in the .egg-info directory -=================================================== - -The `install` command has a new option called `installer`. This option -is the name of the tool used to invoke the installation. It's an normalized -lower-case string matching `[a-z0-9_\-\.]`. - - $ python setup.py install --installer=pkg-system - -It defaults to `distutils` if not provided. - -When a distribution is installed, the INSTALLER file is generated in the -`.egg-info` directory with this value, to keep track of **who** installed the -distribution. The file is a single-line text file. - -Adding a REQUESTED file in the .egg-info directory -================================================== - -If a distribution is installed by direct user request (the usual -case), a file REQUESTED is added to the .egg-info directory of the -installed distribution. The REQUESTED file may be empty, or may -contain a marker comment line beginning with the "#" character. - -If an install tool installs a distribution automatically, as a -dependency of another distribution, the REQUESTED file should not be -created. - -The ``install`` command of distutils by default creates the REQUESTED -file. It accepts --requested and --no-requested options to explicitly -specify whether the file is created. - -If a package that was already installed on the system as a dependency -is later installed by name, the distutils ``install`` command will -create the REQUESTED file in the .egg-info directory of the existing -installation. - -Rationale ---------- - -Some install tools automatically detect unfulfilled dependencies and -install them. These tools may also want to be able to alert the user -if distributions are left on the system in an "orphan" state: -installed as a dependency of another distribution, which has since -been removed. - -In order to provide information about orphaned dependencies, knowing -the dependency graph for installed distributions does not suffice (a -package that is not required by any other package may be on the system -because the user needs it directly). It is also necessary to know, for -each installed package, one additional bit of information: whether it -was installed "by request" or solely as a dependency. - -Each (un)install tool could of course record that bit in its own -separate metadata cache, but this will break down if multiple tools -are used to work with installed packages on the same system. If -distutils takes care of this bit of metadata in a standard way, -multiple tools can cooperate and correctly handle orphaned -dependencies. - -(In contrast, it is not necessary for distutils to record or manage -the full dependency graph for installed packages, because the list of -installed packages and their dependency metadata, standardized in PEP -345, allow any tool to independently calculate the dependency graph.) - -An (un)installer tool which works with dependencies could use the -REQUESTED metadata for orphan detection as follows: an orphaned -distribution is any installed distribution that doesn't have a -REQUESTED file and is not required by any other installed -distribution. - -The availability of the REQUESTED metadata of course does not obligate -any tool to provide this orphan-detection feature, or to implement it -in a certain way; for instance, distutils has no opinion about whether -tools should automatically remove newly-orphaned dependencies at -uninstall time. - - -New APIs in pkgutil -=================== - -To use the `.egg-info` directory content, we need to add in the standard -library a set of APIs. The best place to put these APIs is `pkgutil`. - -Query functions ---------------- - -The new functions added in the ``pkgutil`` are : - -- ``get_distributions()`` -> iterator of ``Distribution`` instances. - - Provides an iterator that looks for ``.egg-info`` directories in - ``sys.path`` and returns ``Distribution`` instances for - each one of them. - -- ``get_distribution(name)`` -> ``Distribution`` or None. - - Scans all elements in ``sys.path`` and looks for all directories ending with - ``.egg-info``. Returns a ``Distribution`` corresponding to the - ``.egg-info`` directory that contains a PKG-INFO that matches `name` - for the `name` metadata. - - Notice that there should be at most one result. The first result found - is returned. If the directory is not found, returns None. - -- ``get_file_users(path)`` -> iterator of ``Distribution`` instances. - - Iterates over all distributions to find out which distributions uses ``path``. - ``path`` can be a local absolute path or a relative '/'-separated path. - -Distribution class ------------------- - -A new class called ``Distribution`` is created with the path of the -`.egg-info` directory provided to the constructor. It reads the metadata -contained in `PKG-INFO` when it is instantiated. - -``Distribution(path)`` -> instance - - Creates a ``Distribution`` instance for the given ``path``. - -``Distribution`` provides the following attributes: - -- ``name``: The name of the distribution. - -- ``metadata``: A ``Metadata`` instance loaded with the - distribution's PKG-INFO file. - -- ``requested``: A boolean that indicates whether the REQUESTED - metadata file is present (in other words, whether the package was - installed by user request). - -And following methods: - -- ``get_installed_files(local=False)`` -> iterator of (path, md5, size) - - Iterates over the `RECORD` entries and return a tuple ``(path, md5, size)`` - for each line. If ``local`` is ``True``, the path is transformed into a - local absolute path. Otherwise the raw value from `RECORD` is returned. - - A local absolute path is an absolute path in which occurrences of '/' - have been replaced by the system separator given by ``os.sep``. - -- ``uses(path)`` -> Boolean - - Returns ``True`` if ``path`` is listed in `RECORD`. ``path`` - can be a local absolute path or a relative '/'-separated path. - -- ``get_egginfo_file(path, binary=False)`` -> file object - - Returns a file located under the `.egg-info` directory. - - Returns a ``file`` instance for the file pointed by ``path``. - - ``path`` has to be a '/'-separated path relative to the `.egg-info` - directory or an absolute path. - - If ``path`` is an absolute path and doesn't start with the `.egg-info` - directory path, a ``DistutilsError`` is raised. - - If ``binary`` is ``True``, opens the file in read-only binary mode (`rb`), - otherwise opens it in read-only mode (`r`). - -- ``get_egginfo_files(local=False)`` -> iterator of paths - - Iterates over the `RECORD` entries and return paths for each line if the path - is pointing a file located in the `.egg-info` directory or one of its - subdirectory. - - If ``local`` is ``True``, each path is transformed into a - local absolute path. Otherwise the raw value from `RECORD` is returned. - - -Notice that the API is organized in five classes that work with directories -and Zip files (so it works with files included in Zip files, see PEP 273 for -more details [#pep273]_). These classes are described in the documentation -of the prototype implementation for interested readers [#prototype]_. - -Usage example -------------- - -Let's use some of the new APIs with our `docutils` example:: - - >>> from pkgutil import get_distribution, get_file_users - >>> dist = get_distribution('docutils') - >>> dist.name - 'docutils' - >>> dist.metadata.version - '0.5' - - >>> for path, hash, size in dist.get_installed_files():: - ... print '%s %s %d' % (path, hash, size) - ... - docutils/__init__.py b690274f621402dda63bf11ba5373bf2 9544 - docutils/core.py 9c4b84aff68aa55f2e9bf70481b94333 66188 - roman.py a4b84aff68aa55f2e9bf70481b943D3 234 - /usr/local/bin/rst2html.py a4b84aff68aa55f2e9bf70481b943D3 234 - docutils-0.5.egg-info/PKG-INFO 6fe57de576d749536082d8e205b77748 195 - docutils-0.5.egg-info/RECORD None None - - >>> dist.uses('docutils/core.py') - True - - >>> dist.uses('/usr/local/bin/rst2html.py') - True - - >>> dist.get_egginfo_file('PKG-INFO') - - - >>> dist.requested - True - -PEP 262 replacement -=================== - -In the past an attempt was made to create a installation database (see PEP 262 -[#pep262]_). - -Extract from PEP 262 Requirements: - - " We need a way to figure out what distributions, and what versions of - those distributions, are installed on a system..." - - -Since the APIs proposed in the current PEP provide everything needed to meet -this requirement, PEP 376 replaces PEP 262 and becomes the official -`installation database` standard. - -The new version of PEP 345 (XXX work in progress) extends the Metadata -standard and fullfills the requirements described in PEP 262, like the -`REQUIRES` section. - -Adding an Uninstall function -============================ - -Distutils already provides a very basic way to install a distribution, which -is running the `install` command over the `setup.py` script of the -distribution. - -Distutils will provide a very basic ``uninstall`` function, that is added -in ``distutils.util`` and takes the name of the distribution to uninstall -as its argument. ``uninstall`` uses the APIs described earlier and remove all -unique files, as long as their hash didn't change. Then it removes empty -directories left behind. - -``uninstall`` returns a list of uninstalled files:: - - >>> from distutils.util import uninstall - >>> uninstall('docutils') - ['/opt/local/lib/python2.6/site-packages/docutils/core.py', - ... - '/opt/local/lib/python2.6/site-packages/docutils/__init__.py'] - -If the distribution is not found, a ``DistutilsUninstallError`` is be raised. - -Filtering ---------- - -To make it a reference API for third-party projects that wish to control -how `uninstall` works, a second callable argument can be used. It's -called for each file that is removed. If the callable returns `True`, the -file is removed. If it returns False, it's left alone. - -Examples:: - - >>> def _remove_and_log(path): - ... logging.info('Removing %s' % path) - ... return True - ... - >>> uninstall('docutils', _remove_and_log) - - >>> def _dry_run(path): - ... logging.info('Removing %s (dry run)' % path) - ... return False - ... - >>> uninstall('docutils', _dry_run) - -Of course, a third-party tool can use ``pkgutil`` APIs to implement -its own uninstall feature. - -Installer marker ----------------- - -As explained earlier in this PEP, the `install` command adds an `INSTALLER` -file in the `.egg-info` directory with the name of the installer. - -To avoid removing distributions that where installed by another packaging system, -the ``uninstall`` function takes an extra argument ``installer`` which default -to ``distutils``. - -When called, ``uninstall`` controls that the ``INSTALLER`` file matches -this argument. If not, it raises a ``DistutilsUninstallError``:: - - >>> uninstall('docutils') - Traceback (most recent call last): - ... - DistutilsUninstallError: docutils was installed by 'cool-pkg-manager' - - >>> uninstall('docutils', installer='cool-pkg-manager') - -This allows a third-party application to use the ``uninstall`` function -and strongly suggest that no other program remove a distribution it has -previously installed. This is useful when a third-party program that relies -on Distutils APIs does extra steps on the system at installation time, -it has to undo at uninstallation time. - -Adding an Uninstall script -========================== - -An `uninstall` script is added in Distutils. and is used like this:: - - $ python -m distutils.uninstall packagename - -Notice that script doesn't control if the removal of a distribution breaks -another distribution. Although it makes sure that all the files it removes -are not used by any other distribution, by using the uninstall function. - -Also note that this uninstall script pays no attention to the -REQUESTED metadata; that is provided only for use by external tools to -provide more advanced dependency management. - -Backward compatibility and roadmap -================================== - -These changes don't introduce any compatibility problems with the previous -version of Distutils, and will also work with existing third-party tools. - -The plan is to include the functionality outlined in this PEP in distutils for -Python 2.7 and Python 3.2. A backport of the new distutils for 2.5, 2.6, 3.0 -and 3.1 is provided so people can benefit from these new features. - -Distributions installed using existing, pre-standardization formats do not have -the necessary metadata available for the new API, and thus will be -ignored. Third-party tools may of course continue to support previous -formats in addition to the new format, in order to ease the transition. - - -References -========== - -.. [#distutils] - http://docs.python.org/distutils - -.. [#pep262] - http://www.python.org/dev/peps/pep-0262 - -.. [#pep314] - http://www.python.org/dev/peps/pep-0314 - -.. [#setuptools] - http://peak.telecommunity.com/DevCenter/setuptools - -.. [#easyinstall] - http://peak.telecommunity.com/DevCenter/EasyInstall - -.. [#pip] - http://pypi.python.org/pypi/pip - -.. [#eggformats] - http://peak.telecommunity.com/DevCenter/EggFormats - -.. [#pep273] - http://www.python.org/dev/peps/pep-0273 - -.. [#pep278] - http://www.python.org/dev/peps/pep-0278 - -.. [#fedora] - http://fedoraproject.org/wiki/Packaging/Python/Eggs#Providing_Eggs_using_Setuptools - -.. [#debian] - http://wiki.debian.org/DebianPython/NewPolicy - -.. [#prototype] - http://bitbucket.org/tarek/pep376/ - -Acknowledgements -================ - -Jim Fulton, Ian Bicking, Phillip Eby, and many people at Pycon and Distutils-SIG. - -Copyright -========= - -This document has been placed in the public domain. - - - -.. - Local Variables: - mode: indented-text - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 70 - coding: utf-8 - End: diff --git a/docs/design/wiki.rst b/docs/design/wiki.rst deleted file mode 100644 --- a/docs/design/wiki.rst +++ /dev/null @@ -1,637 +0,0 @@ -====================== -PyCon packaging sprint -====================== - -.. contents:: - -We sprinted on Distutils2 at the US Pycon 2010 sessions. This is one -of the results of that work. - -Distutils is used by both developers and packagers. - -:developers: People who write code in python. The code may be - distributed as an sdist or a variety of binary versions. The - developer presently uses setup.py to tell distutils how to build - the sdist and binary packages. -:packagers: People who package sdists into binary packages for a Linux - distribution. (Is there an equivalent role for people who make - Windows binary packages? Or do developers generally do that for - their own packages?) - ----------------------- -Problems for packagers ----------------------- - -We identified specific problems packagers face when creating deb/rpm: - -The problem this document is intended to solve: **want to lay out files across the filesystem in a FHS-compliant way** - -Problems that are fixed simply by not using setuptools: - -- get rid of ez_setup.py - -- breakages using ez_setup => Some setup.py scripts import ez_setup. - ez_setup requires a specific version of setuptools but doesn't - actually need it -- lesser versions work fine. - -Problems that are out of scope, at least for now: - -- Requires that are for a specific version (or range) because of bugs - (not API change/features) but the distro packages have backported - the fixes needed to an earlier version: - -- differences between distribution names of packages e.g. "what are - the packages of NumPy called?" - -- Egg version (specified in a Require section in setup.py) doesn't - match the distro package version - https://www.redhat.com/archives/fedora-python-devel-list/2008-June/msg00002.html - -We want to solve these issues for Linux distribution packages without -negatively impacting Windows, OS X, or pure-python -(i.e. easy_install/pip/virtualenv) installs. - -Example problem with current distutils -====================================== - -In -http://docs.python.org/distutils/setupscript.html#installing-additional-files -there is this example of supplying an initscript within a setup.py:: - - setup(..., - data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']), - ('config', ['cfg/data.cfg']), - ('/etc/init.d', ['init-script'])] - ) - -This suffers from several problems: - -1. The file hardcodes "/etc/init.d" as the directory for installation - of the initscript. However, this varies between different Linux - distributions. The above example assumes SysV init, but isn't - correct for systems using Upstart (the initscripts are likely to - need to be different for this case). Even within systems using - SysV init, the content of the script can vary between different - distributions - -2. The FHS mandates that configuration files go below /etc, but on a - Windows box that's meaningless. - -3. The file is a python script: if we want to extract data from it, we - have to either run it, or somehow parse it; we would need to - sandbox. We would prefer a declarative minilanguage for specifying - this data. - -Similarly: documentation files, .h files (e.g. NumPy) - -We want a system that: - -1. is easy for developers, does not require an "install" or "build" - phase during the edit/test development loop in a working copy - -2. supports both FHS-compliant scattering across the filesystem - hierarchy, and Windows, and virtualenv-style trees. - ------------------------ -Problems for Developers ------------------------ - -Package/file lists in multiple places -===================================== - -* MANIFEST -* MANIFEST.in -* setup.py::data_files -* setup.py::package_data -* setup.py::packages -* setup.py::scripts - -Replace all of these with settings in ``setup.cfg`` to specify runtime -files (python code, resource files) and files that belong in the sdist -but are not wanted for runtime. - -No idea where Linux distros want files -====================================== - -Sometimes programmers want to do the right thing for people wanting to -package their programs in Linux distributions, but they don't know -where they belong. Making matters worse, the files can go in -different places on different Linux distributions or on Windows and -MacOS. Placing the files in the wrong place can lead to errors at -runtime, for instance, if the file needs to be writable by the module -but it's placed on a read-only filesystem. - -This PEP attempts to deal with this by categorizing files so -developers can properly mark what properties their files need and -using an API to access the files, abstracting the different file -locations on different platforms. - -Hard to extend the build commands -================================= - -* distutils documentation is very poor - -* distutils build commands are classes with special method names -- - why not simple functions? - -* how do you extend the data allowed to be set in entries setup()? - -* build commands sometimes need to act on the same arguments. No way - to pass these between them right now. - - ------------------------------------ -Proposed solution for placing files ------------------------------------ - -This solution attempts to make several pieces of building and -installing better. It merges the many file lists into a single file, -simplifies (or eliminates the need for) setup.py, and allows packagers -to place resource files in locations appropriate to their -distribution. - -This solution comes in three pieces: - -1. A ``resources`` section in ``setup.cfg`` that maps resource files - to their categories (and optionally subdirectory prefixes within - those categories) - -2. A ``sysconfig.cfg`` file at the system Python level that maps - categories to a position on the filesystem - -3. A simple ``pkgutil.open()`` API to access resources from code - -Rationale -========= - -1. The evidence (from ``__file__`` usage) is strong that package devs - want to think in terms of paths within their local dev tree. They - don't want to worry about categorizing or finding their static - files elsewhere. - -2. Package devs are more likely to use an API that makes them think - less and type less. - -3. Package devs are more likely to accept patches from packagers if - that patch only touches a single .cfg file, rather than touching - every single ``pkgutil.open()`` call throughout their code. - -Therefore, the ``pkgutil.open()`` call should accept a simple path -relative to the package/distribution root. The ``resources`` section -in ``setup.cfg`` uses globs to categorize those files: -forward-thinking package devs can write this section, or packagers can -do it for them and submit patches. - - -"resources" section in setup.cfg -================================ - -The setup.py file has many sections that need to list files. We plan -to remove those lists to ``setup.cfg``. The ``resources`` section of -``setup.cfg`` replaces the current ``package_data``, ``data_files``, -and ``extra_files`` options in ``setup.py``. - -There are three pieces of information that are needed for resource -files: - -1. Position in the source tree - (e.g. 'mailman/database/schemas/schema.cfg', 'mywidget/jquery.js') - -* Position when installed - (e.g. '/etc/mailman/database/schemas/schema.cfg', - '/usr/share/mywidget-1.1/javascript/jquery.js'). For simple - virtualenv-style installations, this may well be the same as (1). - -* Key used when referencing the resource from code. Ideally, this - could be the same as (1), but because of difficulties in finding - "distribution root" at runtime from a ``pkgutil.open()`` call, it - will instead have to be a combination of "module name" and "path - relative to module", similar to what ``pkg_resources`` does. - -The information that the developer is concerned with: -* Position in the source tree -* Key used in referencing it - -The information the downstream packager (RPM/deb/sysadmin) cares about are: -* Position when installed -* Key used in referencing it - -Example -------- - -We have a source tree with the following files:: - - mailman-1.0/ - README - some.tpl - some-new-semantic.sns - mailman/ - database/ - mailman.db - schemas/ - blah.schema - etc/ - my.cnf - foo/ - some/ - path/ - bar/ - my.cfg - other.cfg - developer-docs/ - index.txt - api/ - toc.txt - -Here's where we want the files to end up in a typical Linux distribution: - -== ==================================== =================================================================================================== -## Relative path in source tree Final full installed path -== ==================================== =================================================================================================== -1 mailman/database/schemas/blah.schema /var/mailman/schemas/blah.schema -2 some.tpl /var/mailman/templates/some.tpl -3 path/to/some.tpl /var/mailman/templates/path/to/some.tpl ! -4 mailman/database/mailman.db /var/mailman/database/mailman.db ! -5 developer-docs/index.txt /usr/share/doc/mailman/developer-docs/index.txt -6 developer-docs/api/toc.txt /usr/share/doc/mailman/developer-docs/api/toc.txt -7 README /usr/share/doc/mailman/README -8 mailman/etc/my.cnf /etc/mailman/my.cnf -9 mailman/foo/some/path/bar/my.cfg /etc/mailman/baz/some/path/bar/my.cfg AND - /etc/mailman/hmm/some/path/bar/my.cfg + - emit a warning -10 mailman/foo/some/path/other.cfg /etc/mailman/some/path/other.cfg ! -11 some-new-semantic.sns /var/funky/mailman/some-new-semantic.sns -== ==================================== =================================================================================================== - -The numbers in the above placements are referenced below. - -setup.cfg -~~~~~~~~~ - -The setup.cfg file allows the developer and/or packager to mark what -categories the files belong to. These are drawn from the types of -files that the FHS and GNU coding standards define:: - - [resources] - # path glob category placement from above table - - mailman/database/schemas/* = {appdata}/schemas # 1 - **/*.tpl = {appdata}/templates # 2, 3 # does NOT flatten folder structure in destination - developer-docs/**/*.txt = {doc} # 5, 6 - README = {doc} # 7 - mailman/etc/* = {config} # 8 - mailman/foo/**/bar/*.cfg = {config}/baz # 9 - mailman/foo/**/*.cfg = {config}/hmm # 9, 10 - some-new-semantic.sns = {funky-crazy-category} # 11 - -The glob definitions are relative paths that match files from the top -of the source tree (the location of ``setup.cfg``). Forward slashes -(only) are used as path separator. - -:"*": is a glob that matches any characters within a file or directory -name -:"**": is a recursive glob that matches any (or no) characters within a file -or directory name as well as a forward slash (thus an arbitrarily deep -number of directories) - -The "category" value both categorizes the files and allows for placing -them in a more fine-grained subdirectory within a category. This value -must begin with a {category}; raw absolute or relative paths are not -allowed. - -The full Python 3 string interpolation language is not supported, only -simple {category} substitutions. The {category} is looked up in a -system-level Python ``sysconfig.cfg`` file, where operating system -vendors and system administrators can define where in the filesystem -various types of files are placed. The category paths will generally -include a {distribution.name} variable, to isolate one package's files -of a given type from other packages. - -As can be seen from the examples above, explicitly-matched directory -prefixes are stripped from the relative path before it is appended to -the category location. Glob matches are never stripped (to avoid -flattening hierarchies and overwriting files). In the -``mailman/foo/\*\*/\*.cfg`` example, ``mailman/foo`` is removed, but -not any directories matched by the recursive glob: see entries 9 and -10 in the example table. - -sysconfig.cfg -~~~~~~~~~~~~~ - -This is a system-wide Python configuration file (TODO: can be -overridden by e.g. virtualenv) that defines where on the filesystem -resources will actually be installed. A sample ``sysconfig.cfg`` can -be found in the ``distutils2`` repository at -``src/distutils2/_backport/sysconfig.cfg`` [3]. - -Links - -.. [1] Filesystem Hierarchy Standard http://www.pathname.com/fhs/ -.. [2] Rationale from the FHS which makes the distinctions between parts of the filesystem: http://www.pathname.com/fhs/pub/fhs-2.3.html#THEFILESYSTEM -.. [3] sample sysconfig.cfg: http://bitbucket.org/tarek/distutils2/src/tip/src/distutils2/_backport/sysconfig.cfg - -What happens? -~~~~~~~~~~~~~ - -As an example, ``mailman/database/schemas/blah.schema``: - -1. The file ``mailman/database/schemas/blah.schema`` in the source - tree matches ``mailman/database/schemas/*`` within the - ``resources`` stanza of the setup.cfg, which has right-hand side - ``{appdata}/schemas`` - -2. The ``*`` in the left-hand-side matches ``blah.schema``, and the - initial ``mailman/database/schemas/`` is stripped, so the - installation path for the file is mapped to - ``{appdata}/schemas/blah.schema`` - -3. The label ``appdata`` is listed in the ``sysconfig.cfg`` section - for the ``posix_prefix`` installation scheme as installed to - ``/usr/share/{distribution.name}``. This expands out to: - ``/usr/share/mailman`` - -4. The result is that the source file - ``mailman/database/schemas/blah.schema`` is installed to - ``/var/mailman/schemas/blah.schema``, and this mapping is recorded - in a RESOURCES file in the installation metadata for the - distribution. - -5. The source code can open the file at runtime via the API call - ``pkgutil.open('mailman', 'database/schemas/blah.schema')`` (where - the first argument is an importable Python package name, and the - second is a path relative to the location of that package), and - pkgutil will (using the RESOURCES mapping) open it from - ``/var/mailman/schemas/blah.schema``. - -6. If the package is not installed, and thus has no RESOURCES mapping, - ``pkgutil.open('mailman', - 'database/schemas/blah.schema')`` - -1. The file `mailman/database/schemas/blah.schema` in the source tree matches `mailman/database/schemas/*` within the data clause of the setup.cfg, so it is treated as having the label `{data}`. -2. The clause specified a prefix path, so the installation path for the file is mapped to "schemas/blah.schema" -3. The label "data" is listed in the [resource_variables] stanza as being installed to "/var/mailman" -4. The result is that the source file "mailman/database/schemas/blah.schema" is installed within the rpm/deb to "/var/mailman/schemas/blah.schema" -5. The source code can still open the file via an API using pkgutil.open('mailman', 'database/schemas/blah.schema') and have the underlying system open it from "/var/mailman/schemas/blah.schema". - - -Advice to packagers for fixing file locations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There are two places where you might need to change things in order to -customize the locations that files are installed into. The setup.cfg file can -be patched if the files are miscategorized. For instance someone marks a help -file that is used by the app at runtime as {doc} when it should be marked as -{help}. These types of patches should be submitted to the upstream project. -The resource_variables file can be changed to define different locations for -all apps on a system. This should usually be done once in a systemwide file -for the distribution. Changing this again may require the system packager to -rebuild all their Python modules to change the file location. There is API in -pkgutil to allow adding categories to the resource_variables file from -a script that should be used instead of trying to edit the file with raw text -processing. - -Open issues -=========== - -* setup.cfg is in the distribution, not in the module. Thus, in the unbuilt-egg - case, how can we find the distro when all we have is a module name? It would - be nice to not need an equivalent of ``setup.py develop``. Can we just walk up - the folder hierarchy from the module until we find a setup.cfg? A setup.cfg is - necessary if you use distutils2, is it not? - - -> information found in setup.cfg will be put in the *FILES* file upon - installation in the egg-info directory. - IOW in the unbuit-egg case, we would need to create that dir, then use - pkgutil APIs. - -* If sysconfig.cfg lands in Python 2.7, what happens when we run distutils2 in - 2.4? - - -> A backport of sysconfig.cfg is provided within the distutils2 distribution. - -* Our new glob-based [resources] section is much more compact (and consistent - with other systems, like bash) than the explicit MANIFEST.in directives, but - they don't offer some of the old features. Is it okay to lose exclude, - global-exclude, and recursive-exclude? What do graft and prune do, and do we - cover their behavior? I think we could probably use a [resource:exclude] - section with additional exclude globs in it. - - -> let's list the use cases we don't cover, and see - -API -=== - -pkgutil.open -------------- - -Returns a file object for the resource. - -:: - - pkgutil.open('STRING_NAME_FOR_PACKAGE', 'filename/with/path/relative/to/the/source/package/directory') - Example: - pkgutil.open('mailman', 'database/schemas/blah.schema') - - -* First argument is the string name for a python package. -* Second argument is the directory path relative to the python package's directory. -* At install (or build) time we create a metadata file that maps from the source tree files to the files in their installed locations on the filesystem. -* pkgutil.open() consults the metadata file to decide where to find the resource. If the metadata file is not found (as in a package before the egg is built), open() falls back to traversing the given relative path starting from the root of the calling package (using __name__). -* pkgutil.open() calls from nested packages aren't a problem because, after all, we pass the desired 'module_name' to start from as the first arg. - -* ? Do we still need this? Default behavior: alongside the package files (if the real-installed-locations metadata file does not exist). Or if the package is installed without any resource_variables specified. ?? - -pkgutil.filename ------------------ - -Returns a resource's filename with the full path. - -:: - - pkgutil.filename('STRING_NAME_FOR_PACKAGE', 'filename/with/path/relative/to/the/source/package/directory') - Example: - pkgutil.filename('mailman', 'database/schemas/blah.schema') - '/usr/share/mailman/schemas/blah.schema' - -pkgutil.add_category ---------------------- - -Adds a new category to the resource variables filename. - -:: - - pkgutil.add_category('CATEGORY', 'LOCATION') - Example: - pkgutil.add_category('lockdir', '{statedir}/lock') - -Using the API allows the parser to protect from adding duplicate categories. - ----- -Todo ----- - -These need to be worked in or discarded somehow - - * Differences between applications and packages - - Applications sometimes want a private library (for instance to do their commandline parsing) - -Ideally, for every resource file, the developer (or the defaults) have classified with a "label" *TODO*: we don't have a default classifier right now: for instance:: - - **/*.txt = doc - **/*.png = data - **/*.jpg = data - **/*.gif = data - **/*.cfg = config - - -Similar to i18n: marking of strings for translatability: gives you an ID, and a default value -Analagous to gettext: parse the source, figure out the resources - -[X] Per-distro (per site ?): label placement file, mapping labels to system locations *I think this is done* - -[X] What strings are valid as labels? only strings that are valid Python 2 identifiers: ([_A-Za-z][_A-Za-z0-9]*) TODO: doublecheck this! *Obsolete* We have gotten rid of the labels - -[X] So now, when it comes to building a deb/rpm, we have another file: "label placement" which maps from labels to rules about placement on the filesystem, written once by each linux distribution: *I think this is done* - - - -How Debian does a .install file -=============================== - -In `packagename.install`:: - - etc/* etc - usr/* usr - Products/statusmessages/* usr/share/zope/Products/statusmessages3 - -Each line has 2 parts: -* A glob of the source path within the deb -* Where it should land within the fakeroot (which corresponds to the final installed path) - -This gives the packager the opportunity to both move and rename things, and it's fairly concise. - - -Building different packages from one source -=========================================== - -?? Do we want to do this?? - -Use case --------- - -Split the docs into a separate sdist from the code so that people can download them separately. -(Matthias) - -Another use case ----------------- - -Need to split submodule into its own binary package (essentially converting top-level to a namespace package). - - - -Alternate ways of specifying labels ------------------------------------ -Noufal's:: - - [mailman] - data = *.txt, README - data.persistent = sqlite.db - ----------------------- - -Tarek's:: - - [files] - - data = - mailman/database/schemas/* - *.txt - README - - data.persistent = sqlite.db - ----------------------- - -Toshio's:: - - [resources] - *.jpg = data - -Alternative Label Idea -====================== - -labels for different resource types: images, manpages, script, config files etc, javascript, schema, sql, data files - -(those labels impose some other issues - what would one do to differences in statically servable on a webserver versus gtkbuilder can find it) - -pkg_resources already provides software with an API:: - - pkg_resource.open(label='javascript', name='jquery.js') - -Then we have the ability for Linux distros to place the different labels in FHS-compliant (or whatever) locations on the filesystem, mapping each label to a fs path:: - - pkg_resource.open(label='config', name=') - - pkg_resource.resource_stream(pkgname='mailman', label='config', victim='schema.cfg') - pkg_resource.resource_stream('mailman', 'mailman.config', 'schema.cfg') - pkg_resource.resource_stream('mailman', 'mailman.config', 'schema.cfg', label='config') - -analogy with logging: - -- with logging: developer sets up streams of data; sysadmin decides what to do with each log stream -- with packaging: developer sets up streams of data; packaging system decides where to put each one - -developer: - -(1) everything's within my local working copy; look within it; want to be able to quickly hack on stuff without having to "install" somewhere, for fast edit/test loop -(2) "setup.py sdist" has given us a zipfile, put it on pypi, someone uses buildout on it -(3) as (2) but a distribution has moved things to FHS-compliant location - - - pkgutil.open(pkgname='mailman.database.schemas', filename='schema.cfg') # <-- Does this work with our examples below? - - pkgutil.open(pkgname='mailman', label='data', filename='schemas/schema.cfg') - -(It won't be easy to get package devs to use this API; __file__ feels less magic than some strange call from pkgutil. The simpler the API call and the more "builtin" it looks, the better.) - -*TODO* Can we make sane defaults? For instance, can pkgname default to the pkgname or modulename that the call is being made from? - -*TODO* can we match things against a range of packages/paths - -(1) ./mailman/config/schema.cfg -(2) . -(3) /etc/mailman/database/schemas/schema.cfg - -mapping from labels to dirs:: - - distro_dict = { - 'config':'/etc', - 'mandir':'/usr/share/mandir', - } - -Another old syntax proposal -=========================== -:: - - [resources] - - # data are composed of two elements - # 1. the path relative to the package - # 2. an optional prefix path that will replace the explicit (non-glob) initial path from (1) - - data = - mailman/database/schemas/* schemas/ - **/*.tpl templates/ - - data.persistent = - mailman/database/mailman.db database/ - - doc = - developer-docs/**/*.txt - README - - config = - mailman/etc/* . # all files in mailman/etc/* copied to - mailman/foo/**/*.cfg foo # all .cfg files below mailman/foo/SOME/PATH/TO/FILE/ will get copied to foo/SOME/PATH/TO/FILE/ - mailman/foo/**/*.cfg - mailman/foo/**/bar/*.cfg baz diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 --- a/docs/make.bat +++ /dev/null @@ -1,113 +0,0 @@ - at ECHO OFF - -REM Command file for Sphinx documentation - -set SPHINXBUILD=sphinx-build -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Distutils2.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Distutils2.ghc - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/docs/source/_static/depgraph_big.png b/docs/source/_static/depgraph_big.png deleted file mode 100644 Binary file docs/source/_static/depgraph_big.png has changed diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 --- a/docs/source/conf.py +++ /dev/null @@ -1,199 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Distutils2 documentation build configuration file, created by -# sphinx-quickstart on Sun Feb 28 15:23:06 2010. -# -# This file is execfile()d with the current directory set to its containing -# dir. It requires Sphinx 1.0. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import os -import sys -import sphinx - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.append(os.path.abspath('.')) -sys.path.append(os.path.abspath(os.path.join(__file__, '..', '..', '..'))) - -# -- General configuration ----------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Distutils2' -copyright = u'2010, Tarek Ziad? and contributors' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '1.0a3' -# The full version, including alpha/beta/rc tags. -release = '1.0a3+' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of documents that shouldn't be included in the build. -#unused_docs = [] - -# List of directories, relative to source directory, that shouldn't be searched -# for source files. -exclude_trees = [] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -modindex_common_prefix = ['distutils2.', 'distutils2.command.'] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -if sphinx.__version__[:3] >= '1.0': - html_theme_options = {'collapsiblesidebar': True} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -html_title = 'Distutils2' - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_use_modindex = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Distutils2doc' - - -# -- Options for LaTeX output -------------------------------------------------- - -# The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'Distutils2.tex', u'Distutils2 Documentation', - u'Tarek Ziad? and contributors', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# Additional stuff for the LaTeX preamble. -#latex_preamble = '' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_use_modindex = True diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst deleted file mode 100644 --- a/docs/source/contributing.rst +++ /dev/null @@ -1,27 +0,0 @@ -========================== -Contributing to Distutils2 -========================== - ----------------- -Reporting Issues ----------------- - -When using, testing or developping distutils2, you may encounter issues. Please report to the following sections to know how these issues should be reported. - -Please keep in mind that this guide is intended to ease the triage and fixing processes by giving the maximum information to the developers. It should not be viewed as mandatory, only advisory ;). - - -- Go to http://bugs.python.org/ (you'll need a Python Bugs account), then "Issues" > "Create ticket". -- **Title**: write in a short summary of the issue. You may prefix the issue title with ?component:?, where component can be something like installer, sdist, setup.cfg, etc., or add it at the end of your title if the normal flow of the sentence allows it. This will ease up later searches. -- **Components**: choose "Distutils2" -- **Version**: choose "3rd party" -- **Body**: explain how to reproduce the bug: What you want to do, what code you write, what happens, what should happen, how to fix it (if you have an idea). - * You should always test with the tip of the main repository, not releases. - * Mention the versions of Python you tested with. d2 supports 2.4 to 2.7. - * If relevant, mention the version of your operating system (for example with issues related to C extensions). - * When referencing commits, be careful to use the universal changeset identifiers (12 characters, for instance c3cf81fc64db), not the local sequential numbers (for example 925) that are not shared among clones. - * Try to be as concise as possible, but not too much. - * If useful, paste tracebacks. - * If useful, attach setup.cfg or other files (binary files like archives are not very convenient, better to stick to text). - -Issues related to PyPI are reported via email to the **catalog-sig at python.org** mailing list, not within bugs.python.org. diff --git a/docs/source/devresources.rst b/docs/source/devresources.rst deleted file mode 100644 --- a/docs/source/devresources.rst +++ /dev/null @@ -1,49 +0,0 @@ -=================== -Developer Resources -=================== - - -Source code -~~~~~~~~~~~ - -* Main repo: http://hg.python.org/distutils2 -* For contributors at: http://bitbucket.org/tarek/distutils2 - -Dependencies -~~~~~~~~~~~~ - -* unittest2 -* If your operating system splits core python and a python-dev (or -devel) - packages, install the dev package too: It contains header files needed by - tests. - -Issue Tracker -~~~~~~~~~~~~~ - -Using the `distutils2` component at the `python.org bug tracker `_, - -Mailing List -~~~~~~~~~~~~ - -http://groups.google.com/group/the-fellowship-of-the-packaging - -more general discussion at distutils-sig at python.org - -IRC Channel -~~~~~~~~~~~ - -#distutils on irc.freenode.net - -Documentation -~~~~~~~~~~~~~ - -This documentation is present in the docs/source directory of the above source -code. - -Additional useful information available at: - -* `Hitchhikers guide to packaging `_ - - - - diff --git a/docs/source/distutils/apiref.rst b/docs/source/distutils/apiref.rst deleted file mode 100644 --- a/docs/source/distutils/apiref.rst +++ /dev/null @@ -1,2010 +0,0 @@ -.. _api-reference: - -************* -API Reference -************* - - -:mod:`distutils2.core` --- Core Distutils functionality -======================================================= - -.. module:: distutils2.core - :synopsis: The core Distutils functionality - - -The :mod:`distutils2.core` module is the only module that needs to be installed -to use the Distutils. It provides the :func:`setup` (which is called from the -setup script). Indirectly provides the :class:`distutils2.dist.Distribution` and -:class:`distutils2.cmd.Command` class. - - -.. function:: setup(arguments) - - The basic do-everything function that does most everything you could ever ask - for from a Distutils method. - - The setup function takes a large number of arguments. These are laid out in - the following table. - - +--------------------+--------------------------------+-------------------------------------------------------------+ - | argument name | value | type | - +====================+================================+=============================================================+ - | *name* | The name of the package | a string | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *version* | The version number of the | See :mod:`distutils2.version` | - | | package | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *summary* | A single line describing the | a string | - | | package | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *description* | Longer description of the | a string | - | | package | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *author* | The name of the package author | a string | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *author_email* | The email address of the | a string | - | | package author | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *maintainer* | The name of the current | a string | - | | maintainer, if different from | | - | | the author | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *maintainer_email* | The email address of the | | - | | current maintainer, if | | - | | different from the author | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *home_page* | A URL for the package | a URL | - | | (homepage) | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *download_url* | A URL to download the package | a URL | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *packages* | A list of Python packages that | a list of strings | - | | distutils will manipulate | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *py_modules* | A list of Python modules that | a list of strings | - | | distutils will manipulate | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *scripts* | A list of standalone script | a list of strings | - | | files to be built and | | - | | installed | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *ext_modules* | A list of Python extensions to | A list of instances of | - | | be built | :class:`distutils2.extension.Extension` | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *classifiers* | A list of categories for the | The list of available | - | | package | categorizations is at | - | | | http://pypi.python.org/pypi?:action=list_classifiers. | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *distclass* | the :class:`Distribution` | A subclass of | - | | class to use | :class:`distutils2.dist.Distribution` | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *script_name* | The name of the setup.py | a string | - | | script - defaults to | | - | | ``sys.argv[0]`` | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *script_args* | Arguments to supply to the | a list of strings | - | | setup script | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *options* | default options for the setup | a string | - | | script | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *license* | The license for the package | a string | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *keywords* | Descriptive metadata, see | | - | | :PEP:`314` | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *platforms* | | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *cmdclass* | A mapping of command names to | a dictionary | - | | :class:`Command` subclasses | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *data_files* | A list of data files to | a list | - | | install | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *package_dir* | A mapping of package to | a dictionary | - | | directory names | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - | *extra_path* | Information about an | a string, 1-tuple or 2-tuple | - | | intervening directory the | | - | | install directory and the | | - | | actual installation directory. | | - | | | | - | | If the value is a string is is | | - | | treated as a comma-separated | | - | | tuple. | | - | | | | - | | If the value is a 2-tuple, | | - | | the first element is the | | - | | ``.pth`` file and the second | | - | | is the name of the intervening | | - | | directory. | | - | | | | - | | If the value is a 1-tuple that | | - | | element is both the name of | | - | | the ``.pth`` file and the | | - | | intervening directory. | | - +--------------------+--------------------------------+-------------------------------------------------------------+ - - - -.. function:: run_setup(script_name[, script_args=None, stop_after='run']) - - Run a setup script in a somewhat controlled environment, and return the - :class:`distutils2.dist.Distribution` instance that drives things. This is - useful if you need to find out the distribution metadata (passed as keyword - args from *script* to :func:`setup`), or the contents of the config files or - command line. - - *script_name* is a file that will be run with :func:`execfile` - ``sys.argv[0]`` will be replaced with *script* for the duration of the call. - *script_args* is a list of strings; if supplied, ``sys.argv[1:]`` will be - replaced by *script_args* for the duration of the call. - - *stop_after* tells :func:`setup` when to stop processing; possible values: - - +---------------+---------------------------------------------+ - | value | description | - +===============+=============================================+ - | *init* | Stop after the :class:`Distribution` | - | | instance has been created and populated | - | | with the keyword arguments to :func:`setup` | - +---------------+---------------------------------------------+ - | *config* | Stop after config files have been parsed | - | | (and their data stored in the | - | | :class:`Distribution` instance) | - +---------------+---------------------------------------------+ - | *commandline* | Stop after the command line | - | | (``sys.argv[1:]`` or *script_args*) have | - | | been parsed (and the data stored in the | - | | :class:`Distribution` instance.) | - +---------------+---------------------------------------------+ - | *run* | Stop after all commands have been run (the | - | | same as if :func:`setup` had been called in | - | | the usual way). This is the default value. | - +---------------+---------------------------------------------+ - -In addition, the :mod:`distutils2.core` module exposed a number of classes that -live elsewhere. - -* :class:`~distutils.extension.Extension` from :mod:`distutils2.extension` - -* :class:`~distutils.command.cmd.Command` from :mod:`distutils2.command.cmd` - -* :class:`~distutils.dist.Distribution` from :mod:`distutils2.dist` - -A short description of each of these follows, but see the relevant module for -the full reference. - - -.. class:: Extension - - The Extension class describes a single C or C++extension module in a setup - script. It accepts the following keyword arguments in its constructor - - +------------------------+--------------------------------+---------------------------+ - | argument name | value | type | - +========================+================================+===========================+ - | *name* | the full name of the | string | - | | extension, including any | | - | | packages --- i.e. *not* a | | - | | filename or pathname, but | | - | | Python dotted name | | - +------------------------+--------------------------------+---------------------------+ - | *sources* | list of source filenames, | string | - | | relative to the distribution | | - | | root (where the setup script | | - | | lives), in Unix form (slash- | | - | | separated) for portability. | | - | | Source files may be C, C++, | | - | | SWIG (.i), platform-specific | | - | | resource files, or whatever | | - | | else is recognized by the | | - | | :command:`build_ext` command | | - | | as source for a Python | | - | | extension. | | - +------------------------+--------------------------------+---------------------------+ - | *include_dirs* | list of directories to search | string | - | | for C/C++ header files (in | | - | | Unix form for portability) | | - +------------------------+--------------------------------+---------------------------+ - | *define_macros* | list of macros to define; each | (string, string) tuple or | - | | macro is defined using a | (name, ``None``) | - | | 2-tuple ``(name, value)``, | | - | | where *value* is | | - | | either the string to define it | | - | | to or ``None`` to define it | | - | | without a particular value | | - | | (equivalent of ``#define FOO`` | | - | | in source or :option:`-DFOO` | | - | | on Unix C compiler command | | - | | line) | | - +------------------------+--------------------------------+---------------------------+ - | *undef_macros* | list of macros to undefine | string | - | | explicitly | | - +------------------------+--------------------------------+---------------------------+ - | *library_dirs* | list of directories to search | string | - | | for C/C++ libraries at link | | - | | time | | - +------------------------+--------------------------------+---------------------------+ - | *libraries* | list of library names (not | string | - | | filenames or paths) to link | | - | | against | | - +------------------------+--------------------------------+---------------------------+ - | *runtime_library_dirs* | list of directories to search | string | - | | for C/C++ libraries at run | | - | | time (for shared extensions, | | - | | this is when the extension is | | - | | loaded) | | - +------------------------+--------------------------------+---------------------------+ - | *extra_objects* | list of extra files to link | string | - | | with (e.g. object files not | | - | | implied by 'sources', static | | - | | library that must be | | - | | explicitly specified, binary | | - | | resource files, etc.) | | - +------------------------+--------------------------------+---------------------------+ - | *extra_compile_args* | any extra platform- and | string | - | | compiler-specific information | | - | | to use when compiling the | | - | | source files in 'sources'. For | | - | | platforms and compilers where | | - | | a command line makes sense, | | - | | this is typically a list of | | - | | command-line arguments, but | | - | | for other platforms it could | | - | | be anything. | | - +------------------------+--------------------------------+---------------------------+ - | *extra_link_args* | any extra platform- and | string | - | | compiler-specific information | | - | | to use when linking object | | - | | files together to create the | | - | | extension (or to create a new | | - | | static Python interpreter). | | - | | Similar interpretation as for | | - | | 'extra_compile_args'. | | - +------------------------+--------------------------------+---------------------------+ - | *export_symbols* | list of symbols to be exported | string | - | | from a shared extension. Not | | - | | used on all platforms, and not | | - | | generally necessary for Python | | - | | extensions, which typically | | - | | export exactly one symbol: | | - | | ``init`` + extension_name. | | - +------------------------+--------------------------------+---------------------------+ - | *depends* | list of files that the | string | - | | extension depends on | | - +------------------------+--------------------------------+---------------------------+ - | *language* | extension language (i.e. | string | - | | ``'c'``, ``'c++'``, | | - | | ``'objc'``). Will be detected | | - | | from the source extensions if | | - | | not provided. | | - +------------------------+--------------------------------+---------------------------+ - - -.. class:: Distribution - - A :class:`Distribution` describes how to build, install and package up a - Python software package. - - See the :func:`setup` function for a list of keyword arguments accepted by - the Distribution constructor. :func:`setup` creates a Distribution instance. - - -.. class:: Command - - A :class:`Command` class (or rather, an instance of one of its subclasses) - implement a single distutils command. - - -:mod:`distutils2.ccompiler` --- CCompiler base class -==================================================== - -.. module:: distutils2.ccompiler - :synopsis: Abstract CCompiler class - - -This module provides the abstract base class for the :class:`CCompiler` -classes. A :class:`CCompiler` instance can be used for all the compile and -link steps needed to build a single project. Methods are provided to set -options for the compiler --- macro definitions, include directories, link path, -libraries and the like. - -This module provides the following functions. - - -.. function:: gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries) - - Generate linker options for searching library directories and linking with - specific libraries. *libraries* and *library_dirs* are, respectively, lists - of library names (not filenames!) and search directories. Returns a list of - command-line options suitable for use with some compiler (depending on the - two format strings passed in). - - -.. function:: gen_preprocess_options(macros, include_dirs) - - Generate C preprocessor options (:option:`-D`, :option:`-U`, :option:`-I`) as - used by at least two types of compilers: the typical Unix compiler and Visual - C++. *macros* is the usual thing, a list of 1- or 2-tuples, where ``(name,)`` - means undefine (:option:`-U`) macro *name*, and ``(name, value)`` means - define (:option:`-D`) macro *name* to *value*. *include_dirs* is just a list - of directory names to be added to the header file search path (:option:`-I`). - Returns a list of command-line options suitable for either Unix compilers or - Visual C++. - - -.. function:: get_default_compiler(osname, platform) - - Determine the default compiler to use for the given platform. - - *osname* should be one of the standard Python OS names (i.e. the ones - returned by ``os.name``) and *platform* the common value returned by - ``sys.platform`` for the platform in question. - - The default values are ``os.name`` and ``sys.platform``. - - -.. function:: new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0) - - Factory function to generate an instance of some CCompiler subclass for the - supplied platform/compiler combination. *plat* defaults to ``os.name`` (e.g. - ``'posix'``, ``'nt'``), and *compiler* defaults to the default compiler for - that platform. Currently only ``'posix'`` and ``'nt'`` are supported, and the - default compilers are "traditional Unix interface" (:class:`UnixCCompiler` - class) and Visual C++ (:class:`MSVCCompiler` class). Note that it's perfectly - possible to ask for a Unix compiler object under Windows, and a Microsoft - compiler object under Unix---if you supply a value for *compiler*, *plat* is - ignored. - - .. % Is the posix/nt only thing still true? Mac OS X seems to work, and - .. % returns a UnixCCompiler instance. How to document this... hmm. - - -.. function:: show_compilers() - - Print list of available compilers (used by the :option:`--help-compiler` - options to :command:`build`, :command:`build_ext`, :command:`build_clib`). - - -.. class:: CCompiler([verbose=0, dry_run=0, force=0]) - - The abstract base class :class:`CCompiler` defines the interface that must be - implemented by real compiler classes. The class also has some utility - methods used by several compiler classes. - - The basic idea behind a compiler abstraction class is that each instance can - be used for all the compile/link steps in building a single project. Thus, - attributes common to all of those compile and link steps --- include - directories, macros to define, libraries to link against, etc. --- are - attributes of the compiler instance. To allow for variability in how - individual files are treated, most of those attributes may be varied on a - per-compilation or per-link basis. - - The constructor for each subclass creates an instance of the Compiler object. - Flags are *verbose* (show verbose output), *dry_run* (don't actually execute - the steps) and *force* (rebuild everything, regardless of dependencies). All - of these flags default to ``0`` (off). Note that you probably don't want to - instantiate :class:`CCompiler` or one of its subclasses directly - use the - :func:`distutils2.CCompiler.new_compiler` factory function instead. - - The following methods allow you to manually alter compiler options for the - instance of the Compiler class. - - - .. method:: CCompiler.add_include_dir(dir) - - Add *dir* to the list of directories that will be searched for header - files. The compiler is instructed to search directories in the order in - which they are supplied by successive calls to :meth:`add_include_dir`. - - - .. method:: CCompiler.set_include_dirs(dirs) - - Set the list of directories that will be searched to *dirs* (a list of - strings). Overrides any preceding calls to :meth:`add_include_dir`; - subsequent calls to :meth:`add_include_dir` add to the list passed to - :meth:`set_include_dirs`. This does not affect any list of standard - include directories that the compiler may search by default. - - - .. method:: CCompiler.add_library(libname) - - Add *libname* to the list of libraries that will be included in all links - driven by this compiler object. Note that *libname* should *not* be the - name of a file containing a library, but the name of the library itself: - the actual filename will be inferred by the linker, the compiler, or the - compiler class (depending on the platform). - - The linker will be instructed to link against libraries in the order they - were supplied to :meth:`add_library` and/or :meth:`set_libraries`. It is - perfectly valid to duplicate library names; the linker will be instructed - to link against libraries as many times as they are mentioned. - - - .. method:: CCompiler.set_libraries(libnames) - - Set the list of libraries to be included in all links driven by this - compiler object to *libnames* (a list of strings). This does not affect - any standard system libraries that the linker may include by default. - - - .. method:: CCompiler.add_library_dir(dir) - - Add *dir* to the list of directories that will be searched for libraries - specified to :meth:`add_library` and :meth:`set_libraries`. The linker - will be instructed to search for libraries in the order they are supplied - to :meth:`add_library_dir` and/or :meth:`set_library_dirs`. - - - .. method:: CCompiler.set_library_dirs(dirs) - - Set the list of library search directories to *dirs* (a list of strings). - This does not affect any standard library search path that the linker may - search by default. - - - .. method:: CCompiler.add_runtime_library_dir(dir) - - Add *dir* to the list of directories that will be searched for shared - libraries at runtime. - - - .. method:: CCompiler.set_runtime_library_dirs(dirs) - - Set the list of directories to search for shared libraries at runtime to - *dirs* (a list of strings). This does not affect any standard search path - that the runtime linker may search by default. - - - .. method:: CCompiler.define_macro(name[, value=None]) - - Define a preprocessor macro for all compilations driven by this compiler - object. The optional parameter *value* should be a string; if it is not - supplied, then the macro will be defined without an explicit value and the - exact outcome depends on the compiler used (XXX true? does ANSI say - anything about this?) - - - .. method:: CCompiler.undefine_macro(name) - - Undefine a preprocessor macro for all compilations driven by this compiler - object. If the same macro is defined by :meth:`define_macro` and - undefined by :meth:`undefine_macro` the last call takes precedence - (including multiple redefinitions or undefinitions). If the macro is - redefined/undefined on a per-compilation basis (i.e. in the call to - :meth:`compile`), then that takes precedence. - - - .. method:: CCompiler.add_link_object(object) - - Add *object* to the list of object files (or analogues, such as explicitly - named library files or the output of "resource compilers") to be included - in every link driven by this compiler object. - - - .. method:: CCompiler.set_link_objects(objects) - - Set the list of object files (or analogues) to be included in every link - to *objects*. This does not affect any standard object files that the - linker may include by default (such as system libraries). - - The following methods implement methods for autodetection of compiler - options, providing some functionality similar to GNU :program:`autoconf`. - - - .. method:: CCompiler.detect_language(sources) - - Detect the language of a given file, or list of files. Uses the instance - attributes :attr:`language_map` (a dictionary), and :attr:`language_order` - (a list) to do the job. - - - .. method:: CCompiler.find_library_file(dirs, lib[, debug=0]) - - Search the specified list of directories for a static or shared library file - *lib* and return the full path to that file. If *debug* is true, look for a - debugging version (if that makes sense on the current platform). Return - ``None`` if *lib* wasn't found in any of the specified directories. - - - .. method:: CCompiler.has_function(funcname [, includes=None, include_dirs=None, libraries=None, library_dirs=None]) - - Return a boolean indicating whether *funcname* is supported on the current - platform. The optional arguments can be used to augment the compilation - environment by providing additional include files and paths and libraries and - paths. - - - .. method:: CCompiler.library_dir_option(dir) - - Return the compiler option to add *dir* to the list of directories searched for - libraries. - - - .. method:: CCompiler.library_option(lib) - - Return the compiler option to add *dir* to the list of libraries linked into the - shared library or executable. - - - .. method:: CCompiler.runtime_library_dir_option(dir) - - Return the compiler option to add *dir* to the list of directories searched for - runtime libraries. - - - .. method:: CCompiler.set_executables(**args) - - Define the executables (and options for them) that will be run to perform the - various stages of compilation. The exact set of executables that may be - specified here depends on the compiler class (via the 'executables' class - attribute), but most will have: - - +--------------+------------------------------------------+ - | attribute | description | - +==============+==========================================+ - | *compiler* | the C/C++ compiler | - +--------------+------------------------------------------+ - | *linker_so* | linker used to create shared objects and | - | | libraries | - +--------------+------------------------------------------+ - | *linker_exe* | linker used to create binary executables | - +--------------+------------------------------------------+ - | *archiver* | static library creator | - +--------------+------------------------------------------+ - - On platforms with a command line (Unix, DOS/Windows), each of these is a string - that will be split into executable name and (optional) list of arguments. - (Splitting the string is done similarly to how Unix shells operate: words are - delimited by spaces, but quotes and backslashes can override this. See - :func:`distutils2.util.split_quoted`.) - - The following methods invoke stages in the build process. - - - .. method:: CCompiler.compile(sources[, output_dir=None, macros=None, include_dirs=None, debug=0, extra_preargs=None, extra_postargs=None, depends=None]) - - Compile one or more source files. Generates object files (e.g. transforms a - :file:`.c` file to a :file:`.o` file.) - - *sources* must be a list of filenames, most likely C/C++ files, but in reality - anything that can be handled by a particular compiler and compiler class (e.g. - :class:`MSVCCompiler` can handle resource files in *sources*). Return a list of - object filenames, one per source filename in *sources*. Depending on the - implementation, not all source files will necessarily be compiled, but all - corresponding object filenames will be returned. - - If *output_dir* is given, object files will be put under it, while retaining - their original path component. That is, :file:`foo/bar.c` normally compiles to - :file:`foo/bar.o` (for a Unix implementation); if *output_dir* is *build*, then - it would compile to :file:`build/foo/bar.o`. - - *macros*, if given, must be a list of macro definitions. A macro definition is - either a ``(name, value)`` 2-tuple or a ``(name,)`` 1-tuple. The former defines - a macro; if the value is ``None``, the macro is defined without an explicit - value. The 1-tuple case undefines a macro. Later - definitions/redefinitions/undefinitions take precedence. - - *include_dirs*, if given, must be a list of strings, the directories to add to - the default include file search path for this compilation only. - - *debug* is a boolean; if true, the compiler will be instructed to output debug - symbols in (or alongside) the object file(s). - - *extra_preargs* and *extra_postargs* are implementation-dependent. On platforms - that have the notion of a command line (e.g. Unix, DOS/Windows), they are most - likely lists of strings: extra command-line arguments to prepend/append to the - compiler command line. On other platforms, consult the implementation class - documentation. In any event, they are intended as an escape hatch for those - occasions when the abstract compiler framework doesn't cut the mustard. - - *depends*, if given, is a list of filenames that all targets depend on. If a - source file is older than any file in depends, then the source file will be - recompiled. This supports dependency tracking, but only at a coarse - granularity. - - Raises :exc:`CompileError` on failure. - - - .. method:: CCompiler.create_static_lib(objects, output_libname[, output_dir=None, debug=0, target_lang=None]) - - Link a bunch of stuff together to create a static library file. The "bunch of - stuff" consists of the list of object files supplied as *objects*, the extra - object files supplied to :meth:`add_link_object` and/or - :meth:`set_link_objects`, the libraries supplied to :meth:`add_library` and/or - :meth:`set_libraries`, and the libraries supplied as *libraries* (if any). - - *output_libname* should be a library name, not a filename; the filename will be - inferred from the library name. *output_dir* is the directory where the library - file will be put. XXX defaults to what? - - *debug* is a boolean; if true, debugging information will be included in the - library (note that on most platforms, it is the compile step where this matters: - the *debug* flag is included here just for consistency). - - *target_lang* is the target language for which the given objects are being - compiled. This allows specific linkage time treatment of certain languages. - - Raises :exc:`LibError` on failure. - - - .. method:: CCompiler.link(target_desc, objects, output_filename[, output_dir=None, libraries=None, library_dirs=None, runtime_library_dirs=None, export_symbols=None, debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, target_lang=None]) - - Link a bunch of stuff together to create an executable or shared library file. - - The "bunch of stuff" consists of the list of object files supplied as *objects*. - *output_filename* should be a filename. If *output_dir* is supplied, - *output_filename* is relative to it (i.e. *output_filename* can provide - directory components if needed). - - *libraries* is a list of libraries to link against. These are library names, - not filenames, since they're translated into filenames in a platform-specific - way (e.g. *foo* becomes :file:`libfoo.a` on Unix and :file:`foo.lib` on - DOS/Windows). However, they can include a directory component, which means the - linker will look in that specific directory rather than searching all the normal - locations. - - *library_dirs*, if supplied, should be a list of directories to search for - libraries that were specified as bare library names (i.e. no directory - component). These are on top of the system default and those supplied to - :meth:`add_library_dir` and/or :meth:`set_library_dirs`. *runtime_library_dirs* - is a list of directories that will be embedded into the shared library and used - to search for other shared libraries that \*it\* depends on at run-time. (This - may only be relevant on Unix.) - - *export_symbols* is a list of symbols that the shared library will export. - (This appears to be relevant only on Windows.) - - *debug* is as for :meth:`compile` and :meth:`create_static_lib`, with the - slight distinction that it actually matters on most platforms (as opposed to - :meth:`create_static_lib`, which includes a *debug* flag mostly for form's - sake). - - *extra_preargs* and *extra_postargs* are as for :meth:`compile` (except of - course that they supply command-line arguments for the particular linker being - used). - - *target_lang* is the target language for which the given objects are being - compiled. This allows specific linkage time treatment of certain languages. - - Raises :exc:`LinkError` on failure. - - - .. method:: CCompiler.link_executable(objects, output_progname[, output_dir=None, libraries=None, library_dirs=None, runtime_library_dirs=None, debug=0, extra_preargs=None, extra_postargs=None, target_lang=None]) - - Link an executable. *output_progname* is the name of the file executable, while - *objects* are a list of object filenames to link in. Other arguments are as for - the :meth:`link` method. - - - .. method:: CCompiler.link_shared_lib(objects, output_libname[, output_dir=None, libraries=None, library_dirs=None, runtime_library_dirs=None, export_symbols=None, debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, target_lang=None]) - - Link a shared library. *output_libname* is the name of the output library, - while *objects* is a list of object filenames to link in. Other arguments are - as for the :meth:`link` method. - - - .. method:: CCompiler.link_shared_object(objects, output_filename[, output_dir=None, libraries=None, library_dirs=None, runtime_library_dirs=None, export_symbols=None, debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, target_lang=None]) - - Link a shared object. *output_filename* is the name of the shared object that - will be created, while *objects* is a list of object filenames to link in. - Other arguments are as for the :meth:`link` method. - - - .. method:: CCompiler.preprocess(source[, output_file=None, macros=None, include_dirs=None, extra_preargs=None, extra_postargs=None]) - - Preprocess a single C/C++ source file, named in *source*. Output will be written - to file named *output_file*, or *stdout* if *output_file* not supplied. - *macros* is a list of macro definitions as for :meth:`compile`, which will - augment the macros set with :meth:`define_macro` and :meth:`undefine_macro`. - *include_dirs* is a list of directory names that will be added to the default - list, in the same way as :meth:`add_include_dir`. - - Raises :exc:`PreprocessError` on failure. - - The following utility methods are defined by the :class:`CCompiler` class, for - use by the various concrete subclasses. - - - .. method:: CCompiler.executable_filename(basename[, strip_dir=0, output_dir='']) - - Returns the filename of the executable for the given *basename*. Typically for - non-Windows platforms this is the same as the basename, while Windows will get - a :file:`.exe` added. - - - .. method:: CCompiler.library_filename(libname[, lib_type='static', strip_dir=0, output_dir='']) - - Returns the filename for the given library name on the current platform. On Unix - a library with *lib_type* of ``'static'`` will typically be of the form - :file:`liblibname.a`, while a *lib_type* of ``'dynamic'`` will be of the form - :file:`liblibname.so`. - - - .. method:: CCompiler.object_filenames(source_filenames[, strip_dir=0, output_dir='']) - - Returns the name of the object files for the given source files. - *source_filenames* should be a list of filenames. - - - .. method:: CCompiler.shared_object_filename(basename[, strip_dir=0, output_dir='']) - - Returns the name of a shared object file for the given file name *basename*. - - - .. method:: CCompiler.execute(func, args[, msg=None, level=1]) - - Invokes :func:`distutils2.util.execute` This method invokes a Python function - *func* with the given arguments *args*, after logging and taking into account - the *dry_run* flag. XXX see also. - - - .. method:: CCompiler.spawn(cmd) - - Invokes :func:`distutils2.util.spawn`. This invokes an external process to run - the given command. XXX see also. - - - .. method:: CCompiler.mkpath(name[, mode=511]) - - Invokes :func:`distutils2.dir_util.mkpath`. This creates a directory and any - missing ancestor directories. XXX see also. - - - .. method:: CCompiler.move_file(src, dst) - - Invokes :meth:`distutils2.file_util.move_file`. Renames *src* to *dst*. XXX see - also. - - - .. method:: CCompiler.announce(msg[, level=1]) - - Write a message using :func:`distutils2.log.debug`. XXX see also. - - - .. method:: CCompiler.warn(msg) - - Write a warning message *msg* to standard error. - - - .. method:: CCompiler.debug_print(msg) - - If the *debug* flag is set on this :class:`CCompiler` instance, print *msg* to - standard output, otherwise do nothing. - -.. % \subsection{Compiler-specific modules} -.. % -.. % The following modules implement concrete subclasses of the abstract -.. % \class{CCompiler} class. They should not be instantiated directly, but should -.. % be created using \function{distutils.ccompiler.new_compiler()} factory -.. % function. - - -:mod:`distutils2.unixccompiler` --- Unix C Compiler -=================================================== - -.. module:: distutils2.unixccompiler - :synopsis: UNIX C Compiler - - -This module provides the :class:`UnixCCompiler` class, a subclass of -:class:`CCompiler` that handles the typical Unix-style command-line C compiler: - -* macros defined with :option:`-Dname[=value]` - -* macros undefined with :option:`-Uname` - -* include search directories specified with :option:`-Idir` - -* libraries specified with :option:`-llib` - -* library search directories specified with :option:`-Ldir` - -* compile handled by :program:`cc` (or similar) executable with :option:`-c` - option: compiles :file:`.c` to :file:`.o` - -* link static library handled by :program:`ar` command (possibly with - :program:`ranlib`) - -* link shared library handled by :program:`cc` :option:`-shared` - - -:mod:`distutils2.msvccompiler` --- Microsoft Compiler -===================================================== - -.. module:: distutils2.msvccompiler - :synopsis: Microsoft Compiler - - -This module provides :class:`MSVCCompiler`, an implementation of the abstract -:class:`CCompiler` class for Microsoft Visual Studio. Typically, extension -modules need to be compiled with the same compiler that was used to compile -Python. For Python 2.3 and earlier, the compiler was Visual Studio 6. For Python -2.4 and 2.5, the compiler is Visual Studio .NET 2003. The AMD64 and Itanium -binaries are created using the Platform SDK. - -:class:`MSVCCompiler` will normally choose the right compiler, linker etc. on -its own. To override this choice, the environment variables *DISTUTILS_USE_SDK* -and *MSSdk* must be both set. *MSSdk* indicates that the current environment has -been setup by the SDK's ``SetEnv.Cmd`` script, or that the environment variables -had been registered when the SDK was installed; *DISTUTILS_USE_SDK* indicates -that the distutils user has made an explicit choice to override the compiler -selection by :class:`MSVCCompiler`. - - -:mod:`distutils2.bcppcompiler` --- Borland Compiler -=================================================== - -.. module:: distutils2.bcppcompiler - - -This module provides :class:`BorlandCCompiler`, an subclass of the abstract -:class:`CCompiler` class for the Borland C++ compiler. - - -:mod:`distutils2.cygwincompiler` --- Cygwin Compiler -==================================================== - -.. module:: distutils2.cygwinccompiler - - -This module provides the :class:`CygwinCCompiler` class, a subclass of -:class:`UnixCCompiler` that handles the Cygwin port of the GNU C compiler to -Windows. It also contains the Mingw32CCompiler class which handles the mingw32 -port of GCC (same as cygwin in no-cygwin mode). - - -:mod:`distutils2.emxccompiler` --- OS/2 EMX Compiler -==================================================== - -.. module:: distutils2.emxccompiler - :synopsis: OS/2 EMX Compiler support - - -This module provides the EMXCCompiler class, a subclass of -:class:`UnixCCompiler` that handles the EMX port of the GNU C compiler to OS/2. - - -:mod:`distutils2.archive_util` --- Archiving utilities -====================================================== - -.. module:: distutils2.archive_util - :synopsis: Utility functions for creating archive files (tarballs, zip files, ...) - - -This module provides a few functions for creating archive files, such as -tarballs or zipfiles. - - -.. function:: make_archive(base_name, format[, root_dir=None, base_dir=None, verbose=0, dry_run=0]) - - Create an archive file (e.g. ``zip`` or ``tar``). *base_name* is the name of - the file to create, minus any format-specific extension; *format* is the - archive format: one of ``zip``, ``tar``, ``ztar``, or ``gztar``. *root_dir* - is a directory that will be the root directory of the archive; i.e. we - typically - ``chdir`` into *root_dir* before creating the archive. *base_dir* is the - directory where we start archiving from; i.e. *base_dir* will be the common - prefix of all files and directories in the archive. *root_dir* and *base_dir* - both default to the current directory. Returns the name of the archive file. - - .. XXX This should be changed to support bz2 files. - - -.. function:: make_tarball(base_name, base_dir[, compress='gzip', verbose=0, dry_run=0]) - - 'Create an (optional compressed) archive as a tar file from all files in and - under *base_dir*. *compress* must be ``'gzip'`` (the default), ``'compress'``, - ``'bzip2'``, or ``None``. Both :program:`tar` and the compression utility named - by *compress* must be on the default program search path, so this is probably - Unix-specific. The output tar file will be named :file:`base_dir.tar`, - possibly plus the appropriate compression extension (:file:`.gz`, :file:`.bz2` - or :file:`.Z`). Return the output filename. - - .. TODO update to reflect use of the :mod:`tarfile` module. - - -.. function:: make_zipfile(base_name, base_dir[, verbose=0, dry_run=0]) - - Create a zip file from all files in and under *base_dir*. The output zip file - will be named *base_name* + :file:`.zip`. Uses either the :mod:`zipfile` Python - module (if available) or the InfoZIP :file:`zip` utility (if installed and - found on the default search path). If neither tool is available, raises - :exc:`DistutilsExecError`. Returns the name of the output zip file. - - -:mod:`distutils2.dep_util` --- Dependency checking -================================================== - -.. module:: distutils2.dep_util - :synopsis: Utility functions for simple dependency checking - - -This module provides functions for performing simple, timestamp-based -dependency of files and groups of files; also, functions based entirely on such -timestamp dependency analysis. - - -.. function:: newer(source, target) - - Return true if *source* exists and is more recently modified than *target*, - or if *source* exists and *target* doesn't. Return false if both exist and - *target* is the same age or newer than *source*. Raise - :exc:`DistutilsFileError` if *source* does not exist. - - -.. function:: newer_pairwise(sources, targets) - - Walk two filename lists in parallel, testing if each source is newer than its - corresponding target. Return a pair of lists (*sources*, *targets*) where - source is newer than target, according to the semantics of :func:`newer` - - .. % % equivalent to a listcomp... - - -.. function:: newer_group(sources, target[, missing='error']) - - Return true if *target* is out-of-date with respect to any file listed in - *sources*. In other words, if *target* exists and is newer than every file - in *sources*, return false; otherwise return true. *missing* controls what - we do when a source file is missing; the default (``'error'``) is to blow up - with an :exc:`OSError` from inside :func:`os.stat`; if it is ``'ignore'``, we - silently drop any missing source files; if it is ``'newer'``, any missing - source files make us assume that *target* is out-of-date (this is handy in - "dry-run" mode: it'll make you pretend to carry out commands that wouldn't - work because inputs are missing, but that doesn't matter because you're not - actually going to run the commands). - - -:mod:`distutils2.dir_util` --- Directory tree operations -======================================================== - -.. module:: distutils2.dir_util - :synopsis: Utility functions for operating on directories and directory trees - - -This module provides functions for operating on directories and trees of -directories. - - -.. function:: mkpath(name[, mode=0777, verbose=0, dry_run=0]) - - Create a directory and any missing ancestor directories. If the directory - already exists (or if *name* is the empty string, which means the current - directory, which of course exists), then do nothing. Raise - :exc:`DistutilsFileError` if unable to create some directory along the way - (e.g. some sub-path exists, but is a file rather than a directory). If - *verbose* is true, print a one-line summary of each mkdir to stdout. Return - the list of directories actually created. - - -.. function:: create_tree(base_dir, files[, mode=0777, verbose=0, dry_run=0]) - - Create all the empty directories under *base_dir* needed to put *files* - there. *base_dir* is just the a name of a directory which doesn't necessarily - exist yet; *files* is a list of filenames to be interpreted relative to - *base_dir*. *base_dir* + the directory portion of every file in *files* will - be created if it doesn't already exist. *mode*, *verbose* and *dry_run* - flags are as for :func:`mkpath`. - - -.. function:: copy_tree(src, dst[, preserve_mode=1, preserve_times=1, preserve_symlinks=0, update=0, verbose=0, dry_run=0]) - - Copy an entire directory tree *src* to a new location *dst*. Both *src* and - *dst* must be directory names. If *src* is not a directory, raise - :exc:`DistutilsFileError`. If *dst* does not exist, it is created with - :func:`mkpath`. The end result of the copy is that every file in *src* is - copied to *dst*, and directories under *src* are recursively copied to - *dst*. Return the list of files that were copied or might have been copied, - using their output name. The return value is unaffected by *update* or - *dry_run*: it is simply the list of all files under *src*, with the names - changed to be under *dst*. - - *preserve_mode* and *preserve_times* are the same as for :func:`copy_file` - in :mod:`distutils2.file_util`; note that they only apply to regular files, - not to directories. If *preserve_symlinks* is true, symlinks will be copied - as symlinks (on platforms that support them!); otherwise (the default), the - destination of the symlink will be copied. *update* and *verbose* are the - same as for :func:`copy_file`. - - -.. function:: remove_tree(directory[, verbose=0, dry_run=0]) - - Recursively remove *directory* and all files and directories underneath it. - Any errors are ignored (apart from being reported to ``sys.stdout`` if - *verbose* is true). - -.. XXX Some of this could be replaced with the shutil module? - - -:mod:`distutils2.file_util` --- Single file operations -====================================================== - -.. module:: distutils2.file_util - :synopsis: Utility functions for operating on single files - - -This module contains some utility functions for operating on individual files. - - -.. function:: copy_file(src, dst[, preserve_mode=1, preserve_times=1, update=0, link=None, verbose=0, dry_run=0]) - - Copy file *src* to *dst*. If *dst* is a directory, then *src* is copied there - with the same name; otherwise, it must be a filename. (If the file exists, it - will be ruthlessly clobbered.) If *preserve_mode* is true (the default), the - file's mode (type and permission bits, or whatever is analogous on the - current platform) is copied. If *preserve_times* is true (the default), the - last-modified and last-access times are copied as well. If *update* is true, - *src* will only be copied if *dst* does not exist, or if *dst* does exist but - is older than *src*. - - *link* allows you to make hard links (using :func:`os.link`) or symbolic - links (using :func:`os.symlink`) instead of copying: set it to ``'hard'`` or - ``'sym'``; if it is ``None`` (the default), files are copied. Don't set - *link* on systems that don't support it: :func:`copy_file` doesn't check if - hard or symbolic linking is available. It uses :func:`_copy_file_contents` - to copy file contents. - - Return a tuple ``(dest_name, copied)``: *dest_name* is the actual name of - the output file, and *copied* is true if the file was copied (or would have - been copied, if *dry_run* true). - - .. % XXX if the destination file already exists, we clobber it if - .. % copying, but blow up if linking. Hmmm. And I don't know what - .. % macostools.copyfile() does. Should definitely be consistent, and - .. % should probably blow up if destination exists and we would be - .. % changing it (i.e. it's not already a hard/soft link to src OR - .. % (not update) and (src newer than dst)). - - -.. function:: move_file(src, dst[, verbose, dry_run]) - - Move file *src* to *dst*. If *dst* is a directory, the file will be moved - into it with the same name; otherwise, *src* is just renamed to *dst*. - Returns the new full name of the file. - - .. warning:: - - Handles cross-device moves on Unix using :func:`copy_file`. What about - other systems? - - -.. function:: write_file(filename, contents) - - Create a file called *filename* and write *contents* (a sequence of strings - without line terminators) to it. - -:mod:`distutils2.metadata` --- Metadata handling -================================================================ - -.. module:: distutils2.metadata - -.. FIXME CPython/stdlib docs don't use autoclass, write doc manually here - -.. autoclass:: distutils2.metadata.Metadata - :members: - -:mod:`distutils2.util` --- Miscellaneous other utility functions -================================================================ - -.. module:: distutils2.util - :synopsis: Miscellaneous other utility functions - - -This module contains other assorted bits and pieces that don't fit into any -other utility module. - - -.. function:: get_platform() - - Return a string that identifies the current platform. This is used mainly to - distinguish platform-specific build directories and platform-specific built - distributions. Typically includes the OS name and version and the - architecture (as supplied by 'os.uname()'), although the exact information - included depends on the OS; e.g. for IRIX the architecture isn't particularly - important (IRIX only runs on SGI hardware), but for Linux the kernel version - isn't particularly important. - - Examples of returned values: - - * ``linux-i586`` - * ``linux-alpha`` - * ``solaris-2.6-sun4u`` - * ``irix-5.3`` - * ``irix64-6.2`` - - For non-POSIX platforms, currently just returns ``sys.platform``. - - For Mac OS X systems the OS version reflects the minimal version on which - binaries will run (that is, the value of ``MACOSX_DEPLOYMENT_TARGET`` - during the build of Python), not the OS version of the current system. - - For universal binary builds on Mac OS X the architecture value reflects - the univeral binary status instead of the architecture of the current - processor. For 32-bit universal binaries the architecture is ``fat``, - for 64-bit universal binaries the architecture is ``fat64``, and - for 4-way universal binaries the architecture is ``universal``. Starting - from Python 2.7 and Python 3.2 the architecture ``fat3`` is used for - a 3-way universal build (ppc, i386, x86_64) and ``intel`` is used for - a univeral build with the i386 and x86_64 architectures - - Examples of returned values on Mac OS X: - - * ``macosx-10.3-ppc`` - - * ``macosx-10.3-fat`` - - * ``macosx-10.5-universal`` - - * ``macosx-10.6-intel`` - - .. XXX reinvention of platform module? - - -.. function:: convert_path(pathname) - - Return 'pathname' as a name that will work on the native filesystem, i.e. - split it on '/' and put it back together again using the current directory - separator. Needed because filenames in the setup script are always supplied - in Unix style, and have to be converted to the local convention before we - can actually use them in the filesystem. Raises :exc:`ValueError` on - non-Unix-ish systems if *pathname* either starts or ends with a slash. - - -.. function:: change_root(new_root, pathname) - - Return *pathname* with *new_root* prepended. If *pathname* is relative, this - is equivalent to ``os.path.join(new_root,pathname)`` Otherwise, it requires - making *pathname* relative and then joining the two, which is tricky on - DOS/Windows. - - -.. function:: check_environ() - - Ensure that 'os.environ' has all the environment variables we guarantee that - users can use in config files, command-line options, etc. Currently this - includes: - - * :envvar:`HOME` - user's home directory (Unix only) - * :envvar:`PLAT` - description of the current platform, including hardware - and OS (see :func:`get_platform`) - - -.. function:: subst_vars(s, local_vars) - - Perform shell/Perl-style variable substitution on *s*. Every occurrence of - ``$`` followed by a name is considered a variable, and variable is - substituted by the value found in the *local_vars* dictionary, or in - ``os.environ`` if it's not in *local_vars*. *os.environ* is first - checked/augmented to guarantee that it contains certain values: see - :func:`check_environ`. Raise :exc:`ValueError` for any variables not found - in either *local_vars* or ``os.environ``. - - Note that this is not a fully-fledged string interpolation function. A valid - ``$variable`` can consist only of upper and lower case letters, numbers and - an underscore. No { } or ( ) style quoting is available. - - -.. function:: split_quoted(s) - - Split a string up according to Unix shell-like rules for quotes and - backslashes. In short: words are delimited by spaces, as long as those spaces - are not escaped by a backslash, or inside a quoted string. Single and double - quotes are equivalent, and the quote characters can be backslash-escaped. - The backslash is stripped from any two-character escape sequence, leaving - only the escaped character. The quote characters are stripped from any - quoted string. Returns a list of words. - - .. % Should probably be moved into the standard library. - - -.. function:: execute(func, args[, msg=None, verbose=0, dry_run=0]) - - Perform some action that affects the outside world (for instance, writing to - the filesystem). Such actions are special because they are disabled by the - *dry_run* flag. This method takes care of all that bureaucracy for you; - all you have to do is supply the function to call and an argument tuple for - it (to embody the "external action" being performed), and an optional message - to print. - - -.. function:: strtobool(val) - - Convert a string representation of truth to true (1) or false (0). - - True values are ``y``, ``yes``, ``t``, ``true``, ``on`` and ``1``; false - values are ``n``, ``no``, ``f``, ``false``, ``off`` and ``0``. Raises - :exc:`ValueError` if *val* is anything else. - -.. TODO Add :term: markup to bytecode when merging into the stdlib - -.. function:: byte_compile(py_files[, optimize=0, force=0, prefix=None, base_dir=None, verbose=1, dry_run=0, direct=None]) - - Byte-compile a collection of Python source files to either :file:`.pyc` or - :file:`.pyo` files in the same directory. *py_files* is a list of files to - compile; any files that don't end in :file:`.py` are silently skipped. - *optimize* must be one of the following: - - * ``0`` - don't optimize (generate :file:`.pyc`) - * ``1`` - normal optimization (like ``python -O``) - * ``2`` - extra optimization (like ``python -OO``) - - If *force* is true, all files are recompiled regardless of timestamps. - - The source filename encoded in each bytecode file defaults to the filenames - listed in *py_files*; you can modify these with *prefix* and *basedir*. - *prefix* is a string that will be stripped off of each source filename, and - *base_dir* is a directory name that will be prepended (after *prefix* is - stripped). You can supply either or both (or neither) of *prefix* and - *base_dir*, as you wish. - - If *dry_run* is true, doesn't actually do anything that would affect the - filesystem. - - Byte-compilation is either done directly in this interpreter process with the - standard :mod:`py_compile` module, or indirectly by writing a temporary - script and executing it. Normally, you should let :func:`byte_compile` - figure out to use direct compilation or not (see the source for details). - The *direct* flag is used by the script generated in indirect mode; unless - you know what you're doing, leave it set to ``None``. - - -.. function:: rfc822_escape(header) - - Return a version of *header* escaped for inclusion in an :rfc:`822` header, by - ensuring there are 8 spaces space after each newline. Note that it does no - other modification of the string. - - .. % this _can_ be replaced - -.. % \subsection{Distutils objects} - - -:mod:`distutils2.dist` --- The Distribution class -================================================= - -.. module:: distutils2.dist - :synopsis: Provides the Distribution class, which represents the module - distribution being built/installed/distributed - - -This module provides the :class:`Distribution` class, which represents the -module distribution being built/installed/distributed. - - -:mod:`distutils2.extension` --- The Extension class -=================================================== - -.. module:: distutils2.extension - :synopsis: Provides the Extension class, used to describe C/C++ extension - modules in setup scripts - - -This module provides the :class:`Extension` class, used to describe C/C++ -extension modules in setup scripts. - -.. % \subsection{Ungrouped modules} -.. % The following haven't been moved into a more appropriate section yet. - - -:mod:`distutils2.debug` --- Distutils debug mode -================================================ - -.. module:: distutils2.debug - :synopsis: Provides the debug flag for distutils - - -This module provides the DEBUG flag. - - -:mod:`distutils2.errors` --- Distutils exceptions -================================================= - -.. module:: distutils2.errors - :synopsis: Provides standard distutils exceptions - - -Provides exceptions used by the Distutils modules. Note that Distutils modules -may raise standard exceptions; in particular, SystemExit is usually raised for -errors that are obviously the end-user's fault (e.g. bad command-line arguments). - -This module is safe to use in ``from ... import *`` mode; it only exports -symbols whose names start with ``Distutils`` and end with ``Error``. - - -:mod:`distutils2.fancy_getopt` --- Wrapper around the standard getopt module -============================================================================ - -.. module:: distutils2.fancy_getopt - :synopsis: Additional getopt functionality - - -This module provides a wrapper around the standard :mod:`getopt` module that -provides the following additional features: - -* short and long options are tied together - -* options have help strings, so :func:`fancy_getopt` could potentially create a - complete usage summary - -* options set attributes of a passed-in object - -* boolean options can have "negative aliases" --- e.g. if :option:`--quiet` is - the "negative alias" of :option:`--verbose`, then :option:`--quiet` on the - command line sets *verbose* to false. - -.. XXX Should be replaced with :mod:`argparse`. - - -.. function:: fancy_getopt(options, negative_opt, object, args) - - Wrapper function. *options* is a list of ``(long_option, short_option, - help_string)`` 3-tuples as described in the constructor for - :class:`FancyGetopt`. *negative_opt* should be a dictionary mapping option names - to option names, both the key and value should be in the *options* list. - *object* is an object which will be used to store values (see the :meth:`getopt` - method of the :class:`FancyGetopt` class). *args* is the argument list. Will use - ``sys.argv[1:]`` if you pass ``None`` as *args*. - - -.. function:: wrap_text(text, width) - - Wraps *text* to less than *width* wide. - - .. XXX Should be replaced with :mod:`textwrap` (which is available in Python - 2.3 and later). - - -.. class:: FancyGetopt([option_table=None]) - - The option_table is a list of 3-tuples: ``(long_option, short_option, - help_string)`` - - If an option takes an argument, its *long_option* should have ``'='`` appended; - *short_option* should just be a single character, no ``':'`` in any case. - *short_option* should be ``None`` if a *long_option* doesn't have a - corresponding *short_option*. All option tuples must have long options. - -The :class:`FancyGetopt` class provides the following methods: - - -.. method:: FancyGetopt.getopt([args=None, object=None]) - - Parse command-line options in args. Store as attributes on *object*. - - If *args* is ``None`` or not supplied, uses ``sys.argv[1:]``. If *object* is - ``None`` or not supplied, creates a new :class:`OptionDummy` instance, stores - option values there, and returns a tuple ``(args, object)``. If *object* is - supplied, it is modified in place and :func:`getopt` just returns *args*; in - both cases, the returned *args* is a modified copy of the passed-in *args* list, - which is left untouched. - - .. % and args returned are? - - -.. method:: FancyGetopt.get_option_order() - - Returns the list of ``(option, value)`` tuples processed by the previous run of - :meth:`getopt` Raises :exc:`RuntimeError` if :meth:`getopt` hasn't been called - yet. - - -.. method:: FancyGetopt.generate_help([header=None]) - - Generate help text (a list of strings, one per suggested line of output) from - the option table for this :class:`FancyGetopt` object. - - If supplied, prints the supplied *header* at the top of the help. - - -:mod:`distutils2.filelist` --- The FileList class -================================================= - -.. module:: distutils2.filelist - :synopsis: The FileList class, used for poking about the file system and - building lists of files. - - -This module provides the :class:`FileList` class, used for poking about the -filesystem and building lists of files. - -.. TODO move to util - - -:mod:`distutils2.log` --- Simple PEP 282-style logging -====================================================== - -.. module:: distutils2.log - :synopsis: A simple logging mechanism, 282-style - - -.. XXX Should be replaced with standard :mod:`logging` module. - - - -:mod:`distutils2.spawn` --- Spawn a sub-process -=============================================== - -.. module:: distutils2.spawn - :synopsis: Provides the spawn() function - - -This module provides the :func:`spawn` function, a front-end to various -platform-specific functions for launching another program in a sub-process. -Also provides :func:`find_executable` to search the path for a given executable -name. - - -:mod:`distutils2.sysconfig` --- System configuration information -================================================================ - -.. module:: distutils2.sysconfig - :synopsis: Low-level access to configuration information of the Python interpreter. -.. moduleauthor:: Fred L. Drake, Jr. -.. moduleauthor:: Greg Ward -.. sectionauthor:: Fred L. Drake, Jr. - - -The :mod:`distutils2.sysconfig` module provides access to Python's low-level -configuration information. The specific configuration variables available -depend heavily on the platform and configuration. The specific variables depend -on the build process for the specific version of Python being run; the variables -are those found in the :file:`Makefile` and configuration header that are -installed with Python on Unix systems. The configuration header is called -:file:`pyconfig.h` for Python versions starting with 2.2, and :file:`config.h` -for earlier versions of Python. - -Some additional functions are provided which perform some useful manipulations -for other parts of the :mod:`distutils2` package. - - -.. data:: PREFIX - - The result of ``os.path.normpath(sys.prefix)``. - - -.. data:: EXEC_PREFIX - - The result of ``os.path.normpath(sys.exec_prefix)``. - - -.. function:: get_config_var(name) - - Return the value of a single variable. This is equivalent to - ``get_config_vars().get(name)``. - - -.. function:: get_config_vars(...) - - Return a set of variable definitions. If there are no arguments, this returns a - dictionary mapping names of configuration variables to values. If arguments are - provided, they should be strings, and the return value will be a sequence giving - the associated values. If a given name does not have a corresponding value, - ``None`` will be included for that variable. - - -.. function:: get_config_h_filename() - - Return the full path name of the configuration header. For Unix, this will be - the header generated by the :program:`configure` script; for other platforms the - header will have been supplied directly by the Python source distribution. The - file is a platform-specific text file. - - -.. function:: get_makefile_filename() - - Return the full path name of the :file:`Makefile` used to build Python. For - Unix, this will be a file generated by the :program:`configure` script; the - meaning for other platforms will vary. The file is a platform-specific text - file, if it exists. This function is only useful on POSIX platforms. - - -.. function:: get_python_inc([plat_specific[, prefix]]) - - Return the directory for either the general or platform-dependent C include - files. If *plat_specific* is true, the platform-dependent include directory is - returned; if false or omitted, the platform-independent directory is returned. - If *prefix* is given, it is used as either the prefix instead of - :const:`PREFIX`, or as the exec-prefix instead of :const:`EXEC_PREFIX` if - *plat_specific* is true. - - -.. function:: get_python_lib([plat_specific[, standard_lib[, prefix]]]) - - Return the directory for either the general or platform-dependent library - installation. If *plat_specific* is true, the platform-dependent include - directory is returned; if false or omitted, the platform-independent directory - is returned. If *prefix* is given, it is used as either the prefix instead of - :const:`PREFIX`, or as the exec-prefix instead of :const:`EXEC_PREFIX` if - *plat_specific* is true. If *standard_lib* is true, the directory for the - standard library is returned rather than the directory for the installation of - third-party extensions. - -The following function is only intended for use within the :mod:`distutils2` -package. - - -.. function:: customize_compiler(compiler) - - Do any platform-specific customization of a - :class:`distutils2.ccompiler.CCompiler` instance. - - This function is only needed on Unix at this time, but should be called - consistently to support forward-compatibility. It inserts the information that - varies across Unix flavors and is stored in Python's :file:`Makefile`. This - information includes the selected compiler, compiler and linker options, and the - extension used by the linker for shared objects. - -This function is even more special-purpose, and should only be used from -Python's own build procedures. - - -.. function:: set_python_build() - - Inform the :mod:`distutils2.sysconfig` module that it is being used as part of - the build process for Python. This changes a lot of relative locations for - files, allowing them to be located in the build area rather than in an installed - Python. - - -:mod:`distutils2.text_file` --- The TextFile class -================================================== - -.. module:: distutils2.text_file - :synopsis: provides the TextFile class, a simple interface to text files - - -This module provides the :class:`TextFile` class, which gives an interface to -text files that (optionally) takes care of stripping comments, ignoring blank -lines, and joining lines with backslashes. - - -.. class:: TextFile([filename=None, file=None, **options]) - - This class provides a file-like object that takes care of all the things you - commonly want to do when processing a text file that has some line-by-line - syntax: strip comments (as long as ``#`` is your comment character), skip blank - lines, join adjacent lines by escaping the newline (i.e. backslash at end of - line), strip leading and/or trailing whitespace. All of these are optional and - independently controllable. - - The class provides a :meth:`warn` method so you can generate warning messages - that report physical line number, even if the logical line in question spans - multiple physical lines. Also provides :meth:`unreadline` for implementing - line-at-a-time lookahead. - - :class:`TextFile` instances are create with either *filename*, *file*, or both. - :exc:`RuntimeError` is raised if both are ``None``. *filename* should be a - string, and *file* a file object (or something that provides :meth:`readline` - and :meth:`close` methods). It is recommended that you supply at least - *filename*, so that :class:`TextFile` can include it in warning messages. If - *file* is not supplied, :class:`TextFile` creates its own using the - :func:`open` built-in function. - - The options are all boolean, and affect the values returned by :meth:`readline` - - +------------------+--------------------------------+---------+ - | option name | description | default | - +==================+================================+=========+ - | *strip_comments* | strip from ``'#'`` to end-of- | true | - | | line, as well as any | | - | | whitespace leading up to the | | - | | ``'#'``\ ---unless it is | | - | | escaped by a backslash | | - +------------------+--------------------------------+---------+ - | *lstrip_ws* | strip leading whitespace from | false | - | | each line before returning it | | - +------------------+--------------------------------+---------+ - | *rstrip_ws* | strip trailing whitespace | true | - | | (including line terminator!) | | - | | from each line before | | - | | returning it. | | - +------------------+--------------------------------+---------+ - | *skip_blanks* | skip lines that are empty | true | - | | \*after\* stripping comments | | - | | and whitespace. (If both | | - | | lstrip_ws and rstrip_ws are | | - | | false, then some lines may | | - | | consist of solely whitespace: | | - | | these will \*not\* be skipped, | | - | | even if *skip_blanks* is | | - | | true.) | | - +------------------+--------------------------------+---------+ - | *join_lines* | if a backslash is the last | false | - | | non-newline character on a | | - | | line after stripping comments | | - | | and whitespace, join the | | - | | following line to it to form | | - | | one logical line; if N | | - | | consecutive lines end with a | | - | | backslash, then N+1 physical | | - | | lines will be joined to form | | - | | one logical line. | | - +------------------+--------------------------------+---------+ - | *collapse_join* | strip leading whitespace from | false | - | | lines that are joined to their | | - | | predecessor; only matters if | | - | | ``(join_lines and not | | - | | lstrip_ws)`` | | - +------------------+--------------------------------+---------+ - - Note that since *rstrip_ws* can strip the trailing newline, the semantics of - :meth:`readline` must differ from those of the built-in file object's - :meth:`readline` method! In particular, :meth:`readline` returns ``None`` for - end-of-file: an empty string might just be a blank line (or an all-whitespace - line), if *rstrip_ws* is true but *skip_blanks* is not. - - - .. method:: TextFile.open(filename) - - Open a new file *filename*. This overrides any *file* or *filename* - constructor arguments. - - - .. method:: TextFile.close() - - Close the current file and forget everything we know about it (including the - filename and the current line number). - - - .. method:: TextFile.warn(msg[,line=None]) - - Print (to stderr) a warning message tied to the current logical line in the - current file. If the current logical line in the file spans multiple physical - lines, the warning refers to the whole range, such as ``"lines 3-5"``. If - *line* is supplied, it overrides the current line number; it may be a list or - tuple to indicate a range of physical lines, or an integer for a single - physical line. - - - .. method:: TextFile.readline() - - Read and return a single logical line from the current file (or from an internal - buffer if lines have previously been "unread" with :meth:`unreadline`). If the - *join_lines* option is true, this may involve reading multiple physical lines - concatenated into a single string. Updates the current line number, so calling - :meth:`warn` after :meth:`readline` emits a warning about the physical line(s) - just read. Returns ``None`` on end-of-file, since the empty string can occur - if *rstrip_ws* is true but *strip_blanks* is not. - - - .. method:: TextFile.readlines() - - Read and return the list of all logical lines remaining in the current file. - This updates the current line number to the last line of the file. - - - .. method:: TextFile.unreadline(line) - - Push *line* (a string) onto an internal buffer that will be checked by future - :meth:`readline` calls. Handy for implementing a parser with line-at-a-time - lookahead. Note that lines that are "unread" with :meth:`unreadline` are not - subsequently re-cleansed (whitespace stripped, or whatever) when read with - :meth:`readline`. If multiple calls are made to :meth:`unreadline` before a call - to :meth:`readline`, the lines will be returned most in most recent first order. - - -:mod:`distutils2.version` --- Version number classes -==================================================== - -.. module:: distutils2.version - :synopsis: implements classes that represent module version numbers. - - -.. % todo -.. % \section{Distutils Commands} -.. % -.. % This part of Distutils implements the various Distutils commands, such -.. % as \code{build}, \code{install} \&c. Each command is implemented as a -.. % separate module, with the command name as the name of the module. - - -:mod:`distutils2.cmd` --- Abstract base class for Distutils commands -==================================================================== - -.. module:: distutils2.cmd - :synopsis: This module provides the abstract base class Command. This class - is subclassed by the modules in the distutils.command subpackage. - - -This module supplies the abstract base class :class:`Command`. - - -.. class:: Command(dist) - - Abstract base class for defining command classes, the "worker bees" of the - Distutils. A useful analogy for command classes is to think of them as - subroutines with local variables called *options*. The options are declared - in :meth:`initialize_options` and defined (given their final values) in - :meth:`finalize_options`, both of which must be defined by every command - class. The distinction between the two is necessary because option values - might come from the outside world (command line, config file, ...), and any - options dependent on other options must be computed after these outside - influences have been processed --- hence :meth:`finalize_options`. The body - of the subroutine, where it does all its work based on the values of its - options, is the :meth:`run` method, which must also be implemented by every - command class. - - The class constructor takes a single argument *dist*, a :class:`Distribution` - instance. - - -.. % todo - -:mod:`distutils2.command.check` --- Check the metadata of a package -=================================================================== - -.. module:: distutils2.command.check - :synopsis: Check the metadata of a package - - -The ``check`` command performs some tests on the metadata of a package. -For example, it verifies that all required metadata are provided as -the arguments passed to the :func:`setup` function. - -.. % todo - -Creating a new Distutils command -================================ - -This section outlines the steps to create a new Distutils command. - -A new command lives in a module in the :mod:`distutils2.command` package. There -is a sample template in that directory called :file:`command_template`. Copy -this file to a new module with the same name as the new command you're -implementing. This module should implement a class with the same name as the -module (and the command). So, for instance, to create the command -``peel_banana`` (so that users can run ``setup.py peel_banana``), you'd copy -:file:`command_template` to :file:`distutils2/command/peel_banana.py`, then edit -it so that it's implementing the class :class:`peel_banana`, a subclass of -:class:`distutils2.cmd.Command`. - -Subclasses of :class:`Command` must define the following methods. - -.. method:: Command.initialize_options() - - Set default values for all the options that this command supports. Note that - these defaults may be overridden by other commands, by the setup script, by - config files, or by the command line. Thus, this is not the place to code - dependencies between options; generally, :meth:`initialize_options` - implementations are just a bunch of ``self.foo = None`` assignments. - - -.. method:: Command.finalize_options() - - Set final values for all the options that this command supports. This is - always called as late as possible, i.e. after any option assignments from the - command line or from other commands have been done. Thus, this is the place - to to code option dependencies: if *foo* depends on *bar*, then it is safe to - set *foo* from *bar* as long as *foo* still has the same value it was - assigned in :meth:`initialize_options`. - - -.. method:: Command.run() - - A command's raison d'etre: carry out the action it exists to perform, - controlled by the options initialized in :meth:`initialize_options`, - customized by other commands, the setup script, the command line, and config - files, and finalized in :meth:`finalize_options`. All terminal output and - filesystem interaction should be done by :meth:`run`. - - -.. attribute:: Command.sub_commands - - *sub_commands* formalizes the notion of a "family" of commands, - e.g. ``install`` as the parent with sub-commands ``install_lib``, - ``install_headers``, etc. The parent of a family of commands defines - *sub_commands* as a class attribute; it's a list of 2-tuples ``(command_name, - predicate)``, with *command_name* a string and *predicate* a function, a - string or ``None``. *predicate* is a method of the parent command that - determines whether the corresponding command is applicable in the current - situation. (E.g. ``install_headers`` is only applicable if we have any C - header files to install.) If *predicate* is ``None``, that command is always - applicable. - - *sub_commands* is usually defined at the *end* of a class, because - predicates can be methods of the class, so they must already have been - defined. The canonical example is the :command:`install` command. - - -:mod:`distutils2.command` --- Individual Distutils commands -=========================================================== - -.. module:: distutils2.command - :synopsis: This subpackage contains one module for each standard Distutils command. - - -.. % \subsubsection{Individual Distutils commands} -.. % todo - - -:mod:`distutils2.command.bdist` --- Build a binary installer -============================================================ - -.. module:: distutils2.command.bdist - :synopsis: Build a binary installer for a package - - -.. % todo - - -:mod:`distutils2.command.bdist_dumb` --- Build a "dumb" installer -================================================================= - -.. module:: distutils2.command.bdist_dumb - :synopsis: Build a "dumb" installer - a simple archive of files - - -.. % todo - - -:mod:`distutils2.command.bdist_msi` --- Build a Microsoft Installer binary package -================================================================================== - -.. module:: distutils2.command.bdist_msi - :synopsis: Build a binary distribution as a Windows MSI file - -.. class:: bdist_msi(Command) - - Builds a `Windows Installer`_ (.msi) binary package. - - .. _Windows Installer: http://msdn.microsoft.com/en-us/library/cc185688(VS.85).aspx - - In most cases, the ``bdist_msi`` installer is a better choice than the - ``bdist_wininst`` installer, because it provides better support for - Win64 platforms, allows administrators to perform non-interactive - installations, and allows installation through group policies. - - -:mod:`distutils2.command.bdist_wininst` --- Build a Windows installer -===================================================================== - -.. module:: distutils2.command.bdist_wininst - :synopsis: Build a Windows installer - - -.. % todo - - -:mod:`distutils2.command.sdist` --- Build a source distribution -=============================================================== - -.. module:: distutils2.command.sdist - :synopsis: Build a source distribution - - -.. % todo - - -:mod:`distutils2.command.build` --- Build all files of a package -================================================================ - -.. module:: distutils2.command.build - :synopsis: Build all files of a package - - -.. % todo - - -:mod:`distutils2.command.build_clib` --- Build any C libraries in a package -=========================================================================== - -.. module:: distutils2.command.build_clib - :synopsis: Build any C libraries in a package - - -.. % todo - - -:mod:`distutils2.command.build_ext` --- Build any extensions in a package -========================================================================= - -.. module:: distutils2.command.build_ext - :synopsis: Build any extensions in a package - - -.. % todo - - -:mod:`distutils2.command.build_py` --- Build the .py/.pyc files of a package -============================================================================ - -.. module:: distutils2.command.build_py - :synopsis: Build the .py/.pyc files of a package - - -.. class:: build_py(Command) - - -:mod:`distutils2.command.build_scripts` --- Build the scripts of a package -========================================================================== - -.. module:: distutils2.command.build_scripts - :synopsis: Build the scripts of a package - - -.. % todo - - -:mod:`distutils2.command.clean` --- Clean a package build area -============================================================== - -.. module:: distutils2.command.clean - :synopsis: Clean a package build area - - -.. % todo - - -:mod:`distutils2.command.config` --- Perform package configuration -================================================================== - -.. module:: distutils2.command.config - :synopsis: Perform package configuration - - -.. % todo - - -:mod:`distutils2.command.install` --- Install a package -======================================================= - -.. module:: distutils2.command.install - :synopsis: Install a package - - -.. % todo - - -:mod:`distutils2.command.install_data` --- Install data files from a package -============================================================================ - -.. module:: distutils2.command.install_data - :synopsis: Install data files from a package - - -.. % todo - - -:mod:`distutils2.command.install_headers` --- Install C/C++ header files from a package -======================================================================================= - -.. module:: distutils2.command.install_headers - :synopsis: Install C/C++ header files from a package - - -.. % todo - - -:mod:`distutils2.command.install_lib` --- Install library files from a package -============================================================================== - -.. module:: distutils2.command.install_lib - :synopsis: Install library files from a package - - -.. % todo - - -:mod:`distutils2.command.install_scripts` --- Install script files from a package -================================================================================= - -.. module:: distutils2.command.install_scripts - :synopsis: Install script files from a package - - -.. % todo - - -:mod:`distutils2.command.register` --- Register a module with the Python Package Index -====================================================================================== - -.. module:: distutils2.command.register - :synopsis: Register a module with the Python Package Index - - -The ``register`` command registers the package with the Python Package Index. -This is described in more detail in :PEP:`301`. - -.. % todo diff --git a/docs/source/distutils/builtdist.rst b/docs/source/distutils/builtdist.rst deleted file mode 100644 --- a/docs/source/distutils/builtdist.rst +++ /dev/null @@ -1,454 +0,0 @@ -.. _built-dist: - -**************************** -Creating Built Distributions -**************************** - -A "built distribution" is what you're probably used to thinking of either as a -"binary package" or an "installer" (depending on your background). It's not -necessarily binary, though, because it might contain only Python source code -and/or byte-code; and we don't call it a package, because that word is already -spoken for in Python. (And "installer" is a term specific to the world of -mainstream desktop systems.) - -A built distribution is how you make life as easy as possible for installers of -your module distribution: for users of RPM-based Linux systems, it's a binary -RPM; for Windows users, it's an executable installer; for Debian-based Linux -users, it's a Debian package; and so forth. Obviously, no one person will be -able to create built distributions for every platform under the sun, so the -Distutils are designed to enable module developers to concentrate on their -specialty---writing code and creating source distributions---while an -intermediary species called *packagers* springs up to turn source distributions -into built distributions for as many platforms as there are packagers. - -Of course, the module developer could be his own packager; or the packager could -be a volunteer "out there" somewhere who has access to a platform which the -original developer does not; or it could be software periodically grabbing new -source distributions and turning them into built distributions for as many -platforms as the software has access to. Regardless of who they are, a packager -uses the setup script and the :command:`bdist` command family to generate built -distributions. - -As a simple example, if I run the following command in the Distutils source -tree:: - - python setup.py bdist - -then the Distutils builds my module distribution (the Distutils itself in this -case), does a "fake" installation (also in the :file:`build` directory), and -creates the default type of built distribution for my platform. The default -format for built distributions is a "dumb" tar file on Unix, and a simple -executable installer on Windows. (That tar file is considered "dumb" because it -has to be unpacked in a specific location to work.) - -Thus, the above command on a Unix system creates -:file:`Distutils-1.0.{plat}.tar.gz`; unpacking this tarball from the right place -installs the Distutils just as though you had downloaded the source distribution -and run ``python setup.py install``. (The "right place" is either the root of -the filesystem or Python's :file:`{prefix}` directory, depending on the options -given to the :command:`bdist_dumb` command; the default is to make dumb -distributions relative to :file:`{prefix}`.) - -Obviously, for pure Python distributions, this isn't any simpler than just -running ``python setup.py install``\ ---but for non-pure distributions, which -include extensions that would need to be compiled, it can mean the difference -between someone being able to use your extensions or not. And creating "smart" -built distributions, such as an RPM package or an executable installer for -Windows, is far more convenient for users even if your distribution doesn't -include any extensions. - -The :command:`bdist` command has a :option:`--formats` option, similar to the -:command:`sdist` command, which you can use to select the types of built -distribution to generate: for example, :: - - python setup.py bdist --format=zip - -would, when run on a Unix system, create :file:`Distutils-1.0.{plat}.zip`\ ----again, this archive would be unpacked from the root directory to install the -Distutils. - -The available formats for built distributions are: - -+-------------+------------------------------+---------+ -| Format | Description | Notes | -+=============+==============================+=========+ -| ``gztar`` | gzipped tar file | (1),(3) | -| | (:file:`.tar.gz`) | | -+-------------+------------------------------+---------+ -| ``ztar`` | compressed tar file | \(3) | -| | (:file:`.tar.Z`) | | -+-------------+------------------------------+---------+ -| ``tar`` | tar file (:file:`.tar`) | \(3) | -+-------------+------------------------------+---------+ -| ``zip`` | zip file (:file:`.zip`) | (2),(4) | -+-------------+------------------------------+---------+ -| ``rpm`` | RPM | \(5) | -+-------------+------------------------------+---------+ -| ``pkgtool`` | Solaris :program:`pkgtool` | | -+-------------+------------------------------+---------+ -| ``sdux`` | HP-UX :program:`swinstall` | | -+-------------+------------------------------+---------+ -| ``rpm`` | RPM | \(5) | -+-------------+------------------------------+---------+ -| ``wininst`` | self-extracting ZIP file for | \(4) | -| | Windows | | -+-------------+------------------------------+---------+ -| ``msi`` | Microsoft Installer. | | -+-------------+------------------------------+---------+ - - -Notes: - -(1) - default on Unix - -(2) - default on Windows - -(3) - requires external utilities: :program:`tar` and possibly one of :program:`gzip`, - :program:`bzip2`, or :program:`compress` - -(4) - requires either external :program:`zip` utility or :mod:`zipfile` module (part - of the standard Python library since Python 1.6) - -(5) - requires external :program:`rpm` utility, version 3.0.4 or better (use ``rpm - --version`` to find out which version you have) - -You don't have to use the :command:`bdist` command with the :option:`--formats` -option; you can also use the command that directly implements the format you're -interested in. Some of these :command:`bdist` "sub-commands" actually generate -several similar formats; for instance, the :command:`bdist_dumb` command -generates all the "dumb" archive formats (``tar``, ``ztar``, ``gztar``, and -``zip``), and :command:`bdist_rpm` generates both binary and source RPMs. The -:command:`bdist` sub-commands, and the formats generated by each, are: - -+--------------------------+-----------------------+ -| Command | Formats | -+==========================+=======================+ -| :command:`bdist_dumb` | tar, ztar, gztar, zip | -+--------------------------+-----------------------+ -| :command:`bdist_rpm` | rpm, srpm | -+--------------------------+-----------------------+ -| :command:`bdist_wininst` | wininst | -+--------------------------+-----------------------+ -| :command:`bdist_msi` | msi | -+--------------------------+-----------------------+ - -The following sections give details on the individual :command:`bdist_\*` -commands. - - -.. _creating-dumb: - -Creating dumb built distributions -================================= - -.. XXX Need to document absolute vs. prefix-relative packages here, but first - I have to implement it! - - -.. _creating-rpms: - -Creating RPM packages -===================== - -The RPM format is used by many popular Linux distributions, including Red Hat, -SuSE, and Mandrake. If one of these (or any of the other RPM-based Linux -distributions) is your usual environment, creating RPM packages for other users -of that same distribution is trivial. Depending on the complexity of your module -distribution and differences between Linux distributions, you may also be able -to create RPMs that work on different RPM-based distributions. - -The usual way to create an RPM of your module distribution is to run the -:command:`bdist_rpm` command:: - - python setup.py bdist_rpm - -or the :command:`bdist` command with the :option:`--format` option:: - - python setup.py bdist --formats=rpm - -The former allows you to specify RPM-specific options; the latter allows you to -easily specify multiple formats in one run. If you need to do both, you can -explicitly specify multiple :command:`bdist_\*` commands and their options:: - - python setup.py bdist_rpm --packager="John Doe " \ - bdist_wininst --target-version="2.0" - -Creating RPM packages is driven by a :file:`.spec` file, much as using the -Distutils is driven by the setup script. To make your life easier, the -:command:`bdist_rpm` command normally creates a :file:`.spec` file based on the -information you supply in the setup script, on the command line, and in any -Distutils configuration files. Various options and sections in the -:file:`.spec` file are derived from options in the setup script as follows: - -+------------------------------------------+----------------------------------------------+ -| RPM :file:`.spec` file option or section | Distutils setup script option | -+==========================================+==============================================+ -| Name | :option:`name` | -+------------------------------------------+----------------------------------------------+ -| Summary (in preamble) | :option:`description` | -+------------------------------------------+----------------------------------------------+ -| Version | :option:`version` | -+------------------------------------------+----------------------------------------------+ -| Vendor | :option:`author` and :option:`author_email`, | -| | or --- & :option:`maintainer` and | -| | :option:`maintainer_email` | -+------------------------------------------+----------------------------------------------+ -| Copyright | :option:`license` | -+------------------------------------------+----------------------------------------------+ -| Url | :option:`url` | -+------------------------------------------+----------------------------------------------+ -| %description (section) | :option:`long_description` | -+------------------------------------------+----------------------------------------------+ - -Additionally, there are many options in :file:`.spec` files that don't have -corresponding options in the setup script. Most of these are handled through -options to the :command:`bdist_rpm` command as follows: - -+-------------------------------+-----------------------------+-------------------------+ -| RPM :file:`.spec` file option | :command:`bdist_rpm` option | default value | -| or section | | | -+===============================+=============================+=========================+ -| Release | :option:`release` | "1" | -+-------------------------------+-----------------------------+-------------------------+ -| Group | :option:`group` | "Development/Libraries" | -+-------------------------------+-----------------------------+-------------------------+ -| Vendor | :option:`vendor` | (see above) | -+-------------------------------+-----------------------------+-------------------------+ -| Packager | :option:`packager` | (none) | -+-------------------------------+-----------------------------+-------------------------+ -| Provides | :option:`provides` | (none) | -+-------------------------------+-----------------------------+-------------------------+ -| Requires | :option:`requires` | (none) | -+-------------------------------+-----------------------------+-------------------------+ -| Conflicts | :option:`conflicts` | (none) | -+-------------------------------+-----------------------------+-------------------------+ -| Obsoletes | :option:`obsoletes` | (none) | -+-------------------------------+-----------------------------+-------------------------+ -| Distribution | :option:`distribution_name` | (none) | -+-------------------------------+-----------------------------+-------------------------+ -| BuildRequires | :option:`build_requires` | (none) | -+-------------------------------+-----------------------------+-------------------------+ -| Icon | :option:`icon` | (none) | -+-------------------------------+-----------------------------+-------------------------+ - -Obviously, supplying even a few of these options on the command line would be -tedious and error-prone, so it's usually best to put them in the setup -configuration file, :file:`setup.cfg`\ ---see section :ref:`setup-config`. If -you distribute or package many Python module distributions, you might want to -put options that apply to all of them in your personal Distutils configuration -file (:file:`~/.pydistutils.cfg`). If you want to temporarily disable -this file, you can pass the --no-user-cfg option to setup.py. - -There are three steps to building a binary RPM package, all of which are -handled automatically by the Distutils: - -#. create a :file:`.spec` file, which describes the package (analogous to the - Distutils setup script; in fact, much of the information in the setup script - winds up in the :file:`.spec` file) - -#. create the source RPM - -#. create the "binary" RPM (which may or may not contain binary code, depending - on whether your module distribution contains Python extensions) - -Normally, RPM bundles the last two steps together; when you use the Distutils, -all three steps are typically bundled together. - -If you wish, you can separate these three steps. You can use the -:option:`--spec-only` option to make :command:`bdist_rpm` just create the -:file:`.spec` file and exit; in this case, the :file:`.spec` file will be -written to the "distribution directory"---normally :file:`dist/`, but -customizable with the :option:`--dist-dir` option. (Normally, the :file:`.spec` -file winds up deep in the "build tree," in a temporary directory created by -:command:`bdist_rpm`.) - -.. % \XXX{this isn't implemented yet---is it needed?!} -.. % You can also specify a custom \file{.spec} file with the -.. % \longprogramopt{spec-file} option; used in conjunction with -.. % \longprogramopt{spec-only}, this gives you an opportunity to customize -.. % the \file{.spec} file manually: -.. % -.. % \ begin{verbatim} -.. % > python setup.py bdist_rpm --spec-only -.. % # ...edit dist/FooBar-1.0.spec -.. % > python setup.py bdist_rpm --spec-file=dist/FooBar-1.0.spec -.. % \ end{verbatim} -.. % -.. % (Although a better way to do this is probably to override the standard -.. % \command{bdist\_rpm} command with one that writes whatever else you want -.. % to the \file{.spec} file.) - - -.. _creating-wininst: - -Creating Windows Installers -=========================== - -Executable installers are the natural format for binary distributions on -Windows. They display a nice graphical user interface, display some information -about the module distribution to be installed taken from the metadata in the -setup script, let the user select a few options, and start or cancel the -installation. - -Since the metadata is taken from the setup script, creating Windows installers -is usually as easy as running:: - - python setup.py bdist_wininst - -or the :command:`bdist` command with the :option:`--formats` option:: - - python setup.py bdist --formats=wininst - -If you have a pure module distribution (only containing pure Python modules and -packages), the resulting installer will be version independent and have a name -like :file:`foo-1.0.win32.exe`. These installers can even be created on Unix -platforms or Mac OS X. - -If you have a non-pure distribution, the extensions can only be created on a -Windows platform, and will be Python version dependent. The installer filename -will reflect this and now has the form :file:`foo-1.0.win32-py2.0.exe`. You -have to create a separate installer for every Python version you want to -support. - -.. TODO Add :term: markup to bytecode when merging into the stdlib - -The installer will try to compile pure modules into bytecode after installation -on the target system in normal and optimizing mode. If you don't want this to -happen for some reason, you can run the :command:`bdist_wininst` command with -the :option:`--no-target-compile` and/or the :option:`--no-target-optimize` -option. - -By default the installer will display the cool "Python Powered" logo when it is -run, but you can also supply your own 152x261 bitmap which must be a Windows -:file:`.bmp` file with the :option:`--bitmap` option. - -The installer will also display a large title on the desktop background window -when it is run, which is constructed from the name of your distribution and the -version number. This can be changed to another text by using the -:option:`--title` option. - -The installer file will be written to the "distribution directory" --- normally -:file:`dist/`, but customizable with the :option:`--dist-dir` option. - -.. _cross-compile-windows: - -Cross-compiling on Windows -========================== - -Starting with Python 2.6, distutils is capable of cross-compiling between -Windows platforms. In practice, this means that with the correct tools -installed, you can use a 32bit version of Windows to create 64bit extensions -and vice-versa. - -To build for an alternate platform, specify the :option:`--plat-name` option -to the build command. Valid values are currently 'win32', 'win-amd64' and -'win-ia64'. For example, on a 32bit version of Windows, you could execute:: - - python setup.py build --plat-name=win-amd64 - -to build a 64bit version of your extension. The Windows Installers also -support this option, so the command:: - - python setup.py build --plat-name=win-amd64 bdist_wininst - -would create a 64bit installation executable on your 32bit version of Windows. - -To cross-compile, you must download the Python source code and cross-compile -Python itself for the platform you are targetting - it is not possible from a -binary installtion of Python (as the .lib etc file for other platforms are -not included.) In practice, this means the user of a 32 bit operating -system will need to use Visual Studio 2008 to open the -:file:`PCBuild/PCbuild.sln` solution in the Python source tree and build the -"x64" configuration of the 'pythoncore' project before cross-compiling -extensions is possible. - -Note that by default, Visual Studio 2008 does not install 64bit compilers or -tools. You may need to reexecute the Visual Studio setup process and select -these tools (using Control Panel->[Add/Remove] Programs is a convenient way to -check or modify your existing install.) - -.. _postinstallation-script: - -The Postinstallation script ---------------------------- - -Starting with Python 2.3, a postinstallation script can be specified with the -:option:`--install-script` option. The basename of the script must be -specified, and the script filename must also be listed in the scripts argument -to the setup function. - -This script will be run at installation time on the target system after all the -files have been copied, with ``argv[1]`` set to :option:`-install`, and again at -uninstallation time before the files are removed with ``argv[1]`` set to -:option:`-remove`. - -The installation script runs embedded in the windows installer, every output -(``sys.stdout``, ``sys.stderr``) is redirected into a buffer and will be -displayed in the GUI after the script has finished. - -Some functions especially useful in this context are available as additional -built-in functions in the installation script. - - -.. function:: directory_created(path) - file_created(path) - - These functions should be called when a directory or file is created by the - postinstall script at installation time. It will register *path* with the - uninstaller, so that it will be removed when the distribution is uninstalled. - To be safe, directories are only removed if they are empty. - - -.. function:: get_special_folder_path(csidl_string) - - This function can be used to retrieve special folder locations on Windows like - the Start Menu or the Desktop. It returns the full path to the folder. - *csidl_string* must be one of the following strings:: - - "CSIDL_APPDATA" - - "CSIDL_COMMON_STARTMENU" - "CSIDL_STARTMENU" - - "CSIDL_COMMON_DESKTOPDIRECTORY" - "CSIDL_DESKTOPDIRECTORY" - - "CSIDL_COMMON_STARTUP" - "CSIDL_STARTUP" - - "CSIDL_COMMON_PROGRAMS" - "CSIDL_PROGRAMS" - - "CSIDL_FONTS" - - If the folder cannot be retrieved, :exc:`OSError` is raised. - - Which folders are available depends on the exact Windows version, and probably - also the configuration. For details refer to Microsoft's documentation of the - c:function:`SHGetSpecialFolderPath` function. - - -.. function:: create_shortcut(target, description, filename[, arguments[, workdir[, iconpath[, iconindex]]]]) - - This function creates a shortcut. *target* is the path to the program to be - started by the shortcut. *description* is the description of the shortcut. - *filename* is the title of the shortcut that the user will see. *arguments* - specifies the command-line arguments, if any. *workdir* is the working directory - for the program. *iconpath* is the file containing the icon for the shortcut, - and *iconindex* is the index of the icon in the file *iconpath*. Again, for - details consult the Microsoft documentation for the :class:`IShellLink` - interface. - - -Vista User Access Control (UAC) -=============================== - -Starting with Python 2.6, bdist_wininst supports a :option:`--user-access-control` -option. The default is 'none' (meaning no UAC handling is done), and other -valid values are 'auto' (meaning prompt for UAC elevation if Python was -installed for all users) and 'force' (meaning always prompt for elevation). diff --git a/docs/source/distutils/commandhooks.rst b/docs/source/distutils/commandhooks.rst deleted file mode 100644 --- a/docs/source/distutils/commandhooks.rst +++ /dev/null @@ -1,31 +0,0 @@ -============= -Command hooks -============= - -Distutils2 provides a way of extending its commands by the use of pre- and -post- command hooks. The hooks are simple Python functions (or any callable -objects) and are specified in the config file using their full qualified names. -The pre-hooks are run after the command is finalized (its options are -processed), but before it is run. The post-hooks are run after the command -itself. Both types of hooks receive an instance of the command object. - -Sample usage of hooks -===================== - -Firstly, you need to make sure your hook is present in the path. This is usually -done by dropping them to the same folder where `setup.py` file lives :: - - # file: myhooks.py - def my_install_hook(install_cmd): - print "Oh la la! Someone is installing my project!" - -Then, you need to point to it in your `setup.cfg` file, under the appropriate -command section :: - - [install] - pre-hook.project = myhooks.my_install_hook - -The hooks defined in different config files (system-wide, user-wide and -package-wide) do not override each other as long as they are specified with -different aliases (additional names after the dot). The alias in the example -above is ``project``. diff --git a/docs/source/distutils/commandref.rst b/docs/source/distutils/commandref.rst deleted file mode 100644 --- a/docs/source/distutils/commandref.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. _reference: - -***************** -Command Reference -***************** - -.. % \section{Building modules: the \protect\command{build} command family} -.. % \label{build-cmds} -.. % \subsubsection{\protect\command{build}} -.. % \label{build-cmd} -.. % \subsubsection{\protect\command{build\_py}} -.. % \label{build-py-cmd} -.. % \subsubsection{\protect\command{build\_ext}} -.. % \label{build-ext-cmd} -.. % \subsubsection{\protect\command{build\_clib}} -.. % \label{build-clib-cmd} - - -.. _install-cmd: - -Installing modules: the :command:`install` command family -========================================================= - -The install command ensures that the build commands have been run and then runs -the subcommands :command:`install_lib`, :command:`install_data` and -:command:`install_scripts`. - -.. % \subsubsection{\protect\command{install\_lib}} -.. % \label{install-lib-cmd} - - -.. _install-data-cmd: - -:command:`install_data` ------------------------ - -This command installs all data files provided with the distribution. - - -.. _install-scripts-cmd: - -:command:`install_scripts` --------------------------- - -This command installs all (Python) scripts in the distribution. - -.. % \subsection{Cleaning up: the \protect\command{clean} command} -.. % \label{clean-cmd} - - -.. % \section{Creating a built distribution: the -.. % \protect\command{bdist} command family} -.. % \label{bdist-cmds} - -.. % \subsection{\protect\command{bdist}} -.. % \subsection{\protect\command{bdist\_dumb}} -.. % \subsection{\protect\command{bdist\_rpm}} -.. % \subsection{\protect\command{bdist\_wininst}} - - diff --git a/docs/source/distutils/configfile.rst b/docs/source/distutils/configfile.rst deleted file mode 100644 --- a/docs/source/distutils/configfile.rst +++ /dev/null @@ -1,131 +0,0 @@ -.. _setup-config: - -************************************ -Writing the Setup Configuration File -************************************ - -Often, it's not possible to write down everything needed to build a distribution -*a priori*: you may need to get some information from the user, or from the -user's system, in order to proceed. As long as that information is fairly -simple---a list of directories to search for C header files or libraries, for -example---then providing a configuration file, :file:`setup.cfg`, for users to -edit is a cheap and easy way to solicit it. Configuration files also let you -provide default values for any command option, which the installer can then -override either on the command line or by editing the config file. - -The setup configuration file is a useful middle-ground between the setup script ----which, ideally, would be opaque to installers [#]_---and the command line to -the setup script, which is outside of your control and entirely up to the -installer. In fact, :file:`setup.cfg` (and any other Distutils configuration -files present on the target system) are processed after the contents of the -setup script, but before the command line. This has several useful -consequences: - -.. If you have more advanced needs, such as determining which extensions to - build based on what capabilities are present on the target system, then you - need the Distutils auto-configuration facility. This started to appear in - Distutils 0.9 but, as of this writing, isn't mature or stable enough yet - for real-world use. - -* installers can override some of what you put in :file:`setup.py` by editing - :file:`setup.cfg` - -* you can provide non-standard defaults for options that are not easily set in - :file:`setup.py` - -* installers can override anything in :file:`setup.cfg` using the command-line - options to :file:`setup.py` - -The basic syntax of the configuration file is simple:: - - [command] - option = value - ... - -where *command* is one of the Distutils commands (e.g. :command:`build_py`, -:command:`install`), and *option* is one of the options that command supports. -Any number of options can be supplied for each command, and any number of -command sections can be included in the file. Blank lines are ignored, as are -comments, which run from a ``'#'`` character until the end of the line. Long -option values can be split across multiple lines simply by indenting the -continuation lines. - -You can find out the list of options supported by a particular command with the -universal :option:`--help` option, e.g. :: - - > python setup.py --help build_ext - [...] - Options for 'build_ext' command: - --build-lib (-b) directory for compiled extension modules - --build-temp (-t) directory for temporary files (build by-products) - --inplace (-i) ignore build-lib and put compiled extensions into the - source directory alongside your pure Python modules - --include-dirs (-I) list of directories to search for header files - --define (-D) C preprocessor macros to define - --undef (-U) C preprocessor macros to undefine - --swig-opts list of SWIG command-line options - [...] - -.. XXX do we want to support ``setup.py --help metadata``? - -Note that an option spelled :option:`--foo-bar` on the command line is spelled -:option:`foo_bar` in configuration files. - -For example, say you want your extensions to be built "in-place"---that is, you -have an extension :mod:`pkg.ext`, and you want the compiled extension file -(:file:`ext.so` on Unix, say) to be put in the same source directory as your -pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the -:option:`--inplace` option on the command line to ensure this:: - - python setup.py build_ext --inplace - -But this requires that you always specify the :command:`build_ext` command -explicitly, and remember to provide :option:`--inplace`. An easier way is to -"set and forget" this option, by encoding it in :file:`setup.cfg`, the -configuration file for this distribution:: - - [build_ext] - inplace = 1 - -This will affect all builds of this module distribution, whether or not you -explicitly specify :command:`build_ext`. If you include :file:`setup.cfg` in -your source distribution, it will also affect end-user builds---which is -probably a bad idea for this option, since always building extensions in-place -would break installation of the module distribution. In certain peculiar cases, -though, modules are built right in their installation directory, so this is -conceivably a useful ability. (Distributing extensions that expect to be built -in their installation directory is almost always a bad idea, though.) - -Another example: certain commands take a lot of options that don't change from -run to run; for example, :command:`bdist_rpm` needs to know everything required -to generate a "spec" file for creating an RPM distribution. Some of this -information comes from the setup script, and some is automatically generated by -the Distutils (such as the list of files installed). But some of it has to be -supplied as options to :command:`bdist_rpm`, which would be very tedious to do -on the command line for every run. Hence, here is a snippet from the Distutils' -own :file:`setup.cfg`:: - - [bdist_rpm] - release = 1 - packager = Greg Ward - doc_files = CHANGES.txt - README.txt - USAGE.txt - doc/ - examples/ - -Note that the :option:`doc_files` option is simply a whitespace-separated string -split across multiple lines for readability. - - -.. seealso:: - - :ref:`inst-config-syntax` in "Installing Python Projects" - More information on the configuration files is available in the manual for - system administrators. - - -.. rubric:: Footnotes - -.. [#] This ideal probably won't be achieved until auto-configuration is fully - supported by the Distutils. diff --git a/docs/source/distutils/examples.rst b/docs/source/distutils/examples.rst deleted file mode 100644 --- a/docs/source/distutils/examples.rst +++ /dev/null @@ -1,332 +0,0 @@ -.. _examples: - -******** -Examples -******** - -This chapter provides a number of basic examples to help get started with -Distutils2. - - -.. _pure-mod: - -Pure Python distribution (by module) -==================================== - -If you're just distributing a couple of modules, especially if they don't live -in a particular package, you can specify them individually using the -:option:`py_modules` option in the setup script. - -In the simplest case, you'll have two files to worry about: a setup script and -the single module you're distributing, :file:`foo.py` in this example:: - - / - setup.py - foo.py - -(In all diagrams in this section, ** will refer to the distribution root -directory.) A minimal setup script to describe this situation would be:: - - from distutils2.core import setup - setup(name='foo', - version='1.0', - py_modules=['foo']) - -Note that the name of the distribution is specified independently with the -:option:`name` option, and there's no rule that says it has to be the same as -the name of the sole module in the distribution (although that's probably a good -convention to follow). However, the distribution name is used to generate -filenames, so you should stick to letters, digits, underscores, and hyphens. - -Since :option:`py_modules` is a list, you can of course specify multiple -modules, e.g. if you're distributing modules :mod:`foo` and :mod:`bar`, your -setup might look like this:: - - / - setup.py - foo.py - bar.py - -and the setup script might be :: - - from distutils2.core import setup - setup(name='foobar', - version='1.0', - py_modules=['foo', 'bar']) - -You can put module source files into another directory, but if you have enough -modules to do that, it's probably easier to specify modules by package rather -than listing them individually. - - -.. _pure-pkg: - -Pure Python distribution (by package) -===================================== - -If you have more than a couple of modules to distribute, especially if they are -in multiple packages, it's probably easier to specify whole packages rather than -individual modules. This works even if your modules are not in a package; you -can just tell the Distutils to process modules from the root package, and that -works the same as any other package (except that you don't have to have an -:file:`__init__.py` file). - -The setup script from the last example could also be written as :: - - from distutils2.core import setup - setup(name='foobar', - version='1.0', - packages=['']) - -(The empty string stands for the root package.) - -If those two files are moved into a subdirectory, but remain in the root -package, e.g.:: - - / - setup.py - src/ - foo.py - bar.py - -then you would still specify the root package, but you have to tell the -Distutils where source files in the root package live:: - - from distutils2.core import setup - setup(name='foobar', - version='1.0', - package_dir={'': 'src'}, - packages=['']) - -More typically, though, you will want to distribute multiple modules in the same -package (or in sub-packages). For example, if the :mod:`foo` and :mod:`bar` -modules belong in package :mod:`foobar`, one way to lay out your source tree is - -:: - - / - setup.py - foobar/ - __init__.py - foo.py - bar.py - -This is in fact the default layout expected by the Distutils, and the one that -requires the least work to describe in your setup script:: - - from distutils2.core import setup - setup(name='foobar', - version='1.0', - packages=['foobar']) - -If you want to put modules in directories not named for their package, then you -need to use the :option:`package_dir` option again. For example, if the -:file:`src` directory holds modules in the :mod:`foobar` package:: - - / - setup.py - src/ - __init__.py - foo.py - bar.py - -an appropriate setup script would be :: - - from distutils2.core import setup - setup(name='foobar', - version='1.0', - package_dir={'foobar': 'src'}, - packages=['foobar']) - -Or, you might put modules from your main package right in the distribution -root:: - - / - setup.py - __init__.py - foo.py - bar.py - -in which case your setup script would be :: - - from distutils2.core import setup - setup(name='foobar', - version='1.0', - package_dir={'foobar': ''}, - packages=['foobar']) - -(The empty string also stands for the current directory.) - -If you have sub-packages, they must be explicitly listed in :option:`packages`, -but any entries in :option:`package_dir` automatically extend to sub-packages. -(In other words, the Distutils does *not* scan your source tree, trying to -figure out which directories correspond to Python packages by looking for -:file:`__init__.py` files.) Thus, if the default layout grows a sub-package:: - - / - setup.py - foobar/ - __init__.py - foo.py - bar.py - subfoo/ - __init__.py - blah.py - -then the corresponding setup script would be :: - - from distutils2.core import setup - setup(name='foobar', - version='1.0', - packages=['foobar', 'foobar.subfoo']) - -(Again, the empty string in :option:`package_dir` stands for the current -directory.) - - -.. _single-ext: - -Single extension module -======================= - -Extension modules are specified using the :option:`ext_modules` option. -:option:`package_dir` has no effect on where extension source files are found; -it only affects the source for pure Python modules. The simplest case, a -single extension module in a single C source file, is:: - - / - setup.py - foo.c - -If the :mod:`foo` extension belongs in the root package, the setup script for -this could be :: - - from distutils2.core import setup, Extension - setup(name='foobar', - version='1.0', - ext_modules=[Extension('foo', ['foo.c'])]) - -If the extension actually belongs in a package, say :mod:`foopkg`, then - -With exactly the same source tree layout, this extension can be put in the -:mod:`foopkg` package simply by changing the name of the extension:: - - from distutils2.core import setup, Extension - setup(name='foobar', - version='1.0', - packages=['foopkg'], - ext_modules=[Extension('foopkg.foo', ['foo.c'])]) - - -Checking metadata -================= - -The ``check`` command allows you to verify if your project's metadata -meets the minimum requirements to build a distribution. - -To run it, just call it using your :file:`setup.py` script. If something is -missing, ``check`` will display a warning. - -Let's take an example with a simple script:: - - from distutils2.core import setup - - setup(name='foobar') - -Running the ``check`` command will display some warnings:: - - $ python setup.py check - running check - warning: check: missing required metadata: version, home_page - warning: check: missing metadata: either (author and author_email) or - (maintainer and maintainer_email) must be supplied - - -If you use the reStructuredText syntax in the ``long_description`` field and -`Docutils `_ is installed you can check if -the syntax is fine with the ``check`` command, using the ``restructuredtext`` -option. - -For example, if the :file:`setup.py` script is changed like this:: - - from distutils2.core import setup - - desc = """\ - Welcome to foobar! - =============== - - This is the description of the ``foobar`` project. - """ - - setup(name='foobar', - version='1.0', - author=u'Tarek Ziad?', - author_email='tarek at ziade.org', - summary='Foobar utilities' - description=desc, - home_page='http://example.com') - -Where the long description is broken, ``check`` will be able to detect it -by using the :mod:`docutils` parser:: - - $ python setup.py check --restructuredtext - running check - warning: check: Title underline too short. (line 2) - warning: check: Could not finish the parsing. - - -.. _reading-metadata: - -Reading the metadata -==================== - -The :func:`distutils2.core.setup` function provides a command-line interface -that allows you to query the metadata fields of a project through the -:file:`setup.py` script of a given project:: - - $ python setup.py --name - foobar - -This call reads the ``name`` metadata by running the -:func:`distutils2.core.setup` function. When a source or binary -distribution is created with Distutils, the metadata fields are written -in a static file called :file:`PKG-INFO`. When a Distutils-based project is -installed in Python, the :file:`PKG-INFO` file is copied alongside the modules -and packages of the distribution under :file:`NAME-VERSION-pyX.X.egg-info`, -where ``NAME`` is the name of the project, ``VERSION`` its version as defined -in the Metadata, and ``pyX.X`` the major and minor version of Python like -``2.7`` or ``3.2``. - -You can read back this static file, by using the -:class:`distutils2.dist.Metadata` class and its -:func:`read_pkg_file` method:: - - >>> from distutils2.metadata import Metadata - >>> metadata = Metadata() - >>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info')) - >>> metadata.name - 'distribute' - >>> metadata.version - '0.6.8' - >>> metadata.description - 'Easily download, build, install, upgrade, and uninstall Python packages' - -Notice that the class can also be instantiated with a metadata file path to -loads its values:: - - >>> pkg_info_path = 'distribute-0.6.8-py2.7.egg-info' - >>> Metadata(pkg_info_path).name - 'distribute' - - -.. XXX These comments have been here for at least ten years. Write the - sections or delete the comments (we can maybe ask Greg Ward about - the planned contents). (Unindent to make them section titles) - - .. multiple-ext:: - - Multiple extension modules - ========================== - - Putting it all together - ======================= diff --git a/docs/source/distutils/extending.rst b/docs/source/distutils/extending.rst deleted file mode 100644 --- a/docs/source/distutils/extending.rst +++ /dev/null @@ -1,95 +0,0 @@ -.. _extending-distutils: - -******************* -Extending Distutils -******************* - -Distutils can be extended in various ways. Most extensions take the form of new -commands or replacements for existing commands. New commands may be written to -support new types of platform-specific packaging, for example, while -replacements for existing commands may be made to modify details of how the -command operates on a package. - -Most extensions of the distutils are made within :file:`setup.py` scripts that -want to modify existing commands; many simply add a few file extensions that -should be copied into packages in addition to :file:`.py` files as a -convenience. - -Most distutils command implementations are subclasses of the -:class:`distutils2.cmd.Command` class. New commands may directly inherit from -:class:`Command`, while replacements often derive from :class:`Command` -indirectly, directly subclassing the command they are replacing. Commands are -required to derive from :class:`Command`. - -.. .. _extend-existing: - Extending existing commands - =========================== - - -.. .. _new-commands: - Writing new commands - ==================== - - -Integrating new commands -======================== - -There are different ways to integrate new command implementations into -distutils. The most difficult is to lobby for the inclusion of the new features -in distutils itself, and wait for (and require) a version of Python that -provides that support. This is really hard for many reasons. - -The most common, and possibly the most reasonable for most needs, is to include -the new implementations with your :file:`setup.py` script, and cause the -:func:`distutils2.core.setup` function use them:: - - from distutils2.core import setup - from distutils2.command.build_py import build_py as _build_py - - class build_py(_build_py): - """Specialized Python source builder.""" - - # implement whatever needs to be different... - - setup(..., cmdclass={'build_py': build_py}) - -This approach is most valuable if the new implementations must be used to use a -particular package, as everyone interested in the package will need to have the -new command implementation. - -Beginning with Python 2.4, a third option is available, intended to allow new -commands to be added which can support existing :file:`setup.py` scripts without -requiring modifications to the Python installation. This is expected to allow -third-party extensions to provide support for additional packaging systems, but -the commands can be used for anything distutils commands can be used for. A new -configuration option, :option:`command_packages` (command-line option -:option:`--command-packages`), can be used to specify additional packages to be -searched for modules implementing commands. Like all distutils options, this -can be specified on the command line or in a configuration file. This option -can only be set in the ``[global]`` section of a configuration file, or before -any commands on the command line. If set in a configuration file, it can be -overridden from the command line; setting it to an empty string on the command -line causes the default to be used. This should never be set in a configuration -file provided with a package. - -This new option can be used to add any number of packages to the list of -packages searched for command implementations; multiple package names should be -separated by commas. When not specified, the search is only performed in the -:mod:`distutils2.command` package. When :file:`setup.py` is run with the option -:option:`--command-packages` :option:`distcmds,buildcmds`, however, the packages -:mod:`distutils2.command`, :mod:`distcmds`, and :mod:`buildcmds` will be searched -in that order. New commands are expected to be implemented in modules of the -same name as the command by classes sharing the same name. Given the example -command-line option above, the command :command:`bdist_openpkg` could be -implemented by the class :class:`distcmds.bdist_openpkg.bdist_openpkg` or -:class:`buildcmds.bdist_openpkg.bdist_openpkg`. - - -Adding new distribution types -============================= - -Commands that create distributions (files in the :file:`dist/` directory) need -to add ``(command, filename)`` pairs to ``self.distribution.dist_files`` so that -:command:`upload` can upload it to PyPI. The *filename* in the pair contains no -path information, only the name of the file itself. In dry-run mode, pairs -should still be added to represent what would have been created. diff --git a/docs/source/distutils/index.rst b/docs/source/distutils/index.rst deleted file mode 100644 --- a/docs/source/distutils/index.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. _distutils-index: - -############################### - Distributing Python Projects -############################### - -:Authors: Greg Ward, Anthony Baxter and Distutils2 contributors -:Email: distutils-sig at python.org -:Release: |version| -:Date: |today| - -This document describes the Python Distribution Utilities ("Distutils2") from -the developer's point of view, describing how to use the Distutils to make -Python applications, packages or modules easily available to a wider audience -with very little overhead for build/release/install mechanics. - -.. toctree:: - :maxdepth: 2 - :numbered: - - introduction - setupscript - configfile - sourcedist - builtdist - packageindex - uploading - examples - extending - commandhooks - commandref - newcommands - apiref diff --git a/docs/source/distutils/introduction.rst b/docs/source/distutils/introduction.rst deleted file mode 100644 --- a/docs/source/distutils/introduction.rst +++ /dev/null @@ -1,193 +0,0 @@ -.. _distutils-intro: - -***************************** -An Introduction to Distutils2 -***************************** - -This document covers using Distutils2 to distribute your Python modules, -concentrating on the role of developer/distributor. If you're looking for -information on installing Python modules you should refer to the -:ref:`install-index` chapter. - -Throughout this documentation, the terms "Distutils", "the Distutils" and -"Distutils2" will be used interchangeably. - -.. _distutils-concepts: - -Concepts & Terminology -====================== - -Using Distutils is quite simple both for module developers and for -users/administrators installing third-party modules. As a developer, your -responsibilities (apart from writing solid, well-documented and well-tested -code, of course!) are: - -* writing a setup script (:file:`setup.py` by convention) - -* (optional) writing a setup configuration file - -* creating a source distribution - -* (optional) creating one or more "built" (binary) distributions of your - project - -All of these tasks are covered in this document. - -Not all module developers have access to multiple platforms, so one cannot -expect them to create buildt distributions for every platform. To remedy -this, it is hoped that intermediaries called *packagers* will arise to address -this need. Packagers take source distributions released by module developers, -build them on one or more platforms and release the resulting built -distributions. Thus, users on a greater range of platforms will be able to -install the most popular Python modules in the most natural way for their -platform without having to run a setup script or compile a single line of code. - - -.. _distutils-simple-example: - -A Simple Example -================ - -A setup script is usually quite simple, although since it's written in Python -there are no arbitrary limits to what you can do with it, though you should be -careful about putting expensive operations in your setup script. -Unlike, say, Autoconf-style configure scripts the setup script may be run -multiple times in the course of building and installing a module -distribution. - -If all you want to do is distribute a module called :mod:`foo`, contained in a -file :file:`foo.py`, then your setup script can be as simple as:: - - from distutils2.core import setup - setup(name='foo', - version='1.0', - py_modules=['foo']) - -Some observations: - -* most information that you supply to the Distutils is supplied as keyword - arguments to the :func:`setup` function - -* those keyword arguments fall into two categories: package metadata (name, - version number, etc.) and information about what's in the package (a list - of pure Python modules in this case) - -* modules are specified by module name, not filename (the same will hold true - for packages and extensions) - -* it's recommended that you supply a little more metadata than we have in the - example. In particular your name, email address and a URL for the - project if appropriate (see section :ref:`setup-script` for an example) - -To create a source distribution for this module you would create a setup -script, :file:`setup.py`, containing the above code and run:: - - python setup.py sdist - -which will create an archive file (e.g., tarball on Unix, ZIP file on Windows) -containing your setup script :file:`setup.py`, and your module :file:`foo.py`. -The archive file will be named :file:`foo-1.0.tar.gz` (or :file:`.zip`), and -will unpack into a directory :file:`foo-1.0`. - -If an end-user wishes to install your :mod:`foo` module all he has to do is -download :file:`foo-1.0.tar.gz` (or :file:`.zip`), unpack it, and from the -:file:`foo-1.0` directory run :: - - python setup.py install - -which will copy :file:`foo.py` to the appropriate directory for -third-party modules in their Python installation. - -This simple example demonstrates some fundamental concepts of Distutils. -First, both developers and installers have the same basic user interface, i.e. -the setup script. The difference is which Distutils *commands* they use: the -:command:`sdist` command is almost exclusively for module developers, while -:command:`install` is more often used by installers (although some developers -will want to install their own code occasionally). - -If you want to make things really easy for your users, you can create more -than one built distributions for them. For instance, if you are running on a -Windows machine and want to make things easy for other Windows users, you can -create an executable installer (the most appropriate type of built distribution -for this platform) with the :command:`bdist_wininst` command. For example:: - - python setup.py bdist_wininst - -will create an executable installer, :file:`foo-1.0.win32.exe`, in the current -directory. You can find out what distribution formats are available at any time -by running :: - - python setup.py bdist --help-formats - - -.. _python-terms: - -General Python terminology -========================== - -If you're reading this document, you probably have a good idea of what Python -modules, extensions and so forth are. Nevertheless, just to be sure that -everyone is on the same page, here's a quick overview of Python terms: - -module - The basic unit of code reusability in Python: a block of code imported by - some other code. Three types of modules are important to us here: pure - Python modules, extension modules and packages. - -pure Python module - A module written in Python and contained in a single :file:`.py` file (and - possibly associated :file:`.pyc` and/or :file:`.pyo` files). Sometimes - referred to as a "pure module." - -extension module - A module written in the low-level language of the Python implementation: C/C++ - for Python, Java for Jython. Typically contained in a single dynamically - loaded pre-compiled file, e.g. a shared object (:file:`.so`) file for Python - extensions on Unix, a DLL (given the :file:`.pyd` extension) for Python - extensions on Windows, or a Java class file for Jython extensions. Note that - currently Distutils only handles C/C++ extensions for Python. - -package - A module that contains other modules, typically contained in a directory of - the filesystem and distinguished from other directories by the presence of a - file :file:`__init__.py`. - -root package - The root of the hierarchy of packages. (This isn't really a package, - since it doesn't have an :file:`__init__.py` file. But... we have to - call it something, right?) The vast majority of the standard library is - in the root package, as are many small standalone third-party modules that - don't belong to a larger module collection. Unlike regular packages, - modules in the root package can be found in many directories: in fact, - every directory listed in ``sys.path`` contributes modules to the root - package. - - -.. _distutils-term: - -Distutils-specific terminology -============================== - -The following terms apply more specifically to the domain of distributing Python -modules using Distutils: - -module distribution - A collection of Python modules distributed together as a single downloadable - resource and meant to be installed all as one. Examples of some well-known - module distributions are Numeric Python, PyXML, PIL (the Python Imaging - Library) or mxBase. (Module distributions would be called a *package*, - except that term is already taken in the Python context: a single module - distribution may contain zero, one, or many Python packages.) - -pure module distribution - A module distribution that contains only pure Python modules and packages. - Sometimes referred to as a "pure distribution." - -non-pure module distribution - A module distribution that contains at least one extension module. Sometimes - referred to as a "non-pure distribution." - -distribution root - The top-level directory of your source tree (or source distribution). The - directory where :file:`setup.py` exists. Generally :file:`setup.py` will - be run from this directory. diff --git a/docs/source/distutils/newcommands.rst b/docs/source/distutils/newcommands.rst deleted file mode 100644 --- a/docs/source/distutils/newcommands.rst +++ /dev/null @@ -1,144 +0,0 @@ -======== -Commands -======== - -Distutils2 provides a set of commands that are not present in distutils itself. -You might recognize some of them from other projects, like Distribute or -Setuptools. - -``test`` - Build package and run a unittest suite -================================================= - -When doing test-driven development, or running automated builds that need -testing before they are deployed for downloading or use, it's often useful -to be able to run a project's unit tests without actually deploying the project -anywhere. The ``test`` command runs -project's unit tests without actually deploying it, by temporarily putting the -project's source on ``sys.path``, after first running ``build_ext -i`` -to ensure that any C extensions are built. - -You can use this command in one of two ways: either by specifying a -unittest-compatible test suite for your project (or any callable that returns -it) or by passing a test runner function that will run your tests and display -results in the console. Both options: ``suite`` and ``runner`` accept dotted -names that will be resolved into actual objects. - -If none of these options are specified, distutils2 will try to perform test -discovery using either unittest2 (if installed) or unittest (if running on -recent Python version). - -``--suite=NAME, -s NAME`` - Specify the test suite (or module, class, or method) to be run - (for example ``my_package.tests.all_tests``). The default for this option can be - set by in your ``setup.cfg`` file. - -.. code-block:: ini - - [test] - suite = my_package.tests.all_tests - -``--runner=NAME, -r NAME`` - Specify the test runner to be called. - - -``upload`` - Upload source and/or binary distributions to PyPI -============================================================== - -The Python Package Index (PyPI) not only stores the package info, but also the -package data if the author of the package wishes to. The distutils command -:command:`upload` pushes the distribution files to PyPI. - -The command is invoked immediately after building one or more distribution -files. For example, the command :: - - python setup.py sdist bdist_wininst upload - -will cause the source distribution and the Windows installer to be uploaded to -PyPI. Note that these will be uploaded even if they are built using an earlier -invocation of :file:`setup.py`, but that only distributions named on the command -line for the invocation including the :command:`upload` command are uploaded. - -The :command:`upload` command uses the username, password, and repository URL -from the :file:`$HOME/.pypirc` file . If a :command:`register` command was -previously called in the same command, and if the password was entered in the -prompt, :command:`upload` will reuse the entered password. This is useful if -you do not want to store a clear text password in the :file:`$HOME/.pypirc` -file. - -The ``upload`` command has a few options worth noting: - -``--sign, -s`` - Sign each uploaded file using GPG (GNU Privacy Guard). The ``gpg`` program - must be available for execution on the system ``PATH``. - -``--identity=NAME, -i NAME`` - Specify the identity or key name for GPG to use when signing. The value of - this option will be passed through the ``--local-user`` option of the - ``gpg`` program. - -``--show-response`` - Display the full response text from server; this is useful for debugging - PyPI problems. - -``--repository=URL, -r URL`` - The URL of the repository to upload to. Defaults to - http://pypi.python.org/pypi (i.e., the main PyPI installation). - - -``upload_docs`` - Upload package documentation to PyPI -====================================================== - -PyPI now supports uploading project documentation to the dedicated URL -http://packages.python.org//. - -The ``upload_docs`` command will create the necessary zip file out of a -documentation directory and will post to the repository. - -Note that to upload the documentation of a project, the corresponding version -must already be registered with PyPI, using the distutils ``register`` -command -- just like the ``upload`` command. - -Assuming there is an ``Example`` project with documentation in the -subdirectory ``docs``, for example:: - - Example/ - |-- example.py - |-- setup.cfg - |-- setup.py - |-- docs - | |-- build - | | `-- html - | | | |-- index.html - | | | `-- tips_tricks.html - | |-- conf.py - | |-- index.txt - | `-- tips_tricks.txt - -You can simply pass the documentation directory path to the ``upload_docs`` -command:: - - python setup.py upload_docs --upload-dir=docs/build/html - -As with any other command, you can define useful -defaults in the ``setup.cfg`` of your Python project, for example: - -.. code-block:: ini - - [upload_docs] - upload-dir = docs/build/html - -The ``upload_docs`` command has the following options: - -``--upload-dir`` - The directory to be uploaded to the repository. By default documentation - is searched for in ``docs`` (or ``doc``) directory in project root. - -``--show-response`` - Display the full response text from server; this is useful for debugging - PyPI problems. - -``--repository=URL, -r URL`` - The URL of the repository to upload to. Defaults to - http://pypi.python.org/pypi (i.e., the main PyPI installation). - - diff --git a/docs/source/distutils/packageindex.rst b/docs/source/distutils/packageindex.rst deleted file mode 100644 --- a/docs/source/distutils/packageindex.rst +++ /dev/null @@ -1,104 +0,0 @@ -.. _package-index: - -********************************** -Registering with the Package Index -********************************** - -The Python Package Index (PyPI) holds metadata describing distributions -packaged with distutils. The distutils command :command:`register` is used to -submit your distribution's metadata to the index. It is invoked as follows:: - - python setup.py register - -Distutils will respond with the following prompt:: - - running register - We need to know who you are, so please choose either: - 1. use your existing login, - 2. register as a new user, - 3. have the server generate a new password for you (and email it to you), or - 4. quit - Your selection [default 1]: - -Note: if your username and password are saved locally, you will not see this -menu. - -If you have not registered with PyPI, then you will need to do so now. You -should choose option 2, and enter your details as required. Soon after -submitting your details, you will receive an email which will be used to confirm -your registration. - -Once you are registered, you may choose option 1 from the menu. You will be -prompted for your PyPI username and password, and :command:`register` will then -submit your metadata to the index. - -You may submit any number of versions of your distribution to the index. If you -alter the metadata for a particular version, you may submit it again and the -index will be updated. - -PyPI holds a record for each (name, version) combination submitted. The first -user to submit information for a given name is designated the Owner of that -name. They may submit changes through the :command:`register` command or through -the web interface. They may also designate other users as Owners or Maintainers. -Maintainers may edit the package information, but not designate other Owners or -Maintainers. - -By default PyPI will list all versions of a given package. To hide certain -versions, the Hidden property should be set to yes. This must be edited through -the web interface. - - -.. _pypirc: - -The .pypirc file -================ - -The format of the :file:`.pypirc` file is as follows:: - - [distutils] - index-servers = - pypi - - [pypi] - repository: - username: - password: - -The *distutils* section defines a *index-servers* variable that lists the -name of all sections describing a repository. - -Each section describing a repository defines three variables: - -- *repository*, that defines the url of the PyPI server. Defaults to - ``http://www.python.org/pypi``. -- *username*, which is the registered username on the PyPI server. -- *password*, that will be used to authenticate. If omitted the user - will be prompt to type it when needed. - -If you want to define another server a new section can be created and -listed in the *index-servers* variable:: - - [distutils] - index-servers = - pypi - other - - [pypi] - repository: - username: - password: - - [other] - repository: http://example.com/pypi - username: - password: - -:command:`register` can then be called with the -r option to point the -repository to work with:: - - python setup.py register -r http://example.com/pypi - -For convenience, the name of the section that describes the repository -may also be used:: - - python setup.py register -r other diff --git a/docs/source/distutils/setupscript.rst b/docs/source/distutils/setupscript.rst deleted file mode 100644 --- a/docs/source/distutils/setupscript.rst +++ /dev/null @@ -1,686 +0,0 @@ -.. _setup-script: - -************************ -Writing the Setup Script -************************ - -The setup script is the center of all activity in building, distributing, and -installing modules using Distutils. The main purpose of the setup script is -to describe your module distribution to Distutils, so that the various -commands that operate on your modules do the right thing. As we saw in section -:ref:`distutils-simple-example`, the setup script consists mainly of a -call to :func:`setup` where the most information is supplied as -keyword arguments to :func:`setup`. - -Here's a slightly more involved example, which we'll follow for the next couple -of sections: a setup script that could be used for Distutils2 itself:: - - #!/usr/bin/env python - - from distutils2.core import setup, find_packages - - setup(name='Distutils2', - version='1.0', - summary='Python Distribution Utilities', - keywords=['packaging', 'distutils2'], - author=u'Tarek Ziad?', - author_email='tarek at ziade.org', - home_page='http://bitbucket.org/tarek/distutils2/wiki/Home', - license='PSF', - packages=find_packages()) - - -There are only two differences between this and the trivial one-file -distribution presented in section :ref:`distutils-simple-example`: more -metadata and the specification of pure Python modules by package rather than -by module. This is important since Ristutils consist of a couple of dozen -modules split into (so far) two packages; an explicit list of every module -would be tedious to generate and difficult to maintain. For more information -on the additional metadata, see section :ref:`metadata`. - -Note that any pathnames (files or directories) supplied in the setup script -should be written using the Unix convention, i.e. slash-separated. The -Distutils will take care of converting this platform-neutral representation into -whatever is appropriate on your current platform before actually using the -pathname. This makes your setup script portable across operating systems, which -of course is one of the major goals of the Distutils. In this spirit, all -pathnames in this document are slash-separated. - -This, of course, only applies to pathnames given to Distutils functions. If -you, for example, use standard Python functions such as :func:`glob.glob` or -:func:`os.listdir` to specify files, you should be careful to write portable -code instead of hardcoding path separators:: - - glob.glob(os.path.join('mydir', 'subdir', '*.html')) - os.listdir(os.path.join('mydir', 'subdir')) - - -.. _listing-packages: - -Listing whole packages -====================== - -The :option:`packages` option tells the Distutils to process (build, distribute, -install, etc.) all pure Python modules found in each package mentioned in the -:option:`packages` list. In order to do this, of course, there has to be a -correspondence between package names and directories in the filesystem. The -default correspondence is the most obvious one, i.e. package :mod:`distutils2` is -found in the directory :file:`distutils2` relative to the distribution root. -Thus, when you say ``packages = ['foo']`` in your setup script, you are -promising that the Distutils will find a file :file:`foo/__init__.py` (which -might be spelled differently on your system, but you get the idea) relative to -the directory where your setup script lives. If you break this promise, the -Distutils will issue a warning but still process the broken package anyways. - -If you use a different convention to lay out your source directory, that's no -problem: you just have to supply the :option:`package_dir` option to tell the -Distutils about your convention. For example, say you keep all Python source -under :file:`lib`, so that modules in the "root package" (i.e., not in any -package at all) are in :file:`lib`, modules in the :mod:`foo` package are in -:file:`lib/foo`, and so forth. Then you would put :: - - package_dir = {'': 'lib'} - -in your setup script. The keys to this dictionary are package names, and an -empty package name stands for the root package. The values are directory names -relative to your distribution root. In this case, when you say ``packages = -['foo']``, you are promising that the file :file:`lib/foo/__init__.py` exists. - -Another possible convention is to put the :mod:`foo` package right in -:file:`lib`, the :mod:`foo.bar` package in :file:`lib/bar`, etc. This would be -written in the setup script as :: - - package_dir = {'foo': 'lib'} - -A ``package: dir`` entry in the :option:`package_dir` dictionary implicitly -applies to all packages below *package*, so the :mod:`foo.bar` case is -automatically handled here. In this example, having ``packages = ['foo', -'foo.bar']`` tells the Distutils to look for :file:`lib/__init__.py` and -:file:`lib/bar/__init__.py`. (Keep in mind that although :option:`package_dir` -applies recursively, you must explicitly list all packages in -:option:`packages`: the Distutils will *not* recursively scan your source tree -looking for any directory with an :file:`__init__.py` file.) - - -.. _listing-modules: - -Listing individual modules -========================== - -For a small module distribution, you might prefer to list all modules rather -than listing packages---especially the case of a single module that goes in the -"root package" (i.e., no package at all). This simplest case was shown in -section :ref:`distutils-simple-example`; here is a slightly more involved -example:: - - py_modules = ['mod1', 'pkg.mod2'] - -This describes two modules, one of them in the "root" package, the other in the -:mod:`pkg` package. Again, the default package/directory layout implies that -these two modules can be found in :file:`mod1.py` and :file:`pkg/mod2.py`, and -that :file:`pkg/__init__.py` exists as well. And again, you can override the -package/directory correspondence using the :option:`package_dir` option. - - -.. _describing-extensions: - -Describing extension modules -============================ - -Just as writing Python extension modules is a bit more complicated than writing -pure Python modules, describing them to the Distutils is a bit more complicated. -Unlike pure modules, it's not enough just to list modules or packages and expect -the Distutils to go out and find the right files; you have to specify the -extension name, source file(s), and any compile/link requirements (include -directories, libraries to link with, etc.). - -.. XXX read over this section - -All of this is done through another keyword argument to :func:`setup`, the -:option:`ext_modules` option. :option:`ext_modules` is just a list of -:class:`Extension` instances, each of which describes a single extension module. -Suppose your distribution includes a single extension, called :mod:`foo` and -implemented by :file:`foo.c`. If no additional instructions to the -compiler/linker are needed, describing this extension is quite simple:: - - Extension('foo', ['foo.c']) - -The :class:`Extension` class can be imported from :mod:`distutils2.core` along -with :func:`setup`. Thus, the setup script for a module distribution that -contains only this one extension and nothing else might be:: - - from distutils2.core import setup, Extension - setup(name='foo', - version='1.0', - ext_modules=[Extension('foo', ['foo.c'])]) - -The :class:`Extension` class (actually, the underlying extension-building -machinery implemented by the :command:`build_ext` command) supports a great deal -of flexibility in describing Python extensions, which is explained in the -following sections. - - -Extension names and packages ----------------------------- - -The first argument to the :class:`Extension` constructor is always the name of -the extension, including any package names. For example, :: - - Extension('foo', ['src/foo1.c', 'src/foo2.c']) - -describes an extension that lives in the root package, while :: - - Extension('pkg.foo', ['src/foo1.c', 'src/foo2.c']) - -describes the same extension in the :mod:`pkg` package. The source files and -resulting object code are identical in both cases; the only difference is where -in the filesystem (and therefore where in Python's namespace hierarchy) the -resulting extension lives. - -If you have a number of extensions all in the same package (or all under the -same base package), use the :option:`ext_package` keyword argument to -:func:`setup`. For example, :: - - setup(..., - ext_package='pkg', - ext_modules=[Extension('foo', ['foo.c']), - Extension('subpkg.bar', ['bar.c'])]) - -will compile :file:`foo.c` to the extension :mod:`pkg.foo`, and :file:`bar.c` to -:mod:`pkg.subpkg.bar`. - - -Extension source files ----------------------- - -The second argument to the :class:`Extension` constructor is a list of source -files. Since the Distutils currently only support C, C++, and Objective-C -extensions, these are normally C/C++/Objective-C source files. (Be sure to use -appropriate extensions to distinguish C++\ source files: :file:`.cc` and -:file:`.cpp` seem to be recognized by both Unix and Windows compilers.) - -However, you can also include SWIG interface (:file:`.i`) files in the list; the -:command:`build_ext` command knows how to deal with SWIG extensions: it will run -SWIG on the interface file and compile the resulting C/C++ file into your -extension. - -.. XXX SWIG support is rough around the edges and largely untested! - -This warning notwithstanding, options to SWIG can be currently passed like -this:: - - setup(..., - ext_modules=[Extension('_foo', ['foo.i'], - swig_opts=['-modern', '-I../include'])], - py_modules=['foo']) - -Or on the command line like this:: - - > python setup.py build_ext --swig-opts="-modern -I../include" - -On some platforms, you can include non-source files that are processed by the -compiler and included in your extension. Currently, this just means Windows -message text (:file:`.mc`) files and resource definition (:file:`.rc`) files for -Visual C++. These will be compiled to binary resource (:file:`.res`) files and -linked into the executable. - - -Preprocessor options --------------------- - -Three optional arguments to :class:`Extension` will help if you need to specify -include directories to search or preprocessor macros to define/undefine: -``include_dirs``, ``define_macros``, and ``undef_macros``. - -For example, if your extension requires header files in the :file:`include` -directory under your distribution root, use the ``include_dirs`` option:: - - Extension('foo', ['foo.c'], include_dirs=['include']) - -You can specify absolute directories there; if you know that your extension will -only be built on Unix systems with X11R6 installed to :file:`/usr`, you can get -away with :: - - Extension('foo', ['foo.c'], include_dirs=['/usr/include/X11']) - -You should avoid this sort of non-portable usage if you plan to distribute your -code: it's probably better to write C code like :: - - #include - -If you need to include header files from some other Python extension, you can -take advantage of the fact that header files are installed in a consistent way -by the Distutils :command:`install_header` command. For example, the Numerical -Python header files are installed (on a standard Unix installation) to -:file:`/usr/local/include/python1.5/Numerical`. (The exact location will differ -according to your platform and Python installation.) Since the Python include -directory---\ :file:`/usr/local/include/python1.5` in this case---is always -included in the search path when building Python extensions, the best approach -is to write C code like :: - - #include - -.. TODO check if it's d2.sysconfig or the new sysconfig module now - -If you must put the :file:`Numerical` include directory right into your header -search path, though, you can find that directory using the Distutils -:mod:`distutils2.sysconfig` module:: - - from distutils2.sysconfig import get_python_inc - incdir = os.path.join(get_python_inc(plat_specific=1), 'Numerical') - setup(..., - Extension(..., include_dirs=[incdir])) - -Even though this is quite portable---it will work on any Python installation, -regardless of platform---it's probably easier to just write your C code in the -sensible way. - -You can define and undefine preprocessor macros with the ``define_macros`` and -``undef_macros`` options. ``define_macros`` takes a list of ``(name, value)`` -tuples, where ``name`` is the name of the macro to define (a string) and -``value`` is its value: either a string or ``None``. (Defining a macro ``FOO`` -to ``None`` is the equivalent of a bare ``#define FOO`` in your C source: with -most compilers, this sets ``FOO`` to the string ``1``.) ``undef_macros`` is -just a list of macros to undefine. - -For example:: - - Extension(..., - define_macros=[('NDEBUG', '1'), - ('HAVE_STRFTIME', None)], - undef_macros=['HAVE_FOO', 'HAVE_BAR']) - -is the equivalent of having this at the top of every C source file:: - - #define NDEBUG 1 - #define HAVE_STRFTIME - #undef HAVE_FOO - #undef HAVE_BAR - - -Library options ---------------- - -You can also specify the libraries to link against when building your extension, -and the directories to search for those libraries. The ``libraries`` option is -a list of libraries to link against, ``library_dirs`` is a list of directories -to search for libraries at link-time, and ``runtime_library_dirs`` is a list of -directories to search for shared (dynamically loaded) libraries at run-time. - -For example, if you need to link against libraries known to be in the standard -library search path on target systems :: - - Extension(..., - libraries=['gdbm', 'readline']) - -If you need to link with libraries in a non-standard location, you'll have to -include the location in ``library_dirs``:: - - Extension(..., - library_dirs=['/usr/X11R6/lib'], - libraries=['X11', 'Xt']) - -(Again, this sort of non-portable construct should be avoided if you intend to -distribute your code.) - -.. XXX Should mention clib libraries here or somewhere else! - - -Other options -------------- - -There are still some other options which can be used to handle special cases. - -The :option:`optional` option is a boolean; if it is true, -a build failure in the extension will not abort the build process, but -instead simply not install the failing extension. - -The :option:`extra_objects` option is a list of object files to be passed to the -linker. These files must not have extensions, as the default extension for the -compiler is used. - -:option:`extra_compile_args` and :option:`extra_link_args` can be used to -specify additional command-line options for the respective compiler and linker -command lines. - -:option:`export_symbols` is only useful on Windows. It can contain a list of -symbols (functions or variables) to be exported. This option is not needed when -building compiled extensions: Distutils will automatically add ``initmodule`` -to the list of exported symbols. - -The :option:`depends` option is a list of files that the extension depends on -(for example header files). The build command will call the compiler on the -sources to rebuild extension if any on this files has been modified since the -previous build. - -Relationships between Distributions and Packages -================================================ - -.. FIXME rewrite to update to PEP 345 (but without dist/release confusion) - -A distribution may relate to packages in three specific ways: - -#. It can require packages or modules. - -#. It can provide packages or modules. - -#. It can obsolete packages or modules. - -These relationships can be specified using keyword arguments to the -:func:`distutils2.core.setup` function. - -Dependencies on other Python modules and packages can be specified by supplying -the *requires* keyword argument to :func:`setup`. The value must be a list of -strings. Each string specifies a package that is required, and optionally what -versions are sufficient. - -To specify that any version of a module or package is required, the string -should consist entirely of the module or package name. Examples include -``'mymodule'`` and ``'xml.parsers.expat'``. - -If specific versions are required, a sequence of qualifiers can be supplied in -parentheses. Each qualifier may consist of a comparison operator and a version -number. The accepted comparison operators are:: - - < > == - <= >= != - -These can be combined by using multiple qualifiers separated by commas (and -optional whitespace). In this case, all of the qualifiers must be matched; a -logical AND is used to combine the evaluations. - -Let's look at a bunch of examples: - -+-------------------------+----------------------------------------------+ -| Requires Expression | Explanation | -+=========================+==============================================+ -| ``==1.0`` | Only version ``1.0`` is compatible | -+-------------------------+----------------------------------------------+ -| ``>1.0, !=1.5.1, <2.0`` | Any version after ``1.0`` and before ``2.0`` | -| | is compatible, except ``1.5.1`` | -+-------------------------+----------------------------------------------+ - -Now that we can specify dependencies, we also need to be able to specify what we -provide that other distributions can require. This is done using the *provides* -keyword argument to :func:`setup`. The value for this keyword is a list of -strings, each of which names a Python module or package, and optionally -identifies the version. If the version is not specified, it is assumed to match -that of the distribution. - -Some examples: - -+---------------------+----------------------------------------------+ -| Provides Expression | Explanation | -+=====================+==============================================+ -| ``mypkg`` | Provide ``mypkg``, using the distribution | -| | version | -+---------------------+----------------------------------------------+ -| ``mypkg (1.1)`` | Provide ``mypkg`` version 1.1, regardless of | -| | the distribution version | -+---------------------+----------------------------------------------+ - -A package can declare that it obsoletes other packages using the *obsoletes* -keyword argument. The value for this is similar to that of the *requires* -keyword: a list of strings giving module or package specifiers. Each specifier -consists of a module or package name optionally followed by one or more version -qualifiers. Version qualifiers are given in parentheses after the module or -package name. - -The versions identified by the qualifiers are those that are obsoleted by the -distribution being described. If no qualifiers are given, all versions of the -named module or package are understood to be obsoleted. - -.. _distutils-installing-scripts: - -Installing Scripts -================== - -So far we have been dealing with pure and non-pure Python modules, which are -usually not run by themselves but imported by scripts. - -Scripts are files containing Python source code, intended to be started from the -command line. Scripts don't require Distutils to do anything very complicated. -The only clever feature is that if the first line of the script starts with -``#!`` and contains the word "python", the Distutils will adjust the first line -to refer to the current interpreter location. By default, it is replaced with -the current interpreter location. The :option:`--executable` (or :option:`-e`) -option will allow the interpreter path to be explicitly overridden. - -The :option:`scripts` option simply is a list of files to be handled in this -way. From the PyXML setup script:: - - setup(..., - scripts=['scripts/xmlproc_parse', 'scripts/xmlproc_val']) - -All the scripts will also be added to the ``MANIFEST`` file if no template is -provided. See :ref:`manifest`. - -.. _distutils-installing-package-data: - -Installing Package Data -======================= - -Often, additional files need to be installed into a package. These files are -often data that's closely related to the package's implementation, or text files -containing documentation that might be of interest to programmers using the -package. These files are called :dfn:`package data`. - -Package data can be added to packages using the ``package_data`` keyword -argument to the :func:`setup` function. The value must be a mapping from -package name to a list of relative path names that should be copied into the -package. The paths are interpreted as relative to the directory containing the -package (information from the ``package_dir`` mapping is used if appropriate); -that is, the files are expected to be part of the package in the source -directories. They may contain glob patterns as well. - -The path names may contain directory portions; any necessary directories will be -created in the installation. - -For example, if a package should contain a subdirectory with several data files, -the files can be arranged like this in the source tree:: - - setup.py - src/ - mypkg/ - __init__.py - module.py - data/ - tables.dat - spoons.dat - forks.dat - -The corresponding call to :func:`setup` might be:: - - setup(..., - packages=['mypkg'], - package_dir={'mypkg': 'src/mypkg'}, - package_data={'mypkg': ['data/*.dat']}) - - -All the files that match ``package_data`` will be added to the ``MANIFEST`` -file if no template is provided. See :ref:`manifest`. - - -.. _distutils-additional-files: - -Installing Additional Files -=========================== - -The :option:`data_files` option can be used to specify additional files needed -by the module distribution: configuration files, message catalogs, data files, -anything which doesn't fit in the previous categories. - -:option:`data_files` specifies a sequence of (*directory*, *files*) pairs in the -following way:: - - setup(..., - data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']), - ('config', ['cfg/data.cfg']), - ('/etc/init.d', ['init-script'])]) - -Note that you can specify the directory names where the data files will be -installed, but you cannot rename the data files themselves. - -Each (*directory*, *files*) pair in the sequence specifies the installation -directory and the files to install there. If *directory* is a relative path, it -is interpreted relative to the installation prefix (Python's ``sys.prefix`` for -pure-Python packages, ``sys.exec_prefix`` for packages that contain extension -modules). Each file name in *files* is interpreted relative to the -:file:`setup.py` script at the top of the package source distribution. No -directory information from *files* is used to determine the final location of -the installed file; only the name of the file is used. - -You can specify the :option:`data_files` options as a simple sequence of files -without specifying a target directory, but this is not recommended, and the -:command:`install` command will print a warning in this case. To install data -files directly in the target directory, an empty string should be given as the -directory. - -All the files that match ``data_files`` will be added to the ``MANIFEST`` file -if no template is provided. See :ref:`manifest`. - - - -.. _metadata: - -Metadata reference -================== - -The setup script may include additional metadata beyond the name and version. -This table describes required and additional information: - -+----------------------+---------------------------+-----------------+--------+ -| Meta-Data | Description | Value | Notes | -+======================+===========================+=================+========+ -| ``name`` | name of the project | short string | \(1) | -+----------------------+---------------------------+-----------------+--------+ -| ``version`` | version of this release | short string | (1)(2) | -+----------------------+---------------------------+-----------------+--------+ -| ``author`` | project author's name | short string | \(3) | -+----------------------+---------------------------+-----------------+--------+ -| ``author_email`` | email address of the | email address | \(3) | -| | project author | | | -+----------------------+---------------------------+-----------------+--------+ -| ``maintainer`` | project maintainer's name | short string | \(3) | -+----------------------+---------------------------+-----------------+--------+ -| ``maintainer_email`` | email address of the | email address | \(3) | -| | project maintainer | | | -+----------------------+---------------------------+-----------------+--------+ -| ``home_page`` | home page for the project | URL | \(1) | -+----------------------+---------------------------+-----------------+--------+ -| ``summary`` | short description of the | short string | | -| | project | | | -+----------------------+---------------------------+-----------------+--------+ -| ``description`` | longer description of the | long string | \(5) | -| | project | | | -+----------------------+---------------------------+-----------------+--------+ -| ``download_url`` | location where the | URL | | -| | project may be downloaded | | | -+----------------------+---------------------------+-----------------+--------+ -| ``classifiers`` | a list of classifiers | list of strings | \(4) | -+----------------------+---------------------------+-----------------+--------+ -| ``platforms`` | a list of platforms | list of strings | | -+----------------------+---------------------------+-----------------+--------+ -| ``license`` | license for the release | short string | \(6) | -+----------------------+---------------------------+-----------------+--------+ - -Notes: - -(1) - These fields are required. - -(2) - It is recommended that versions take the form *major.minor[.patch[.sub]]*. - -(3) - Either the author or the maintainer must be identified. - -(4) - The list of classifiers is available from the `PyPI website - `_. See also :mod:`distutils2.mkcfg`. - -(5) - The ``description`` field is used by PyPI when you are registering a - release, to build its PyPI page. - -(6) - The ``license`` field is a text indicating the license covering the - distribution where the license is not a selection from the "License" Trove - classifiers. See the ``Classifier`` field. Notice that - there's a ``licence`` distribution option which is deprecated but still - acts as an alias for ``license``. - -'short string' - A single line of text, not more than 200 characters. - -'long string' - Multiple lines of plain text in reStructuredText format (see - http://docutils.sf.net/). - -'list of strings' - See below. - -In Python 2.x, "string value" means a unicode object. If a byte string (str or -bytes) is given, it has to be valid ASCII. - -.. TODO move this section to the version document, keep a summary, add a link - -Encoding the version information is an art in itself. Python projects generally -adhere to the version format *major.minor[.patch][sub]*. The major number is 0 -for initial, experimental releases of software. It is incremented for releases -that represent major milestones in a project. The minor number is incremented -when important new features are added to the project. The patch number -increments when bug-fix releases are made. Additional trailing version -information is sometimes used to indicate sub-releases. These are -"a1,a2,...,aN" (for alpha releases, where functionality and API may change), -"b1,b2,...,bN" (for beta releases, which only fix bugs) and "pr1,pr2,...,prN" -(for final pre-release release testing). Some examples: - -0.1.0 - the first, experimental release of a project - -1.0.1a2 - the second alpha release of the first patch version of 1.0 - -:option:`classifiers` are specified in a Python list:: - - setup(..., - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Environment :: Web Environment', - 'Intended Audience :: End Users/Desktop', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: Python Software Foundation License', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX', - 'Programming Language :: Python', - 'Topic :: Communications :: Email', - 'Topic :: Office/Business', - 'Topic :: Software Development :: Bug Tracking', - ]) - - -Debugging the setup script -========================== - -Sometimes things go wrong, and the setup script doesn't do what the developer -wants. - -Distutils catches any exceptions when running the setup script, and print a -simple error message before the script is terminated. The motivation for this -behaviour is to not confuse administrators who don't know much about Python and -are trying to install a project. If they get a big long traceback from deep -inside the guts of Distutils, they may think the project or the Python -installation is broken because they don't read all the way down to the bottom -and see that it's a permission problem. - -.. FIXME DISTUTILS_DEBUG is dead, document logging/warnings here - -On the other hand, this doesn't help the developer to find the cause of the -failure. For this purpose, the DISTUTILS_DEBUG environment variable can be set -to anything except an empty string, and Distutils2 will now print detailed -information about what it is doing, and prints the full traceback in case an -exception occurs. diff --git a/docs/source/distutils/sourcedist.rst b/docs/source/distutils/sourcedist.rst deleted file mode 100644 --- a/docs/source/distutils/sourcedist.rst +++ /dev/null @@ -1,272 +0,0 @@ -.. _source-dist: - -****************************** -Creating a Source Distribution -****************************** - -As shown in section :ref:`distutils-simple-example`, you use the :command:`sdist` command -to create a source distribution. In the simplest case, :: - - python setup.py sdist - -(assuming you haven't specified any :command:`sdist` options in the setup script -or config file), :command:`sdist` creates the archive of the default format for -the current platform. The default format is a gzip'ed tar file -(:file:`.tar.gz`) on Unix, and ZIP file on Windows. - -You can specify as many formats as you like using the :option:`--formats` -option, for example:: - - python setup.py sdist --formats=gztar,zip - -to create a gzipped tarball and a zip file. The available formats are: - -+-----------+-------------------------+---------+ -| Format | Description | Notes | -+===========+=========================+=========+ -| ``zip`` | zip file (:file:`.zip`) | (1),(3) | -+-----------+-------------------------+---------+ -| ``gztar`` | gzip'ed tar file | \(2) | -| | (:file:`.tar.gz`) | | -+-----------+-------------------------+---------+ -| ``bztar`` | bzip2'ed tar file | | -| | (:file:`.tar.bz2`) | | -+-----------+-------------------------+---------+ -| ``ztar`` | compressed tar file | \(4) | -| | (:file:`.tar.Z`) | | -+-----------+-------------------------+---------+ -| ``tar`` | tar file (:file:`.tar`) | | -+-----------+-------------------------+---------+ - -Notes: - -(1) - default on Windows - -(2) - default on Unix - -(3) - requires either external :program:`zip` utility or :mod:`zipfile` module (part - of the standard Python library since Python 1.6) - -(4) - requires the :program:`compress` program. Notice that this format is now - pending for deprecation and will be removed in the future versions of Python. - -When using any ``tar`` format (``gztar``, ``bztar``, ``ztar`` or -``tar``) under Unix, you can specify the ``owner`` and ``group`` names -that will be set for each member of the archive. - -For example, if you want all files of the archive to be owned by root:: - - python setup.py sdist --owner=root --group=root - - -.. _manifest: - -Specifying the files to distribute -================================== - -If you don't supply an explicit list of files (or instructions on how to -generate one), the :command:`sdist` command puts a minimal default set into the -source distribution: - -* all Python source files implied by the :option:`py_modules` and - :option:`packages` options - -* all C source files mentioned in the :option:`ext_modules` or - :option:`libraries` options - -* scripts identified by the :option:`scripts` option - See :ref:`distutils-installing-scripts`. - -* anything that looks like a test script: :file:`test/test\*.py` (currently, the - Distutils don't do anything with test scripts except include them in source - distributions, but in the future there will be a standard for testing Python - module distributions) - -* The configuration file :file:`setup.cfg` - -* all files that matches the ``package_data`` metadata. - See :ref:`distutils-installing-package-data`. - -* all files that matches the ``data_files`` metadata. - See :ref:`distutils-additional-files`. - -.. Warning:: - In Distutils2, setup.py and README (or README.txt) files are not more - included in source distribution by default - -Sometimes this is enough, but usually you will want to specify additional files -to distribute. The typical way to do this is to write a *manifest template*, -called :file:`MANIFEST.in` by default. The manifest template is just a list of -instructions for how to generate your manifest file, :file:`MANIFEST`, which is -the exact list of files to include in your source distribution. The -:command:`sdist` command processes this template and generates a manifest based -on its instructions and what it finds in the filesystem. - -If you prefer to roll your own manifest file, the format is simple: one filename -per line, regular files (or symlinks to them) only. If you do supply your own -:file:`MANIFEST`, you must specify everything: the default set of files -described above does not apply in this case. - -:file:`MANIFEST` files start with a comment indicating they are generated. -Files without this comment are not overwritten or removed. - -See :ref:`manifest_template` section for a syntax reference. - -.. _manifest-options: - -Manifest-related options -======================== - -The normal course of operations for the :command:`sdist` command is as follows: - -* if the manifest file, :file:`MANIFEST` doesn't exist, read :file:`MANIFEST.in` - and create the manifest - -* if neither :file:`MANIFEST` nor :file:`MANIFEST.in` exist, create a manifest - with just the default file set - -* if either :file:`MANIFEST.in` or the setup script (:file:`setup.py`) are more - recent than :file:`MANIFEST`, recreate :file:`MANIFEST` by reading - :file:`MANIFEST.in` - -* use the list of files now in :file:`MANIFEST` (either just generated or read - in) to create the source distribution archive(s) - -There are a couple of options that modify this behaviour. First, use the -:option:`--no-defaults` and :option:`--no-prune` to disable the standard -"include" and "exclude" sets. - -Second, you might just want to (re)generate the manifest, but not create a -source distribution:: - - python setup.py sdist --manifest-only - -:option:`-o` is a shortcut for :option:`--manifest-only`. - -.. _manifest_template: - -The MANIFEST.in template -======================== - -A :file:`MANIFEST.in` file can be added in a project to define the list of -files to include in the distribution built by the :command:`sdist` command. - -When :command:`sdist` is run, it will look for the :file:`MANIFEST.in` file -and interpret it to generate the :file:`MANIFEST` file that contains the -list of files that will be included in the package. - -This mechanism can be used when the default list of files is not enough. -(See :ref:`manifest`). - -Principle ---------- - -The manifest template has one command per line, where each command specifies a -set of files to include or exclude from the source distribution. For an -example, let's look at the Distutils' own manifest template:: - - include *.txt - recursive-include examples *.txt *.py - prune examples/sample?/build - -The meanings should be fairly clear: include all files in the distribution root -matching :file:`\*.txt`, all files anywhere under the :file:`examples` directory -matching :file:`\*.txt` or :file:`\*.py`, and exclude all directories matching -:file:`examples/sample?/build`. All of this is done *after* the standard -include set, so you can exclude files from the standard set with explicit -instructions in the manifest template. (Or, you can use the -:option:`--no-defaults` option to disable the standard set entirely.) - -The order of commands in the manifest template matters: initially, we have the -list of default files as described above, and each command in the template adds -to or removes from that list of files. Once we have fully processed the -manifest template, we remove files that should not be included in the source -distribution: - -* all files in the Distutils "build" tree (default :file:`build/`) - -* all files in directories named :file:`RCS`, :file:`CVS`, :file:`.svn`, - :file:`.hg`, :file:`.git`, :file:`.bzr` or :file:`_darcs` - -Now we have our complete list of files, which is written to the manifest for -future reference, and then used to build the source distribution archive(s). - -You can disable the default set of included files with the -:option:`--no-defaults` option, and you can disable the standard exclude set -with :option:`--no-prune`. - -Following the Distutils' own manifest template, let's trace how the -:command:`sdist` command builds the list of files to include in the Distutils -source distribution: - -#. include all Python source files in the :file:`distutils2` and - :file:`distutils2/command` subdirectories (because packages corresponding to - those two directories were mentioned in the :option:`packages` option in the - setup script---see section :ref:`setup-script`) - -#. include :file:`README.txt`, :file:`setup.py`, and :file:`setup.cfg` (standard - files) - -#. include :file:`test/test\*.py` (standard files) - -#. include :file:`\*.txt` in the distribution root (this will find - :file:`README.txt` a second time, but such redundancies are weeded out later) - -#. include anything matching :file:`\*.txt` or :file:`\*.py` in the sub-tree - under :file:`examples`, - -#. exclude all files in the sub-trees starting at directories matching - :file:`examples/sample?/build`\ ---this may exclude files included by the - previous two steps, so it's important that the ``prune`` command in the manifest - template comes after the ``recursive-include`` command - -#. exclude the entire :file:`build` tree, and any :file:`RCS`, :file:`CVS`, - :file:`.svn`, :file:`.hg`, :file:`.git`, :file:`.bzr` and :file:`_darcs` - directories - -Just like in the setup script, file and directory names in the manifest template -should always be slash-separated; the Distutils will take care of converting -them to the standard representation on your platform. That way, the manifest -template is portable across operating systems. - -Commands --------- - -The manifest template commands are: - -+-------------------------------------------+-----------------------------------------------+ -| Command | Description | -+===========================================+===============================================+ -| :command:`include pat1 pat2 ...` | include all files matching any of the listed | -| | patterns | -+-------------------------------------------+-----------------------------------------------+ -| :command:`exclude pat1 pat2 ...` | exclude all files matching any of the listed | -| | patterns | -+-------------------------------------------+-----------------------------------------------+ -| :command:`recursive-include dir pat1 pat2 | include all files under *dir* matching any of | -| ...` | the listed patterns | -+-------------------------------------------+-----------------------------------------------+ -| :command:`recursive-exclude dir pat1 pat2 | exclude all files under *dir* matching any of | -| ...` | the listed patterns | -+-------------------------------------------+-----------------------------------------------+ -| :command:`global-include pat1 pat2 ...` | include all files anywhere in the source tree | -| | matching --- & any of the listed patterns | -+-------------------------------------------+-----------------------------------------------+ -| :command:`global-exclude pat1 pat2 ...` | exclude all files anywhere in the source tree | -| | matching --- & any of the listed patterns | -+-------------------------------------------+-----------------------------------------------+ -| :command:`prune dir` | exclude all files under *dir* | -+-------------------------------------------+-----------------------------------------------+ -| :command:`graft dir` | include all files under *dir* | -+-------------------------------------------+-----------------------------------------------+ - -The patterns here are Unix-style "glob" patterns: ``*`` matches any sequence of -regular filename characters, ``?`` matches any single regular filename -character, and ``[range]`` matches any of the characters in *range* (e.g., -``a-z``, ``a-zA-Z``, ``a-f0-9_.``). The definition of "regular filename -character" is platform-specific: on Unix it is anything except slash; on Windows -anything except backslash or colon. diff --git a/docs/source/distutils/uploading.rst b/docs/source/distutils/uploading.rst deleted file mode 100644 --- a/docs/source/distutils/uploading.rst +++ /dev/null @@ -1,80 +0,0 @@ -.. _package-upload: - -*************************************** -Uploading Packages to the Package Index -*************************************** - -The Python Package Index (PyPI) not only stores the package info, but also the -package data if the author of the package wishes to. The distutils command -:command:`upload` pushes the distribution files to PyPI. - -The command is invoked immediately after building one or more distribution -files. For example, the command :: - - python setup.py sdist bdist_wininst upload - -will cause the source distribution and the Windows installer to be uploaded to -PyPI. Note that these will be uploaded even if they are built using an earlier -invocation of :file:`setup.py`, but that only distributions named on the command -line for the invocation including the :command:`upload` command are uploaded. - -The :command:`upload` command uses the username, password, and repository URL -from the :file:`$HOME/.pypirc` file (see section :ref:`pypirc` for more on this -file). If a :command:`register` command was previously called in the same -command, and if the password was entered in the prompt, :command:`upload` will -reuse the entered password. This is useful if you do not want to store a clear -text password in the :file:`$HOME/.pypirc` file. - -You can specify another PyPI server with the :option:`--repository=*url*` -option:: - - python setup.py sdist bdist_wininst upload -r http://example.com/pypi - -See section :ref:`pypirc` for more on defining several servers. - -You can use the :option:`--sign` option to tell :command:`upload` to sign each -uploaded file using GPG (GNU Privacy Guard). The :program:`gpg` program must -be available for execution on the system :envvar:`PATH`. You can also specify -which key to use for signing using the :option:`--identity=*name*` option. - -Other :command:`upload` options include :option:`--repository=` or -:option:`--repository=
` where *url* is the url of the server and -*section* the name of the section in :file:`$HOME/.pypirc`, and -:option:`--show-response` (which displays the full response text from the PyPI -server for help in debugging upload problems). - -PyPI package display -==================== - -The ``description`` field plays a special role at PyPI. It is used by -the server to display a home page for the registered package. - -If you use the `reStructuredText `_ -syntax for this field, PyPI will parse it and display an HTML output for -the package home page. - -The ``description`` field can be filled from a text file located in the -project:: - - from distutils2.core import setup - - fp = open('README.txt') - try: - description = fp.read() - finally: - fp.close() - - setup(name='Distutils2', - description=description) - -In that case, :file:`README.txt` is a regular reStructuredText text file located -in the root of the package besides :file:`setup.py`. - -To prevent registering broken reStructuredText content, you can use the -:program:`rst2html` program that is provided by the :mod:`docutils` package -and check the ``description`` from the command line:: - - $ python setup.py --description | rst2html.py > output.html - -:mod:`docutils` will display a warning if there's something wrong with your -syntax. diff --git a/docs/source/images/depgraph_output.png b/docs/source/images/depgraph_output.png deleted file mode 100644 Binary file docs/source/images/depgraph_output.png has changed diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 --- a/docs/source/index.rst +++ /dev/null @@ -1,91 +0,0 @@ -.. Distutils2 doc site master file - This doc serves as project homepage and documentation preview - (on distutils2.notmyidea.org) until distutils2 is merged back into - the Python standard library. - This file should contain the root `toctree` directive. - - -Welcome to Distutils2! -====================== - -Distutils2 is the new, improved version of the Python Distribution Utilities, -a library used to package, distribute, build and install Python projects. - -- `Origin of the project`__ -- `Main code repository`__ -- `Clones of this repository`__ -- `Bug tracker`__ (some bugs may be assigned only to Distutils) -- `Teams that worked on Distutils2 for Google Summer of Code 2010`__ (links to - their code repositories and weblogs) - -.. __: http://tarekziade.wordpress.com/2010/03/03/ - the-fate-of-distutils-pycon-summit-packaging-sprint-detailed-report/ -.. __: http://bitbucket.org/tarek/distutils2/ -.. __: http://bitbucket.org/tarek/distutils2/descendants/ -.. __: http://bugs.python.org/issue?%40sort0=activity&%40sortdir0=on&%40sort1= - &%40group0=priority&%40group1=&%40columns=title%2Cid%2Cactivity%2Cstatus - &%40filter=components%2Cstatus&status=1&components=25&%40pagesize=50 - &%40startwith=0 -.. __: http://bitbucket.org/tarek/distutils2/wiki/GSoC_2010_teams - -If you?re looking for information on how to contribute, head to -:doc:`devresources`, and be sure to have a look at :doc:`contributing`. - - -Documentation -------------- - -These documents are the in-development version of Distutils2's documentation, -started from the existing Distutils documentation and updated by the -Distutils2 group (GSoC students, mentors, volunteers). - -Please remember that this is a work in progress. The documentation is not -complete, not spell-checked, and uses different styles. - -The documentation is split in four sections, as in the standard Python docs: - -:doc:`install/index` - A guide for for end-users wanting to install a Python application or - library. - -:doc:`setupcfg-spec` - Specifications of setup.cfg, the most important file for developers. - -:doc:`setupcfg` - Documenation about using setup.cfg - -:doc:`tutorial` - A tutorial for Python developers to discover Distutils2 main features. - -:doc:`distutils/index` - A guide for Python developers wanting to package and distribute their - project. - -:doc:`library/distutils2` - A reference for developers wanting to use standalone building blocks like - :mod:`~distutils2.version` or :mod:`~distutils2.metadata`, or extend - Distutils2 itself. Since :PEP:`376` is partly implemented in the - :mod:`pkgutil` module, its updated documentation is also included: - :doc:`library/pkgutil`. - - -.. toctree:: - :hidden: - - devresources - install/index - setupcfg-spec - setupcfg - tutorial - distutils/index - library/distutils2 - library/pkgutil - contributing - - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/source/install/index.rst b/docs/source/install/index.rst deleted file mode 100644 --- a/docs/source/install/index.rst +++ /dev/null @@ -1,1004 +0,0 @@ -.. highlightlang:: none - -.. _install-index: - -****************************** - Installing Python Projects -****************************** - -:Author: Greg Ward and Distutils2 contributors -:Release: |version| -:Date: |today| - -.. TODO: Fill in XXX comments - -.. The audience for this document includes people who don't know anything - about Python and aren't about to learn the language just in order to - install and maintain it for their users, i.e. system administrators. - Thus, I have to be sure to explain the basics at some point: - sys.path and PYTHONPATH at least. Should probably give pointers to - other docs on "import site", PYTHONSTARTUP, PYTHONHOME, etc. - - Finally, it might be useful to include all the material from my "Care - and Feeding of a Python Installation" talk in here somewhere. Yow! - -.. topic:: Abstract - - This document describes the Python Distribution Utilities ("Distutils2") from - the end-user's point-of-view, describing how to extend the capabilities of a - standard Python installation by building and installing third-party Python - modules and extensions. - - -.. _inst-intro: - -Introduction -============ - -Although Python's extensive standard library covers many programming needs, -there often comes a time when you need to add some new functionality to your -Python installation in the form of third-party modules. This might be necessary -to support your own programming, or to support an application that you want to -use and that happens to be written in Python. - -In the past, there has been little support for adding third-party modules to an -existing Python installation. With the introduction of the Python Distribution -Utilities (Distutils for short) in Python 2.0, this changed. - -This document is aimed primarily at the people who need to install third-party -Python modules: end-users and system administrators who just need to get some -Python application running, and existing Python programmers who want to add some -new goodies to their toolbox. You don't need to know Python to read this -document; there will be some brief forays into using Python's interactive mode -to explore your installation, but that's it. If you're looking for information -on how to distribute your own Python modules so that others may use them, see -the :ref:`distutils-index` manual. - - -.. _inst-trivial-install: - -Best case: trivial installation -------------------------------- - -In the best case, someone will have prepared a special version of the module -distribution you want to install that is targeted specifically at your platform -and is installed just like any other software on your platform. For example, -the module developer might make an executable installer available for Windows -users, an RPM package for users of RPM-based Linux systems (Red Hat, SuSE, -Mandrake, and many others), a Debian package for users of Debian-based Linux -systems, and so forth. - -In that case, you would download the installer appropriate to your platform and -do the obvious thing with it: run it if it's an executable installer, ``rpm ---install`` it if it's an RPM, etc. You don't need to run Python or a setup -script, you don't need to compile anything---you might not even need to read any -instructions (although it's always a good idea to do so anyways). - -Of course, things will not always be that easy. You might be interested in a -module distribution that doesn't have an easy-to-use installer for your -platform. In that case, you'll have to start with the source distribution -released by the module's author/maintainer. Installing from a source -distribution is not too hard, as long as the modules are packaged in the -standard way. The bulk of this document is about building and installing -modules from standard source distributions. - - -.. _inst-new-standard: - -The new standard: Distutils ---------------------------- - -If you download a module source distribution, you can tell pretty quickly if it -was packaged and distributed in the standard way, i.e. using the Distutils. -First, the distribution's name and version number will be featured prominently -in the name of the downloaded archive, e.g. :file:`foo-1.0.tar.gz` or -:file:`widget-0.9.7.zip`. Next, the archive will unpack into a similarly-named -directory: :file:`foo-1.0` or :file:`widget-0.9.7`. Additionally, the -distribution will contain a setup script :file:`setup.py`, and a file named -:file:`README.txt` or possibly just :file:`README`, which should explain that -building and installing the module distribution is a simple matter of running :: - - python setup.py install - -If all these things are true, then you already know how to build and install the -modules you've just downloaded: Run the command above. Unless you need to -install things in a non-standard way or customize the build process, you don't -really need this manual. Or rather, the above command is everything you need to -get out of this manual. - - -.. _inst-standard-install: - -Standard Build and Install -========================== - -As described in section :ref:`inst-new-standard`, building and installing a module -distribution using the Distutils is usually one simple command:: - - python setup.py install - -On Unix, you'd run this command from a shell prompt; on Windows, you have to -open a command prompt window ("DOS box") and do it there; on Mac OS X, you open -a :command:`Terminal` window to get a shell prompt. - - -.. _inst-platform-variations: - -Platform variations -------------------- - -You should always run the setup command from the distribution root directory, -i.e. the top-level subdirectory that the module source distribution unpacks -into. For example, if you've just downloaded a module source distribution -:file:`foo-1.0.tar.gz` onto a Unix system, the normal thing to do is:: - - gunzip -c foo-1.0.tar.gz | tar xf - # unpacks into directory foo-1.0 - cd foo-1.0 - python setup.py install - -On Windows, you'd probably download :file:`foo-1.0.zip`. If you downloaded the -archive file to :file:`C:\\Temp`, then it would unpack into -:file:`C:\\Temp\\foo-1.0`; you can use either a archive manipulator with a -graphical user interface (such as WinZip) or a command-line tool (such as -:program:`unzip` or :program:`pkunzip`) to unpack the archive. Then, open a -command prompt window ("DOS box"), and run:: - - cd c:\Temp\foo-1.0 - python setup.py install - - -.. _inst-splitting-up: - -Splitting the job up --------------------- - -Running ``setup.py install`` builds and installs all modules in one run. If you -prefer to work incrementally---especially useful if you want to customize the -build process, or if things are going wrong---you can use the setup script to do -one thing at a time. This is particularly helpful when the build and install -will be done by different users---for example, you might want to build a module -distribution and hand it off to a system administrator for installation (or do -it yourself, with super-user privileges). - -For example, you can build everything in one step, and then install everything -in a second step, by invoking the setup script twice:: - - python setup.py build - python setup.py install - -If you do this, you will notice that running the :command:`install` command -first runs the :command:`build` command, which---in this case---quickly notices -that it has nothing to do, since everything in the :file:`build` directory is -up-to-date. - -You may not need this ability to break things down often if all you do is -install modules downloaded off the 'net, but it's very handy for more advanced -tasks. If you get into distributing your own Python modules and extensions, -you'll run lots of individual Distutils commands on their own. - - -.. _inst-how-build-works: - -How building works ------------------- - -As implied above, the :command:`build` command is responsible for putting the -files to install into a *build directory*. By default, this is :file:`build` -under the distribution root; if you're excessively concerned with speed, or want -to keep the source tree pristine, you can change the build directory with the -:option:`--build-base` option. For example:: - - python setup.py build --build-base /tmp/pybuild/foo-1.0 - -(Or you could do this permanently with a directive in your system or personal -Distutils configuration file; see section :ref:`inst-config-files`.) Normally, -this isn't necessary. - -The default layout for the build tree is as follows:: - - --- build/ --- lib/ - or - --- build/ --- lib./ - temp./ - -where ```` expands to a brief description of the current OS/hardware -platform and Python version. The first form, with just a :file:`lib` directory, -is used for "pure module distributions"---that is, module distributions that -include only pure Python modules. If a module distribution contains any -extensions (modules written in C/C++), then the second form, with two ```` -directories, is used. In that case, the :file:`temp.{plat}` directory holds -temporary files generated by the compile/link process that don't actually get -installed. In either case, the :file:`lib` (or :file:`lib.{plat}`) directory -contains all Python modules (pure Python and extensions) that will be installed. - -In the future, more directories will be added to handle Python scripts, -documentation, binary executables, and whatever else is needed to handle the job -of installing Python modules and applications. - - -.. _inst-how-install-works: - -How installation works ----------------------- - -After the :command:`build` command runs (whether you run it explicitly, or the -:command:`install` command does it for you), the work of the :command:`install` -command is relatively simple: all it has to do is copy everything under -:file:`build/lib` (or :file:`build/lib.{plat}`) to your chosen installation -directory. - -If you don't choose an installation directory---i.e., if you just run ``setup.py -install``\ ---then the :command:`install` command installs to the standard -location for third-party Python modules. This location varies by platform and -by how you built/installed Python itself. On Unix (and Mac OS X, which is also -Unix-based), it also depends on whether the module distribution being installed -is pure Python or contains extensions ("non-pure"): - -+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Platform | Standard installation location | Default value | Notes | -+=================+=====================================================+==================================================+=======+ -| Unix (pure) | :file:`{prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) | -+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Unix (non-pure) | :file:`{exec-prefix}/lib/python{X.Y}/site-packages` | :file:`/usr/local/lib/python{X.Y}/site-packages` | \(1) | -+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ -| Windows | :file:`{prefix}` | :file:`C:\\Python` | \(2) | -+-----------------+-----------------------------------------------------+--------------------------------------------------+-------+ - -Notes: - -(1) - Most Linux distributions include Python as a standard part of the system, so - :file:`{prefix}` and :file:`{exec-prefix}` are usually both :file:`/usr` on - Linux. If you build Python yourself on Linux (or any Unix-like system), the - default :file:`{prefix}` and :file:`{exec-prefix}` are :file:`/usr/local`. - -(2) - The default installation directory on Windows was :file:`C:\\Program - Files\\Python` under Python 1.6a1, 1.5.2, and earlier. - -:file:`{prefix}` and :file:`{exec-prefix}` stand for the directories that Python -is installed to, and where it finds its libraries at run-time. They are always -the same under Windows, and very often the same under Unix and Mac OS X. You -can find out what your Python installation uses for :file:`{prefix}` and -:file:`{exec-prefix}` by running Python in interactive mode and typing a few -simple commands. Under Unix, just type ``python`` at the shell prompt. Under -Windows, choose :menuselection:`Start --> Programs --> Python X.Y --> -Python (command line)`. Once the interpreter is started, you type Python code -at the prompt. For example, on my Linux system, I type the three Python -statements shown below, and get the output as shown, to find out my -:file:`{prefix}` and :file:`{exec-prefix}`:: - - Python 2.4 (#26, Aug 7 2004, 17:19:02) - Type "help", "copyright", "credits" or "license" for more information. - >>> import sys - >>> sys.prefix - '/usr' - >>> sys.exec_prefix - '/usr' - -If you don't want to install modules to the standard location, or if you don't -have permission to write there, then you need to read about alternate -installations in section :ref:`inst-alt-install`. If you want to customize your -installation directories more heavily, see section :ref:`inst-custom-install` on -custom installations. - - -.. _inst-alt-install: - -Alternate Installation -====================== - -Often, it is necessary or desirable to install modules to a location other than -the standard location for third-party Python modules. For example, on a Unix -system you might not have permission to write to the standard third-party module -directory. Or you might wish to try out a module before making it a standard -part of your local Python installation. This is especially true when upgrading -a distribution already present: you want to make sure your existing base of -scripts still works with the new version before actually upgrading. - -The Distutils :command:`install` command is designed to make installing module -distributions to an alternate location simple and painless. The basic idea is -that you supply a base directory for the installation, and the -:command:`install` command picks a set of directories (called an *installation -scheme*) under this base directory in which to install files. The details -differ across platforms, so read whichever of the following sections applies to -you. - - -.. _inst-alt-install-prefix: - -Alternate installation: the home scheme ---------------------------------------- - -The idea behind the "home scheme" is that you build and maintain a personal -stash of Python modules. This scheme's name is derived from the idea of a -"home" directory on Unix, since it's not unusual for a Unix user to make their -home directory have a layout similar to :file:`/usr/` or :file:`/usr/local/`. -This scheme can be used by anyone, regardless of the operating system they -are installing for. - -Installing a new module distribution is as simple as :: - - python setup.py install --home - -where you can supply any directory you like for the :option:`--home` option. On -Unix, lazy typists can just type a tilde (``~``); the :command:`install` command -will expand this to your home directory:: - - python setup.py install --home ~ - -The :option:`--home` option defines the installation base directory. Files are -installed to the following directories under the installation base as follows: - -+------------------------------+---------------------------+-----------------------------+ -| Type of file | Installation Directory | Override option | -+==============================+===========================+=============================+ -| pure module distribution | :file:`{home}/lib/python` | :option:`--install-purelib` | -+------------------------------+---------------------------+-----------------------------+ -| non-pure module distribution | :file:`{home}/lib/python` | :option:`--install-platlib` | -+------------------------------+---------------------------+-----------------------------+ -| scripts | :file:`{home}/bin` | :option:`--install-scripts` | -+------------------------------+---------------------------+-----------------------------+ -| data | :file:`{home}/share` | :option:`--install-data` | -+------------------------------+---------------------------+-----------------------------+ - - -.. _inst-alt-install-home: - -Alternate installation: Unix (the prefix scheme) ------------------------------------------------- - -The "prefix scheme" is useful when you wish to use one Python installation to -perform the build/install (i.e., to run the setup script), but install modules -into the third-party module directory of a different Python installation (or -something that looks like a different Python installation). If this sounds a -trifle unusual, it is---that's why the "home scheme" comes first. However, -there are at least two known cases where the prefix scheme will be useful. - -First, consider that many Linux distributions put Python in :file:`/usr`, rather -than the more traditional :file:`/usr/local`. This is entirely appropriate, -since in those cases Python is part of "the system" rather than a local add-on. -However, if you are installing Python modules from source, you probably want -them to go in :file:`/usr/local/lib/python2.{X}` rather than -:file:`/usr/lib/python2.{X}`. This can be done with :: - - /usr/bin/python setup.py install --prefix /usr/local - -Another possibility is a network filesystem where the name used to write to a -remote directory is different from the name used to read it: for example, the -Python interpreter accessed as :file:`/usr/local/bin/python` might search for -modules in :file:`/usr/local/lib/python2.{X}`, but those modules would have to -be installed to, say, :file:`/mnt/{@server}/export/lib/python2.{X}`. This could -be done with :: - - /usr/local/bin/python setup.py install --prefix=/mnt/@server/export - -In either case, the :option:`--prefix` option defines the installation base, and -the :option:`--exec-prefix` option defines the platform-specific installation -base, which is used for platform-specific files. (Currently, this just means -non-pure module distributions, but could be expanded to C libraries, binary -executables, etc.) If :option:`--exec-prefix` is not supplied, it defaults to -:option:`--prefix`. Files are installed as follows: - -+------------------------------+-----------------------------------------------------+-----------------------------+ -| Type of file | Installation Directory | Override option | -+==============================+=====================================================+=============================+ -| pure module distribution | :file:`{prefix}/lib/python{X.Y}/site-packages` | :option:`--install-purelib` | -+------------------------------+-----------------------------------------------------+-----------------------------+ -| non-pure module distribution | :file:`{exec-prefix}/lib/python{X.Y}/site-packages` | :option:`--install-platlib` | -+------------------------------+-----------------------------------------------------+-----------------------------+ -| scripts | :file:`{prefix}/bin` | :option:`--install-scripts` | -+------------------------------+-----------------------------------------------------+-----------------------------+ -| data | :file:`{prefix}/share` | :option:`--install-data` | -+------------------------------+-----------------------------------------------------+-----------------------------+ - -There is no requirement that :option:`--prefix` or :option:`--exec-prefix` -actually point to an alternate Python installation; if the directories listed -above do not already exist, they are created at installation time. - -Incidentally, the real reason the prefix scheme is important is simply that a -standard Unix installation uses the prefix scheme, but with :option:`--prefix` -and :option:`--exec-prefix` supplied by Python itself as ``sys.prefix`` and -``sys.exec_prefix``. Thus, you might think you'll never use the prefix scheme, -but every time you run ``python setup.py install`` without any other options, -you're using it. - -Note that installing extensions to an alternate Python installation has no -effect on how those extensions are built: in particular, the Python header files -(:file:`Python.h` and friends) installed with the Python interpreter used to run -the setup script will be used in compiling extensions. It is your -responsibility to ensure that the interpreter used to run extensions installed -in this way is compatible with the interpreter used to build them. The best way -to do this is to ensure that the two interpreters are the same version of Python -(possibly different builds, or possibly copies of the same build). (Of course, -if your :option:`--prefix` and :option:`--exec-prefix` don't even point to an -alternate Python installation, this is immaterial.) - - -.. _inst-alt-install-windows: - -Alternate installation: Windows (the prefix scheme) ---------------------------------------------------- - -Windows has no concept of a user's home directory, and since the standard Python -installation under Windows is simpler than under Unix, the :option:`--prefix` -option has traditionally been used to install additional packages in separate -locations on Windows. :: - - python setup.py install --prefix "\Temp\Python" - -to install modules to the :file:`\\Temp\\Python` directory on the current drive. - -The installation base is defined by the :option:`--prefix` option; the -:option:`--exec-prefix` option is not supported under Windows. Files are -installed as follows: - -+------------------------------+---------------------------+-----------------------------+ -| Type of file | Installation Directory | Override option | -+==============================+===========================+=============================+ -| pure module distribution | :file:`{prefix}` | :option:`--install-purelib` | -+------------------------------+---------------------------+-----------------------------+ -| non-pure module distribution | :file:`{prefix}` | :option:`--install-platlib` | -+------------------------------+---------------------------+-----------------------------+ -| scripts | :file:`{prefix}\\Scripts` | :option:`--install-scripts` | -+------------------------------+---------------------------+-----------------------------+ -| data | :file:`{prefix}\\Data` | :option:`--install-data` | -+------------------------------+---------------------------+-----------------------------+ - - -.. _inst-custom-install: - -Custom Installation -=================== - -Sometimes, the alternate installation schemes described in section -:ref:`inst-alt-install` just don't do what you want. You might want to tweak -just one or two directories while keeping everything under the same base -directory, or you might want to completely redefine the installation scheme. -In either case, you're creating a *custom installation scheme*. - -You probably noticed the column of "override options" in the tables describing -the alternate installation schemes above. Those options are how you define a -custom installation scheme. These override options can be relative, absolute, -or explicitly defined in terms of one of the installation base directories. -(There are two installation base directories, and they are normally the same--- -they only differ when you use the Unix "prefix scheme" and supply different -:option:`--prefix` and :option:`--exec-prefix` options.) - -For example, say you're installing a module distribution to your home directory -under Unix---but you want scripts to go in :file:`~/scripts` rather than -:file:`~/bin`. As you might expect, you can override this directory with the -:option:`--install-scripts` option; in this case, it makes most sense to supply -a relative path, which will be interpreted relative to the installation base -directory (your home directory, in this case):: - - python setup.py install --home ~ --install-scripts scripts - -Another Unix example: suppose your Python installation was built and installed -with a prefix of :file:`/usr/local/python`, so under a standard installation -scripts will wind up in :file:`/usr/local/python/bin`. If you want them in -:file:`/usr/local/bin` instead, you would supply this absolute directory for the -:option:`--install-scripts` option:: - - python setup.py install --install-scripts /usr/local/bin - -(This performs an installation using the "prefix scheme," where the prefix is -whatever your Python interpreter was installed with--- :file:`/usr/local/python` -in this case.) - -If you maintain Python on Windows, you might want third-party modules to live in -a subdirectory of :file:`{prefix}`, rather than right in :file:`{prefix}` -itself. This is almost as easy as customizing the script installation directory ----you just have to remember that there are two types of modules to worry about, -pure modules and non-pure modules (i.e., modules from a non-pure distribution). -For example:: - - python setup.py install --install-purelib Site --install-platlib Site - -The specified installation directories are relative to :file:`{prefix}`. Of -course, you also have to ensure that these directories are in Python's module -search path, such as by putting a :file:`.pth` file in :file:`{prefix}`. See -section :ref:`inst-search-path` to find out how to modify Python's search path. - -If you want to define an entire installation scheme, you just have to supply all -of the installation directory options. The recommended way to do this is to -supply relative paths; for example, if you want to maintain all Python -module-related files under :file:`python` in your home directory, and you want a -separate directory for each platform that you use your home directory from, you -might define the following installation scheme:: - - python setup.py install --home ~ \ - --install-purelib python/lib \ - --install-platlib python/'lib.$PLAT' \ - --install-scripts python/scripts - --install-data python/data - -or, equivalently, :: - - python setup.py install --home ~/python \ - --install-purelib lib \ - --install-platlib 'lib.$PLAT' \ - --install-scripts scripts - --install-data data - -``$PLAT`` is not (necessarily) an environment variable---it will be expanded by -the Distutils as it parses your command line options, just as it does when -parsing your configuration file(s). - -Obviously, specifying the entire installation scheme every time you install a -new module distribution would be very tedious. Thus, you can put these options -into your Distutils config file (see section :ref:`inst-config-files`):: - - [install] - install-base = $HOME - install-purelib = python/lib - install-platlib = python/lib.$PLAT - install-scripts = python/scripts - install-data = python/data - -or, equivalently, :: - - [install] - install-base = $HOME/python - install-purelib = lib - install-platlib = lib.$PLAT - install-scripts = scripts - install-data = data - -Note that these two are *not* equivalent if you supply a different installation -base directory when you run the setup script. For example, :: - - python setup.py install --install-base /tmp - -would install pure modules to :file:`{/tmp/python/lib}` in the first case, and -to :file:`{/tmp/lib}` in the second case. (For the second case, you probably -want to supply an installation base of :file:`/tmp/python`.) - -You probably noticed the use of ``$HOME`` and ``$PLAT`` in the sample -configuration file input. These are Distutils configuration variables, which -bear a strong resemblance to environment variables. In fact, you can use -environment variables in config files on platforms that have such a notion but -the Distutils additionally define a few extra variables that may not be in your -environment, such as ``$PLAT``. (And of course, on systems that don't have -environment variables, such as Mac OS 9, the configuration variables supplied by -the Distutils are the only ones you can use.) See section :ref:`inst-config-files` -for details. - -.. XXX need some Windows examples---when would custom installation schemes be - needed on those platforms? - - -.. XXX I'm not sure where this section should go. - -.. _inst-search-path: - -Modifying Python's Search Path ------------------------------- - -When the Python interpreter executes an :keyword:`import` statement, it searches -for both Python code and extension modules along a search path. A default value -for the path is configured into the Python binary when the interpreter is built. -You can determine the path by importing the :mod:`sys` module and printing the -value of ``sys.path``. :: - - $ python - Python 2.2 (#11, Oct 3 2002, 13:31:27) - [GCC 2.96 20000731 (Red Hat Linux 7.3 2.96-112)] on linux2 - Type "help", "copyright", "credits" or "license" for more information. - >>> import sys - >>> sys.path - ['', '/usr/local/lib/python2.3', '/usr/local/lib/python2.3/plat-linux2', - '/usr/local/lib/python2.3/lib-tk', '/usr/local/lib/python2.3/lib-dynload', - '/usr/local/lib/python2.3/site-packages'] - >>> - -The null string in ``sys.path`` represents the current working directory. - -The expected convention for locally installed packages is to put them in the -:file:`{...}/site-packages/` directory, but you may want to install Python -modules into some arbitrary directory. For example, your site may have a -convention of keeping all software related to the web server under :file:`/www`. -Add-on Python modules might then belong in :file:`/www/python`, and in order to -import them, this directory must be added to ``sys.path``. There are several -different ways to add the directory. - -The most convenient way is to add a path configuration file to a directory -that's already on Python's path, usually to the :file:`.../site-packages/` -directory. Path configuration files have an extension of :file:`.pth`, and each -line must contain a single path that will be appended to ``sys.path``. (Because -the new paths are appended to ``sys.path``, modules in the added directories -will not override standard modules. This means you can't use this mechanism for -installing fixed versions of standard modules.) - -Paths can be absolute or relative, in which case they're relative to the -directory containing the :file:`.pth` file. See the documentation of -the :mod:`site` module for more information. - -A slightly less convenient way is to edit the :file:`site.py` file in Python's -standard library, and modify ``sys.path``. :file:`site.py` is automatically -imported when the Python interpreter is executed, unless the :option:`-S` switch -is supplied to suppress this behaviour. So you could simply edit -:file:`site.py` and add two lines to it:: - - import sys - sys.path.append('/www/python/') - -However, if you reinstall the same major version of Python (perhaps when -upgrading from 2.2 to 2.2.2, for example) :file:`site.py` will be overwritten by -the stock version. You'd have to remember that it was modified and save a copy -before doing the installation. - -There are two environment variables that can modify ``sys.path``. -:envvar:`PYTHONHOME` sets an alternate value for the prefix of the Python -installation. For example, if :envvar:`PYTHONHOME` is set to ``/www/python``, -the search path will be set to ``['', '/www/python/lib/pythonX.Y/', -'/www/python/lib/pythonX.Y/plat-linux2', ...]``. - -The :envvar:`PYTHONPATH` variable can be set to a list of paths that will be -added to the beginning of ``sys.path``. For example, if :envvar:`PYTHONPATH` is -set to ``/www/python:/opt/py``, the search path will begin with -``['/www/python', '/opt/py']``. (Note that directories must exist in order to -be added to ``sys.path``; the :mod:`site` module removes paths that don't -exist.) - -Finally, ``sys.path`` is just a regular Python list, so any Python application -can modify it by adding or removing entries. - - -.. _inst-config-files: - -Distutils Configuration Files -============================= - -As mentioned above, you can use Distutils configuration files to record personal -or site preferences for any Distutils options. That is, any option to any -command can be stored in one of two or three (depending on your platform) -configuration files, which will be consulted before the command-line is parsed. -This means that configuration files will override default values, and the -command-line will in turn override configuration files. Furthermore, if -multiple configuration files apply, values from "earlier" files are overridden -by "later" files. - - -.. _inst-config-filenames: - -Location and names of config files ----------------------------------- - -The names and locations of the configuration files vary slightly across -platforms. On Unix and Mac OS X, the three configuration files (in the order -they are processed) are: - -+--------------+----------------------------------------------------------+-------+ -| Type of file | Location and filename | Notes | -+==============+==========================================================+=======+ -| system | :file:`{prefix}/lib/python{ver}/distutils/distutils.cfg` | \(1) | -+--------------+----------------------------------------------------------+-------+ -| personal | :file:`$HOME/.pydistutils.cfg` | \(2) | -+--------------+----------------------------------------------------------+-------+ -| local | :file:`setup.cfg` | \(3) | -+--------------+----------------------------------------------------------+-------+ - -And on Windows, the configuration files are: - -+--------------+-------------------------------------------------+-------+ -| Type of file | Location and filename | Notes | -+==============+=================================================+=======+ -| system | :file:`{prefix}\\Lib\\distutils\\distutils.cfg` | \(4) | -+--------------+-------------------------------------------------+-------+ -| personal | :file:`%HOME%\\pydistutils.cfg` | \(5) | -+--------------+-------------------------------------------------+-------+ -| local | :file:`setup.cfg` | \(3) | -+--------------+-------------------------------------------------+-------+ - -On all platforms, the "personal" file can be temporarily disabled by -passing the `--no-user-cfg` option. - -Notes: - -(1) - Strictly speaking, the system-wide configuration file lives in the directory - where the Distutils are installed; under Python 1.6 and later on Unix, this - is as shown. For Python 1.5.2, the Distutils will normally be installed to - :file:`{prefix}/lib/python1.5/site-packages/distutils`, so the system - configuration file should be put there under Python 1.5.2. - -(2) - On Unix, if the :envvar:`HOME` environment variable is not defined, the - user's home directory will be determined with the :func:`getpwuid` function - from the standard :mod:`pwd` module. This is done by the - :func:`os.path.expanduser` function used by Distutils. - -(3) - I.e., in the current directory (usually the location of the setup script). - -(4) - (See also note (1).) Python's default installation prefix is - :file:`C:\\Python`, so the system configuration file is normally - :file:`C:\\Python\\Lib\\distutils\\distutils.cfg`. - -(5) - On Windows, if the :envvar:`HOME` environment variable is not defined, - :envvar:`USERPROFILE` then :envvar:`HOMEDRIVE` and :envvar:`HOMEPATH` will - be tried. This is done by the :func:`os.path.expanduser` function used - by Distutils. - - -.. _inst-config-syntax: - -Syntax of config files ----------------------- - -The Distutils configuration files all have the same syntax. The config files -are grouped into sections. There is one section for each Distutils command, -plus a ``global`` section for global options that affect every command. Each -section consists of one option per line, specified as ``option = value``. - -For example, the following is a complete config file that just forces all -commands to run quietly by default:: - - [global] - verbose = 0 - -If this is installed as the system config file, it will affect all processing -of any Python module distribution by any user on the current system. If it is -installed as your personal config file (on systems that support them), it will -affect only module distributions processed by you. And if it is used as the -:file:`setup.cfg` for a particular module distribution, it affects only that -distribution. - -You could override the default "build base" directory and make the -:command:`build\*` commands always forcibly rebuild all files with the -following:: - - [build] - build-base = blib - force = 1 - -which corresponds to the command-line arguments :: - - python setup.py build --build-base blib --force - -except that including the :command:`build` command on the command-line means -that command will be run. Including a particular command in config files has no -such implication; it only means that if the command is run, the options in the -config file will apply. (Or if other commands that derive values from it are -run, they will use the values in the config file.) - -You can find out the complete list of options for any command using the -:option:`--help` option, e.g.:: - - python setup.py build --help - -and you can find out the complete list of global options by using -:option:`--help` without a command:: - - python setup.py --help - -See also the "Reference" section of the "Distributing Python Modules" manual. - - -.. _inst-building-ext: - -Building Extensions: Tips and Tricks -==================================== - -Whenever possible, the Distutils try to use the configuration information made -available by the Python interpreter used to run the :file:`setup.py` script. -For example, the same compiler and linker flags used to compile Python will also -be used for compiling extensions. Usually this will work well, but in -complicated situations this might be inappropriate. This section discusses how -to override the usual Distutils behaviour. - - -.. _inst-tweak-flags: - -Tweaking compiler/linker flags ------------------------------- - -Compiling a Python extension written in C or C++ will sometimes require -specifying custom flags for the compiler and linker in order to use a particular -library or produce a special kind of object code. This is especially true if the -extension hasn't been tested on your platform, or if you're trying to -cross-compile Python. - -.. TODO update to new setup.cfg - -In the most general case, the extension author might have foreseen that -compiling the extensions would be complicated, and provided a :file:`Setup` file -for you to edit. This will likely only be done if the module distribution -contains many separate extension modules, or if they often require elaborate -sets of compiler flags in order to work. - -A :file:`Setup` file, if present, is parsed in order to get a list of extensions -to build. Each line in a :file:`Setup` describes a single module. Lines have -the following structure:: - - module ... [sourcefile ...] [cpparg ...] [library ...] - - -Let's examine each of the fields in turn. - -* *module* is the name of the extension module to be built, and should be a - valid Python identifier. You can't just change this in order to rename a module - (edits to the source code would also be needed), so this should be left alone. - -* *sourcefile* is anything that's likely to be a source code file, at least - judging by the filename. Filenames ending in :file:`.c` are assumed to be - written in C, filenames ending in :file:`.C`, :file:`.cc`, and :file:`.c++` are - assumed to be C++, and filenames ending in :file:`.m` or :file:`.mm` are assumed - to be in Objective C. - -* *cpparg* is an argument for the C preprocessor, and is anything starting with - :option:`-I`, :option:`-D`, :option:`-U` or :option:`-C`. - -* *library* is anything ending in :file:`.a` or beginning with :option:`-l` or - :option:`-L`. - -If a particular platform requires a special library on your platform, you can -add it by editing the :file:`Setup` file and running ``python setup.py build``. -For example, if the module defined by the line :: - - foo foomodule.c - -must be linked with the math library :file:`libm.a` on your platform, simply add -:option:`-lm` to the line:: - - foo foomodule.c -lm - -Arbitrary switches intended for the compiler or the linker can be supplied with -the :option:`-Xcompiler` *arg* and :option:`-Xlinker` *arg* options:: - - foo foomodule.c -Xcompiler -o32 -Xlinker -shared -lm - -The next option after :option:`-Xcompiler` and :option:`-Xlinker` will be -appended to the proper command line, so in the above example the compiler will -be passed the :option:`-o32` option, and the linker will be passed -:option:`-shared`. If a compiler option requires an argument, you'll have to -supply multiple :option:`-Xcompiler` options; for example, to pass ``-x c++`` -the :file:`Setup` file would have to contain ``-Xcompiler -x -Xcompiler c++``. - -Compiler flags can also be supplied through setting the :envvar:`CFLAGS` -environment variable. If set, the contents of :envvar:`CFLAGS` will be added to -the compiler flags specified in the :file:`Setup` file. - - -.. _inst-non-ms-compilers: - -Using non-Microsoft compilers on Windows ----------------------------------------- - -.. sectionauthor:: Rene Liebscher - - - -Borland/CodeGear C++ -^^^^^^^^^^^^^^^^^^^^ - -This subsection describes the necessary steps to use Distutils with the Borland -C++ compiler version 5.5. First you have to know that Borland's object file -format (OMF) is different from the format used by the Python version you can -download from the Python or ActiveState Web site. (Python is built with -Microsoft Visual C++, which uses COFF as the object file format.) For this -reason you have to convert Python's library :file:`python25.lib` into the -Borland format. You can do this as follows: - -.. Should we mention that users have to create cfg-files for the compiler? -.. see also http://community.borland.com/article/0,1410,21205,00.html - -:: - - coff2omf python25.lib python25_bcpp.lib - -The :file:`coff2omf` program comes with the Borland compiler. The file -:file:`python25.lib` is in the :file:`Libs` directory of your Python -installation. If your extension uses other libraries (zlib, ...) you have to -convert them too. - -The converted files have to reside in the same directories as the normal -libraries. - -How does Distutils manage to use these libraries with their changed names? If -the extension needs a library (eg. :file:`foo`) Distutils checks first if it -finds a library with suffix :file:`_bcpp` (eg. :file:`foo_bcpp.lib`) and then -uses this library. In the case it doesn't find such a special library it uses -the default name (:file:`foo.lib`.) [#]_ - -To let Distutils compile your extension with Borland C++ you now have to type:: - - python setup.py build --compiler bcpp - -If you want to use the Borland C++ compiler as the default, you could specify -this in your personal or system-wide configuration file for Distutils (see -section :ref:`inst-config-files`.) - - -.. seealso:: - - `C++Builder Compiler `_ - Information about the free C++ compiler from Borland, including links to the - download pages. - - `Creating Python Extensions Using Borland's Free Compiler `_ - Document describing how to use Borland's free command-line C++ compiler to build - Python. - - -GNU C / Cygwin / MinGW -^^^^^^^^^^^^^^^^^^^^^^ - -This section describes the necessary steps to use Distutils with the GNU C/C++ -compilers in their Cygwin and MinGW distributions. [#]_ For a Python interpreter -that was built with Cygwin, everything should work without any of these -following steps. - -Not all extensions can be built with MinGW or Cygwin, but many can. Extensions -most likely to not work are those that use C++ or depend on Microsoft Visual C -extensions. - -To let Distutils compile your extension with Cygwin you have to type:: - - python setup.py build --compiler=cygwin - -and for Cygwin in no-cygwin mode [#]_ or for MinGW type:: - - python setup.py build --compiler=mingw32 - -If you want to use any of these options/compilers as default, you should -consider writing it in your personal or system-wide configuration file for -Distutils (see section :ref:`inst-config-files`.) - -Older Versions of Python and MinGW -"""""""""""""""""""""""""""""""""" -The following instructions only apply if you're using a version of Python -inferior to 2.4.1 with a MinGW inferior to 3.0.0 (with -binutils-2.13.90-20030111-1). - -These compilers require some special libraries. This task is more complex than -for Borland's C++, because there is no program to convert the library. First -you have to create a list of symbols which the Python DLL exports. (You can find -a good program for this task at -http://www.emmestech.com/software/pexports-0.43/download_pexports.html). - -.. I don't understand what the next line means. --amk -.. (inclusive the references on data structures.) - -:: - - pexports python25.dll > python25.def - -The location of an installed :file:`python25.dll` will depend on the -installation options and the version and language of Windows. In a "just for -me" installation, it will appear in the root of the installation directory. In -a shared installation, it will be located in the system directory. - -Then you can create from these information an import library for gcc. :: - - /cygwin/bin/dlltool --dllname python25.dll --def python25.def --output-lib libpython25.a - -The resulting library has to be placed in the same directory as -:file:`python25.lib`. (Should be the :file:`libs` directory under your Python -installation directory.) - -If your extension uses other libraries (zlib,...) you might have to convert -them too. The converted files have to reside in the same directories as the -normal libraries do. - - -.. seealso:: - - `Building Python modules on MS Windows platform with MinGW `_ - Information about building the required libraries for the MinGW - environment. - - -.. rubric:: Footnotes - -.. [#] This also means you could replace all existing COFF-libraries with - OMF-libraries of the same name. - -.. [#] Check http://sources.redhat.com/cygwin/ and http://www.mingw.org/ for - more information - -.. [#] Then you have no POSIX emulation available, but you also don't need - :file:`cygwin1.dll`. diff --git a/docs/source/library/distutils2.depgraph.rst b/docs/source/library/distutils2.depgraph.rst deleted file mode 100644 --- a/docs/source/library/distutils2.depgraph.rst +++ /dev/null @@ -1,125 +0,0 @@ -=============================== -Dependency Graph Builder Module -=============================== - -Introduction ------------- - -This module provides the means to analyse the dependencies between various -distributions and furthermore to create a graph representing the relationships -from a list of :class:`distutils2._backport.pkgutil.Distribution` and -:class:`distutils2._backport.pkgutil.EggInfoDistribution` instances. The graph -is represented by the :class:`distutils2.depgraph.DependencyGraph` class that -keeps internally an adjacency list. Several functions are provided that -generate a graph in different manners. First, all of them are documented and -then several use case examples are provided along with -`graphviz `_ illustrations -of the generated graphs. - -API ---- - -.. automodule:: distutils2.depgraph - :members: - -Example Usage -------------- - -Depict all Dependenciess in the System -++++++++++++++++++++++++++++++++++++++ - -First, we shall generate a graph of all the distributions on the system -and then create an image out of it using the tools provided by -`graphviz `_. For obtaining the list of -installed distributions, we will use the functions provided by the module -:mod:`distutils2._backport.pkgutil`:: - - from distutils2._backport.pkgutil import get_distributions - from distutils2.depgraph import generate_graph - - dists = list(pkgutil.get_distributions()) - graph = generate_graph(dists) - -Now, it would be of interest to print out the missing requirements. This -can be done as follows:: - - for dist, reqs in graph.missing.iteritems(): - if len(reqs) > 0: - reqs_s = " ,".join(reqs) - print("Missing dependencies for %s: %s" % (dist.name, reqs_s)) - -Example output on my configuration is: - -.. code-block:: none - - Missing dependencies for TurboCheetah: Cheetah - Missing dependencies for TurboGears: ConfigObj, DecoratorTools, RuleDispatch - Missing dependencies for jockey: PyKDE4.kdecore, PyKDE4.kdeui, PyQt4.QtCore, PyQt4.QtGui - Missing dependencies for TurboKid: kid - Missing dependencies for TurboJson: DecoratorTools, RuleDispatch - -Now, we proceed with generating a graphical representation of the graph. First -we write it to a file, and then we generate a PNG image using the ``dot`` -command-line tool:: - - from distutils2.depgraph import graph_to_dot - f = open('output.dot', 'w') - # we only show the interesting distributions, skipping the disconnected ones - graph_to_dot(graph, f, skip_disconnected=True) - -Now, we can create the actual picture using: - -.. code-block:: bash - - $ dot -Tpng output.dot > output.png - -An example output image is: - -.. figure:: ../images/depgraph_output.png - :alt: An example dot output - -If you want to include ``.egg`` and ``.egg-info`` distributions as well, then -the code requires only one change, namely the line:: - - dists = list(pkgutil.get_distributions()) - -has to be replaced with:: - - dists = list(pkgutil.get_distributions(use_egg_info=True)) - -Then, on most platforms, a richer graph is obtained because at the moment most -distributions are provided in the ``.egg``/``.egg-info`` rather than the -``.dist-info`` format. An example of a more involved graph for illustrative -reasons can be seen `here <_static/depgraph_big.png>`_. - - -List all Dependent Distributions -++++++++++++++++++++++++++++++++ - -We will list all distributions that are dependent on some given distibution. -This time, ``.egg``/``.egg-info`` distributions will be considered as well:: - - from distutils2._backport.pkgutil import get_distributions - from distutils2.depgraph import dependent_dists - import sys - - dists = list(get_distributions(use_egg_info=True)) - dist = None - for d in dists: - if d.name == 'bacon': - dist = d - break - if dist is None: - print('No such distribution in the system') - sys.exit(1) - deps = dependent_dists(dists, dist) - deps_s = ", ".join([x.name for x in deps]) - print("The following distributions depend on %s: %s" % (dist.name, deps_s)) - -And this is example output with the dependency relationships as in the -`previous section <_static/depgraph_big.png>`_: - -.. code-block:: none - - The following distributions depend on bacon: towel-stuff, choxie, grammar - diff --git a/docs/source/library/distutils2.index.client.rst b/docs/source/library/distutils2.index.client.rst deleted file mode 100644 --- a/docs/source/library/distutils2.index.client.rst +++ /dev/null @@ -1,20 +0,0 @@ -=============================== -High level API to Query indexes -=============================== - -Distutils2 provides a high level API to query indexes, search for releases and -distributions, no matters the underlying API you want to use. - -The aim of this module is to choose the best way to query the API, using the -less possible XML-RPC, and when possible the simple index. - -API -=== - -The client comes with the common methods "find_projects", "get_release" and -"get_releases", which helps to query the servers, and returns -:class:`distutils2.index.dist.ReleaseInfo`, and -:class:`distutils2.index.dist.ReleasesList` objects. - -.. autoclass:: distutils2.index.wrapper.ClientWrapper - :members: diff --git a/docs/source/library/distutils2.index.dist.rst b/docs/source/library/distutils2.index.dist.rst deleted file mode 100644 --- a/docs/source/library/distutils2.index.dist.rst +++ /dev/null @@ -1,112 +0,0 @@ -================================================== -Representation of informations coming from indexes -================================================== - -Informations coming from indexes are represented by the classes present in the -:mod:`distutils2.index.dist` module. - -API -=== - -Keep in mind that each project (eg. FooBar) can have several releases -(eg. 1.1, 1.2, 1.3), and each of these releases can be provided in multiple -distributions (eg. a source distribution, a binary one, etc). - -ReleaseInfo ------------- - -Each release have a project name, a project version and contain project -metadata. In addition, releases contain the distributions too. - -These informations are stored in :class:`distutils2.index.dist.ReleaseInfo` -objects. - -.. autoclass:: distutils2.index.dist.ReleaseInfo - :members: - -DistInfo ---------- - -:class:`distutils2.index.dist.DistInfo` is a simple class that contains -informations related to distributions. It's mainly about the URLs where those -distributions can be found. - -.. autoclass:: distutils2.index.dist.DistInfo - :members: - -ReleasesList ------------- - -The :mod:`~distutils2.index.dist` module also provides another class, to work -with lists of :class:`distutils2.index.dist.ReleaseInfo` classes. It allow to -filter and order results. - -.. autoclass:: distutils2.index.dist.ReleasesList - :members: - -Exemple usages -=============== - -Build a list of releases, and order them ----------------------------------------- - -Assuming we have a list of releases:: - - >>> from distutils2.index.dist import ReleaseList, ReleaseInfo - >>> fb10 = ReleaseInfo("FooBar", "1.0") - >>> fb11 = ReleaseInfo("FooBar", "1.1") - >>> fb11a = ReleaseInfo("FooBar", "1.1a1") - >>> ReleasesList("FooBar", [fb11, fb11a, fb10]) - >>> releases.sort_releases() - >>> releases.get_versions() - ['1.1', '1.1a1', '1.0'] - >>> releases.add_release("1.2a1") - >>> releases.get_versions() - ['1.1', '1.1a1', '1.0', '1.2a1'] - >>> releases.sort_releases() - ['1.2a1', '1.1', '1.1a1', '1.0'] - >>> releases.sort_releases(prefer_final=True) - >>> releases.get_versions() - ['1.1', '1.0', '1.2a1', '1.1a1'] - - -Add distribution related informations to releases -------------------------------------------------- - -It's easy to add distribution informatons to releases:: - - >>> from distutils2.index.dist import ReleaseList, ReleaseInfo - >>> r = ReleaseInfo("FooBar", "1.0") - >>> r.add_distribution("sdist", url="http://example.org/foobar-1.0.tar.gz") - >>> r.dists - {'sdist': FooBar 1.0 sdist} - >>> r['sdist'].url - {'url': 'http://example.org/foobar-1.0.tar.gz', 'hashname': None, 'hashval': - None, 'is_external': True} - -Getting attributes from the dist objects ------------------------------------------ - -To abstract a maximum the way of querying informations to the indexes, -attributes and releases informations can be retrieved directly from the objects -returned by the indexes. - -For instance, if you have a release instance that does not contain the metadata -attribute, it can be fetched by using the "fetch_metadata" method:: - - >>> r = Release("FooBar", "1.1") - >>> print r.metadata - None # metadata field is actually set to "None" - >>> r.fetch_metadata() - - -.. XXX add proper roles to these constructs - -Like this, it's possible to retrieve project's releases (`fetch_releases`), -releases metadata (`fetch_metadata` and releases distributions -(`fetch_distributions` informations). - -Internally, this is possible because while retrieving for the first time -informations about projects, releases or distributions, a reference to the -client used is stored in the objects (can be accessed using the object -`_index` attribute. diff --git a/docs/source/library/distutils2.index.rst b/docs/source/library/distutils2.index.rst deleted file mode 100644 --- a/docs/source/library/distutils2.index.rst +++ /dev/null @@ -1,31 +0,0 @@ -=================================== -Query Python Package Indexes (PyPI) -=================================== - -Distutils2 queries PyPI to get information about projects or download those -projects. The low-level facilities used internally are also part of the public -API destined to be used by other tools. - -The :mod:`distutils2.index` package provides those facilities, which can be -used to access informations about Python projects registered at indexes, the -main one being PyPI, located ad http://pypi.python.org/. - -There is two ways to retrieve data from these indexes: using the *simple* API, -and using *XML-RPC*. The first one is a set of HTML pages avalaibles at -`http://pypi.python.org/simple/`, and the second one contains a set of XML-RPC -methods. Mirrors typically implement the simple interface. - -If you dont care about which API to use, the best thing to do is to let -distutils2 decide this for you, by using :class:`distutils2.index.ClientWrapper`. - -Of course, you can rely too on :class:`distutils2.index.simple.Crawler` and -:class:`distutils2.index.xmlrpc.Client` if you need to use a specific API. - -.. toctree:: - :maxdepth: 2 - :numbered: - - distutils2.index.client - distutils2.index.dist - distutils2.index.simple - distutils2.index.xmlrpc diff --git a/docs/source/library/distutils2.index.simple.rst b/docs/source/library/distutils2.index.simple.rst deleted file mode 100644 --- a/docs/source/library/distutils2.index.simple.rst +++ /dev/null @@ -1,143 +0,0 @@ -========================================= -Querying indexes via the simple index API -========================================= - -`distutils2.index.simple` can process Python Package Indexes, and provides -useful informations about distributions. It also can crawl local indexes, for -instance. - -You should use `distutils2.index.simple` for: - - * Search distributions by name and versions. - * Process index external pages. - * Download distributions by name and versions. - -And should not be used to: - - * Things that will end up in too long index processing (like "finding all - distributions with a specific version, no matters the name") - -API ---- - -.. autoclass:: distutils2.index.simple.Crawler - :members: - - -Usage Exemples ---------------- - -To help you understand how using the `Crawler` class, here are some basic -usages. - -Request the simple index to get a specific distribution -++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -Supposing you want to scan an index to get a list of distributions for -the "foobar" project. You can use the "get_releases" method for that. -The get_releases method will browse the project page, and return :class:`ReleaseInfo` -objects for each found link that rely on downloads. :: - - >>> from distutils2.index.simple import Crawler - >>> crawler = Crawler() - >>> crawler.get_releases("FooBar") - [, ] - -Note that you also can request the client about specific versions, using version -specifiers (described in `PEP 345 -`_):: - - >>> client.get_releases("FooBar < 1.2") - [, ] - -`get_releases` returns a list of :class:`ReleaseInfo`, but you also can get the best -distribution that fullfil your requirements, using "get_release":: - - >>> client.get_release("FooBar < 1.2") - - -Download distributions -+++++++++++++++++++++++ - -As it can get the urls of distributions provided by PyPI, the `Crawler` -client also can download the distributions and put it for you in a temporary -destination:: - - >>> client.download("foobar") - /tmp/temp_dir/foobar-1.2.tar.gz - -You also can specify the directory you want to download to:: - - >>> client.download("foobar", "/path/to/my/dir") - /path/to/my/dir/foobar-1.2.tar.gz - -While downloading, the md5 of the archive will be checked, if not matches, it -will try another time, then if fails again, raise `MD5HashDoesNotMatchError`. - -Internally, that's not the Crawler which download the distributions, but the -`DistributionInfo` class. Please refer to this documentation for more details. - -Following PyPI external links -++++++++++++++++++++++++++++++ - -The default behavior for distutils2 is to *not* follow the links provided -by HTML pages in the "simple index", to find distributions related -downloads. - -It's possible to tell the PyPIClient to follow external links by setting the -`follow_externals` attribute, on instantiation or after:: - - >>> client = Crawler(follow_externals=True) - -or :: - - >>> client = Crawler() - >>> client.follow_externals = True - -Working with external indexes, and mirrors -+++++++++++++++++++++++++++++++++++++++++++ - -The default `Crawler` behavior is to rely on the Python Package index stored -on PyPI (http://pypi.python.org/simple). - -As you can need to work with a local index, or private indexes, you can specify -it using the index_url parameter:: - - >>> client = Crawler(index_url="file://filesystem/path/") - -or :: - - >>> client = Crawler(index_url="http://some.specific.url/") - -You also can specify mirrors to fallback on in case the first index_url you -provided doesnt respond, or not correctly. The default behavior for -`Crawler` is to use the list provided by Python.org DNS records, as -described in the :PEP:`381` about mirroring infrastructure. - -If you don't want to rely on these, you could specify the list of mirrors you -want to try by specifying the `mirrors` attribute. It's a simple iterable:: - - >>> mirrors = ["http://first.mirror","http://second.mirror"] - >>> client = Crawler(mirrors=mirrors) - -Searching in the simple index -+++++++++++++++++++++++++++++ - -It's possible to search for projects with specific names in the package index. -Assuming you want to find all projects containing the "distutils" keyword:: - - >>> c.search_projects("distutils") - [, , , , , , ] - -You can also search the projects starting with a specific text, or ending with -that text, using a wildcard.:: - - >>> c.search_projects("distutils*") - [, , ] - - >>> c.search_projects("*distutils") - [, , , , ] diff --git a/docs/source/library/distutils2.index.xmlrpc.rst b/docs/source/library/distutils2.index.xmlrpc.rst deleted file mode 100644 --- a/docs/source/library/distutils2.index.xmlrpc.rst +++ /dev/null @@ -1,128 +0,0 @@ -========================= -Query indexes via XML-RPC -========================= - -Indexes can be queried using XML-RPC calls, and Distutils2 provides a simple -way to interface with XML-RPC. - -You should **use** XML-RPC when: - - * Searching the index for projects **on other fields than project - names**. For instance, you can search for projects based on the - author_email field. - * Searching all the versions that have existed for a project. - * you want to retrive METADATAs informations from releases or - distributions. - -You should **avoid using** XML-RPC method calls when: - - * Retrieving the last version of a project - * Getting the projects with a specific name and version. - * The simple index can match your needs - -When dealing with indexes, keep in mind that the index queriers will always -return you :class:`distutils2.index.ReleaseInfo` and -:class:`distutils2.index.ReleasesList` objects. - -Some methods here share common APIs with the one you can find on -:class:`distutils2.index.simple`, internally, :class:`distutils2.index.client` -is inherited by :class:`distutils2.index.xmlrpc.Client` - -API -==== - -.. autoclass:: distutils2.index.xmlrpc.Client - :members: - -Usage examples -=============== - -Use case described here are use case that are not common to the other clients. -If you want to see all the methods, please refer to API or to usage examples -described in :class:`distutils2.index.client.Client` - -Finding releases ----------------- - -It's a common use case to search for "things" within the index. -We can basically search for projects by their name, which is the -most used way for users (eg. "give me the last version of the FooBar project"). -This can be accomplished using the following syntax:: - - >>> client = xmlrpc.Client() - >>> client.get_release("Foobar (<= 1.3)) - - >>> client.get_releases("FooBar (<= 1.3)") - [FooBar 1.1, FooBar 1.1.1, FooBar 1.2, FooBar 1.2.1] - -And we also can find for specific fields:: - - >>> client.search_projects(field=value) - -You could specify the operator to use, default is "or":: - - >>> client.search_projects(field=value, operator="and") - -The specific fields you can search are: - - * name - * version - * author - * author_email - * maintainer - * maintainer_email - * home_page - * license - * summary - * description - * keywords - * platform - * download_url - -Getting metadata informations ------------------------------ - -XML-RPC is a prefered way to retrieve metadata informations from indexes. -It's really simple to do so:: - - >>> client = xmlrpc.Client() - >>> client.get_metadata("FooBar", "1.1") - - -Assuming we already have a :class:`distutils2.index.ReleaseInfo` object defined, -it's possible to pass it ot the xmlrpc client to retrieve and complete its -metadata:: - - >>> foobar11 = ReleaseInfo("FooBar", "1.1") - >>> client = xmlrpc.Client() - >>> returned_release = client.get_metadata(release=foobar11) - >>> returned_release - - -Get all the releases of a project ---------------------------------- - -To retrieve all the releases for a project, you can build them using -`get_releases`:: - - >>> client = xmlrpc.Client() - >>> client.get_releases("FooBar") - [, , ] - -Get informations about distributions ------------------------------------- - -Indexes have informations about projects, releases **and** distributions. -If you're not familiar with those, please refer to the documentation of -:mod:`distutils2.index.dist`. - -It's possible to retrive informations about distributions, e.g "what are the -existing distributions for this release ? How to retrieve them ?":: - - >>> client = xmlrpc.Client() - >>> release = client.get_distributions("FooBar", "1.1") - >>> release.dists - {'sdist': , 'bdist': } - -As you see, this does not return a list of distributions, but a release, -because a release can be used like a list of distributions. diff --git a/docs/source/library/distutils2.install.rst b/docs/source/library/distutils2.install.rst deleted file mode 100644 --- a/docs/source/library/distutils2.install.rst +++ /dev/null @@ -1,25 +0,0 @@ -================== -Installation tools -================== - -In addition to the install commands, distutils2 provides a set of tools to deal -with installation of distributions. - -Basically, they're intended to download the distribution from indexes, to -resolve the dependencies, and to provide a safe way to install all the -distributions. - -You can find those tools in :module distutils2.install_tools:. - - -API ---- - -.. automodule:: distutils2.install - :members: - -Example usage --------------- - -Get the scheme of what's gonna be installed if we install "foobar": - diff --git a/docs/source/library/distutils2.metadata.rst b/docs/source/library/distutils2.metadata.rst deleted file mode 100644 --- a/docs/source/library/distutils2.metadata.rst +++ /dev/null @@ -1,93 +0,0 @@ -======== -Metadata -======== - -.. module:: distutils2.metadata - -Distutils2 provides a :class:`~distutils2.metadata.Metadata` class that can read and -write metadata files. This class is compatible with all metadata versions: - -* 1.0: :PEP:`241` -* 1.1: :PEP:`314` -* 1.2: :PEP:`345` - -The :PEP:`345` implementation supports the micro-language for the environment -markers, and displays warnings when versions that are supposed to be -:PEP:`386` are violating the scheme. - - -Reading metadata -================ - -The :class:`~distutils2.metadata.Metadata` class can be instantiated with the path of -the metadata file, and provides a dict-like interface to the values:: - - >>> from distutils2.metadata import Metadata - >>> metadata = Metadata('PKG-INFO') - >>> metadata.keys()[:5] - ('Metadata-Version', 'Name', 'Version', 'Platform', 'Supported-Platform') - >>> metadata['Name'] - 'CLVault' - >>> metadata['Version'] - '0.5' - >>> metadata['Requires-Dist'] - ["pywin32; sys.platform == 'win32'", "Sphinx"] - -The fields that supports environment markers can be automatically ignored if -the object is instantiated using the ``platform_dependent`` option. -:class:`~distutils2.metadata.Metadata` will interpret in the case the markers and will -automatically remove the fields that are not compliant with the running -environment. Here's an example under Mac OS X. The win32 dependency -we saw earlier is ignored:: - - >>> from distutils2.metadata import Metadata - >>> metadata = Metadata('PKG-INFO', platform_dependent=True) - >>> metadata['Requires-Dist'] - ['bar'] - -If you want to provide your own execution context, let's say to test the -metadata under a particular environment that is not the current environment, -you can provide your own values in the ``execution_context`` option, which -is the dict that may contain one or more keys of the context the micro-language -expects. - -Here's an example, simulating a win32 environment:: - - >>> from distutils2.metadata import Metadata - >>> context = {'sys.platform': 'win32'} - >>> metadata = Metadata('PKG-INFO', platform_dependent=True, - ... execution_context=context) - ... - >>> metadata['Requires-Dist'] = ["pywin32; sys.platform == 'win32'", - ... "Sphinx"] - ... - >>> metadata['Requires-Dist'] - ['pywin32', 'Sphinx'] - - -Writing metadata -================ - -Writing metadata can be done using the ``write`` API:: - - >>> metadata.write('/to/my/PKG-INFO') - -The class will pick the best version for the metadata, depending on the values -provided. If all the values provided exist in all versions, the class will -use :attr:`metadata.PKG_INFO_PREFERRED_VERSION`. It is set by default to 1.0. - - -Conflict checking and best version -================================== - -Some fields in :PEP:`345` have to follow a version scheme in their versions -predicate. When the scheme is violated, a warning is emitted:: - - >>> from distutils2.metadata import Metadata - >>> metadata = Metadata() - >>> metadata['Requires-Dist'] = ['Funky (Groovie)'] - "Funky (Groovie)" is not a valid predicate - >>> metadata['Requires-Dist'] = ['Funky (1.2)'] - - -.. TODO talk about check() diff --git a/docs/source/library/distutils2.rst b/docs/source/library/distutils2.rst deleted file mode 100644 --- a/docs/source/library/distutils2.rst +++ /dev/null @@ -1,44 +0,0 @@ -:mod:`distutils2` --- Packaging support -======================================= - -.. module:: distutils2 - :synopsis: Packaging system and building blocks for other packaging systems -.. sectionauthor:: Distutils2 contributors - - -The :mod:`distutils2` package provides support for building, packaging, -distributing and installing additional projects into a Python installation. -Projects may be include modules, extension modules, packages and scripts. -:mod:`distutils2` also provides building blocks for other packaging systems -that do not use the command system. - -This manual is the reference documentation for those standalone building -blocks and for extending Distutils2. If you're looking for the user-centric -guides to install a project or package your own code, head to `See also`__. - - -.. toctree:: - :maxdepth: 2 - :numbered: - - distutils2.version - distutils2.metadata - distutils2.depgraph - distutils2.install - distutils2.index - distutils2.tests.pypi_server - - -.. __: - -.. seealso:: - - :doc:`../distutils/index` - The manual for developers of Python projects who want to package and - distribute them. This describes how to use :mod:`distutils2` to make - projects easily found and added to an existing Python installation. - - :doc:`../install/index` - A user-centered manual which includes information on adding projects - into an existing Python installation. You do not need to be a Python - programmer to read this manual. diff --git a/docs/source/library/distutils2.tests.pypi_server.rst b/docs/source/library/distutils2.tests.pypi_server.rst deleted file mode 100644 --- a/docs/source/library/distutils2.tests.pypi_server.rst +++ /dev/null @@ -1,89 +0,0 @@ -============== -Test Framework -============== - -When you are testing code that works with distutils, you might find these tools -useful. - -``PyPIServer`` -============== - -PyPIServer is a class that implements an HTTP server running in a separate -thread. All it does is record the requests for further inspection. The recorded -data is available under ``requests`` attribute. The default -HTTP response can be overriden with the ``default_response_status``, -``default_response_headers`` and ``default_response_data`` attributes. - -By default, when accessing the server with urls beginning with `/simple/`, -the server also record your requests, but will look for files under -the `/tests/pypiserver/simple/` path. - -You can tell the sever to serve static files for other paths. This could be -accomplished by using the `static_uri_paths` parameter, as below:: - - server = PyPIServer(static_uri_paths=["first_path", "second_path"]) - -You need to create the content that will be served under the -`/tests/pypiserver/default` path. If you want to serve content from another -place, you also can specify another filesystem path (wich need to be under -`tests/pypiserver/`. This will replace the default behavior of the server, and -it will not serve content from the `default` dir :: - - server = PyPIServer(static_filesystem_paths=["path/to/your/dir"]) - -If you just need to add some paths to the existing ones, you can do as shown, -keeping in mind that the server will alwas try to load paths in reverse order -(e.g here, try "another/super/path" then the default one) :: - - server = PyPIServer(test_static_path="another/super/path") - server = PyPIServer("another/super/path") - # or - server.static_filesystem_paths.append("another/super/path") - -As a result of what, in your tests, while you need to use the PyPIServer, in -order to isolates the test cases, the best practice is to place the common files -in the `default` folder, and to create a directory for each specific test case:: - - server = PyPIServer(static_filesystem_paths = ["default", "test_pypi_server"], - static_uri_paths=["simple", "external"]) - -``PyPIServerTestCase`` -====================== - -``PyPIServerTestCase`` is a test case class with setUp and tearDown methods that -take care of a single PyPIServer instance attached as a ``pypi`` attribute on -the test class. Use it as one of the base classes in your test case:: - - class UploadTestCase(PyPIServerTestCase): - def test_something(self): - cmd = self.prepare_command() - cmd.ensure_finalized() - cmd.repository = self.pypi.full_address - cmd.run() - - environ, request_data = self.pypi.requests[-1] - self.assertEqual(request_data, EXPECTED_REQUEST_DATA) - -The ``use_pypi_server`` decorator -================================= - -You also can use a decorator for your tests, if you do not need the same server -instance along all you test case. So, you can specify, for each test method, -some initialisation parameters for the server. - -For this, you need to add a `server` parameter to your method, like this:: - - class SampleTestCase(TestCase): - @use_pypi_server() - def test_somthing(self, server): - # your tests goes here - ... - -The decorator will instantiate the server for you, and run and stop it just -before and after your method call. You also can pass the server initializer, -just like this:: - - class SampleTestCase(TestCase): - @use_pypi_server("test_case_name") - def test_something(self, server): - ... diff --git a/docs/source/library/distutils2.version.rst b/docs/source/library/distutils2.version.rst deleted file mode 100644 --- a/docs/source/library/distutils2.version.rst +++ /dev/null @@ -1,70 +0,0 @@ -====================== -Working with versions -====================== - -Distutils2 ships with a python package capable to work with version numbers. -It's an implementation of version specifiers `as defined in PEP 345 -`_ about -Metadatas. - -NormalizedVersion -================= - -A Normalized version is a specific version of a distribution, as -described in the PEP 345. So, you can work with the `NormalizedVersion` like -this:: - - >>> NormalizedVersion("1.2b1") - NormalizedVersion('1.2b1') - -If you try to use irrational version specifiers, an `IrrationalVersionError` -will be raised:: - - >>> NormalizedVersion("irrational_version_number") - ... - IrrationalVersionError: irrational_version_number - -You can compare NormalizedVersion objects, like this:: - - >>> NormalizedVersion("1.2b1") < NormalizedVersion("1.2") - True - -NormalizedVersion is used internally by `VersionPredicate` to do his stuff. - -Suggest a normalized version ----------------------------- - -Before this version scheme, there was existing others ones. Distutils2 provides -a tool that suggests a normalized version: the `suggest_normalized_version` -function:: - - >>> suggest_normalized_version('2.1-rc1') - 2.1c1 - -If `suggest_normalized_version` can't actually suggest you a version, it will -return `None`:: - - >>> print suggest_normalized_version('not a version') - None - -Dealing with version predicates -=============================== - -`VersionPredicate` knows how to parse stuff like "ProjectName (>=version)", the -class also provides a `match` method to test if a version number is the version -predicate:: - - >>> version = VersionPredicate("ProjectName (<1.2,>1.0") - >>> version.match("1.2.1") - False - >>> version.match("1.1.1") - True - -You could test if a predicate is a valid one, usng the `is_valid_predicate` -function:: - - >>> is_valid_predicate('FooBar (1.1)') - True - >>> is_valid_predicate('FooBar (+1.1)') - False - diff --git a/docs/source/library/pkgutil.rst b/docs/source/library/pkgutil.rst deleted file mode 100644 --- a/docs/source/library/pkgutil.rst +++ /dev/null @@ -1,333 +0,0 @@ -:mod:`pkgutil` --- Package utilities -==================================== - -.. module:: pkgutil - :synopsis: Utilities to support packages. - -This module provides utilities to manipulate packages: support for the -Importer protocol defined in :PEP:`302` and implementation of the API -described in :PEP:`376` to work with the database of installed Python -distributions. - -Import system utilities ------------------------ - -.. function:: extend_path(path, name) - - Extend the search path for the modules which comprise a package. Intended - use is to place the following code in a package's :file:`__init__.py`:: - - from pkgutil import extend_path - __path__ = extend_path(__path__, __name__) - - This will add to the package's ``__path__`` all subdirectories of directories - on :data:`sys.path` named after the package. This is useful if one wants to - distribute different parts of a single logical package as multiple - directories. - - It also looks for :file:`\*.pkg` files beginning where ``*`` matches the - *name* argument. This feature is similar to :file:`\*.pth` files (see the - :mod:`site` module for more information), except that it doesn't special-case - lines starting with ``import``. A :file:`\*.pkg` file is trusted at face - value: apart from checking for duplicates, all entries found in a - :file:`\*.pkg` file are added to the path, regardless of whether they exist - on the filesystem. (This is a feature.) - - If the input path is not a list (as is the case for frozen packages) it is - returned unchanged. The input path is not modified; an extended copy is - returned. Items are only appended to the copy at the end. - - It is assumed that :data:`sys.path` is a sequence. Items of :data:`sys.path` - that are not strings referring to existing directories are ignored. Unicode - items on :data:`sys.path` that cause errors when used as filenames may cause - this function to raise an exception (in line with :func:`os.path.isdir` - behavior). - - -.. class:: ImpImporter(dirname=None) - - :pep:`302` Importer that wraps Python's "classic" import algorithm. - - If *dirname* is a string, a :pep:`302` importer is created that searches that - directory. If *dirname* is ``None``, a :pep:`302` importer is created that - searches the current :data:`sys.path`, plus any modules that are frozen or - built-in. - - Note that :class:`ImpImporter` does not currently support being used by - placement on :data:`sys.meta_path`. - - -.. class:: ImpLoader(fullname, file, filename, etc) - - :pep:`302` Loader that wraps Python's "classic" import algorithm. - - -.. function:: find_loader(fullname) - - Find a :pep:`302` "loader" object for *fullname*. - - If *fullname* contains dots, path must be the containing package's - ``__path__``. Returns ``None`` if the module cannot be found or imported. - This function uses :func:`iter_importers`, and is thus subject to the same - limitations regarding platform-specific special import locations such as the - Windows registry. - - -.. function:: get_importer(path_item) - - Retrieve a :pep:`302` importer for the given *path_item*. - - The returned importer is cached in :data:`sys.path_importer_cache` if it was - newly created by a path hook. - - If there is no importer, a wrapper around the basic import machinery is - returned. This wrapper is never inserted into the importer cache (None is - inserted instead). - - The cache (or part of it) can be cleared manually if a rescan of - :data:`sys.path_hooks` is necessary. - - -.. function:: get_loader(module_or_name) - - Get a :pep:`302` "loader" object for *module_or_name*. - - If the module or package is accessible via the normal import mechanism, a - wrapper around the relevant part of that machinery is returned. Returns - ``None`` if the module cannot be found or imported. If the named module is - not already imported, its containing package (if any) is imported, in order - to establish the package ``__path__``. - - This function uses :func:`iter_importers`, and is thus subject to the same - limitations regarding platform-specific special import locations such as the - Windows registry. - - -.. function:: iter_importers(fullname='') - - Yield :pep:`302` importers for the given module name. - - If fullname contains a '.', the importers will be for the package containing - fullname, otherwise they will be importers for :data:`sys.meta_path`, - :data:`sys.path`, and Python's "classic" import machinery, in that order. If - the named module is in a package, that package is imported as a side effect - of invoking this function. - - Non-:pep:`302` mechanisms (e.g. the Windows registry) used by the standard - import machinery to find files in alternative locations are partially - supported, but are searched *after* :data:`sys.path`. Normally, these - locations are searched *before* :data:`sys.path`, preventing :data:`sys.path` - entries from shadowing them. - - For this to cause a visible difference in behaviour, there must be a module - or package name that is accessible via both :data:`sys.path` and one of the - non-:pep:`302` file system mechanisms. In this case, the emulation will find - the former version, while the builtin import mechanism will find the latter. - - Items of the following types can be affected by this discrepancy: - ``imp.C_EXTENSION``, ``imp.PY_SOURCE``, ``imp.PY_COMPILED``, - ``imp.PKG_DIRECTORY``. - - -.. function:: iter_modules(path=None, prefix='') - - Yields ``(module_loader, name, ispkg)`` for all submodules on *path*, or, if - path is ``None``, all top-level modules on :data:`sys.path`. - - *path* should be either ``None`` or a list of paths to look for modules in. - - *prefix* is a string to output on the front of every module name on output. - - -.. function:: walk_packages(path=None, prefix='', onerror=None) - - Yields ``(module_loader, name, ispkg)`` for all modules recursively on - *path*, or, if path is ``None``, all accessible modules. - - *path* should be either ``None`` or a list of paths to look for modules in. - - *prefix* is a string to output on the front of every module name on output. - - Note that this function must import all *packages* (*not* all modules!) on - the given *path*, in order to access the ``__path__`` attribute to find - submodules. - - *onerror* is a function which gets called with one argument (the name of the - package which was being imported) if any exception occurs while trying to - import a package. If no *onerror* function is supplied, :exc:`ImportError`\s - are caught and ignored, while all other exceptions are propagated, - terminating the search. - - Examples:: - - # list all modules python can access - walk_packages() - - # list all submodules of ctypes - walk_packages(ctypes.__path__, ctypes.__name__ + '.') - - -.. function:: get_data(package, resource) - - Get a resource from a package. - - This is a wrapper for the :pep:`302` loader :func:`get_data` API. The - *package* argument should be the name of a package, in standard module format - (``foo.bar``). The *resource* argument should be in the form of a relative - filename, using ``/`` as the path separator. The parent directory name - ``..`` is not allowed, and nor is a rooted name (starting with a ``/``). - - The function returns a binary string that is the contents of the specified - resource. - - For packages located in the filesystem, which have already been imported, - this is the rough equivalent of:: - - d = os.path.dirname(sys.modules[package].__file__) - data = open(os.path.join(d, resource), 'rb').read() - - If the package cannot be located or loaded, or it uses a :pep:`302` loader - which does not support :func:`get_data`, then ``None`` is returned. - - -Installed distributions database --------------------------------- - -Installed Python distributions are represented by instances of -:class:`~distutils2._backport.pkgutil.Distribution`, or its subclass -:class:`~distutils2._backport.pkgutil.EggInfoDistribution` for legacy ``.egg`` -and ``.egg-info`` formats). Most functions also provide an extra argument -``use_egg_info`` to take legacy distributions into account. - -.. TODO write docs here, don't rely on automodule - classes: Distribution and descendents - functions: provides, obsoletes, replaces, etc. - -Caching -+++++++ - -For performance purposes, the list of distributions is being internally -cached. It is enabled by default, but you can turn it off or clear -it using :func:`~distutils2._backport.pkgutil.enable_cache`, -:func:`~distutils2._backport.pkgutil.disable_cache` and -:func:`~distutils2._backport.pkgutil.clear_cache`. - - -Examples --------- - -Print all information about a distribution -++++++++++++++++++++++++++++++++++++++++++ - -Given a path to a ``.dist-info`` distribution, we shall print out all -information that can be obtained using functions provided in this module:: - - from distutils2._backport import pkgutil - import sys - - path = raw_input() # read the path from the keyboard - # first create the Distribution instance - try: - dist = pkgutil.Distribution(path) - except IOError: - print('No such distribution') - sys.exit(1) - - print('Information about %s' % dist.name) - print('Files') - print('=====') - for (path, md5, size) in dist.get_installed_files(): - print('* Path: %s' % path) - print(' Hash %s, Size: %s bytes' % (md5, size)) - print('Metadata') - print('========') - for key, value in dist.metadata.items(): - print('%20s: %s' % (key, value)) - print('Extra') - print('=====') - if dist.requested: - print('* It was installed by user request') - else: - print('* It was installed as a dependency') - -If we save the script above as ``print_info.py`` and we are intested in the -distribution located at -``/home/josip/dev/distutils2/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9`` -then by typing in the console: - -.. code-block:: bash - - $ echo /home/josip/dev/distutils2/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info | python print_info.py - -we get the following output: - -.. code-block:: none - - Information about choxie - Files - ===== - * Path: ../home/josip/dev/distutils2/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/truffles.py - Hash 5e052db6a478d06bad9ae033e6bc08af, Size: 111 bytes - * Path: ../home/josip/dev/distutils2/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py - Hash ac56bf496d8d1d26f866235b95f31030, Size: 214 bytes - * Path: ../home/josip/dev/distutils2/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py - Hash 416aab08dfa846f473129e89a7625bbc, Size: 25 bytes - * Path: ../home/josip/dev/distutils2/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER - Hash d41d8cd98f00b204e9800998ecf8427e, Size: 0 bytes - * Path: ../home/josip/dev/distutils2/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA - Hash 696a209967fef3c8b8f5a7bb10386385, Size: 225 bytes - * Path: ../home/josip/dev/distutils2/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED - Hash d41d8cd98f00b204e9800998ecf8427e, Size: 0 bytes - * Path: ../home/josip/dev/distutils2/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD - Hash None, Size: None bytes - Metadata - ======== - Metadata-Version: 1.2 - Name: choxie - Version: 2.0.0.9 - Platform: [] - Supported-Platform: UNKNOWN - Summary: Chocolate with a kick! - Description: UNKNOWN - Keywords: [] - Home-page: UNKNOWN - Author: UNKNOWN - Author-email: UNKNOWN - Maintainer: UNKNOWN - Maintainer-email: UNKNOWN - License: UNKNOWN - Classifier: [] - Download-URL: UNKNOWN - Obsoletes-Dist: ['truffles (<=0.8,>=0.5)', 'truffles (<=0.9,>=0.6)'] - Project-URL: [] - Provides-Dist: ['truffles (1.0)'] - Requires-Dist: ['towel-stuff (0.1)'] - Requires-Python: UNKNOWN - Requires-External: [] - Extra - ===== - * It was installed as a dependency - -Find out obsoleted distributions -++++++++++++++++++++++++++++++++ - -Now, we take tackle a different problem, we are interested in finding out -which distributions have been obsoleted. This can be easily done as follows:: - - from distutils2._backport import pkgutil - - # iterate over all distributions in the system - for dist in pkgutil.get_distributions(): - name = dist.name - version = dist.metadata['Version'] - # find out which distributions obsolete this name/version combination - for obsoleted_by in pkgutil.obsoletes_distribution(name, version): - print('%s(%s) is obsoleted by %s' % (name, version, obsoleted_by.name)) - -This is how the output might look like: - -.. code-block:: none - - strawberry(0.6) is obsoleted by choxie - grammar(1.0a4) is obsoleted by towel-stuff - diff --git a/docs/source/setupcfg-spec.rst b/docs/source/setupcfg-spec.rst deleted file mode 100644 --- a/docs/source/setupcfg-spec.rst +++ /dev/null @@ -1,308 +0,0 @@ -=================== -setup.cfg file v0.9 -=================== - -This document describes the :file:`setup.cfg`, a ini-like file used by -Distutils2 to replace the :file:`setup.py` file. - -Syntax -====== - -The configuration file is an ini-based file. Variables name can be -assigned values, and grouped into sections. A line that starts with "#" is -commented out. Empty lines are also removed. - -Example:: - - [section1] - # comment - name = value - name2 = "other value" - - [section2] - foo = bar - - -Values conversion -::::::::::::::::: - -Here are a set of rules for converting values: - -- If value is quoted with " chars, it's a string. This notation is useful to - include "=" characters in the value. In case the value contains a " - character, it must be escaped with a "\" character. -- If the value is "true" or "false" --no matter what the case is--, it's - converted to a boolean, or 0 and 1 when the language does not have a - boolean type. -- A value can contains multiple lines. When read, lines are converted into a - sequence of values. Each new line for a multiple lines value must start with - a least one space or tab character. These indentation characters will be - stripped. -- all other values are considered as strings - -Examples:: - - [section] - foo = one - two - three - - bar = false - baz = 1.3 - boo = "ok" - beee = "wqdqw pojpj w\"ddq" - -Extending files -::::::::::::::: - -An INI file can extend another file. For this, a "DEFAULT" section must contain -an "extends" variable that can point to one or several INI files which will be -merged to the current file by adding new sections and values. - -If the file pointed in "extends" contains section/variable names that already -exist in the original file, they will not override existing ones. - -file_one.ini:: - - [section1] - name2 = "other value" - - [section2] - foo = baz - bas = bar - -file_two.ini:: - - [DEFAULT] - extends = file_one.ini - - [section2] - foo = bar - -Result:: - - [section1] - name2 = "other value" - - [section2] - foo = bar - bas = bar - -To point several files, the multi-line notation can be used: - - [DEFAULT] - extends = file_one.ini - file_two.ini - -When several files are provided, they are processed sequentially. So if the -first one has a value that is also present in the second, the second one will -be ignored. This means that the configuration goes from the most specialized to -the most common. - -**Tools will need to provide a way to produce a canonical version of the -file**. This will be useful to publish a single file. - - -Description of sections and fields -================================== - -Each section contains a description of its options. - -- Options that are marked *\*multi* can have multiple values, one value per - line. -- Options that are marked *\*optional* can be omited. - - -The sections are: - -global - Global options for Distutils2. - -metadata - The metadata section contains the metadata for the project as described in - :PEP:`345`. - -files - Declaration of package files included in the project. - -`command` sections - Redefinition of user options for Distutils2 commands. - - -global -:::::: - -Contains global options for Distutils2. This section is shared with Distutils1 -(legacy version distributed in python 2.X standard library). - - -- **commands**: Defined Distutils2 command. A command is defined by its fully - qualified name. - - Examples:: - - [global] - commands = - package.sdist.CustomSdistCommand - - *\*optional* *\*multi* - -- **compilers**: Defined Distutils2 compiler. A compiler is defined by its fully - qualified name. - - Example:: - - [global] - compiler = - package.compiler.CustomCCompiler - - *\*optional* *\*multi* - -- **setup_hook**: defines a callable that will be called right after the - :file:`setup.cfg` file is read. The callable receives the configuration - in form of a mapping and can make some changes to it. *\*optional* - - Example:: - - [global] - setup_hook = - distutils2.tests.test_config.hook - - -metadata -:::::::: - -The metadata section contains the metadata for the project as described in -:PEP:`345`. Field names are case-insensitive. - -- metadata-version -- name -- version -- platform -- supported-platform -- summary -- description -- keywords -- home-page -- download-url -- author -- author-email -- maintainer -- maintainer-email -- license -- classifiers -- requires-dist -- provides-dist -- obsoletes-dist -- requires-python -- requires-externals -- project-url - -There's one extra field, to replace description with a path to a text file: - -- description-file: path to a text file that will be used to replace description - - -files -::::: - -This section describes the files included in the project. - -- **packages_root**: the root directory containing all packages. If not provided - Distutils2 will use the current directory. *\*optional* -- **packages**: a list of packages the project includes *\*optional* *\*multi* -- **modules**: a list of packages the project includes *\*optional* *\*multi* -- **scripts**: a list of scripts the project includes *\*optional* *\*multi* -- **extra_files**: a list of patterns to include extra files *\*optional* *\*multi* -- **resources**: a list of data files. *\*optional* *\*multi* - -Example:: - - [files] - packages_root = src - packages = - pypi2rpm - pypi2rpm.command - - scripts = - pypi2rpm/pypi2rpm.py - - extra_files = - setup.py - README - - resources = - source1 = destination1 - source2 = destination2 - doc/* = {doc} - scripts/foo.sh = {datadir}/scripts/{distribution.name} - -extensions -:::::::::: - - -XXX - -Command sections -::::::::::::::::: - -Each Distutils2 command can have its own user options defined in :file:`setup.cfg` - -Example:: - - [sdist] - manifest-builders = package.module.Maker - - -To override the build class in order to generate Python3 code from your Python2 base:: - - [build_py] - use-2to3 = True - -Extensibility -============= - -Every section can define new variable that are not part of the specification. -They are called **extensions**. - -An extension field starts with *X-*. - -Example:: - - [metadata] - ... - X-Debian-Name = python-distribute - -Changes in the specification -============================ - -The version scheme for this specification is **MAJOR.MINOR**. -Changes in the specification will increment the version. - -- minor version changes (1.x): backwards compatible - - new fields and sections (both optional and mandatory) can be added - - optional fields can be removed -- major channges (2.X): backwards-incompatible - - mandatory fields/sections are removed - - fields change their meaning - -As a consequence, a tool written to consume 1.X (say, X=5) has these -properties: - -- reading 1.Y, YX is also possible. The tool will just ignore the new - fields (even if they are mandatory in that version) - If optional fields were removed, the tool will just consider them absent. -- reading 2.X is not possible; the tool should refuse to interpret - the file. - -A tool written to produce 1.X should have these properties: -- it will write all mandatory fields -- it may write optional fields - -Acks -==== - -XXX - diff --git a/docs/source/setupcfg.rst b/docs/source/setupcfg.rst deleted file mode 100644 --- a/docs/source/setupcfg.rst +++ /dev/null @@ -1,549 +0,0 @@ -================== -The setup.cfg file -================== - -This document describes the :file:`setup.cfg`, a ini-like file used by -Distutils2 to replace the :file:`setup.py` file. - -Each section contains a description of its options. - -- Options that are marked *\*multi* can have multiple values, one value per - line. -- Options that are marked *\*optional* can be omited. -- Options that are marked *\*environ* can use environment markers, as described - in :PEP:`345`. - - -The sections are: - -global - Global options for Distutils2. - -metadata - The metadata section contains the metadata for the project as described in - :PEP:`345`. - -files - Declaration of package files included in the project. - -`command` sections - Redefinition of user options for Distutils2 commands. - - -global -====== - -Contains global options for Distutils2. This section is shared with Distutils1 -(legacy version distributed in python 2.X standard library). - - -- **commands**: Defined Distutils2 command. A command is defined by its fully - qualified name. - - Examples:: - - [global] - commands = - package.sdist.CustomSdistCommand - - *\*optional* *\*multi* - -- **compilers**: Defined Distutils2 compiler. A compiler is defined by its fully - qualified name. - - Example:: - - [global] - compiler = - package.compiler.CustomCCompiler - - *\*optional* *\*multi* - -- **setup_hook**: defines a callable that will be called right after the - :file:`setup.cfg` file is read. The callable receives the configuration - in form of a mapping and can make some changes to it. *\*optional* - - Example:: - - [global] - setup_hook = - distutils2.tests.test_config.hook - - -metadata -======== - -The metadata section contains the metadata for the project as described in -:PEP:`345`. - -.. Note:: - Field names are case-insensitive. - -Fields: - -- **name**: Name of the project. -- **version**: Version of the project. Must comply with :PEP:`386`. -- **platform**: Platform specification describing an operating system supported - by the distribution which is not listed in the "Operating System" Trove - classifiers (:PEP:`301`). *\*multi* *\*optional* -- **supported-platform**: Binary distributions containing a PKG-INFO file will - use the Supported-Platform field in their metadata to specify the OS and - CPU for which the binary distribution was compiled. The semantics of - the Supported-Platform field are freeform. *\*multi* *\*optional* -- **summary**: A one-line summary of what the distribution does. - (Used to be called *description* in Distutils1.) -- **description**: A longer description. (Used to be called *long_description* - in Distutils1.) A file can be provided in the *description-file* field. - *\*optional* -- **description-file**: path to a text file that will be used for the - **description** field. *\*optional* -- **keywords**: A list of additional keywords to be used to assist searching - for the distribution in a larger catalog. Comma or space-separated. *\*optional* -- **home-page**: The URL for the distribution's home page. -- **download-url**: The URL from which this version of the distribution - can be downloaded. *\*optional* -- **author**: Author's name. *\*optional* -- **author-email**: Author's e-mail. *\*optional* -- **maintainer**: Maintainer's name. *\*optional* -- **maintainer-email**: Maintainer's e-mail. *\*optional* -- **license**: A text indicating the term of uses, when a trove classifier does - not match. *\*optional*. -- **classifiers**: Classification for the distribution, as described in PEP 301. - *\*optional* *\*multi* *\*environ* -- **requires-dist**: name of another distutils project required as a dependency. - The format is *name (version)* where version is an optional - version declaration, as described in PEP 345. *\*optional* *\*multi* *\*environ* -- **provides-dist**: name of another distutils project contained whithin this - distribution. Same format than *requires-dist*. *\*optional* *\*multi* *\*environ* -- **obsoletes-dist**: name of another distutils project this version obsoletes. - Same format than *requires-dist*. *\*optional* *\*multi* *\*environ* -- **requires-python**: Specifies the Python version the distribution requires. - The value is a version number, as described in PEP 345. - *\*optional* *\*multi* *\*environ* -- **requires-externals**: a dependency in the system. This field is free-form, - and just a hint for downstream maintainers. *\*optional* *\*multi* *\*environ* -- **project-url**: A label, followed by a browsable URL for the project. - "label, url". The label is limited to 32 signs. *\*optional* *\*multi* - - -Example:: - - [metadata] - name = pypi2rpm - version = 0.1 - author = Tarek Ziade - author-email = tarek at ziade.org - summary = Script that transforms a sdist archive into a rpm archive - description-file = README - home-page = http://bitbucket.org/tarek/pypi2rpm - project-url: RSS feed, https://bitbucket.org/tarek/pypi2rpm/rss - - classifier = Development Status :: 3 - Alpha - License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1) - -.. Note:: - Some metadata fields seen in :PEP:`345` are automatically generated - (for instance Metadata-Version value). - - -files -===== - -This section describes the files included in the project. - -- **packages_root**: the root directory containing all packages. If not provided - Distutils2 will use the current directory. *\*optional* -- **packages**: a list of packages the project includes *\*optional* *\*multi* -- **modules**: a list of packages the project includes *\*optional* *\*multi* -- **scripts**: a list of scripts the project includes *\*optional* *\*multi* -- **extra_files**: a list of patterns to include extra files *\*optional* *\*multi* - -Example:: - - [files] - packages_root = src - packages = - pypi2rpm - pypi2rpm.command - - scripts = - pypi2rpm/pypi2rpm.py - - extra_files = - setup.py - README - -.. Note:: - In Distutils2, setup.cfg will be implicitly included. - -Resources -========= - -This section describes the files used by the project which must not be installed in the same place that python modules or libraries, they are called **resources**. They are for example documentation files, script files, databases, etc... - -For declaring resources, you must use this notation :: - - source = destination - -Data-files are declared in the **resources** field in the **file** section, for example:: - - [files] - resources = - source1 = destination1 - source2 = destination2 - -The **source** part of the declaration are relative paths of resources files (using unix path separator **/**). For example, if you've this source tree:: - - foo/ - doc/ - doc.man - scripts/ - foo.sh - -Your setup.cfg will look like:: - - [files] - resources = - doc/doc.man = destination_doc - scripts/foo.sh = destination_scripts - -The final paths where files will be placed are composed by : **source** + **destination**. In the previous example, **doc/doc.man** will be placed in **destination_doc/doc/doc.man** and **scripts/foo.sh** will be placed in **destination_scripts/scripts/foo.sh**. (If you want more control on the final path, take a look at base_prefix_). - -The **destination** part of resources declaration are paths with categories. Indeed, it's generally a bad idea to give absolute path as it will be cross incompatible. So, you must use resources categories in your **destination** declaration. Categories will be replaced by their real path at the installation time. Using categories is all benefit, your declaration will be simpler, cross platform and it will allow packager to place resources files where they want without breaking your code. - -Categories can be specified by using this syntax:: - - {category} - -Default categories are:: - -* config -* appdata -* appdata.arch -* appdata.persistent -* appdata.disposable -* help -* icon -* scripts -* doc -* info -* man - -A special category also exists **{distribution.name}** that will be replaced by the name of the distribution, but as most of the defaults categories use them, so it's not necessary to add **{distribution.name}** into your destination. - -If you use categories in your declarations, and you are encouraged to do, final path will be:: - - source + destination_expanded - -.. _example_final_path: - -For example, if you have this setup.cfg:: - - [metadata] - name = foo - - [files] - resources = - doc/doc.man = {doc} - -And if **{doc}** is replaced by **{datadir}/doc/{distribution.name}**, final path will be:: - - {datadir}/doc/foo/doc/doc.man - -Where {datafir} category will be platform-dependent. - - -More control on source part ---------------------------- - -Glob syntax -___________ - -When you declare source file, you can use a glob-like syntax to match multiples file, for example:: - - scripts/* = {script} - -Will match all the files in the scripts directory and placed them in the script category. - -Glob tokens are: - - * * : match all files. - * ? : match any character. - * ** : match any level of tree recursion (even 0). - * {} : will match any part separated by comma (example : {sh,bat}). - -TODO :: - - Add an example - -Order of declaration -____________________ - -The order of declaration is important if one file match multiple rules. The last rules matched by file is used, this is useful if you have this source tree:: - - foo/ - doc/ - index.rst - setup.rst - documentation.txt - doc.tex - README - -And you want all the files in the doc directory to be placed in {doc} category, but README must be placed in {help} category, instead of listing all the files one by one, you can declare them in this way:: - - [files] - resources = - doc/* = {doc} - doc/README = {help} - -Exclude -_______ - -You can exclude some files of resources declaration by giving no destination, it can be useful if you have a non-resources file in the same directory of resources files:: - - foo/ - doc/ - RELEASES - doc.tex - documentation.txt - docu.rst - -Your **file** section will be:: - - [files] - resources = - doc/* = {doc} - doc/RELEASES = - -More control on destination part --------------------------------- - -.. _base_prefix: - -Define a base-prefix -____________________ - -When you define your resources, you can have more control of how the final path is compute. - -By default, the final path is:: - - destination + source - -This can generate long paths, for example (example_final_path_):: - - {datadir}/doc/foo/doc/doc.man - -When you declare your source, you can use a separator to split the source in **prefix** **suffix**. The supported separator are : - - * Whitespace - -So, for example, if you have this source:: - - docs/ doc.man - -The **prefix** is "docs/" and the **suffix** is "doc.html". - -.. note:: - - Separator can be placed after a path separator or replace it. So theses two sources are equivalent:: - - docs/ doc.man - docs doc.man - -.. note:: - - Glob syntax is working the same way with standard source and splitted source. So theses rules:: - - docs/* - docs/ * - docs * - - Will match all the files in the docs directory. - -When you use splitted source, the final path is compute in this way:: - - destination + prefix - -So for example, if you have this setup.cfg:: - - [metadata] - name = foo - - [files] - resources = - doc/ doc.man = {doc} - -And if **{doc}** is replaced by **{datadir}/doc/{distribution.name}**, final path will be:: - - {datadir}/doc/foo/doc.man - - -Overwrite paths for categories ------------------------------- - -.. warning:: - - This part is intended for system administrator or packager. - -The real paths of categories are registered in the *sysconfig.cfg* file installed in your python installation. The format of this file is INI-like. The content of the file is organized into several sections : - - * globals : Standard categories's paths. - * posix_prefix : Standard paths for categories and installation paths for posix system. - * other one... - -Standard categories's paths are platform independent, they generally refers to other categories, which are platform dependent. Sysconfig module will choose these category from sections matching os.name. For example:: - - doc = {datadir}/doc/{distribution.name} - -It refers to datadir category, which can be different between platforms. In posix system, it may be:: - - datadir = /usr/share - -So the final path will be:: - - doc = /usr/share/doc/{distribution.name} - -The platform dependent categories are : - - * confdir - * datadir - * libdir - * base - -Define extra-categories ------------------------ - -Examples --------- - -.. note:: - - These examples are incremental but works unitarily. - -Resources in root dir -_____________________ - -Source tree:: - - babar-1.0/ - README - babar.sh - launch.sh - babar.py - -Setup.cfg:: - - [files] - resources = - README = {doc} - *.sh = {scripts} - -So babar.sh and launch.sh will be placed in {scripts} directory. - -Now let's move all the scripts into a scripts directory. - -Resources in sub-directory -__________________________ - -Source tree:: - - babar-1.1/ - README - scripts/ - babar.sh - launch.sh - LAUNCH - babar.py - -Setup.cfg:: - - [files] - resources = - README = {doc} - scripts/ LAUNCH = {doc} - scripts/ *.sh = {scripts} - -It's important to use the separator after scripts/ to install all the bash scripts into {scripts} instead of {scripts}/scripts. - -Now let's add some docs. - -Resources in multiple sub-directories -_____________________________________ - -Source tree:: - - babar-1.2/ - README - scripts/ - babar.sh - launch.sh - LAUNCH - docs/ - api - man - babar.py - -Setup.cfg:: - - [files] - resources = - README = {doc} - scripts/ LAUNCH = {doc} - scripts/ *.sh = {scripts} - doc/ * = {doc} - doc/ man = {man} - -You want to place all the file in the docs script into {doc} category, instead of man, which must be placed into {man} category, we will use the order of declaration of globs to choose the destination, the last glob that match the file is used. - -Now let's add some scripts for windows users. - -Complete example -________________ - -Source tree:: - - babar-1.3/ - README - doc/ - api - man - scripts/ - babar.sh - launch.sh - babar.bat - launch.bat - LAUNCH - -Setup.cfg:: - - [files] - resources = - README = {doc} - scripts/ LAUNCH = {doc} - scripts/ *.{sh,bat} = {scripts} - doc/ * = {doc} - doc/ man = {man} - -We use brace expansion syntax to place all the bash and batch scripts into {scripts} category. - -.. Warning:: - In Distutils2, setup.py and README (or README.txt) files are not more - included in source distribution by default - -`command` sections -================== - -Each Distutils2 command can have its own user options defined in :file:`setup.cfg` - -Example:: - - [sdist] - manifest-builders = package.module.Maker - - -To override the build class in order to generate Python3 code from your Python2 base:: - - [build_py] - use-2to3 = True - - diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst deleted file mode 100644 --- a/docs/source/tutorial.rst +++ /dev/null @@ -1,129 +0,0 @@ -=================== -Distutils2 tutorial -=================== - -Welcome to the Distutils2 tutorial ! We will learn here how to use Distutils2 -to package your project. - - -Installing Distutils2 -===================== - -Quite simple, my dear reader:: - - $ pip install Distutils2 - -Or.. grab it at PyPI and run:: - - $ python setup.py install - - - -Getting started -=============== - -Distutils2 works with the *setup.cfg* file. It contains all the metadata for -your project, as defined in PEP 345, but also declare what your project -contains. - -Let's say you have a project called *CLVault* containing one package called -*clvault*, and a few scripts inside. You can use the *mkcfg* script to create -a *setup.cfg* file for the project. The script will ask you a few questions:: - - $ mkdir CLVault - $ cd CLVault - $ python -m distutils2.mkcfg - Project name [CLVault]: - Current version number: 0.1 - Package description: - >Command-line utility to store and retrieve passwords - Author name: Tarek Ziade - Author e-mail address: tarek at ziade.org - Project Home Page: http://bitbucket.org/tarek/clvault - Do you want to add a package ? (y/n): y - Package name: clvault - Do you want to add a package ? (y/n): n - Do you want to set Trove classifiers? (y/n): y - Please select the project status: - - 1 - Planning - 2 - Pre-Alpha - 3 - Alpha - 4 - Beta - 5 - Production/Stable - 6 - Mature - 7 - Inactive - - Status: 3 - What license do you use: GPL - Matching licenses: - - 1) License :: OSI Approved :: GNU General Public License (GPL) - 2) License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) - - Type the number of the license you wish to use or ? to try again:: 1 - Do you want to set other trove identifiers (y/n) [n]: n - Wrote "setup.cfg". - - -A setup.cfg file is created, containing the metadata of your project and the -list of the packages it contains:: - - $ more setup.cfg - [metadata] - name = CLVault - version = 0.1 - author = Tarek Ziade - author_email = tarek at ziade.org - description = Command-line utility to store and retrieve passwords - home_page = http://bitbucket.org/tarek/clvault - - classifier = Development Status :: 3 - Alpha - License :: OSI Approved :: GNU General Public License (GPL) - - [files] - - packages = clvault - - -Our project will depend on the *keyring* project. Let's add it in the -[metadata] section:: - - [metadata] - ... - requires_dist = - keyring - - - -Running commands -================ - -You can run useful commands on your project once the setup.cfg file is ready: - -- sdist: creates a source distribution -- register: register your project to PyPI -- upload: upload the distribution to PyPI -- install: install it - -All commands are run using the run script:: - - $ python -m distutils2.run install - $ python -m distutils2.run sdist - $ python -m distutils2.run upload - -If you want to push a source distribution of your project at PyPI, do:: - - $ python -m distutils2.run sdist register upload - - -Installing the project -====================== - -People will have to manually run the distutils2 install command:: - - $ python -m distutils2.run install - - - - diff --git a/setup.cfg b/setup.cfg --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,3 @@ [build_ext] # needed so that tests work without mucking with sys.path inplace = 1 - -[upload_docs] -upload-dir = docs/build/html -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Tue Mar 13 17:42:23 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 13 Mar 2012 17:42:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314180=3A_Fix_pytho?= =?utf8?q?ncore=2Evcproj=2C_Modules/=5Ftime=2E=5Bch=5D_have_been_removed?= Message-ID: http://hg.python.org/cpython/rev/760cf150bb99 changeset: 75594:760cf150bb99 user: Victor Stinner date: Tue Mar 13 17:42:18 2012 +0100 summary: Issue #14180: Fix pythoncore.vcproj, Modules/_time.[ch] have been removed files: PCbuild/pythoncore.vcproj | 8 -------- 1 files changed, 0 insertions(+), 8 deletions(-) diff --git a/PCbuild/pythoncore.vcproj b/PCbuild/pythoncore.vcproj --- a/PCbuild/pythoncore.vcproj +++ b/PCbuild/pythoncore.vcproj @@ -1055,14 +1055,6 @@ > - - - - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 19:12:25 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 13 Mar 2012 19:12:25 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314180=3A_Fix_an_in?= =?utf8?q?valid_rounding_when_compiler_optimization_are_enabled?= Message-ID: http://hg.python.org/cpython/rev/9d69a2418d80 changeset: 75595:9d69a2418d80 user: Victor Stinner date: Tue Mar 13 19:12:23 2012 +0100 summary: Issue #14180: Fix an invalid rounding when compiler optimization are enabled Use volatile keyword to disable localy unsafe float optimizations. files: Python/pytime.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Python/pytime.c b/Python/pytime.c --- a/Python/pytime.c +++ b/Python/pytime.c @@ -102,7 +102,9 @@ { assert(denominator <= LONG_MAX); if (PyFloat_Check(obj)) { - double d, intpart, floatpart, err; + double d, intpart, err; + /* volatile avoids unsafe optimization on float enabled by gcc -O3 */ + volatile double floatpart; d = PyFloat_AsDouble(obj); floatpart = modf(d, &intpart); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 19:33:10 2012 From: python-checkins at python.org (ned.deily) Date: Tue, 13 Mar 2012 19:33:10 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MTg0?= =?utf8?q?=3A_Increase_the_default_stack_size_for_secondary_threads_on?= Message-ID: http://hg.python.org/cpython/rev/246e681a4272 changeset: 75596:246e681a4272 branch: 3.2 parent: 75588:397215db7be1 user: Ned Deily date: Tue Mar 13 11:18:18 2012 -0700 summary: Issue #14184: Increase the default stack size for secondary threads on Mac OS X to prevent interpreter crashes when compiled on 10.7. files: Misc/NEWS | 3 +++ Python/thread_pthread.h | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,9 @@ Library ------- +- Issue #14184: Increase the default stack size for secondary threads on + Mac OS X to avoid interpreter crashes when using threads on 10.7. + - Issue #10543: Fix unittest test discovery with Jython bytecode files. - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -19,14 +19,18 @@ #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif -#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 - /* The default stack size for new threads on OSX is small enough that - * we'll get hard crashes instead of 'maximum recursion depth exceeded' - * exceptions. - * - * The default stack size below is the minimal stack size where a - * simple recursive function doesn't cause a hard crash. - */ +/* The default stack size for new threads on OSX and BSD is small enough that + * we'll get hard crashes instead of 'maximum recursion depth exceeded' + * exceptions. + * + * The default stack sizes below are the empirically determined minimal stack + * sizes where a simple recursive function doesn't cause a hard crash. + */ +#if defined(__APPLE__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 +#undef THREAD_STACK_SIZE +#define THREAD_STACK_SIZE 0x500000 +#endif +#if defined(__FreeBSD__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 #undef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0x400000 #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 19:33:11 2012 From: python-checkins at python.org (ned.deily) Date: Tue, 13 Mar 2012 19:33:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314184=3A_merge?= Message-ID: http://hg.python.org/cpython/rev/c00ac2b25048 changeset: 75597:c00ac2b25048 parent: 75595:9d69a2418d80 parent: 75596:246e681a4272 user: Ned Deily date: Tue Mar 13 11:31:36 2012 -0700 summary: Issue #14184: merge files: Misc/NEWS | 3 +++ Python/thread_pthread.h | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #14184: Increase the default stack size for secondary threads on + Mac OS X to avoid interpreter crashes when using threads on 10.7. + - Issue #14180: time.ctime(), gmtime(), time.localtime(), datetime.date.fromtimestamp(), datetime.datetime.fromtimestamp() and datetime.datetime.utcfromtimestamp() now raises an OverflowError, instead of diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -19,14 +19,18 @@ #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif -#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 - /* The default stack size for new threads on OSX is small enough that - * we'll get hard crashes instead of 'maximum recursion depth exceeded' - * exceptions. - * - * The default stack size below is the minimal stack size where a - * simple recursive function doesn't cause a hard crash. - */ +/* The default stack size for new threads on OSX and BSD is small enough that + * we'll get hard crashes instead of 'maximum recursion depth exceeded' + * exceptions. + * + * The default stack sizes below are the empirically determined minimal stack + * sizes where a simple recursive function doesn't cause a hard crash. + */ +#if defined(__APPLE__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 +#undef THREAD_STACK_SIZE +#define THREAD_STACK_SIZE 0x500000 +#endif +#if defined(__FreeBSD__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 #undef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0x400000 #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 21:40:53 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 13 Mar 2012 21:40:53 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=232843=3A_Add_new_Tk?= =?utf8?q?_API_to_Tkinter=2E?= Message-ID: http://hg.python.org/cpython/rev/71041c0dedd5 changeset: 75598:71041c0dedd5 user: Martin v. L?wis date: Tue Mar 13 13:40:42 2012 -0700 summary: Issue #2843: Add new Tk API to Tkinter. Patch by Guilherme Polo and Andrew Svetlov. files: Lib/tkinter/__init__.py | 88 ++++++++++++++++++++++++++++- Misc/NEWS | 2 + 2 files changed, 89 insertions(+), 1 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1245,6 +1245,13 @@ self.tk.call( 'place', 'slaves', self._w))] # Grid methods that apply to the master + def grid_anchor(self, anchor=None): # new in Tk 8.5 + """The anchor value controls how to place the grid within the + master when no row/column has any weight. + + The default anchor is nw.""" + self.tk.call('grid', 'anchor', self._w, anchor) + anchor = grid_anchor def grid_bbox(self, column=None, row=None, col2=None, row2=None): """Return a tuple of integer coordinates for the bounding box of this widget controlled by the geometry manager grid. @@ -1263,7 +1270,6 @@ if col2 is not None and row2 is not None: args = args + (col2, row2) return self._getints(self.tk.call(*args)) or None - bbox = grid_bbox def _grid_configure(self, command, index, cnf, kw): """Internal function.""" @@ -1522,6 +1528,14 @@ the focus. Return current focus model if MODEL is None.""" return self.tk.call('wm', 'focusmodel', self._w, model) focusmodel = wm_focusmodel + def wm_forget(self, window): # new in Tk 8.5 + """The window will be unmappend from the screen and will no longer + be managed by wm. toplevel windows will be treated like frame + windows once they are no longer managed by wm, however, the menu + option configuration will be remembered and the menus will return + once the widget is managed again.""" + self.tk.call('wm', 'forget', window) + forget = wm_forget def wm_frame(self): """Return identifier for decorative frame of this widget if present.""" return self.tk.call('wm', 'frame', self._w) @@ -1575,6 +1589,31 @@ None is given.""" return self.tk.call('wm', 'iconname', self._w, newName) iconname = wm_iconname + def wm_iconphoto(self, default=False, *args): # new in Tk 8.5 + """Sets the titlebar icon for this window based on the named photo + images passed through args. If default is True, this is applied to + all future created toplevels as well. + + The data in the images is taken as a snapshot at the time of + invocation. If the images are later changed, this is not reflected + to the titlebar icons. Multiple images are accepted to allow + different images sizes to be provided. The window manager may scale + provided icons to an appropriate size. + + On Windows, the images are packed into a Windows icon structure. + This will override an icon specified to wm_iconbitmap, and vice + versa. + + On X, the images are arranged into the _NET_WM_ICON X property, + which most modern window managers support. An icon specified by + wm_iconbitmap may exist simuultaneously. + + On Macintosh, this currently does nothing.""" + if default: + self.tk.call('wm', 'iconphoto', self._w, "-default", *args) + else: + self.tk.call('wm', 'iconphoto', self._w, *args) + iconphoto = wm_iconphoto def wm_iconposition(self, x=None, y=None): """Set the position of the icon of this widget to X and Y. Return a tuple of the current values of X and X if None is given.""" @@ -1586,6 +1625,12 @@ value if None is given.""" return self.tk.call('wm', 'iconwindow', self._w, pathName) iconwindow = wm_iconwindow + def wm_manage(self, widget): # new in Tk 8.5 + """The widget specified will become a stand alone top-level window. + The window will be decorated with the window managers title bar, + etc.""" + self.tk.call('wm', 'manage', widget) + manage = wm_manage def wm_maxsize(self, width=None, height=None): """Set max WIDTH and HEIGHT for this widget. If the window is gridded the values are given in grid units. Return the current values if None @@ -2677,6 +2722,10 @@ def unpost(self): """Unmap a menu.""" self.tk.call(self._w, 'unpost') + def xposition(self, index): # new in Tk 8.5 + """Return the x-position of the leftmost pixel of the menu item + at INDEX.""" + return getint(self.tk.call(self._w, 'xposition', index)) def yposition(self, index): """Return the y-position of the topmost pixel of the menu item at INDEX.""" return getint(self.tk.call( @@ -2836,6 +2885,25 @@ relation OP is satisfied. OP is one of <, <=, ==, >=, >, or !=.""" return self.tk.getboolean(self.tk.call( self._w, 'compare', index1, op, index2)) + def count(self, index1, index2, *args): # new in Tk 8.5 + """Counts the number of relevant things between the two indices. + If index1 is after index2, the result will be a negative number + (and this holds for each of the possible options). + + The actual items which are counted depends on the options given by + args. The result is a list of integers, one for the result of each + counting option given. Valid counting options are "chars", + "displaychars", "displayindices", "displaylines", "indices", + "lines", "xpixels" and "ypixels". There is an additional possible + option "update", which if given then all subsequent options ensure + that any possible out of date information is recalculated.""" + args = ['-%s' % arg for arg in args if not arg.startswith('-')] + args += [index1, index2] + res = self.tk.call(self._w, 'count', *args) or None + if res is not None and len(args) <= 3: + return (res, ) + else: + return res def debug(self, boolean=None): """Turn on the internal consistency checks of the B-Tree inside the text widget according to BOOLEAN.""" @@ -2998,6 +3066,24 @@ def mark_previous(self, index): """Return the name of the previous mark before INDEX.""" return self.tk.call(self._w, 'mark', 'previous', index) or None + def peer_create(self, newPathName, cnf={}, **kw): # new in Tk 8.5 + """Creates a peer text widget with the given newPathName, and any + optional standard configuration options. By default the peer will + have the same start and and end line as the parent widget, but + these can be overriden with the standard configuration options.""" + self.tk.call(self._w, 'peer', 'create', newPathName, + *self._options(cnf, kw)) + def peer_names(self): # new in Tk 8.5 + """Returns a list of peers of this widget (this does not include + the widget itself).""" + return self.tk.splitlist(self.tk.call(self._w, 'peer', 'names')) + def replace(self, index1, index2, chars, *args): # new in Tk 8.5 + """Replaces the range of characters between index1 and index2 with + the given characters and tags specified by args. + + See the method insert for some more information about args, and the + method delete for information about the indices.""" + self.tk.call(self._w, 'replace', index1, index2, chars, *args) def scan_mark(self, x, y): """Remember the current X, Y coordinates.""" self.tk.call(self._w, 'scan', 'mark', x, y) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #2843: Add new Tk API to Tkinter. + - Issue #14184: Increase the default stack size for secondary threads on Mac OS X to avoid interpreter crashes when using threads on 10.7. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 21:59:23 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 13 Mar 2012 21:59:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=233835=3A_Refuse_to_?= =?utf8?q?use_unthreaded_Tcl_in_threaded_Python=2E?= Message-ID: http://hg.python.org/cpython/rev/d731dcda2611 changeset: 75599:d731dcda2611 user: Martin v. L?wis date: Tue Mar 13 13:59:15 2012 -0700 summary: Issue #3835: Refuse to use unthreaded Tcl in threaded Python. Patch by Guilherme Polo and Andrew Svetlov. files: Misc/NEWS | 2 ++ Modules/_tkinter.c | 7 +++++++ 2 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #3835: Refuse to use unthreaded Tcl in threaded Python. + - Issue #2843: Add new Tk API to Tkinter. - Issue #14184: Increase the default stack size for secondary threads on diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -613,6 +613,13 @@ } #endif #ifdef WITH_THREAD + if (!(v->threaded)) { + PyErr_SetString(PyExc_RuntimeError, + "Tcl/Tk was not compiled with --enable-threads but " + "Python has threads enabled"); + Py_DECREF(v); + return 0; + } if (v->threaded && tcl_lock) { /* If Tcl is threaded, we don't need the lock. */ PyThread_free_lock(tcl_lock); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:18:47 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 13 Mar 2012 22:18:47 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=235219=3A_Prevent_ev?= =?utf8?q?ent_handler_cascade_in_IDLE=2E?= Message-ID: http://hg.python.org/cpython/rev/505c3b7dc539 changeset: 75600:505c3b7dc539 user: Martin v. L?wis date: Tue Mar 13 14:18:36 2012 -0700 summary: Issue #5219: Prevent event handler cascade in IDLE. Patch by Roger Serwy. files: Lib/idlelib/CallTipWindow.py | 6 +++++- Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py --- a/Lib/idlelib/CallTipWindow.py +++ b/Lib/idlelib/CallTipWindow.py @@ -22,6 +22,7 @@ self.parenline = self.parencol = None self.lastline = None self.hideid = self.checkhideid = None + self.checkhide_after_id = None def position_window(self): """Check if needs to reposition the window, and if so - do it.""" @@ -102,7 +103,10 @@ self.hidetip() else: self.position_window() - self.widget.after(CHECKHIDE_TIME, self.checkhide_event) + if self.checkhide_after_id is not None: + self.widget.after_cancel(self.checkhide_after_id) + self.checkhide_after_id = \ + self.widget.after(CHECKHIDE_TIME, self.checkhide_event) def hide_event(self, event): if not self.tipwindow: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #5219: Prevent event handler cascade in IDLE. + - Issue #3835: Refuse to use unthreaded Tcl in threaded Python. - Issue #2843: Add new Tk API to Tkinter. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:34:13 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 13 Mar 2012 22:34:13 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzUyMTk6?= =?utf8?q?_Prevent_event_handler_cascade_in_IDLE=2E?= Message-ID: http://hg.python.org/cpython/rev/7e79dbceb039 changeset: 75601:7e79dbceb039 branch: 3.2 parent: 75596:246e681a4272 user: Martin v. L?wis date: Tue Mar 13 14:32:29 2012 -0700 summary: Issue #5219: Prevent event handler cascade in IDLE. Patch by Roger Serwy. files: Lib/idlelib/CallTipWindow.py | 6 +++++- Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py --- a/Lib/idlelib/CallTipWindow.py +++ b/Lib/idlelib/CallTipWindow.py @@ -22,6 +22,7 @@ self.parenline = self.parencol = None self.lastline = None self.hideid = self.checkhideid = None + self.checkhide_after_id = None def position_window(self): """Check if needs to reposition the window, and if so - do it.""" @@ -102,7 +103,10 @@ self.hidetip() else: self.position_window() - self.widget.after(CHECKHIDE_TIME, self.checkhide_event) + if self.checkhide_after_id is not None: + self.widget.after_cancel(self.checkhide_after_id) + self.checkhide_after_id = \ + self.widget.after(CHECKHIDE_TIME, self.checkhide_event) def hide_event(self, event): if not self.tipwindow: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,8 @@ Library ------- +- Issue #5219: Prevent event handler cascade in IDLE. + - Issue #14184: Increase the default stack size for secondary threads on Mac OS X to avoid interpreter crashes when using threads on 10.7. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:34:14 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 13 Mar 2012 22:34:14 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/99be11bd4acc changeset: 75602:99be11bd4acc parent: 75600:505c3b7dc539 parent: 75601:7e79dbceb039 user: Martin v. L?wis date: Tue Mar 13 14:34:04 2012 -0700 summary: Merge 3.2 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:46:35 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 13 Mar 2012 22:46:35 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzUyMTk6?= =?utf8?q?_Prevent_event_handler_cascade_in_IDLE=2E?= Message-ID: http://hg.python.org/cpython/rev/af1f8adc913b changeset: 75603:af1f8adc913b branch: 2.7 parent: 75589:48e6d66f708f user: Martin v. L?wis date: Tue Mar 13 14:46:22 2012 -0700 summary: Issue #5219: Prevent event handler cascade in IDLE. Patch by Roger Serwy. files: Lib/idlelib/CallTipWindow.py | 6 +++++- Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py --- a/Lib/idlelib/CallTipWindow.py +++ b/Lib/idlelib/CallTipWindow.py @@ -22,6 +22,7 @@ self.parenline = self.parencol = None self.lastline = None self.hideid = self.checkhideid = None + self.checkhide_after_id = None def position_window(self): """Check if needs to reposition the window, and if so - do it.""" @@ -102,7 +103,10 @@ self.hidetip() else: self.position_window() - self.widget.after(CHECKHIDE_TIME, self.checkhide_event) + if self.checkhide_after_id is not None: + self.widget.after_cancel(self.checkhide_after_id) + self.checkhide_after_id = \ + self.widget.after(CHECKHIDE_TIME, self.checkhide_event) def hide_event(self, event): if not self.tipwindow: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,8 @@ Library ------- +- Issue #5219: Prevent event handler cascade in IDLE. + - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under Windows when the child process has already exited. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:46:48 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 13 Mar 2012 22:46:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_fix_indentation?= Message-ID: http://hg.python.org/cpython/rev/692efd6ac771 changeset: 75604:692efd6ac771 branch: 3.2 parent: 75588:397215db7be1 user: Benjamin Peterson date: Tue Mar 13 16:13:09 2012 -0500 summary: fix indentation files: Modules/mathmodule.c | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -694,13 +694,13 @@ return NULL; } if (Py_IS_INFINITY(r) && Py_IS_FINITE(x)) { - if (can_overflow) - PyErr_SetString(PyExc_OverflowError, - "math range error"); /* overflow */ - else - PyErr_SetString(PyExc_ValueError, - "math domain error"); /* singularity */ - return NULL; + if (can_overflow) + PyErr_SetString(PyExc_OverflowError, + "math range error"); /* overflow */ + else + PyErr_SetString(PyExc_ValueError, + "math domain error"); /* singularity */ + return NULL; } if (Py_IS_FINITE(r) && errno && is_error(r)) /* this branch unnecessary on most platforms */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:46:48 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 13 Mar 2012 22:46:48 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/f0265b76fecd changeset: 75605:f0265b76fecd branch: 3.2 parent: 75604:692efd6ac771 parent: 75596:246e681a4272 user: Benjamin Peterson date: Tue Mar 13 16:13:21 2012 -0500 summary: merge heads files: Misc/NEWS | 3 +++ Python/thread_pthread.h | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,9 @@ Library ------- +- Issue #14184: Increase the default stack size for secondary threads on + Mac OS X to avoid interpreter crashes when using threads on 10.7. + - Issue #10543: Fix unittest test discovery with Jython bytecode files. - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -19,14 +19,18 @@ #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif -#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 - /* The default stack size for new threads on OSX is small enough that - * we'll get hard crashes instead of 'maximum recursion depth exceeded' - * exceptions. - * - * The default stack size below is the minimal stack size where a - * simple recursive function doesn't cause a hard crash. - */ +/* The default stack size for new threads on OSX and BSD is small enough that + * we'll get hard crashes instead of 'maximum recursion depth exceeded' + * exceptions. + * + * The default stack sizes below are the empirically determined minimal stack + * sizes where a simple recursive function doesn't cause a hard crash. + */ +#if defined(__APPLE__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 +#undef THREAD_STACK_SIZE +#define THREAD_STACK_SIZE 0x500000 +#endif +#if defined(__FreeBSD__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 #undef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0x400000 #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:46:49 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 13 Mar 2012 22:46:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/b0d3b441f568 changeset: 75606:b0d3b441f568 parent: 75599:d731dcda2611 parent: 75605:f0265b76fecd user: Benjamin Peterson date: Tue Mar 13 16:13:35 2012 -0500 summary: merge 3.2 files: Modules/mathmodule.c | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -745,13 +745,13 @@ return NULL; } if (Py_IS_INFINITY(r) && Py_IS_FINITE(x)) { - if (can_overflow) - PyErr_SetString(PyExc_OverflowError, - "math range error"); /* overflow */ - else - PyErr_SetString(PyExc_ValueError, - "math domain error"); /* singularity */ - return NULL; + if (can_overflow) + PyErr_SetString(PyExc_OverflowError, + "math range error"); /* overflow */ + else + PyErr_SetString(PyExc_ValueError, + "math domain error"); /* singularity */ + return NULL; } if (Py_IS_FINITE(r) && errno && is_error(r)) /* this branch unnecessary on most platforms */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:46:50 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 13 Mar 2012 22:46:50 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/5e90d83354a6 changeset: 75607:5e90d83354a6 parent: 75606:b0d3b441f568 parent: 75602:99be11bd4acc user: Benjamin Peterson date: Tue Mar 13 16:46:09 2012 -0500 summary: merge heads files: Lib/idlelib/CallTipWindow.py | 6 +++++- Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py --- a/Lib/idlelib/CallTipWindow.py +++ b/Lib/idlelib/CallTipWindow.py @@ -22,6 +22,7 @@ self.parenline = self.parencol = None self.lastline = None self.hideid = self.checkhideid = None + self.checkhide_after_id = None def position_window(self): """Check if needs to reposition the window, and if so - do it.""" @@ -102,7 +103,10 @@ self.hidetip() else: self.position_window() - self.widget.after(CHECKHIDE_TIME, self.checkhide_event) + if self.checkhide_after_id is not None: + self.widget.after_cancel(self.checkhide_after_id) + self.checkhide_after_id = \ + self.widget.after(CHECKHIDE_TIME, self.checkhide_event) def hide_event(self, event): if not self.tipwindow: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #5219: Prevent event handler cascade in IDLE. + - Issue #3835: Refuse to use unthreaded Tcl in threaded Python. - Issue #2843: Add new Tk API to Tkinter. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:46:50 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 13 Mar 2012 22:46:50 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/7bae16233943 changeset: 75608:7bae16233943 branch: 3.2 parent: 75605:f0265b76fecd parent: 75601:7e79dbceb039 user: Benjamin Peterson date: Tue Mar 13 16:46:35 2012 -0500 summary: merge heads files: Lib/idlelib/CallTipWindow.py | 6 +++++- Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py --- a/Lib/idlelib/CallTipWindow.py +++ b/Lib/idlelib/CallTipWindow.py @@ -22,6 +22,7 @@ self.parenline = self.parencol = None self.lastline = None self.hideid = self.checkhideid = None + self.checkhide_after_id = None def position_window(self): """Check if needs to reposition the window, and if so - do it.""" @@ -102,7 +103,10 @@ self.hidetip() else: self.position_window() - self.widget.after(CHECKHIDE_TIME, self.checkhide_event) + if self.checkhide_after_id is not None: + self.widget.after_cancel(self.checkhide_after_id) + self.checkhide_after_id = \ + self.widget.after(CHECKHIDE_TIME, self.checkhide_event) def hide_event(self, event): if not self.tipwindow: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,8 @@ Library ------- +- Issue #5219: Prevent event handler cascade in IDLE. + - Issue #14184: Increase the default stack size for secondary threads on Mac OS X to avoid interpreter crashes when using threads on 10.7. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 22:49:47 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 13 Mar 2012 22:49:47 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/3f12d9a23f6f changeset: 75609:3f12d9a23f6f parent: 75607:5e90d83354a6 parent: 75608:7bae16233943 user: Benjamin Peterson date: Tue Mar 13 16:49:36 2012 -0500 summary: merge 3.2 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 13 23:02:39 2012 From: python-checkins at python.org (r.david.murray) Date: Tue, 13 Mar 2012 23:02:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=238315=3A_add_automatic_un?= =?utf8?q?ittest_test_discovery_in_test=2Etest=5Femail?= Message-ID: http://hg.python.org/cpython/rev/217fdeeaf6e0 changeset: 75610:217fdeeaf6e0 user: R David Murray date: Tue Mar 13 18:02:22 2012 -0400 summary: #8315: add automatic unittest test discovery in test.test_email files: Lib/test/test_email/__init__.py | 10 ++++++++++ Misc/NEWS | 5 +++++ 2 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_email/__init__.py b/Lib/test/test_email/__init__.py --- a/Lib/test/test_email/__init__.py +++ b/Lib/test/test_email/__init__.py @@ -5,6 +5,16 @@ import email from test.test_email import __file__ as landmark +# Run all tests in package for '-m unittest test.test_email' +def load_tests(loader, standard_tests, pattern): + this_dir = os.path.dirname(__file__) + if pattern is None: + pattern = "test*" + package_tests = loader.discover(start_dir=this_dir, pattern=pattern) + standard_tests.addTests(package_tests) + return standard_tests + + # used by regrtest and __main__. def test_main(): here = os.path.dirname(__file__) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -83,6 +83,11 @@ - Issue #14259: The finditer() method of re objects did not take any keyword arguments, contrary to the documentation. +Tests +----- + +- Issue #8315: (partial fix) python -m unittest test.test_email now works. + What's New in Python 3.3.0 Alpha 1? =================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 00:06:06 2012 From: python-checkins at python.org (jason.coombs) Date: Wed, 14 Mar 2012 00:06:06 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Fix_import_error_on_Pyth?= =?utf8?q?on_2=2Ex?= Message-ID: http://hg.python.org/distutils2/rev/09e86884295c changeset: 1302:09e86884295c user: Jason R. Coombs date: Tue Mar 13 16:05:51 2012 -0700 summary: Fix import error on Python 2.x files: distutils2/compiler/msvc9compiler.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/distutils2/compiler/msvc9compiler.py b/distutils2/compiler/msvc9compiler.py --- a/distutils2/compiler/msvc9compiler.py +++ b/distutils2/compiler/msvc9compiler.py @@ -20,7 +20,11 @@ from distutils2 import logger from distutils2.util import get_platform -import winreg +try: + import winreg +except ImportError: + # Python 2 compatibility + import _winreg as winreg RegOpenKeyEx = winreg.OpenKeyEx RegEnumKey = winreg.EnumKey -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Wed Mar 14 00:20:37 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 14 Mar 2012 00:20:37 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314180=3A_datetime?= =?utf8?q?=2Edate=2Efromtimestamp=28=29=2C_datetime=2Edatetime=2Efromtimes?= =?utf8?b?dGFtcCgp?= Message-ID: http://hg.python.org/cpython/rev/5d6a5c5a4ebe changeset: 75611:5d6a5c5a4ebe user: Victor Stinner date: Wed Mar 14 00:15:40 2012 +0100 summary: Issue #14180: datetime.date.fromtimestamp(), datetime.datetime.fromtimestamp() and datetime.datetime.utcfromtimestamp() now raise an OSError instead of ValueError if localtime() or gmtime() failed. files: Doc/library/datetime.rst | 10 ++- Misc/NEWS | 4 + Modules/_datetimemodule.c | 75 ++++++++++++++------------ 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -404,7 +404,8 @@ .. versionchanged:: 3.3 Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp is out of the range of values supported by the platform C - :c:func:`localtime` function. + :c:func:`localtime` function. Raise :exc:`OSError` instead of + :exc:`ValueError` on :c:func:`localtime` failure. .. classmethod:: date.fromordinal(ordinal) @@ -720,7 +721,9 @@ .. versionchanged:: 3.3 Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp is out of the range of values supported by the platform C - :c:func:`localtime` or :c:func:`gmtime` functions + :c:func:`localtime` or :c:func:`gmtime` functions. Raise :exc:`OSError` + instead of :exc:`ValueError` on :c:func:`localtime` or :c:func:`gmtime` + failure. .. classmethod:: datetime.utcfromtimestamp(timestamp) @@ -750,7 +753,8 @@ .. versionchanged:: 3.3 Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp is out of the range of values supported by the platform C - :c:func:`gmtime` function. + :c:func:`gmtime` function. Raise :exc:`OSError` instead of + :exc:`ValueError` on :c:func:`gmtime` failure. .. classmethod:: datetime.fromordinal(ordinal) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -33,6 +33,10 @@ - Issue #14184: Increase the default stack size for secondary threads on Mac OS X to avoid interpreter crashes when using threads on 10.7. +- Issue #14180: datetime.date.fromtimestamp(), + datetime.datetime.fromtimestamp() and datetime.datetime.utcfromtimestamp() + now raise an OSError instead of ValueError if localtime() or gmtime() failed. + - Issue #14180: time.ctime(), gmtime(), time.localtime(), datetime.date.fromtimestamp(), datetime.datetime.fromtimestamp() and datetime.datetime.utcfromtimestamp() now raises an OverflowError, instead of diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -2443,22 +2443,25 @@ { struct tm *tm; time_t t; - PyObject *result = NULL; if (_PyTime_ObjectToTime_t(obj, &t) == -1) return NULL; tm = localtime(&t); - if (tm) - result = PyObject_CallFunction(cls, "iii", - tm->tm_year + 1900, - tm->tm_mon + 1, - tm->tm_mday); - else - PyErr_SetString(PyExc_ValueError, - "timestamp out of range for " - "platform localtime() function"); - return result; + if (tm == NULL) { + /* unconvertible time */ +#ifdef EINVAL + if (errno == 0) + errno = EINVAL; +#endif + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return PyObject_CallFunction(cls, "iii", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday); } /* Return new date from current time. @@ -4057,33 +4060,33 @@ PyObject *tzinfo) { struct tm *tm; - PyObject *result = NULL; tm = f(&timet); - if (tm) { - /* The platform localtime/gmtime may insert leap seconds, - * indicated by tm->tm_sec > 59. We don't care about them, - * except to the extent that passing them on to the datetime - * constructor would raise ValueError for a reason that - * made no sense to the user. - */ - if (tm->tm_sec > 59) - tm->tm_sec = 59; - result = PyObject_CallFunction(cls, "iiiiiiiO", - tm->tm_year + 1900, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_hour, - tm->tm_min, - tm->tm_sec, - us, - tzinfo); + if (tm == NULL) { +#ifdef EINVAL + if (errno == 0) + errno = EINVAL; +#endif + return PyErr_SetFromErrno(PyExc_OSError); } - else - PyErr_SetString(PyExc_ValueError, - "timestamp out of range for " - "platform localtime()/gmtime() function"); - return result; + + /* The platform localtime/gmtime may insert leap seconds, + * indicated by tm->tm_sec > 59. We don't care about them, + * except to the extent that passing them on to the datetime + * constructor would raise ValueError for a reason that + * made no sense to the user. + */ + if (tm->tm_sec > 59) + tm->tm_sec = 59; + return PyObject_CallFunction(cls, "iiiiiiiO", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + us, + tzinfo); } /* Internal helper. @@ -4102,7 +4105,7 @@ if (_PyTime_ObjectToTimeval(timestamp, &timet, &us) == -1) return NULL; - return datetime_from_timet_and_us(cls, f, timet, us, tzinfo); + return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo); } /* Internal helper. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 00:20:38 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 14 Mar 2012 00:20:38 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314180=3A_TestDateT?= =?utf8?q?ime=2Etest=5Fmicrosecond=5Frounding=28=29_handles_localtime=28?= =?utf8?q?=29_and?= Message-ID: http://hg.python.org/cpython/rev/706689b2d678 changeset: 75612:706689b2d678 user: Victor Stinner date: Wed Mar 14 00:17:05 2012 +0100 summary: Issue #14180: TestDateTime.test_microsecond_rounding() handles localtime() and gmtime() failure on Windows files: Lib/test/datetimetester.py | 25 +++++++++++++++---------- 1 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -1741,16 +1741,21 @@ zero = fts(0) self.assertEqual(zero.second, 0) self.assertEqual(zero.microsecond, 0) - minus_one = fts(-1e-6) - self.assertEqual(minus_one.second, 59) - self.assertEqual(minus_one.microsecond, 999999) - - t = fts(-1e-8) - self.assertEqual(t, minus_one) - t = fts(-9e-7) - self.assertEqual(t, minus_one) - t = fts(-1e-7) - self.assertEqual(t, minus_one) + try: + minus_one = fts(-1e-6) + except OSError: + # localtime(-1) and gmtime(-1) is not supported on Windows + pass + else: + self.assertEqual(minus_one.second, 59) + self.assertEqual(minus_one.microsecond, 999999) + + t = fts(-1e-8) + self.assertEqual(t, minus_one) + t = fts(-9e-7) + self.assertEqual(t, minus_one) + t = fts(-1e-7) + self.assertEqual(t, minus_one) t = fts(1e-7) self.assertEqual(t, zero) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 00:20:39 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 14 Mar 2012 00:20:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314180=3A_Fix_the_s?= =?utf8?q?elect_module_to_handle_correctly_the_Windows_timeval?= Message-ID: http://hg.python.org/cpython/rev/a0d101220f96 changeset: 75613:a0d101220f96 user: Victor Stinner date: Wed Mar 14 00:20:51 2012 +0100 summary: Issue #14180: Fix the select module to handle correctly the Windows timeval structure. timeval.tv_sec is a long on Windows, not time_t. files: Modules/selectmodule.c | 19 ++++++++++++++++--- 1 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -223,10 +223,23 @@ return NULL; } else { - long usec; - if (_PyTime_ObjectToTimeval(tout, &tv.tv_sec, &usec) == -1) +#ifdef MS_WINDOWS + time_t sec; + if (_PyTime_ObjectToTimeval(tout, &sec, &tv.tv_usec) == -1) return NULL; - tv.tv_usec = usec; + assert(sizeof(tv.tv_sec) == sizeof(long)); +#if SIZEOF_TIME_T > SIZEOF_LONG + if (sec > LONG_MAX) { + PyErr_SetString(PyExc_OverflowError, + "timeout is too large"); + return NULL; + } +#endif + tv.tv_sec = (long)sec; +#else + if (_PyTime_ObjectToTimeval(tout, &tv.tv_sec, &tv.tv_usec) == -1) + return NULL; +#endif if (tv.tv_sec < 0) { PyErr_SetString(PyExc_ValueError, "timeout must be non-negative"); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 00:39:15 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 14 Mar 2012 00:39:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_doc_of_datetime=2Edate*?= =?utf8?q?=2E*fromtimestamp=28=29_methods?= Message-ID: http://hg.python.org/cpython/rev/7c0e15496b43 changeset: 75614:7c0e15496b43 user: Victor Stinner date: Wed Mar 14 00:39:29 2012 +0100 summary: Fix doc of datetime.date*.*fromtimestamp() methods files: Doc/library/datetime.rst | 14 +++++++++----- Doc/whatsnew/3.3.rst | 5 +++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -396,7 +396,8 @@ Return the local date corresponding to the POSIX timestamp, such as is returned by :func:`time.time`. This may raise :exc:`OverflowError`, if the timestamp is out - of the range of values supported by the platform C :c:func:`localtime` function. + of the range of values supported by the platform C :c:func:`localtime` function, + and :exc:`OSError` on :c:func:`localtime` failure. It's common for this to be restricted to years from 1970 through 2038. Note that on non-POSIX systems that include leap seconds in their notion of a timestamp, leap seconds are ignored by :meth:`fromtimestamp`. @@ -710,9 +711,11 @@ equivalent to ``tz.fromutc(datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz))``. - :meth:`fromtimestamp` may raise :exc:`ValueError`, if the timestamp is out of + :meth:`fromtimestamp` may raise :exc:`OverflowError`, if the timestamp is out of the range of values supported by the platform C :c:func:`localtime` or - :c:func:`gmtime` functions. It's common for this to be restricted to years in + :c:func:`gmtime` functions, and :exc:`OSError` on :c:func:`localtime` or + :c:func:`gmtime` failure. + It's common for this to be restricted to years in 1970 through 2038. Note that on non-POSIX systems that include leap seconds in their notion of a timestamp, leap seconds are ignored by :meth:`fromtimestamp`, and then it's possible to have two timestamps differing by a second that yield @@ -729,8 +732,9 @@ .. classmethod:: datetime.utcfromtimestamp(timestamp) Return the UTC :class:`.datetime` corresponding to the POSIX timestamp, with - :attr:`tzinfo` ``None``. This may raise :exc:`ValueError`, if the timestamp is - out of the range of values supported by the platform C :c:func:`gmtime` function. + :attr:`tzinfo` ``None``. This may raise :exc:`OverflowError`, if the timestamp is + out of the range of values supported by the platform C :c:func:`gmtime` function, + and :exc:`OSError` on :c:func:`gmtime` failure. It's common for this to be restricted to years in 1970 through 2038. See also :meth:`fromtimestamp`. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1123,6 +1123,11 @@ with sys.platform.startswith('linux'), or directly sys.platform == 'linux' if you don't need to support older Python versions. +* :issue:`13847`, :issue:`14180`: :mod:`time` and :mod:`datetime`: + :exc:`OverflowError` is now raised instead of :exc:`ValueError` if a + timestamp is out of range. :exc:`OSError` is now raised if C functions + :c:func:`gmtime` or :c:func:`localtime` failed. + Porting C code -------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 00:40:42 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 14 Mar 2012 00:40:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_What=27s_New_in_Python_3=2E?= =?utf8?q?3=3A_Repeat_the_dict_lookup_change_in_Porting_section?= Message-ID: http://hg.python.org/cpython/rev/f6199284ef3a changeset: 75615:f6199284ef3a user: Victor Stinner date: Wed Mar 14 00:40:57 2012 +0100 summary: What's New in Python 3.3: Repeat the dict lookup change in Porting section files: Doc/whatsnew/3.3.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1117,6 +1117,11 @@ .. XXX add a point about hash randomization and that it's always on in 3.3 +* :issue:`14205`: A dict lookup now raises a :exc:`RuntimeError` if the dict is + modified during the lookup. If you implement your own comparison function for + objects used as dict keys and the dict is shared by multiple threads, access + to the dict should be protected by a lock. + * :issue:`12326`: On Linux, sys.platform doesn't contain the major version anymore. It is now always 'linux', instead of 'linux2' or 'linux3' depending on the Linux version used to build Python. Replace sys.platform == 'linux2' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 01:02:13 2012 From: python-checkins at python.org (tarek.ziade) Date: Wed, 14 Mar 2012 01:02:13 +0100 Subject: [Python-checkins] =?utf8?q?distutils2_=28merge_default_-=3E_defau?= =?utf8?q?lt=29=3A_merged_from_upstream?= Message-ID: http://hg.python.org/distutils2/rev/932b3cea4285 changeset: 1304:932b3cea4285 parent: 1303:05f0910881fa parent: 1302:09e86884295c user: Tarek Ziade date: Tue Mar 13 17:01:28 2012 -0700 summary: merged from upstream files: distutils2/compiler/msvc9compiler.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/distutils2/compiler/msvc9compiler.py b/distutils2/compiler/msvc9compiler.py --- a/distutils2/compiler/msvc9compiler.py +++ b/distutils2/compiler/msvc9compiler.py @@ -20,7 +20,11 @@ from distutils2 import logger from distutils2.util import get_platform -import winreg +try: + import winreg +except ImportError: + # Python 2 compatibility + import _winreg as winreg RegOpenKeyEx = winreg.OpenKeyEx RegEnumKey = winreg.EnumKey -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Wed Mar 14 01:02:13 2012 From: python-checkins at python.org (tarek.ziade) Date: Wed, 14 Mar 2012 01:02:13 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_switching_to_use=5Fegg?= =?utf8?q?=5Finfo_by_default?= Message-ID: http://hg.python.org/distutils2/rev/05f0910881fa changeset: 1303:05f0910881fa parent: 1301:efdfd98bd217 user: Tarek Ziade date: Tue Mar 13 16:59:45 2012 -0700 summary: switching to use_egg_info by default files: distutils2/database.py | 8 +- distutils2/tests/test_database.py | 49 ++++++++++++------ 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/distutils2/database.py b/distutils2/database.py --- a/distutils2/database.py +++ b/distutils2/database.py @@ -495,7 +495,7 @@ return '-'.join([name, normalized_version]) + file_extension -def get_distributions(use_egg_info=False, paths=None): +def get_distributions(use_egg_info=True, paths=None): """ Provides an iterator that looks for ``.dist-info`` directories in ``sys.path`` and returns :class:`Distribution` instances for each one of @@ -522,7 +522,7 @@ yield dist -def get_distribution(name, use_egg_info=False, paths=None): +def get_distribution(name, use_egg_info=True, paths=None): """ Scans all elements in ``sys.path`` and looks for all directories ending with ``.dist-info``. Returns a :class:`Distribution` @@ -557,7 +557,7 @@ return None -def obsoletes_distribution(name, version=None, use_egg_info=False): +def obsoletes_distribution(name, version=None, use_egg_info=True): """ Iterates over all distributions to find which distributions obsolete *name*. @@ -591,7 +591,7 @@ break -def provides_distribution(name, version=None, use_egg_info=False): +def provides_distribution(name, version=None, use_egg_info=True): """ Iterates over all distributions to find which distributions provide *name*. If a *version* is provided, it will be used to filter the results. Scans diff --git a/distutils2/tests/test_database.py b/distutils2/tests/test_database.py --- a/distutils2/tests/test_database.py +++ b/distutils2/tests/test_database.py @@ -330,7 +330,7 @@ found_dists = [] # Verify the fake dists have been found. - dists = [dist for dist in get_distributions()] + dists = [dist for dist in get_distributions(use_egg_info=False)] for dist in dists: self.assertIsInstance(dist, Distribution) if (dist.name in dict(fake_dists) and @@ -381,10 +381,10 @@ # Verify that it does not find egg-info distributions, when not # instructed to - self.assertIsNone(get_distribution('bacon')) - self.assertIsNone(get_distribution('cheese')) - self.assertIsNone(get_distribution('strawberry')) - self.assertIsNone(get_distribution('banana')) + self.assertIsNone(get_distribution('bacon', use_egg_info=False)) + self.assertIsNone(get_distribution('cheese', use_egg_info=False)) + self.assertIsNone(get_distribution('strawberry', use_egg_info=False)) + self.assertIsNone(get_distribution('banana', use_egg_info=False)) # Now check that it works well in both situations, when egg-info # is a file and directory respectively. @@ -418,24 +418,29 @@ # Test for looking up distributions by what they provide checkLists = lambda x, y: self.assertEqual(sorted(x), sorted(y)) - l = [dist.name for dist in provides_distribution('truffles')] + l = [dist.name for dist in provides_distribution('truffles', + use_egg_info=False)] checkLists(l, ['choxie', 'towel-stuff']) - l = [dist.name for dist in provides_distribution('truffles', '1.0')] + l = [dist.name for dist in provides_distribution('truffles', '1.0', + use_egg_info=False)] checkLists(l, ['choxie']) l = [dist.name for dist in provides_distribution('truffles', '1.0', use_egg_info=True)] checkLists(l, ['choxie', 'cheese']) - l = [dist.name for dist in provides_distribution('truffles', '1.1.2')] + l = [dist.name for dist in provides_distribution('truffles', '1.1.2', + use_egg_info=False)] checkLists(l, ['towel-stuff']) - l = [dist.name for dist in provides_distribution('truffles', '1.1')] + l = [dist.name for dist in provides_distribution('truffles', '1.1', + use_egg_info=False)] checkLists(l, ['towel-stuff']) l = [dist.name for dist in provides_distribution('truffles', - '!=1.1,<=2.0')] + '!=1.1,<=2.0', + use_egg_info=False)] checkLists(l, ['choxie']) l = [dist.name for dist in provides_distribution('truffles', @@ -443,17 +448,20 @@ use_egg_info=True)] checkLists(l, ['choxie', 'bacon', 'cheese']) - l = [dist.name for dist in provides_distribution('truffles', '>1.0')] + l = [dist.name for dist in provides_distribution('truffles', '>1.0', + use_egg_info=False)] checkLists(l, ['towel-stuff']) - l = [dist.name for dist in provides_distribution('truffles', '>1.5')] + l = [dist.name for dist in provides_distribution('truffles', '>1.5', + use_egg_info=False)] checkLists(l, []) l = [dist.name for dist in provides_distribution('truffles', '>1.5', use_egg_info=True)] checkLists(l, ['bacon']) - l = [dist.name for dist in provides_distribution('truffles', '>=1.0')] + l = [dist.name for dist in provides_distribution('truffles', '>=1.0', + use_egg_info=False)] checkLists(l, ['choxie', 'towel-stuff']) l = [dist.name for dist in provides_distribution('strawberry', '0.6', @@ -485,28 +493,33 @@ # Test looking for distributions based on what they obsolete checkLists = lambda x, y: self.assertEqual(sorted(x), sorted(y)) - l = [dist.name for dist in obsoletes_distribution('truffles', '1.0')] + l = [dist.name for dist in obsoletes_distribution('truffles', '1.0', + use_egg_info=False)] checkLists(l, []) l = [dist.name for dist in obsoletes_distribution('truffles', '1.0', use_egg_info=True)] checkLists(l, ['cheese', 'bacon']) - l = [dist.name for dist in obsoletes_distribution('truffles', '0.8')] + l = [dist.name for dist in obsoletes_distribution('truffles', '0.8', + use_egg_info=False)] checkLists(l, ['choxie']) l = [dist.name for dist in obsoletes_distribution('truffles', '0.8', use_egg_info=True)] checkLists(l, ['choxie', 'cheese']) - l = [dist.name for dist in obsoletes_distribution('truffles', '0.9.6')] + l = [dist.name for dist in obsoletes_distribution('truffles', '0.9.6', + use_egg_info=False)] checkLists(l, ['choxie', 'towel-stuff']) l = [dist.name for dist in obsoletes_distribution('truffles', - '0.5.2.3')] + '0.5.2.3', + use_egg_info=False)] checkLists(l, ['choxie', 'towel-stuff']) - l = [dist.name for dist in obsoletes_distribution('truffles', '0.2')] + l = [dist.name for dist in obsoletes_distribution('truffles', '0.2', + use_egg_info=False)] checkLists(l, ['towel-stuff']) @requires_zlib -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Wed Mar 14 01:04:12 2012 From: python-checkins at python.org (jason.coombs) Date: Wed, 14 Mar 2012 01:04:12 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Fix_ImportError_in_test?= Message-ID: http://hg.python.org/distutils2/rev/9a84abc0e879 changeset: 1305:9a84abc0e879 user: Jason R. Coombs date: Tue Mar 13 17:01:26 2012 -0700 summary: Fix ImportError in test files: distutils2/tests/test_msvc9compiler.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/distutils2/tests/test_msvc9compiler.py b/distutils2/tests/test_msvc9compiler.py --- a/distutils2/tests/test_msvc9compiler.py +++ b/distutils2/tests/test_msvc9compiler.py @@ -101,7 +101,10 @@ v = Reg.get_value(path, 'dragfullwindows') self.assertIn(v, ('0', '1', '2')) - import winreg + try: + import winreg + except ImportError: + import _winreg as winreg HKCU = winreg.HKEY_CURRENT_USER keys = Reg.read_keys(HKCU, 'xxxx') self.assertEqual(keys, None) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Wed Mar 14 01:04:12 2012 From: python-checkins at python.org (jason.coombs) Date: Wed, 14 Mar 2012 01:04:12 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Add_coding_declaration_f?= =?utf8?q?or_utf-8_characters_in_comments?= Message-ID: http://hg.python.org/distutils2/rev/d9a17cfd3f5c changeset: 1306:d9a17cfd3f5c user: Jason R. Coombs date: Tue Mar 13 17:02:27 2012 -0700 summary: Add coding declaration for utf-8 characters in comments files: distutils2/command/bdist_msi.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/distutils2/command/bdist_msi.py b/distutils2/command/bdist_msi.py --- a/distutils2/command/bdist_msi.py +++ b/distutils2/command/bdist_msi.py @@ -1,3 +1,5 @@ +#-*- coding: utf-8 -*- + """Create a Microsoft Installer (.msi) binary distribution.""" # Copyright (C) 2005, 2006 Martin von L?wis -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Wed Mar 14 01:53:31 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 14 Mar 2012 01:53:31 +0100 Subject: [Python-checkins] =?utf8?q?devguide=3A_Add_Andrew_Svetlov=2E?= Message-ID: http://hg.python.org/devguide/rev/1582c22e435a changeset: 495:1582c22e435a user: Martin v. L?wis date: Tue Mar 13 17:53:27 2012 -0700 summary: Add Andrew Svetlov. files: developers.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/developers.rst b/developers.rst --- a/developers.rst +++ b/developers.rst @@ -24,6 +24,9 @@ Permissions History ------------------- +- Andrew Svetlov was given push privileges on Mar 13 2012 by MvL at + the PyCon sprint. + - Petri Lehtinen was given push privileges on Oct 22 2011 by GFB, for general contributions, on recommendation by Antoine Pitrou. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Mar 14 02:38:45 2012 From: python-checkins at python.org (andrew.svetlov) Date: Wed, 14 Mar 2012 02:38:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=23989712=3A_Support_?= =?utf8?q?using_Tk_without_a_mainloop=2E?= Message-ID: http://hg.python.org/cpython/rev/535bb0bf1f49 changeset: 75616:535bb0bf1f49 user: Andrew Svetlov date: Tue Mar 13 18:36:13 2012 -0700 summary: Issue #989712: Support using Tk without a mainloop. files: Lib/idlelib/run.py | 16 ++++++++++++++++ Misc/NEWS | 2 ++ 2 files changed, 18 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -38,6 +38,21 @@ return s warnings.formatwarning = idle_formatwarning_subproc + +def handle_tk_events(): + """Process any tk events that are ready to be dispatched if tkinter + has been imported, a tcl interpreter has been created and tk has been + loaded.""" + tkinter = sys.modules.get('tkinter') + if tkinter and tkinter._default_root: + # tkinter has been imported, an Tcl interpreter was created and + # tk has been loaded. + root = tkinter._default_root + while root.tk.dooneevent(tkinter._tkinter.DONT_WAIT): + # Process pending events. + pass + + # Thread shared globals: Establish a queue between a subthread (which handles # the socket) and the main thread (which runs user code), plus global # completion, exit and interruptable (the main thread) flags: @@ -93,6 +108,7 @@ try: seq, request = rpc.request_queue.get(block=True, timeout=0.05) except queue.Empty: + handle_tk_events() continue method, args, kwargs = request ret = method(*args, **kwargs) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #989712: Support using Tk without a mainloop. + - Issue #5219: Prevent event handler cascade in IDLE. - Issue #3835: Refuse to use unthreaded Tcl in threaded Python. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 03:29:45 2012 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 14 Mar 2012 03:29:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue10050_-_urlretrieve_us?= =?utf8?q?es_newer_urlopen=2E_reporthook_of_urlretrieve_takes=2C?= Message-ID: http://hg.python.org/cpython/rev/53715804dc71 changeset: 75617:53715804dc71 user: Senthil Kumaran date: Tue Mar 13 19:29:33 2012 -0700 summary: Issue10050 - urlretrieve uses newer urlopen. reporthook of urlretrieve takes, block number, block read size, file_size files: Doc/howto/urllib2.rst | 7 + Doc/library/urllib.request.rst | 39 ++++++---- Lib/test/test_urllib.py | 34 ++++---- Lib/urllib/request.py | 80 +++++++++++++++++++-- Misc/ACKS | 1 + 5 files changed, 119 insertions(+), 42 deletions(-) diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -56,6 +56,13 @@ response = urllib.request.urlopen('http://python.org/') html = response.read() +If you wish to retrieve a resource via URL and store it in a temporary location, +you can do so via the :func:`urlretrieve` function:: + + import urllib.request + local_filename, headers = urllib.request.urlretrieve('http://python.org/') + html = open(local_filename) + Many uses of urllib will be that simple (note that instead of an 'http:' URL we could have used an URL starting with 'ftp:', 'file:', etc.). However, it's the purpose of this tutorial to explain the more complicated cases, concentrating on diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -1124,16 +1124,14 @@ ``urllib`` (as opposed to ``urllib2``). They might become deprecated at some point in the future. - .. function:: urlretrieve(url, filename=None, reporthook=None, data=None) - Copy a network object denoted by a URL to a local file, if necessary. If the URL - points to a local file, or a valid cached copy of the object exists, the object - is not copied. Return a tuple ``(filename, headers)`` where *filename* is the + Copy a network object denoted by a URL to a local file. If the URL + points to a local file, the object will not be copied unless filename is supplied. + Return a tuple ``(filename, headers)`` where *filename* is the local file name under which the object can be found, and *headers* is whatever the :meth:`info` method of the object returned by :func:`urlopen` returned (for - a remote object, possibly cached). Exceptions are the same as for - :func:`urlopen`. + a remote object). Exceptions are the same as for :func:`urlopen`. The second argument, if present, specifies the file location to copy to (if absent, the location will be a tempfile with a generated name). The third @@ -1144,11 +1142,18 @@ third argument may be ``-1`` on older FTP servers which do not return a file size in response to a retrieval request. + The following example illustrates the most common usage scenario:: + + >>> import urllib.request + >>> local_filename, headers = urllib.request.urlretrieve('http://python.org/') + >>> html = open(local_filename) + >>> html.close() + If the *url* uses the :file:`http:` scheme identifier, the optional *data* - argument may be given to specify a ``POST`` request (normally the request type - is ``GET``). The *data* argument must in standard - :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode` - function below. + argument may be given to specify a ``POST`` request (normally the request + type is ``GET``). The *data* argument must in standard + :mimetype:`application/x-www-form-urlencoded` format; see the + :func:`urlencode` function below. :func:`urlretrieve` will raise :exc:`ContentTooShortError` when it detects that the amount of data available was less than the expected amount (which is the @@ -1156,20 +1161,20 @@ the download is interrupted. The *Content-Length* is treated as a lower bound: if there's more data to read, - :func:`urlretrieve` reads more data, but if less data is available, it raises - the exception. + urlretrieve reads more data, but if less data is available, it raises the + exception. You can still retrieve the downloaded data in this case, it is stored in the :attr:`content` attribute of the exception instance. - If no *Content-Length* header was supplied, :func:`urlretrieve` can not check - the size of the data it has downloaded, and just returns it. In this case - you just have to assume that the download was successful. + If no *Content-Length* header was supplied, urlretrieve can not check the size + of the data it has downloaded, and just returns it. In this case you just have + to assume that the download was successful. .. function:: urlcleanup() - Clear the cache that may have been built up by previous calls to - :func:`urlretrieve`. + Cleans up temporary files that may have been left behind by previous + calls to :func:`urlretrieve`. .. class:: URLopener(proxies=None, **x509) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -384,11 +384,11 @@ def test_reporthook(self): # Make sure that the reporthook works. - def hooktester(count, block_size, total_size, count_holder=[0]): - self.assertIsInstance(count, int) - self.assertIsInstance(block_size, int) - self.assertIsInstance(total_size, int) - self.assertEqual(count, count_holder[0]) + def hooktester(block_count, block_read_size, file_size, count_holder=[0]): + self.assertIsInstance(block_count, int) + self.assertIsInstance(block_read_size, int) + self.assertIsInstance(file_size, int) + self.assertEqual(block_count, count_holder[0]) count_holder[0] = count_holder[0] + 1 second_temp = "%s.2" % support.TESTFN self.registerFileForCleanUp(second_temp) @@ -399,8 +399,8 @@ def test_reporthook_0_bytes(self): # Test on zero length file. Should call reporthook only 1 time. report = [] - def hooktester(count, block_size, total_size, _report=report): - _report.append((count, block_size, total_size)) + def hooktester(block_count, block_read_size, file_size, _report=report): + _report.append((block_count, block_read_size, file_size)) srcFileName = self.createNewTempFile() urllib.request.urlretrieve(self.constructLocalFileUrl(srcFileName), support.TESTFN, hooktester) @@ -410,31 +410,31 @@ def test_reporthook_5_bytes(self): # Test on 5 byte file. Should call reporthook only 2 times (once when # the "network connection" is established and once when the block is - # read). Since the block size is 8192 bytes, only one block read is - # required to read the entire file. + # read). report = [] - def hooktester(count, block_size, total_size, _report=report): - _report.append((count, block_size, total_size)) + def hooktester(block_count, block_read_size, file_size, _report=report): + _report.append((block_count, block_read_size, file_size)) srcFileName = self.createNewTempFile(b"x" * 5) urllib.request.urlretrieve(self.constructLocalFileUrl(srcFileName), support.TESTFN, hooktester) self.assertEqual(len(report), 2) - self.assertEqual(report[0][1], 8192) - self.assertEqual(report[0][2], 5) + self.assertEqual(report[0][1], 0) + self.assertEqual(report[1][1], 5) def test_reporthook_8193_bytes(self): # Test on 8193 byte file. Should call reporthook only 3 times (once # when the "network connection" is established, once for the next 8192 # bytes, and once for the last byte). report = [] - def hooktester(count, block_size, total_size, _report=report): - _report.append((count, block_size, total_size)) + def hooktester(block_count, block_read_size, file_size, _report=report): + _report.append((block_count, block_read_size, file_size)) srcFileName = self.createNewTempFile(b"x" * 8193) urllib.request.urlretrieve(self.constructLocalFileUrl(srcFileName), support.TESTFN, hooktester) self.assertEqual(len(report), 3) - self.assertEqual(report[0][1], 8192) - self.assertEqual(report[0][2], 8193) + self.assertEqual(report[0][1], 0) + self.assertEqual(report[1][1], 8192) + self.assertEqual(report[2][1], 1) class urlretrieve_HttpTests(unittest.TestCase, FakeHTTPMixin): diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -94,6 +94,9 @@ import sys import time import collections +import tempfile +import contextlib + from urllib.error import URLError, HTTPError, ContentTooShortError from urllib.parse import ( @@ -156,17 +159,78 @@ global _opener _opener = opener -# TODO(jhylton): Make this work with the same global opener. -_urlopener = None +_url_tempfiles = [] def urlretrieve(url, filename=None, reporthook=None, data=None): - global _urlopener - if not _urlopener: - _urlopener = FancyURLopener() - return _urlopener.retrieve(url, filename, reporthook, data) + """ + Retrieve a URL into a temporary location on disk. + + Requires a URL argument. If a filename is passed, it is used as + the temporary file location. The reporthook argument should be + a callable that accepts a block number, a read size, and the + total file size of the URL target. The data argument should be + valid URL encoded data. + + If a filename is passed and the URL points to a local resource, + the result is a copy from local file to new file. + + Returns a tuple containing the path to the newly created + data file as well as the resulting HTTPMessage object. + """ + url_type, path = splittype(url) + + with contextlib.closing(urlopen(url, data)) as fp: + headers = fp.info() + + # Just return the local path and the "headers" for file:// + # URLs. No sense in performing a copy unless requested. + if url_type == "file" and not filename: + return os.path.normpath(path), headers + + # Handle temporary file setup. + if filename: + tfp = open(filename, 'wb') + else: + tfp = tempfile.NamedTemporaryFile(delete=False) + filename = tfp.name + _url_tempfiles.append(filename) + + with tfp: + result = filename, headers + bs = 1024*8 + size = -1 + read = 0 + blocknum = 0 + if "content-length" in headers: + size = int(headers["Content-Length"]) + + if reporthook: + reporthook(blocknum, 0, size) + + while True: + block = fp.read(bs) + if not block: + break + read += len(block) + tfp.write(block) + blocknum += 1 + if reporthook: + reporthook(blocknum, len(block), size) + + if size >= 0 and read < size: + raise ContentTooShortError( + "retrieval incomplete: got only %i out of %i bytes" + % (read, size), result) + + return result def urlcleanup(): - if _urlopener: - _urlopener.cleanup() + for temp_file in _url_tempfiles: + try: + os.unlink(temp_file) + except EnvironmentError: + pass + + del _url_tempfiles[:] global _opener if _opener: _opener = None diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -288,6 +288,7 @@ Lance Ellinghaus David Ely Jeff Epler +Jeff McNeil Tom Epperly Stoffel Erasmus J?rgen A. Erhard -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 03:48:48 2012 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 14 Mar 2012 03:48:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_closes_Issue123?= =?utf8?q?65_-_Add_an_example_explaining_the_context_manager_use_case_of?= Message-ID: http://hg.python.org/cpython/rev/8625627969aa changeset: 75618:8625627969aa branch: 3.2 parent: 75608:7bae16233943 user: Senthil Kumaran date: Tue Mar 13 19:47:51 2012 -0700 summary: closes Issue12365 - Add an example explaining the context manager use case of urllib.urlopen files: Doc/library/urllib.request.rst | 18 +++++++++++++----- 1 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -46,8 +46,8 @@ If neither *cafile* nor *capath* is specified, an HTTPS request will not do any verification of the server's certificate. - This function returns a file-like object with two additional methods from - the :mod:`urllib.response` module + This function returns a file-like object that works as a :term:`context manager`, + with two additional methods from the :mod:`urllib.response` module * :meth:`geturl` --- return the URL of the resource retrieved, commonly used to determine if a redirect was followed @@ -967,8 +967,17 @@ the various ways in which a (X)HTML or a XML document could have specified its encoding information. -As python.org website uses *utf-8* encoding as specified in it's meta tag, we -will use same for decoding the bytes object. :: +As the python.org website uses *utf-8* encoding as specified in it's meta tag, we +will use the same for decoding the bytes object. :: + + >>> with urllib.request.urlopen('http://www.python.org/') as f: + ... print(f.read(100).decode('utf-8')) + ... + >> import urllib.request >>> f = urllib.request.urlopen('http://www.python.org/') @@ -976,7 +985,6 @@ http://hg.python.org/cpython/rev/074e12441ed6 changeset: 75619:074e12441ed6 parent: 75617:53715804dc71 parent: 75618:8625627969aa user: Senthil Kumaran date: Tue Mar 13 19:48:37 2012 -0700 summary: default: closes Issue12365 - Add an example explaining the context manager use case of urllib.urlopen files: Doc/library/urllib.request.rst | 18 +++++++++++++----- 1 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -46,8 +46,8 @@ If neither *cafile* nor *capath* is specified, an HTTPS request will not do any verification of the server's certificate. - This function returns a file-like object with two additional methods from - the :mod:`urllib.response` module + This function returns a file-like object that works as a :term:`context manager`, + with two additional methods from the :mod:`urllib.response` module * :meth:`geturl` --- return the URL of the resource retrieved, commonly used to determine if a redirect was followed @@ -998,8 +998,17 @@ the various ways in which a (X)HTML or a XML document could have specified its encoding information. -As python.org website uses *utf-8* encoding as specified in it's meta tag, we -will use same for decoding the bytes object. :: +As the python.org website uses *utf-8* encoding as specified in it's meta tag, we +will use the same for decoding the bytes object. :: + + >>> with urllib.request.urlopen('http://www.python.org/') as f: + ... print(f.read(100).decode('utf-8')) + ... + >> import urllib.request >>> f = urllib.request.urlopen('http://www.python.org/') @@ -1007,7 +1016,6 @@ http://hg.python.org/distutils2/rev/f453054a7d8b changeset: 1307:f453054a7d8b parent: 1304:932b3cea4285 user: Preston Holmes date: Tue Mar 13 20:26:28 2012 -0700 summary: fix for 14294 files: distutils2/database.py | 76 ++-------------------- distutils2/tests/requires.txt | 15 ++++ distutils2/tests/test_util.py | 12 +++- distutils2/util.py | 77 +++++++++++++++++++++++ 4 files changed, 111 insertions(+), 69 deletions(-) diff --git a/distutils2/database.py b/distutils2/database.py --- a/distutils2/database.py +++ b/distutils2/database.py @@ -15,6 +15,7 @@ from distutils2.errors import PackagingError from distutils2.version import suggest_normalized_version, VersionPredicate from distutils2.metadata import Metadata +from distutils2.util import parse_requires __all__ = [ @@ -300,11 +301,6 @@ """A :class:`distutils2.metadata.Metadata` instance loaded with the distribution's ``METADATA`` file.""" - _REQUIREMENT = re.compile( - r'(?P[-A-Za-z0-9_.]+)\s*' - r'(?P(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)?\s*' - r'(?P(?:\s*,\s*(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)*)\s*' - r'(?P\[.*\])?') def __init__(self, path): self.path = path @@ -314,20 +310,7 @@ self.version = self.metadata['Version'] return - # reused from Distribute's pkg_resources - def yield_lines(strs): - """Yield non-empty/non-comment lines of a ``basestring`` - or sequence""" - if isinstance(strs, basestring): - for s in strs.splitlines(): - s = s.strip() - # skip blank lines/comments - if s and not s.startswith('#'): - yield s - else: - for ss in strs: - for s in yield_lines(ss): - yield s + requires = None @@ -335,15 +318,8 @@ if os.path.isdir(path): meta_path = os.path.join(path, 'EGG-INFO', 'PKG-INFO') self.metadata = Metadata(path=meta_path) - try: - req_path = os.path.join(path, 'EGG-INFO', 'requires.txt') - fp = open(req_path, 'r') - try: - requires = fp.read() - finally: - fp.close() - except IOError: - requires = None + req_path = os.path.join(path, 'EGG-INFO', 'requires.txt') + requires = parse_requires(req_path) else: # FIXME handle the case where zipfile is not available zipf = zipimport.zipimporter(path) @@ -360,14 +336,8 @@ elif path.endswith('.egg-info'): if os.path.isdir(path): path = os.path.join(path, 'PKG-INFO') - try: - fp = open(os.path.join(path, 'requires.txt'), 'r') - try: - requires = fp.read() - finally: - fp.close() - except IOError: - requires = None + req_path = os.path.join(path, 'requires.txt') + requires = parse_requires(req_path) self.metadata = Metadata(path=path) self.name = self.metadata['Name'] self.version = self.metadata['Version'] @@ -383,40 +353,10 @@ if field in self.metadata: del self.metadata[field] - reqs = [] - if requires is not None: - for line in yield_lines(requires): - if line.startswith('['): - logger.warning( - 'extensions in requires.txt are not supported ' - '(used by %r %s)', self.name, self.version) - break - else: - match = self._REQUIREMENT.match(line.strip()) - if not match: - # this happens when we encounter extras; since they - # are written at the end of the file we just exit - break - else: - if match.group('extras'): - msg = ('extra requirements are not supported ' - '(used by %r %s)', self.name, self.version) - logger.warning(msg, self.name) - name = match.group('name') - version = None - if match.group('first'): - version = match.group('first') - if match.group('rest'): - version += match.group('rest') - version = version.replace(' ', '') # trim spaces - if version is None: - reqs.append(name) - else: - reqs.append('%s (%s)' % (name, version)) - if len(reqs) > 0: - self.metadata['Requires-Dist'] += reqs + if requires is not None and len(requires)>0: + self.metadata['Requires-Dist'] += requires if _cache_enabled: _cache_path_egg[self.path] = self diff --git a/distutils2/tests/requires.txt b/distutils2/tests/requires.txt new file mode 100644 --- /dev/null +++ b/distutils2/tests/requires.txt @@ -0,0 +1,15 @@ +setuptools +zope.browser +zope.component +zope.configuration +zope.contenttype >= 3.5 +zope.event +zope.exceptions +zope.i18n +zope.interface +zope.location +zope.proxy +zope.security + +[test] +zope.testing \ No newline at end of file diff --git a/distutils2/tests/test_util.py b/distutils2/tests/test_util.py --- a/distutils2/tests/test_util.py +++ b/distutils2/tests/test_util.py @@ -18,7 +18,8 @@ get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages, spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob, RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging, - get_install_method, cfg_to_args, generate_setup_py, encode_multipart) + get_install_method, cfg_to_args, generate_setup_py, encode_multipart, + parse_requires) from distutils2.tests import support, unittest from distutils2.tests.test_config import SETUP_CFG @@ -378,6 +379,15 @@ self.assertEqual(sorted(res), ['pkg1', 'pkg1.pkg3', 'pkg1.pkg3.pkg6', 'pkg5']) + def test_parse_requires(self): + req_file = os.path.join(os.path.dirname(__file__), 'requires.txt') + expected_requires = ['setuptools', 'zope.browser', 'zope.component', + 'zope.configuration', 'zope.contenttype', 'zope.event', + 'zope.exceptions', 'zope.i18n', 'zope.interface', + 'zope.location', 'zope.proxy', 'zope.security'] + requires = parse_requires(req_file) + self.assertEqual(requires, expected_requires) + def test_resolve_name(self): # test raw module name tmpdir = self.mkdtemp() diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -25,6 +25,7 @@ from distutils2.errors import (PackagingPlatformError, PackagingFileError, PackagingExecError, InstallationException, PackagingInternalError) +from distutils2.metadata import Metadata from distutils2._backport import shutil, sysconfig __all__ = [ @@ -1172,6 +1173,71 @@ f.close() return record_path +def parse_requires(req_path): + """Takes the raw content of a requires.txt file and returns a list of requirements""" + + # reused from Distribute's pkg_resources + def yield_lines(strs): + """Yield non-empty/non-comment lines of a ``basestring`` + or sequence""" + if isinstance(strs, basestring): + for s in strs.splitlines(): + s = s.strip() + # skip blank lines/comments + if s and not s.startswith('#'): + yield s + else: + for ss in strs: + for s in yield_lines(ss): + yield s + + _REQUIREMENT = re.compile( + r'(?P[-A-Za-z0-9_.]+)\s*' + r'(?P(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)?\s*' + r'(?P(?:\s*,\s*(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)*)\s*' + r'(?P\[.*\])?') + + reqs = [] + try: + fp = open(req_path, 'r') + try: + requires = fp.read() + finally: + fp.close() + except IOError: + return None + + for line in yield_lines(requires): + if line.startswith('['): + logger.warning('extensions in requires.txt are not supported') + break + else: + match = _REQUIREMENT.match(line.strip()) + if not match: + # this happens when we encounter extras; since they + # are written at the end of the file we just exit + break + else: + if match.group('extras'): + # msg = ('extra requirements are not supported ' + # '(used by %r %s)', self.name, self.version) + msg = 'extra requirements are not supported' + logger.warning(msg) + name = match.group('name') + version = None + if match.group('first'): + version = match.group('first') + if match.group('rest'): + version += match.group('rest') + version = version.replace(' ', '') # trim spaces + if version is None: + reqs.append(name) + else: + reqs.append('%s (%s)' % (name, version)) + return reqs + + + def egginfo_to_distinfo(record_file, installer=_DEFAULT_INSTALLER, requested=False, remove_egginfo=False): @@ -1201,6 +1267,17 @@ metadata_path = distinfo['metadata_path'] logger.info('creating %s', metadata_path) shutil.copy2(distinfo['metadata'], metadata_path) + # add requirements and output metadata + requires = None + req_path = os.path.join(distinfo_dir, 'requires.txt') + requires = parse_requires(req_path) + if requires is not None: + # create a metadata instance to handle the reqs injection + metadata = Metadata(path=metadata_path) + metadata['Requires-Dist'] = requires + metadata.write(metadata_path) + + installer_path = distinfo['installer_path'] logger.info('creating %s', installer_path) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Wed Mar 14 04:32:20 2012 From: python-checkins at python.org (tarek.ziade) Date: Wed, 14 Mar 2012 04:32:20 +0100 Subject: [Python-checkins] =?utf8?q?distutils2_=28merge_default_-=3E_defau?= =?utf8?q?lt=29=3A_merged?= Message-ID: http://hg.python.org/distutils2/rev/d5f57d07abe6 changeset: 1308:d5f57d07abe6 parent: 1307:f453054a7d8b parent: 1306:d9a17cfd3f5c user: Tarek Ziade date: Tue Mar 13 20:31:36 2012 -0700 summary: merged files: distutils2/command/bdist_msi.py | 2 ++ distutils2/tests/test_msvc9compiler.py | 5 ++++- 2 files changed, 6 insertions(+), 1 deletions(-) diff --git a/distutils2/command/bdist_msi.py b/distutils2/command/bdist_msi.py --- a/distutils2/command/bdist_msi.py +++ b/distutils2/command/bdist_msi.py @@ -1,3 +1,5 @@ +#-*- coding: utf-8 -*- + """Create a Microsoft Installer (.msi) binary distribution.""" # Copyright (C) 2005, 2006 Martin von L?wis diff --git a/distutils2/tests/test_msvc9compiler.py b/distutils2/tests/test_msvc9compiler.py --- a/distutils2/tests/test_msvc9compiler.py +++ b/distutils2/tests/test_msvc9compiler.py @@ -101,7 +101,10 @@ v = Reg.get_value(path, 'dragfullwindows') self.assertIn(v, ('0', '1', '2')) - import winreg + try: + import winreg + except ImportError: + import _winreg as winreg HKCU = winreg.HKEY_CURRENT_USER keys = Reg.read_keys(HKCU, 'xxxx') self.assertEqual(keys, None) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Wed Mar 14 07:50:21 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 14 Mar 2012 07:50:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Closes_=2314298=3A_update_s?= =?utf8?q?ection_about_dict_implementation=2E?= Message-ID: http://hg.python.org/cpython/rev/305cf9be1cd3 changeset: 75620:305cf9be1cd3 user: Georg Brandl date: Wed Mar 14 07:50:17 2012 +0100 summary: Closes #14298: update section about dict implementation. files: Doc/faq/design.rst | 17 ++++++++++------- 1 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -526,14 +526,16 @@ Dictionaries work by computing a hash code for each key stored in the dictionary using the :func:`hash` built-in function. The hash code varies widely depending -on the key; for example, "Python" hashes to -539294296 while "python", a string -that differs by a single bit, hashes to 1142331976. The hash code is then used -to calculate a location in an internal array where the value will be stored. -Assuming that you're storing keys that all have different hash values, this -means that dictionaries take constant time -- O(1), in computer science notation --- to retrieve a key. It also means that no sorted order of the keys is -maintained, and traversing the array as the ``.keys()`` and ``.items()`` do will -output the dictionary's content in some arbitrary jumbled order. +on the key and a per-process seed; for example, "Python" could hash to +-539294296 while "python", a string that differs by a single bit, could hash +to 1142331976. The hash code is then used to calculate a location in an +internal array where the value will be stored. Assuming that you're storing +keys that all have different hash values, this means that dictionaries take +constant time -- O(1), in computer science notation -- to retrieve a key. It +also means that no sorted order of the keys is maintained, and traversing the +array as the ``.keys()`` and ``.items()`` do will output the dictionary's +content in some arbitrary jumbled order that can change with every invocation of +a program. Why must dictionary keys be immutable? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 08:03:45 2012 From: python-checkins at python.org (r.david.murray) Date: Wed, 14 Mar 2012 08:03:45 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzE0MjkxOiBpZiBh?= =?utf8?q?_header_has_non-ascii_unicode=2C_default_to_CTE_using_utf-8?= Message-ID: http://hg.python.org/cpython/rev/fd4b4650856f changeset: 75621:fd4b4650856f branch: 3.2 parent: 75618:8625627969aa user: R David Murray date: Wed Mar 14 02:59:51 2012 -0400 summary: #14291: if a header has non-ascii unicode, default to CTE using utf-8 In Python2, if a unicode string was assigned as the value of a header, email would automatically CTE encode it using the UTF8 charset. This capability was lost in the Python3 translation, and this patch restores it. Patch by Ali Ikinci, assisted by R. David Murray. I also added a fix for the mailbox test that was depending (with a comment that it was a bad idea to so depend) on non-ASCII causing message_from_string to raise an error. It now uses support.patch to induce an error during message serialization. files: Lib/email/header.py | 7 ++++++- Lib/email/test/test_email.py | 21 +++++++++++++++++++-- Lib/test/test_mailbox.py | 8 ++++---- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -283,7 +283,12 @@ # character set, otherwise an early error is thrown. output_charset = charset.output_codec or 'us-ascii' if output_charset != _charset.UNKNOWN8BIT: - s.encode(output_charset, errors) + try: + s.encode(output_charset, errors) + except UnicodeEncodeError: + if output_charset!='us-ascii': + raise + charset = UTF8 self._chunks.append((s, charset)) def encode(self, splitchars=';, \t', maxlinelen=None, linesep='\n'): diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -619,6 +619,19 @@ msg['Dummy'] = 'dummy\nX-Injected-Header: test' self.assertRaises(errors.HeaderParseError, msg.as_string) + def test_unicode_header_defaults_to_utf8_encoding(self): + # Issue 14291 + m = MIMEText('abc\n') + m['Subject'] = '? test' + self.assertEqual(str(m),textwrap.dedent("""\ + Content-Type: text/plain; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + Subject: =?utf-8?q?=C3=89_test?= + + abc + """)) + # Test the email.encoders module class TestEncoders(unittest.TestCase): @@ -1060,9 +1073,13 @@ 'f\xfcr Offshore-Windkraftprojekte ' '') msg['Reply-To'] = header_string - self.assertRaises(UnicodeEncodeError, msg.as_string) + eq(msg.as_string(maxheaderlen=78), """\ +Reply-To: =?utf-8?q?Britische_Regierung_gibt_gr=C3=BCnes_Licht_f=C3=BCr_Offs?= + =?utf-8?q?hore-Windkraftprojekte_=3Ca-very-long-address=40example=2Ecom=3E?= + +""") msg = Message() - msg['Reply-To'] = Header(header_string, 'utf-8', + msg['Reply-To'] = Header(header_string, header_name='Reply-To') eq(msg.as_string(maxheaderlen=78), """\ Reply-To: =?utf-8?q?Britische_Regierung_gibt_gr=C3=BCnes_Licht_f=C3=BCr_Offs?= diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -111,10 +111,10 @@ self.assertMailboxEmpty() def test_add_that_raises_leaves_mailbox_empty(self): - # XXX This test will start failing when Message learns to handle - # non-ASCII string headers, and a different internal failure will - # need to be found or manufactured. - with self.assertRaises(ValueError): + def raiser(*args, **kw): + raise Exception("a fake error") + support.patch(self, email.generator.BytesGenerator, 'flatten', raiser) + with self.assertRaises(Exception): self._box.add(email.message_from_string("From: Alph?so")) self.assertEqual(len(self._box), 0) self._box.close() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -430,6 +430,7 @@ Gerhard H?ring Fredrik H??rd Mihai Ibanescu +Ali Ikinci Lars Immisch Bobby Impollonia Meador Inge diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,9 @@ Library ------- +- Issue #14291: Email now defaults to utf-8 for non-ASCII unicode headers + instead of raising an error. This fixes a regression relative to 2.7. + - Issue #5219: Prevent event handler cascade in IDLE. - Issue #14184: Increase the default stack size for secondary threads on -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 08:03:46 2012 From: python-checkins at python.org (r.david.murray) Date: Wed, 14 Mar 2012 08:03:46 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2314291=3A_if_a_header_has_non-ascii_unicode=2C_defau?= =?utf8?q?lt_to_CTE_using_utf-8?= Message-ID: http://hg.python.org/cpython/rev/f5dcb2d58893 changeset: 75622:f5dcb2d58893 parent: 75620:305cf9be1cd3 parent: 75621:fd4b4650856f user: R David Murray date: Wed Mar 14 03:03:27 2012 -0400 summary: Merge #14291: if a header has non-ascii unicode, default to CTE using utf-8 In Python2, if a unicode string was assigned as the value of a header, email would automatically CTE encode it using the UTF8 charset. This capability was lost in the Python3 translation, and this patch restores it. Patch by Ali Ikinci, assisted by R. David Murray. I also added a fix for the mailbox test that was depending (with a comment that it was a bad idea to so depend) on non-ASCII causing message_from_string to raise an error. It now uses support.patch to induce an error during message serialization. files: Lib/email/header.py | 7 +++++- Lib/test/test_email/test_email.py | 21 +++++++++++++++++- Lib/test/test_mailbox.py | 8 +++--- Misc/ACKS | 1 + Misc/NEWS | 3 ++ 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Lib/email/header.py b/Lib/email/header.py --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -283,7 +283,12 @@ # character set, otherwise an early error is thrown. output_charset = charset.output_codec or 'us-ascii' if output_charset != _charset.UNKNOWN8BIT: - s.encode(output_charset, errors) + try: + s.encode(output_charset, errors) + except UnicodeEncodeError: + if output_charset!='us-ascii': + raise + charset = UTF8 self._chunks.append((s, charset)) def encode(self, splitchars=';, \t', maxlinelen=None, linesep='\n'): diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -604,6 +604,19 @@ msg['Dummy'] = 'dummy\nX-Injected-Header: test' self.assertRaises(errors.HeaderParseError, msg.as_string) + def test_unicode_header_defaults_to_utf8_encoding(self): + # Issue 14291 + m = MIMEText('abc\n') + m['Subject'] = '? test' + self.assertEqual(str(m),textwrap.dedent("""\ + Content-Type: text/plain; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + Subject: =?utf-8?q?=C3=89_test?= + + abc + """)) + # Test the email.encoders module class TestEncoders(unittest.TestCase): @@ -1045,9 +1058,13 @@ 'f\xfcr Offshore-Windkraftprojekte ' '') msg['Reply-To'] = header_string - self.assertRaises(UnicodeEncodeError, msg.as_string) + eq(msg.as_string(maxheaderlen=78), """\ +Reply-To: =?utf-8?q?Britische_Regierung_gibt_gr=C3=BCnes_Licht_f=C3=BCr_Offs?= + =?utf-8?q?hore-Windkraftprojekte_=3Ca-very-long-address=40example=2Ecom=3E?= + +""") msg = Message() - msg['Reply-To'] = Header(header_string, 'utf-8', + msg['Reply-To'] = Header(header_string, header_name='Reply-To') eq(msg.as_string(maxheaderlen=78), """\ Reply-To: =?utf-8?q?Britische_Regierung_gibt_gr=C3=BCnes_Licht_f=C3=BCr_Offs?= diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -111,10 +111,10 @@ self.assertMailboxEmpty() def test_add_that_raises_leaves_mailbox_empty(self): - # XXX This test will start failing when Message learns to handle - # non-ASCII string headers, and a different internal failure will - # need to be found or manufactured. - with self.assertRaises(ValueError): + def raiser(*args, **kw): + raise Exception("a fake error") + support.patch(self, email.generator.BytesGenerator, 'flatten', raiser) + with self.assertRaises(Exception): self._box.add(email.message_from_string("From: Alph?so")) self.assertEqual(len(self._box), 0) self._box.close() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -470,6 +470,7 @@ Fredrik H??rd Catalin Iacob Mihai Ibanescu +Ali Ikinci Lars Immisch Bobby Impollonia Meador Inge diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #14291: Email now defaults to utf-8 for non-ASCII unicode headers + instead of raising an error. This fixes a regression relative to 2.7. + - Issue #989712: Support using Tk without a mainloop. - Issue #5219: Prevent event handler cascade in IDLE. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 08:07:44 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 14 Mar 2012 08:07:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314283?= =?utf8?q?=3A_match=28=29_and_search=28=29_are_regex_methods=2C_not_match_?= =?utf8?q?methods=2E?= Message-ID: http://hg.python.org/cpython/rev/544ed2cfb097 changeset: 75623:544ed2cfb097 branch: 3.2 parent: 75621:fd4b4650856f user: Georg Brandl date: Wed Mar 14 08:02:43 2012 +0100 summary: Closes #14283: match() and search() are regex methods, not match methods. files: Doc/library/re.rst | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -944,16 +944,15 @@ .. attribute:: match.pos The value of *pos* which was passed to the :meth:`~regex.search` or - :meth:`~regex.match` method of a :ref:`match object `. This - is the index into the string at which the RE engine started looking for a - match. + :meth:`~regex.match` method of a :ref:`regex object `. This is + the index into the string at which the RE engine started looking for a match. .. attribute:: match.endpos The value of *endpos* which was passed to the :meth:`~regex.search` or - :meth:`~regex.match` method of a :ref:`match object `. This - is the index into the string beyond which the RE engine will not go. + :meth:`~regex.match` method of a :ref:`regex object `. This is + the index into the string beyond which the RE engine will not go. .. attribute:: match.lastindex -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 08:07:45 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 14 Mar 2012 08:07:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=2314283=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/3ffa1b88e9f6 changeset: 75624:3ffa1b88e9f6 parent: 75622:f5dcb2d58893 parent: 75623:544ed2cfb097 user: Georg Brandl date: Wed Mar 14 08:07:29 2012 +0100 summary: #14283: merge with 3.2 files: Doc/library/re.rst | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -947,16 +947,15 @@ .. attribute:: match.pos The value of *pos* which was passed to the :meth:`~regex.search` or - :meth:`~regex.match` method of a :ref:`match object `. This - is the index into the string at which the RE engine started looking for a - match. + :meth:`~regex.match` method of a :ref:`regex object `. This is + the index into the string at which the RE engine started looking for a match. .. attribute:: match.endpos The value of *endpos* which was passed to the :meth:`~regex.search` or - :meth:`~regex.match` method of a :ref:`match object `. This - is the index into the string beyond which the RE engine will not go. + :meth:`~regex.match` method of a :ref:`regex object `. This is + the index into the string beyond which the RE engine will not go. .. attribute:: match.lastindex -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 08:19:20 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 14 Mar 2012 08:19:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314289?= =?utf8?q?=3A_put_a_link_to_the_CHM_download_page_on_the_docs_download_pag?= =?utf8?q?e=2E?= Message-ID: http://hg.python.org/cpython/rev/2800530b00d3 changeset: 75625:2800530b00d3 branch: 3.2 parent: 75623:544ed2cfb097 user: Georg Brandl date: Wed Mar 14 08:18:47 2012 +0100 summary: Closes #14289: put a link to the CHM download page on the docs download page. files: Doc/tools/sphinxext/download.html | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Doc/tools/sphinxext/download.html b/Doc/tools/sphinxext/download.html --- a/Doc/tools/sphinxext/download.html +++ b/Doc/tools/sphinxext/download.html @@ -39,8 +39,12 @@
+

These archives contain all the content in the documentation.

-

These archives contain all the content in the documentation.

+

HTML Help (.chm) files are made available in the "Windows" section +on the Python +download page.

+

Unpacking

-- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 08:19:21 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 14 Mar 2012 08:19:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=2314289=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/b4d1e51d91f8 changeset: 75626:b4d1e51d91f8 parent: 75624:3ffa1b88e9f6 parent: 75625:2800530b00d3 user: Georg Brandl date: Wed Mar 14 08:18:59 2012 +0100 summary: #14289: merge with 3.2 files: Doc/tools/sphinxext/download.html | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Doc/tools/sphinxext/download.html b/Doc/tools/sphinxext/download.html --- a/Doc/tools/sphinxext/download.html +++ b/Doc/tools/sphinxext/download.html @@ -39,8 +39,12 @@ +

These archives contain all the content in the documentation.

-

These archives contain all the content in the documentation.

+

HTML Help (.chm) files are made available in the "Windows" section +on the Python +download page.

+

Unpacking

-- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 08:19:22 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 14 Mar 2012 08:19:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314289?= =?utf8?q?=3A_put_a_link_to_the_CHM_download_page_on_the_docs_download_pag?= =?utf8?q?e=2E?= Message-ID: http://hg.python.org/cpython/rev/3e62379008c2 changeset: 75627:3e62379008c2 branch: 2.7 parent: 75603:af1f8adc913b user: Georg Brandl date: Wed Mar 14 08:18:47 2012 +0100 summary: Closes #14289: put a link to the CHM download page on the docs download page. files: Doc/tools/sphinxext/download.html | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Doc/tools/sphinxext/download.html b/Doc/tools/sphinxext/download.html --- a/Doc/tools/sphinxext/download.html +++ b/Doc/tools/sphinxext/download.html @@ -35,8 +35,12 @@ +

These archives contain all the content in the documentation.

-

These archives contain all the content in the documentation.

+

HTML Help (.chm) files are made available in the "Windows" section +on the Python +download page.

+

Unpacking

-- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 13:55:32 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 14 Mar 2012 13:55:32 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_416=3A_add_a_section_about?= =?utf8?q?_dictproxy=2C_add_more_links_to_Python_recipes?= Message-ID: http://hg.python.org/peps/rev/622068a60e50 changeset: 4135:622068a60e50 user: Victor Stinner date: Wed Mar 14 13:55:31 2012 +0100 summary: PEP 416: add a section about dictproxy, add more links to Python recipes files: pep-0416.txt | 32 ++++++++++++++++++++++++++++++-- 1 files changed, 30 insertions(+), 2 deletions(-) diff --git a/pep-0416.txt b/pep-0416.txt --- a/pep-0416.txt +++ b/pep-0416.txt @@ -108,15 +108,43 @@ object is not the purpose of this PEP. +Alternative: dictproxy +====================== + +Python has a builtin dictproxy type used by type.__dict__ getter descriptor. +This type is not public. dictproxy is a read-only view of a dictionary, but it +is not read-only mapping. If a dictionary is modified, the dictproxy is also +modified. + +dictproxy can be used using ctypes and the Python C API, see for example the +`make dictproxy object via ctypes.pythonapi and type() (Python recipe 576540)`_ +by Ikkei Shimomura. The recipe contains a test checking that a dictproxy is +"mutable" (modify the dictionary linked to the dictproxy). + +However dictproxy can be useful in some cases, where its mutable property is +not an issue, to avoid a copy of the dictionary. + + Links ===== + * `Issue #14162: PEP 416: Add a builtin frozendict type + `_ * PEP 412: Key-Sharing Dictionary (`issue #13903 `_) * PEP 351: The freeze protocol * `The case for immutable dictionaries; and the central misunderstanding of PEP 351 `_ - * `Frozen dictionaries (Python recipe 414283) `_ - by Oren Tirosh + * `Frozen dictionaries (Python recipe 414283) `_ + by Oren Tirosh. Blacklist approach: inherit from dict and override write + methods to raise an exception. It is not truly read-only: it is still + possible to call dict methods on such "frozen dictionary" to modify it. + * `Implementing an Immutable Dictionary (Python recipe 498072) `_ + by Aristotelis Mikropoulos. Similar to frozendict except that it is not + truly read-only. It is possible to access to this private internal dict. + It does not implement __hash__ and has an implementation issue: it is + possible to call again __init__() to modify the mapping. + * `make dictproxy object via ctypes.pythonapi and type() (Python recipe + 576540) `_ by Ikkei Shimomura. * Python security modules implementing read-only object proxies using a C extension: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Mar 14 14:05:13 2012 From: python-checkins at python.org (eric.araujo) Date: Wed, 14 Mar 2012 14:05:13 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Update_list_of_Trove_cla?= =?utf8?q?ssifiers_=28these_reproduce_fast=29?= Message-ID: http://hg.python.org/distutils2/rev/2a2297e25a32 changeset: 1309:2a2297e25a32 user: ?ric Araujo date: Wed Mar 14 13:58:48 2012 +0100 summary: Update list of Trove classifiers (these reproduce fast) files: distutils2/_trove.py | 11 ++++++++++- distutils2/command/register.py | 1 + 2 files changed, 11 insertions(+), 1 deletions(-) diff --git a/distutils2/_trove.py b/distutils2/_trove.py --- a/distutils2/_trove.py +++ b/distutils2/_trove.py @@ -114,6 +114,7 @@ 'License :: OSI Approved :: Motosoto License', 'License :: OSI Approved :: Mozilla Public License 1.0 (MPL)', 'License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)', +'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)', 'License :: OSI Approved :: Nethack General Public License', 'License :: OSI Approved :: Nokia Open Source License', 'License :: OSI Approved :: Open Group Test Suite License', @@ -149,6 +150,7 @@ 'Natural Language :: Esperanto', 'Natural Language :: Finnish', 'Natural Language :: French', +'Natural Language :: Galician', 'Natural Language :: German', 'Natural Language :: Greek', 'Natural Language :: Hebrew', @@ -193,9 +195,14 @@ 'Operating System :: Microsoft :: MS-DOS', 'Operating System :: Microsoft :: Windows', 'Operating System :: Microsoft :: Windows :: Windows 3.1 or Earlier', +'Operating System :: Microsoft :: Windows :: Windows 7', 'Operating System :: Microsoft :: Windows :: Windows 95/98/2000', 'Operating System :: Microsoft :: Windows :: Windows CE', 'Operating System :: Microsoft :: Windows :: Windows NT/2000', +'Operating System :: Microsoft :: Windows :: Windows Server 2003', +'Operating System :: Microsoft :: Windows :: Windows Server 2008', +'Operating System :: Microsoft :: Windows :: Windows Vista', +'Operating System :: Microsoft :: Windows :: Windows XP', 'Operating System :: OS/2', 'Operating System :: OS Independent', 'Operating System :: Other OS', @@ -263,10 +270,12 @@ 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', +'Programming Language :: Python :: 2 :: Only', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', +'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: Implementation', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: IronPython', @@ -449,8 +458,8 @@ 'Topic :: Printing', 'Topic :: Religion', 'Topic :: Scientific/Engineering', +'Topic :: Scientific/Engineering :: Artificial Intelligence', 'Topic :: Scientific/Engineering :: Artificial Life', -'Topic :: Scientific/Engineering :: Artificial Intelligence', 'Topic :: Scientific/Engineering :: Astronomy', 'Topic :: Scientific/Engineering :: Atmospheric Science', 'Topic :: Scientific/Engineering :: Bio-Informatics', diff --git a/distutils2/command/register.py b/distutils2/command/register.py --- a/distutils2/command/register.py +++ b/distutils2/command/register.py @@ -80,6 +80,7 @@ def classifiers(self): ''' Fetch the list of classifiers from the server. ''' + # TODO use _trove module response = urllib2.urlopen(self.repository+'?:action=list_classifiers') logger.info(response.read()) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Wed Mar 14 14:05:13 2012 From: python-checkins at python.org (eric.araujo) Date: Wed, 14 Mar 2012 14:05:13 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Fix_winreg_imports=3B_we?= =?utf8?q?_are_not_using_a_single_codebase?= Message-ID: http://hg.python.org/distutils2/rev/2cec52b682a9 changeset: 1310:2cec52b682a9 user: ?ric Araujo date: Wed Mar 14 14:04:48 2012 +0100 summary: Fix winreg imports; we are not using a single codebase files: distutils2/compiler/msvc9compiler.py | 6 +----- distutils2/compiler/msvccompiler.py | 2 +- distutils2/tests/test_msvc9compiler.py | 5 +---- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/distutils2/compiler/msvc9compiler.py b/distutils2/compiler/msvc9compiler.py --- a/distutils2/compiler/msvc9compiler.py +++ b/distutils2/compiler/msvc9compiler.py @@ -20,11 +20,7 @@ from distutils2 import logger from distutils2.util import get_platform -try: - import winreg -except ImportError: - # Python 2 compatibility - import _winreg as winreg +import _winreg as winreg RegOpenKeyEx = winreg.OpenKeyEx RegEnumKey = winreg.EnumKey diff --git a/distutils2/compiler/msvccompiler.py b/distutils2/compiler/msvccompiler.py --- a/distutils2/compiler/msvccompiler.py +++ b/distutils2/compiler/msvccompiler.py @@ -19,7 +19,7 @@ _can_read_reg = False try: - import winreg + import _winreg as winreg _can_read_reg = True hkey_mod = winreg diff --git a/distutils2/tests/test_msvc9compiler.py b/distutils2/tests/test_msvc9compiler.py --- a/distutils2/tests/test_msvc9compiler.py +++ b/distutils2/tests/test_msvc9compiler.py @@ -101,10 +101,7 @@ v = Reg.get_value(path, 'dragfullwindows') self.assertIn(v, ('0', '1', '2')) - try: - import winreg - except ImportError: - import _winreg as winreg + import _winreg as winreg HKCU = winreg.HKEY_CURRENT_USER keys = Reg.read_keys(HKCU, 'xxxx') self.assertEqual(keys, None) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Wed Mar 14 17:40:17 2012 From: python-checkins at python.org (andrew.svetlov) Date: Wed, 14 Mar 2012 17:40:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Revert_the_patch_for_issue_?= =?utf8?q?3835_because_failed_on_Windows_buildbot?= Message-ID: http://hg.python.org/cpython/rev/7cbc48324938 changeset: 75628:7cbc48324938 parent: 75626:b4d1e51d91f8 user: Andrew Svetlov date: Wed Mar 14 09:39:36 2012 -0700 summary: Revert the patch for issue 3835 because failed on Windows buildbot Windows build is compiled with no-threaded tcl/tk by default files: Modules/_tkinter.c | 7 ------- 1 files changed, 0 insertions(+), 7 deletions(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -613,13 +613,6 @@ } #endif #ifdef WITH_THREAD - if (!(v->threaded)) { - PyErr_SetString(PyExc_RuntimeError, - "Tcl/Tk was not compiled with --enable-threads but " - "Python has threads enabled"); - Py_DECREF(v); - return 0; - } if (v->threaded && tcl_lock) { /* If Tcl is threaded, we don't need the lock. */ PyThread_free_lock(tcl_lock); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 17:51:37 2012 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 14 Mar 2012 17:51:37 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2313839=3A_When_invo?= =?utf8?q?ked_on_the_command-line=2C_the_pstats_module_now_accepts?= Message-ID: http://hg.python.org/cpython/rev/3a5a0e7d38c5 changeset: 75629:3a5a0e7d38c5 user: Antoine Pitrou date: Wed Mar 14 17:47:11 2012 +0100 summary: Issue #13839: When invoked on the command-line, the pstats module now accepts several filenames of profile stat files and merges them all. Patch by Matt Joiner. files: Lib/pstats.py | 2 ++ Misc/NEWS | 4 ++++ 2 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/pstats.py b/Lib/pstats.py --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -680,6 +680,8 @@ initprofile = None try: browser = ProfileBrowser(initprofile) + for profile in sys.argv[2:]: + browser.do_add(profile) print("Welcome to the profile statistics browser.", file=browser.stream) browser.cmdloop() print("Goodbye.", file=browser.stream) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,10 @@ Library ------- +- Issue #13839: When invoked on the command-line, the pstats module now + accepts several filenames of profile stat files and merges them all. + Patch by Matt Joiner. + - Issue #14291: Email now defaults to utf-8 for non-ASCII unicode headers instead of raising an error. This fixes a regression relative to 2.7. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 19:24:45 2012 From: python-checkins at python.org (r.david.murray) Date: Wed, 14 Mar 2012 19:24:45 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzE0MDYyOiBmaXgg?= =?utf8?q?BytesParser_handling_of_linesep_for_Header_objects?= Message-ID: http://hg.python.org/cpython/rev/d0bf40ff20ef changeset: 75630:d0bf40ff20ef branch: 3.2 parent: 75625:2800530b00d3 user: R David Murray date: Wed Mar 14 14:05:03 2012 -0400 summary: #14062: fix BytesParser handling of linesep for Header objects This also affected smtplib.SMTP.send_message, which calls BytesParser. files: Lib/email/generator.py | 2 +- Lib/email/test/test_email.py | 25 +++++++++++++++++++++++- Misc/NEWS | 3 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -360,7 +360,7 @@ for h, v in msg._headers: self.write('%s: ' % h) if isinstance(v, Header): - self.write(v.encode(maxlinelen=self._maxheaderlen)+NL) + self.write(v.encode(maxlinelen=self._maxheaderlen)+self._NL) elif _has_surrogates(v): # If we have raw 8bit data in a byte string, we have no idea # what the encoding is. There is no safe way to split this diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -1243,7 +1243,6 @@ =?utf-8?q?_folding_white_space_works?=""")+'\n') - # Test mangling of "From " lines in the body of a message class TestFromMangling(unittest.TestCase): def setUp(self): @@ -3441,6 +3440,30 @@ g.flatten(msg) self.assertEqual(s.getvalue(), source) + def test_bytes_generator_b_encoding_linesep(self): + # Issue 14062: b encoding was tacking on an extra \n. + m = Message() + # This has enough non-ascii that it should always end up b encoded. + m['Subject'] = Header('?lu?ou?k? k??') + s = BytesIO() + g = email.generator.BytesGenerator(s) + g.flatten(m, linesep='\r\n') + self.assertEqual( + s.getvalue(), + b'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n') + + def test_generator_b_encoding_linesep(self): + # Since this broke in ByteGenerator, test Generator for completeness. + m = Message() + # This has enough non-ascii that it should always end up b encoded. + m['Subject'] = Header('?lu?ou?k? k??') + s = StringIO() + g = email.generator.Generator(s) + g.flatten(m, linesep='\r\n') + self.assertEqual( + s.getvalue(), + 'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n') + maxDiff = None diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,9 @@ Library ------- +- Issue #14062: Header objects now correctly respect the 'linesep' setting + when processed by BytesParser (which smtplib.SMTP.send_message uses). + - Issue #14291: Email now defaults to utf-8 for non-ASCII unicode headers instead of raising an error. This fixes a regression relative to 2.7. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 19:24:46 2012 From: python-checkins at python.org (r.david.murray) Date: Wed, 14 Mar 2012 19:24:46 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_=2314062=3A_fix_BytesParser_handling_of_Header_objects?= Message-ID: http://hg.python.org/cpython/rev/7617f3071320 changeset: 75631:7617f3071320 parent: 75629:3a5a0e7d38c5 parent: 75630:d0bf40ff20ef user: R David Murray date: Wed Mar 14 14:24:22 2012 -0400 summary: #14062: fix BytesParser handling of Header objects This is a different fix than the 3.2 fix, but the new tests are the same. This also affected smtplib.SMTP.send_message, which calls BytesParser. files: Lib/email/generator.py | 3 ++ Lib/test/test_email/test_email.py | 24 +++++++++++++++++++ Misc/NEWS | 3 ++ 3 files changed, 30 insertions(+), 0 deletions(-) diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -386,6 +386,9 @@ h = Header(v, charset=_charset.UNKNOWN8BIT, header_name=h) else: h = Header(v, header_name=h) + else: + # Assume it is a Header-like object. + h = v self.write(h.encode(linesep=self._NL, maxlinelen=self._maxheaderlen)+self._NL) # A blank line always separates headers from body diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -3601,6 +3601,30 @@ g.flatten(msg) self.assertEqual(s.getvalue(), source) + def test_bytes_generator_b_encoding_linesep(self): + # Issue 14062: b encoding was tacking on an extra \n. + m = Message() + # This has enough non-ascii that it should always end up b encoded. + m['Subject'] = Header('?lu?ou?k? k??') + s = BytesIO() + g = email.generator.BytesGenerator(s) + g.flatten(m, linesep='\r\n') + self.assertEqual( + s.getvalue(), + b'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n') + + def test_generator_b_encoding_linesep(self): + # Since this broke in ByteGenerator, test Generator for completeness. + m = Message() + # This has enough non-ascii that it should always end up b encoded. + m['Subject'] = Header('?lu?ou?k? k??') + s = StringIO() + g = email.generator.Generator(s) + g.flatten(m, linesep='\r\n') + self.assertEqual( + s.getvalue(), + 'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n') + def test_crlf_control_via_policy(self): # msg_26 is crlf terminated with openfile('msg_26.txt', 'rb') as fp: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #14062: BytesGenerator now correctly folds Header objects, + including using linesep when folding. + - Issue #13839: When invoked on the command-line, the pstats module now accepts several filenames of profile stat files and merges them all. Patch by Matt Joiner. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 20:00:38 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 14 Mar 2012 20:00:38 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Update_with_news_from_language?= =?utf8?q?_summit_summary=2E?= Message-ID: http://hg.python.org/peps/rev/de4051307505 changeset: 4136:de4051307505 user: Georg Brandl date: Wed Mar 14 20:00:37 2012 +0100 summary: Update with news from language summit summary. files: pep-0398.txt | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -76,9 +76,10 @@ Candidate PEPs: * PEP 362: Function Signature Object -* PEP 382: Namespace Packages * PEP 395: Module Aliasing * PEP 397: Python launcher for Windows +* PEP 402: Simplified Package Layout (likely a new PEP derived from it) +* PEP 405: Python Virtual Environments * PEP 412: Key-Sharing Dictionary * PEP 3143: Standard daemon process library * PEP 3144: IP Address manipulation library @@ -88,6 +89,8 @@ Other planned large-scale changes: +* Addition of the "mock" library +* Addition of the C decimal implementation * Addition of the "regex" module * Email version 6 * Implementing ``__import__`` using importlib -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Mar 14 20:25:08 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 14 Mar 2012 20:25:08 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_PEP_417=3A_Adding_unittest?= =?utf8?q?=2Emock?= Message-ID: http://hg.python.org/cpython/rev/2fda048ee32a changeset: 75632:2fda048ee32a user: Michael Foord date: Wed Mar 14 12:24:34 2012 -0700 summary: PEP 417: Adding unittest.mock files: Lib/unittest/mock.py | 2151 ++++++++++ Lib/unittest/test/__init__.py | 1 + Lib/unittest/test/testmock/__init__.py | 17 + Lib/unittest/test/testmock/support.py | 23 + Lib/unittest/test/testmock/testcallable.py | 159 + Lib/unittest/test/testmock/testhelpers.py | 835 +++ Lib/unittest/test/testmock/testmagicmethods.py | 382 + Lib/unittest/test/testmock/testmock.py | 1258 +++++ Lib/unittest/test/testmock/testpatch.py | 1652 +++++++ Lib/unittest/test/testmock/testsentinel.py | 28 + Lib/unittest/test/testmock/testwith.py | 176 + 11 files changed, 6682 insertions(+), 0 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/mock.py @@ -0,0 +1,2151 @@ +# mock.py +# Test tools for mocking and patching. + +__all__ = ( + 'Mock', + 'MagicMock', + 'patch', + 'sentinel', + 'DEFAULT', + 'ANY', + 'call', + 'create_autospec', + 'FILTER_DIR', + 'NonCallableMock', + 'NonCallableMagicMock', + 'mock_open', + 'PropertyMock', +) + + +__version__ = '1.0' + + +import inspect +import pprint +import sys +from functools import wraps + + +BaseExceptions = (BaseException,) +if 'java' in sys.platform: + # jython + import java + BaseExceptions = (BaseException, java.lang.Throwable) + + +FILTER_DIR = True + + +def _is_instance_mock(obj): + # can't use isinstance on Mock objects because they override __class__ + # The base class for all mocks is NonCallableMock + return issubclass(type(obj), NonCallableMock) + + +def _is_exception(obj): + return ( + isinstance(obj, BaseExceptions) or + isinstance(obj, type) and issubclass(obj, BaseExceptions) + ) + + +class _slotted(object): + __slots__ = ['a'] + + +DescriptorTypes = ( + type(_slotted.a), + property, +) + + +def _getsignature(func, skipfirst, instance=False): + if isinstance(func, type) and not instance: + try: + func = func.__init__ + except AttributeError: + return + skipfirst = True + elif not isinstance(func, FunctionTypes): + # for classes where instance is True we end up here too + try: + func = func.__call__ + except AttributeError: + return + + try: + regargs, varargs, varkwargs, defaults = inspect.getargspec(func) + except TypeError: + # C function / method, possibly inherited object().__init__ + return + + # instance methods and classmethods need to lose the self argument + if getattr(func, '__self__', None) is not None: + regargs = regargs[1:] + if skipfirst: + # this condition and the above one are never both True - why? + regargs = regargs[1:] + + signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults, + formatvalue=lambda value: "") + return signature[1:-1], func + + +def _check_signature(func, mock, skipfirst, instance=False): + if not _callable(func): + return + + result = _getsignature(func, skipfirst, instance) + if result is None: + return + signature, func = result + + # can't use self because "self" is common as an argument name + # unfortunately even not in the first place + src = "lambda _mock_self, %s: None" % signature + checksig = eval(src, {}) + _copy_func_details(func, checksig) + type(mock)._mock_check_sig = checksig + + +def _copy_func_details(func, funcopy): + funcopy.__name__ = func.__name__ + funcopy.__doc__ = func.__doc__ + # we explicitly don't copy func.__dict__ into this copy as it would + # expose original attributes that should be mocked + funcopy.__module__ = func.__module__ + funcopy.__defaults__ = func.__defaults__ + funcopy.__kwdefaults__ = func.__kwdefaults__ + + +def _callable(obj): + if isinstance(obj, type): + return True + if getattr(obj, '__call__', None) is not None: + return True + return False + + +def _is_list(obj): + # checks for list or tuples + # XXXX badly named! + return type(obj) in (list, tuple) + + +def _instance_callable(obj): + """Given an object, return True if the object is callable. + For classes, return True if instances would be callable.""" + if not isinstance(obj, type): + # already an instance + return getattr(obj, '__call__', None) is not None + + klass = obj + # uses __bases__ instead of __mro__ so that we work with old style classes + if klass.__dict__.get('__call__') is not None: + return True + + for base in klass.__bases__: + if _instance_callable(base): + return True + return False + + +def _set_signature(mock, original, instance=False): + # creates a function with signature (*args, **kwargs) that delegates to a + # mock. It still does signature checking by calling a lambda with the same + # signature as the original. + if not _callable(original): + return + + skipfirst = isinstance(original, type) + result = _getsignature(original, skipfirst, instance) + if result is None: + # was a C function (e.g. object().__init__ ) that can't be mocked + return + + signature, func = result + + src = "lambda %s: None" % signature + context = {'_mock_': mock} + checksig = eval(src, context) + _copy_func_details(func, checksig) + + name = original.__name__ + if not name.isidentifier(): + name = 'funcopy' + context = {'checksig': checksig, 'mock': mock} + src = """def %s(*args, **kwargs): + checksig(*args, **kwargs) + return mock(*args, **kwargs)""" % name + exec (src, context) + funcopy = context[name] + _setup_func(funcopy, mock) + return funcopy + + +def _setup_func(funcopy, mock): + funcopy.mock = mock + + # can't use isinstance with mocks + if not _is_instance_mock(mock): + return + + def assert_called_with(*args, **kwargs): + return mock.assert_called_with(*args, **kwargs) + def assert_called_once_with(*args, **kwargs): + return mock.assert_called_once_with(*args, **kwargs) + def assert_has_calls(*args, **kwargs): + return mock.assert_has_calls(*args, **kwargs) + def assert_any_call(*args, **kwargs): + return mock.assert_any_call(*args, **kwargs) + def reset_mock(): + funcopy.method_calls = _CallList() + funcopy.mock_calls = _CallList() + mock.reset_mock() + ret = funcopy.return_value + if _is_instance_mock(ret) and not ret is mock: + ret.reset_mock() + + funcopy.called = False + funcopy.call_count = 0 + funcopy.call_args = None + funcopy.call_args_list = _CallList() + funcopy.method_calls = _CallList() + funcopy.mock_calls = _CallList() + + funcopy.return_value = mock.return_value + funcopy.side_effect = mock.side_effect + funcopy._mock_children = mock._mock_children + + funcopy.assert_called_with = assert_called_with + funcopy.assert_called_once_with = assert_called_once_with + funcopy.assert_has_calls = assert_has_calls + funcopy.assert_any_call = assert_any_call + funcopy.reset_mock = reset_mock + + mock._mock_delegate = funcopy + + +def _is_magic(name): + return '__%s__' % name[2:-2] == name + + +class _SentinelObject(object): + "A unique, named, sentinel object." + def __init__(self, name): + self.name = name + + def __repr__(self): + return 'sentinel.%s' % self.name + + +class _Sentinel(object): + """Access attributes to return a named object, usable as a sentinel.""" + def __init__(self): + self._sentinels = {} + + def __getattr__(self, name): + if name == '__bases__': + # Without this help(unittest.mock) raises an exception + raise AttributeError + return self._sentinels.setdefault(name, _SentinelObject(name)) + + +sentinel = _Sentinel() + +DEFAULT = sentinel.DEFAULT +_missing = sentinel.MISSING +_deleted = sentinel.DELETED + + +class OldStyleClass: + pass +ClassType = type(OldStyleClass) + + +def _copy(value): + if type(value) in (dict, list, tuple, set): + return type(value)(value) + return value + + +_allowed_names = set( + [ + 'return_value', '_mock_return_value', 'side_effect', + '_mock_side_effect', '_mock_parent', '_mock_new_parent', + '_mock_name', '_mock_new_name' + ] +) + + +def _delegating_property(name): + _allowed_names.add(name) + _the_name = '_mock_' + name + def _get(self, name=name, _the_name=_the_name): + sig = self._mock_delegate + if sig is None: + return getattr(self, _the_name) + return getattr(sig, name) + def _set(self, value, name=name, _the_name=_the_name): + sig = self._mock_delegate + if sig is None: + self.__dict__[_the_name] = value + else: + setattr(sig, name, value) + + return property(_get, _set) + + + +class _CallList(list): + + def __contains__(self, value): + if not isinstance(value, list): + return list.__contains__(self, value) + len_value = len(value) + len_self = len(self) + if len_value > len_self: + return False + + for i in range(0, len_self - len_value + 1): + sub_list = self[i:i+len_value] + if sub_list == value: + return True + return False + + def __repr__(self): + return pprint.pformat(list(self)) + + +def _check_and_set_parent(parent, value, name, new_name): + if not _is_instance_mock(value): + return False + if ((value._mock_name or value._mock_new_name) or + (value._mock_parent is not None) or + (value._mock_new_parent is not None)): + return False + + _parent = parent + while _parent is not None: + # setting a mock (value) as a child or return value of itself + # should not modify the mock + if _parent is value: + return False + _parent = _parent._mock_new_parent + + if new_name: + value._mock_new_parent = parent + value._mock_new_name = new_name + if name: + value._mock_parent = parent + value._mock_name = name + return True + + + +class Base(object): + _mock_return_value = DEFAULT + _mock_side_effect = None + def __init__(self, *args, **kwargs): + pass + + + +class NonCallableMock(Base): + """A non-callable version of `Mock`""" + + def __new__(cls, *args, **kw): + # every instance has its own class + # so we can create magic methods on the + # class without stomping on other mocks + new = type(cls.__name__, (cls,), {'__doc__': cls.__doc__}) + instance = object.__new__(new) + return instance + + + def __init__( + self, spec=None, wraps=None, name=None, spec_set=None, + parent=None, _spec_state=None, _new_name='', _new_parent=None, + **kwargs + ): + if _new_parent is None: + _new_parent = parent + + __dict__ = self.__dict__ + __dict__['_mock_parent'] = parent + __dict__['_mock_name'] = name + __dict__['_mock_new_name'] = _new_name + __dict__['_mock_new_parent'] = _new_parent + + if spec_set is not None: + spec = spec_set + spec_set = True + + self._mock_add_spec(spec, spec_set) + + __dict__['_mock_children'] = {} + __dict__['_mock_wraps'] = wraps + __dict__['_mock_delegate'] = None + + __dict__['_mock_called'] = False + __dict__['_mock_call_args'] = None + __dict__['_mock_call_count'] = 0 + __dict__['_mock_call_args_list'] = _CallList() + __dict__['_mock_mock_calls'] = _CallList() + + __dict__['method_calls'] = _CallList() + + if kwargs: + self.configure_mock(**kwargs) + + super(NonCallableMock, self).__init__( + spec, wraps, name, spec_set, parent, + _spec_state + ) + + + def attach_mock(self, mock, attribute): + """ + Attach a mock as an attribute of this one, replacing its name and + parent. Calls to the attached mock will be recorded in the + `method_calls` and `mock_calls` attributes of this one.""" + mock._mock_parent = None + mock._mock_new_parent = None + mock._mock_name = '' + mock._mock_new_name = None + + setattr(self, attribute, mock) + + + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + + + def _mock_add_spec(self, spec, spec_set): + _spec_class = None + + if spec is not None and not _is_list(spec): + if isinstance(spec, type): + _spec_class = spec + else: + _spec_class = _get_class(spec) + + spec = dir(spec) + + __dict__ = self.__dict__ + __dict__['_spec_class'] = _spec_class + __dict__['_spec_set'] = spec_set + __dict__['_mock_methods'] = spec + + + def __get_return_value(self): + ret = self._mock_return_value + if self._mock_delegate is not None: + ret = self._mock_delegate.return_value + + if ret is DEFAULT: + ret = self._get_child_mock( + _new_parent=self, _new_name='()' + ) + self.return_value = ret + return ret + + + def __set_return_value(self, value): + if self._mock_delegate is not None: + self._mock_delegate.return_value = value + else: + self._mock_return_value = value + _check_and_set_parent(self, value, None, '()') + + __return_value_doc = "The value to be returned when the mock is called." + return_value = property(__get_return_value, __set_return_value, + __return_value_doc) + + + @property + def __class__(self): + if self._spec_class is None: + return type(self) + return self._spec_class + + called = _delegating_property('called') + call_count = _delegating_property('call_count') + call_args = _delegating_property('call_args') + call_args_list = _delegating_property('call_args_list') + mock_calls = _delegating_property('mock_calls') + + + def __get_side_effect(self): + delegated = self._mock_delegate + if delegated is None: + return self._mock_side_effect + return delegated.side_effect + + def __set_side_effect(self, value): + value = _try_iter(value) + delegated = self._mock_delegate + if delegated is None: + self._mock_side_effect = value + else: + delegated.side_effect = value + + side_effect = property(__get_side_effect, __set_side_effect) + + + def reset_mock(self): + "Restore the mock object to its initial state." + self.called = False + self.call_args = None + self.call_count = 0 + self.mock_calls = _CallList() + self.call_args_list = _CallList() + self.method_calls = _CallList() + + for child in self._mock_children.values(): + child.reset_mock() + + ret = self._mock_return_value + if _is_instance_mock(ret) and ret is not self: + ret.reset_mock() + + + def configure_mock(self, **kwargs): + """Set attributes on the mock through keyword arguments. + + Attributes plus return values and side effects can be set on child + mocks using standard dot notation and unpacking a dictionary in the + method call: + + >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> mock.configure_mock(**attrs)""" + for arg, val in sorted(kwargs.items(), + # we sort on the number of dots so that + # attributes are set before we set attributes on + # attributes + key=lambda entry: entry[0].count('.')): + args = arg.split('.') + final = args.pop() + obj = self + for entry in args: + obj = getattr(obj, entry) + setattr(obj, final, val) + + + def __getattr__(self, name): + if name == '_mock_methods': + raise AttributeError(name) + elif self._mock_methods is not None: + if name not in self._mock_methods or name in _all_magics: + raise AttributeError("Mock object has no attribute %r" % name) + elif _is_magic(name): + raise AttributeError(name) + + result = self._mock_children.get(name) + if result is _deleted: + raise AttributeError(name) + elif result is None: + wraps = None + if self._mock_wraps is not None: + # XXXX should we get the attribute without triggering code + # execution? + wraps = getattr(self._mock_wraps, name) + + result = self._get_child_mock( + parent=self, name=name, wraps=wraps, _new_name=name, + _new_parent=self + ) + self._mock_children[name] = result + + elif isinstance(result, _SpecState): + result = create_autospec( + result.spec, result.spec_set, result.instance, + result.parent, result.name + ) + self._mock_children[name] = result + + return result + + + def __repr__(self): + _name_list = [self._mock_new_name] + _parent = self._mock_new_parent + last = self + + dot = '.' + if _name_list == ['()']: + dot = '' + seen = set() + while _parent is not None: + last = _parent + + _name_list.append(_parent._mock_new_name + dot) + dot = '.' + if _parent._mock_new_name == '()': + dot = '' + + _parent = _parent._mock_new_parent + + # use ids here so as not to call __hash__ on the mocks + if id(_parent) in seen: + break + seen.add(id(_parent)) + + _name_list = list(reversed(_name_list)) + _first = last._mock_name or 'mock' + if len(_name_list) > 1: + if _name_list[1] not in ('()', '().'): + _first += '.' + _name_list[0] = _first + name = ''.join(_name_list) + + name_string = '' + if name not in ('mock', 'mock.'): + name_string = ' name=%r' % name + + spec_string = '' + if self._spec_class is not None: + spec_string = ' spec=%r' + if self._spec_set: + spec_string = ' spec_set=%r' + spec_string = spec_string % self._spec_class.__name__ + return "<%s%s%s id='%s'>" % ( + type(self).__name__, + name_string, + spec_string, + id(self) + ) + + + def __dir__(self): + """Filter the output of `dir(mock)` to only useful members. + XXXX + """ + extras = self._mock_methods or [] + from_type = dir(type(self)) + from_dict = list(self.__dict__) + + if FILTER_DIR: + from_type = [e for e in from_type if not e.startswith('_')] + from_dict = [e for e in from_dict if not e.startswith('_') or + _is_magic(e)] + return sorted(set(extras + from_type + from_dict + + list(self._mock_children))) + + + def __setattr__(self, name, value): + if name in _allowed_names: + # property setters go through here + return object.__setattr__(self, name, value) + elif (self._spec_set and self._mock_methods is not None and + name not in self._mock_methods and + name not in self.__dict__): + raise AttributeError("Mock object has no attribute '%s'" % name) + elif name in _unsupported_magics: + msg = 'Attempting to set unsupported magic method %r.' % name + raise AttributeError(msg) + elif name in _all_magics: + if self._mock_methods is not None and name not in self._mock_methods: + raise AttributeError("Mock object has no attribute '%s'" % name) + + if not _is_instance_mock(value): + setattr(type(self), name, _get_method(name, value)) + original = value + value = lambda *args, **kw: original(self, *args, **kw) + else: + # only set _new_name and not name so that mock_calls is tracked + # but not method calls + _check_and_set_parent(self, value, None, name) + setattr(type(self), name, value) + elif name == '__class__': + self._spec_class = value + return + else: + if _check_and_set_parent(self, value, name, name): + self._mock_children[name] = value + return object.__setattr__(self, name, value) + + + def __delattr__(self, name): + if name in _all_magics and name in type(self).__dict__: + delattr(type(self), name) + if name not in self.__dict__: + # for magic methods that are still MagicProxy objects and + # not set on the instance itself + return + + if name in self.__dict__: + object.__delattr__(self, name) + + obj = self._mock_children.get(name, _missing) + if obj is _deleted: + raise AttributeError(name) + if obj is not _missing: + del self._mock_children[name] + self._mock_children[name] = _deleted + + + + def _format_mock_call_signature(self, args, kwargs): + name = self._mock_name or 'mock' + return _format_call_signature(name, args, kwargs) + + + def _format_mock_failure_message(self, args, kwargs): + message = 'Expected call: %s\nActual call: %s' + expected_string = self._format_mock_call_signature(args, kwargs) + call_args = self.call_args + if len(call_args) == 3: + call_args = call_args[1:] + actual_string = self._format_mock_call_signature(*call_args) + return message % (expected_string, actual_string) + + + def assert_called_with(_mock_self, *args, **kwargs): + """assert that the mock was called with the specified arguments. + + Raises an AssertionError if the args and keyword args passed in are + different to the last call to the mock.""" + self = _mock_self + if self.call_args is None: + expected = self._format_mock_call_signature(args, kwargs) + raise AssertionError('Expected call: %s\nNot called' % (expected,)) + + if self.call_args != (args, kwargs): + msg = self._format_mock_failure_message(args, kwargs) + raise AssertionError(msg) + + + def assert_called_once_with(_mock_self, *args, **kwargs): + """assert that the mock was called exactly once and with the specified + arguments.""" + self = _mock_self + if not self.call_count == 1: + msg = ("Expected to be called once. Called %s times." % + self.call_count) + raise AssertionError(msg) + return self.assert_called_with(*args, **kwargs) + + + def assert_has_calls(self, calls, any_order=False): + """assert the mock has been called with the specified calls. + The `mock_calls` list is checked for the calls. + + If `any_order` is False (the default) then the calls must be + sequential. There can be extra calls before or after the + specified calls. + + If `any_order` is True then the calls can be in any order, but + they must all appear in `mock_calls`.""" + if not any_order: + if calls not in self.mock_calls: + raise AssertionError( + 'Calls not found.\nExpected: %r\n' + 'Actual: %r' % (calls, self.mock_calls) + ) + return + + all_calls = list(self.mock_calls) + + not_found = [] + for kall in calls: + try: + all_calls.remove(kall) + except ValueError: + not_found.append(kall) + if not_found: + raise AssertionError( + '%r not all found in call list' % (tuple(not_found),) + ) + + + def assert_any_call(self, *args, **kwargs): + """assert the mock has been called with the specified arguments. + + The assert passes if the mock has *ever* been called, unlike + `assert_called_with` and `assert_called_once_with` that only pass if + the call is the most recent one.""" + kall = call(*args, **kwargs) + if kall not in self.call_args_list: + expected_string = self._format_mock_call_signature(args, kwargs) + raise AssertionError( + '%s call not found' % expected_string + ) + + + def _get_child_mock(self, **kw): + """Create the child mocks for attributes and return value. + By default child mocks will be the same type as the parent. + Subclasses of Mock may want to override this to customize the way + child mocks are made. + + For non-callable mocks the callable variant will be used (rather than + any custom subclass).""" + _type = type(self) + if not issubclass(_type, CallableMixin): + if issubclass(_type, NonCallableMagicMock): + klass = MagicMock + elif issubclass(_type, NonCallableMock) : + klass = Mock + else: + klass = _type.__mro__[1] + return klass(**kw) + + + +def _try_iter(obj): + if obj is None: + return obj + if _is_exception(obj): + return obj + if _callable(obj): + return obj + try: + return iter(obj) + except TypeError: + # XXXX backwards compatibility + # but this will blow up on first call - so maybe we should fail early? + return obj + + + +class CallableMixin(Base): + + def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, + wraps=None, name=None, spec_set=None, parent=None, + _spec_state=None, _new_name='', _new_parent=None, **kwargs): + self.__dict__['_mock_return_value'] = return_value + + super(CallableMixin, self).__init__( + spec, wraps, name, spec_set, parent, + _spec_state, _new_name, _new_parent, **kwargs + ) + + self.side_effect = side_effect + + + def _mock_check_sig(self, *args, **kwargs): + # stub method that can be replaced with one with a specific signature + pass + + + def __call__(_mock_self, *args, **kwargs): + # can't use self in-case a function / method we are mocking uses self + # in the signature + _mock_self._mock_check_sig(*args, **kwargs) + return _mock_self._mock_call(*args, **kwargs) + + + def _mock_call(_mock_self, *args, **kwargs): + self = _mock_self + self.called = True + self.call_count += 1 + self.call_args = _Call((args, kwargs), two=True) + self.call_args_list.append(_Call((args, kwargs), two=True)) + + _new_name = self._mock_new_name + _new_parent = self._mock_new_parent + self.mock_calls.append(_Call(('', args, kwargs))) + + seen = set() + skip_next_dot = _new_name == '()' + do_method_calls = self._mock_parent is not None + name = self._mock_name + while _new_parent is not None: + this_mock_call = _Call((_new_name, args, kwargs)) + if _new_parent._mock_new_name: + dot = '.' + if skip_next_dot: + dot = '' + + skip_next_dot = False + if _new_parent._mock_new_name == '()': + skip_next_dot = True + + _new_name = _new_parent._mock_new_name + dot + _new_name + + if do_method_calls: + if _new_name == name: + this_method_call = this_mock_call + else: + this_method_call = _Call((name, args, kwargs)) + _new_parent.method_calls.append(this_method_call) + + do_method_calls = _new_parent._mock_parent is not None + if do_method_calls: + name = _new_parent._mock_name + '.' + name + + _new_parent.mock_calls.append(this_mock_call) + _new_parent = _new_parent._mock_new_parent + + # use ids here so as not to call __hash__ on the mocks + _new_parent_id = id(_new_parent) + if _new_parent_id in seen: + break + seen.add(_new_parent_id) + + ret_val = DEFAULT + effect = self.side_effect + if effect is not None: + if _is_exception(effect): + raise effect + + if not _callable(effect): + return next(effect) + + ret_val = effect(*args, **kwargs) + if ret_val is DEFAULT: + ret_val = self.return_value + + if (self._mock_wraps is not None and + self._mock_return_value is DEFAULT): + return self._mock_wraps(*args, **kwargs) + if ret_val is DEFAULT: + ret_val = self.return_value + return ret_val + + + +class Mock(CallableMixin, NonCallableMock): + """ + Create a new `Mock` object. `Mock` takes several optional arguments + that specify the behaviour of the Mock object: + + * `spec`: This can be either a list of strings or an existing object (a + class or instance) that acts as the specification for the mock object. If + you pass in an object then a list of strings is formed by calling dir on + the object (excluding unsupported magic attributes and methods). Accessing + any attribute not in this list will raise an `AttributeError`. + + If `spec` is an object (rather than a list of strings) then + `mock.__class__` returns the class of the spec object. This allows mocks + to pass `isinstance` tests. + + * `spec_set`: A stricter variant of `spec`. If used, attempting to *set* + or get an attribute on the mock that isn't on the object passed as + `spec_set` will raise an `AttributeError`. + + * `side_effect`: A function to be called whenever the Mock is called. See + the `side_effect` attribute. Useful for raising exceptions or + dynamically changing return values. The function is called with the same + arguments as the mock, and unless it returns `DEFAULT`, the return + value of this function is used as the return value. + + Alternatively `side_effect` can be an exception class or instance. In + this case the exception will be raised when the mock is called. + + If `side_effect` is an iterable then each call to the mock will return + the next value from the iterable. + + * `return_value`: The value returned when the mock is called. By default + this is a new Mock (created on first access). See the + `return_value` attribute. + + * `wraps`: Item for the mock object to wrap. If `wraps` is not None + then calling the Mock will pass the call through to the wrapped object + (returning the real result and ignoring `return_value`). Attribute + access on the mock will return a Mock object that wraps the corresponding + attribute of the wrapped object (so attempting to access an attribute that + doesn't exist will raise an `AttributeError`). + + If the mock has an explicit `return_value` set then calls are not passed + to the wrapped object and the `return_value` is returned instead. + + * `name`: If the mock has a name then it will be used in the repr of the + mock. This can be useful for debugging. The name is propagated to child + mocks. + + Mocks can also be called with arbitrary keyword arguments. These will be + used to set attributes on the mock after it is created. + """ + + + +def _dot_lookup(thing, comp, import_path): + try: + return getattr(thing, comp) + except AttributeError: + __import__(import_path) + return getattr(thing, comp) + + +def _importer(target): + components = target.split('.') + import_path = components.pop(0) + thing = __import__(import_path) + + for comp in components: + import_path += ".%s" % comp + thing = _dot_lookup(thing, comp, import_path) + return thing + + +def _is_started(patcher): + # XXXX horrible + return hasattr(patcher, 'is_local') + + +class _patch(object): + + attribute_name = None + + def __init__( + self, getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ): + if new_callable is not None: + if new is not DEFAULT: + raise ValueError( + "Cannot use 'new' and 'new_callable' together" + ) + if autospec is not False: + raise ValueError( + "Cannot use 'autospec' and 'new_callable' together" + ) + + self.getter = getter + self.attribute = attribute + self.new = new + self.new_callable = new_callable + self.spec = spec + self.create = create + self.has_local = False + self.spec_set = spec_set + self.autospec = autospec + self.kwargs = kwargs + self.additional_patchers = [] + + + def copy(self): + patcher = _patch( + self.getter, self.attribute, self.new, self.spec, + self.create, self.spec_set, + self.autospec, self.new_callable, self.kwargs + ) + patcher.attribute_name = self.attribute_name + patcher.additional_patchers = [ + p.copy() for p in self.additional_patchers + ] + return patcher + + + def __call__(self, func): + if isinstance(func, type): + return self.decorate_class(func) + return self.decorate_callable(func) + + + def decorate_class(self, klass): + for attr in dir(klass): + if not attr.startswith(patch.TEST_PREFIX): + continue + + attr_value = getattr(klass, attr) + if not hasattr(attr_value, "__call__"): + continue + + patcher = self.copy() + setattr(klass, attr, patcher(attr_value)) + return klass + + + def decorate_callable(self, func): + if hasattr(func, 'patchings'): + func.patchings.append(self) + return func + + @wraps(func) + def patched(*args, **keywargs): + # could use with statement here + extra_args = [] + entered_patchers = [] + + # could use try..except...finally here + try: + try: + for patching in patched.patchings: + arg = patching.__enter__() + entered_patchers.append(patching) + if patching.attribute_name is not None: + keywargs.update(arg) + elif patching.new is DEFAULT: + extra_args.append(arg) + + args += tuple(extra_args) + return func(*args, **keywargs) + except: + if (patching not in entered_patchers and + _is_started(patching)): + # the patcher may have been started, but an exception + # raised whilst entering one of its additional_patchers + entered_patchers.append(patching) + # re-raise the exception + raise + finally: + for patching in reversed(entered_patchers): + patching.__exit__() + + patched.patchings = [self] + if hasattr(func, 'func_code'): + # not in Python 3 + patched.compat_co_firstlineno = getattr( + func, "compat_co_firstlineno", + func.func_code.co_firstlineno + ) + return patched + + + def get_original(self): + target = self.getter() + name = self.attribute + + original = DEFAULT + local = False + + try: + original = target.__dict__[name] + except (AttributeError, KeyError): + original = getattr(target, name, DEFAULT) + else: + local = True + + if not self.create and original is DEFAULT: + raise AttributeError( + "%s does not have the attribute %r" % (target, name) + ) + return original, local + + + def __enter__(self): + """Perform the patch.""" + new, spec, spec_set = self.new, self.spec, self.spec_set + autospec, kwargs = self.autospec, self.kwargs + new_callable = self.new_callable + self.target = self.getter() + + original, local = self.get_original() + + if new is DEFAULT and autospec is False: + inherit = False + if spec_set == True: + spec_set = original + elif spec == True: + # set spec to the object we are replacing + spec = original + + if (spec or spec_set) is not None: + if isinstance(original, type): + # If we're patching out a class and there is a spec + inherit = True + + Klass = MagicMock + _kwargs = {} + if new_callable is not None: + Klass = new_callable + elif (spec or spec_set) is not None: + if not _callable(spec or spec_set): + Klass = NonCallableMagicMock + + if spec is not None: + _kwargs['spec'] = spec + if spec_set is not None: + _kwargs['spec_set'] = spec_set + + # add a name to mocks + if (isinstance(Klass, type) and + issubclass(Klass, NonCallableMock) and self.attribute): + _kwargs['name'] = self.attribute + + _kwargs.update(kwargs) + new = Klass(**_kwargs) + + if inherit and _is_instance_mock(new): + # we can only tell if the instance should be callable if the + # spec is not a list + if (not _is_list(spec or spec_set) and not + _instance_callable(spec or spec_set)): + Klass = NonCallableMagicMock + + _kwargs.pop('name') + new.return_value = Klass(_new_parent=new, _new_name='()', + **_kwargs) + elif autospec is not False: + # spec is ignored, new *must* be default, spec_set is treated + # as a boolean. Should we check spec is not None and that spec_set + # is a bool? + if new is not DEFAULT: + raise TypeError( + "autospec creates the mock for you. Can't specify " + "autospec and new." + ) + spec_set = bool(spec_set) + if autospec is True: + autospec = original + + new = create_autospec(autospec, spec_set=spec_set, + _name=self.attribute, **kwargs) + elif kwargs: + # can't set keyword args when we aren't creating the mock + # XXXX If new is a Mock we could call new.configure_mock(**kwargs) + raise TypeError("Can't pass kwargs to a mock we aren't creating") + + new_attr = new + + self.temp_original = original + self.is_local = local + setattr(self.target, self.attribute, new_attr) + if self.attribute_name is not None: + extra_args = {} + if self.new is DEFAULT: + extra_args[self.attribute_name] = new + for patching in self.additional_patchers: + arg = patching.__enter__() + if patching.new is DEFAULT: + extra_args.update(arg) + return extra_args + + return new + + + def __exit__(self, *_): + """Undo the patch.""" + if not _is_started(self): + raise RuntimeError('stop called on unstarted patcher') + + if self.is_local and self.temp_original is not DEFAULT: + setattr(self.target, self.attribute, self.temp_original) + else: + delattr(self.target, self.attribute) + if not self.create and not hasattr(self.target, self.attribute): + # needed for proxy objects like django settings + setattr(self.target, self.attribute, self.temp_original) + + del self.temp_original + del self.is_local + del self.target + for patcher in reversed(self.additional_patchers): + if _is_started(patcher): + patcher.__exit__() + + start = __enter__ + stop = __exit__ + + + +def _get_target(target): + try: + target, attribute = target.rsplit('.', 1) + except (TypeError, ValueError): + raise TypeError("Need a valid target to patch. You supplied: %r" % + (target,)) + getter = lambda: _importer(target) + return getter, attribute + + +def _patch_object( + target, attribute, new=DEFAULT, spec=None, + create=False, spec_set=None, autospec=False, + new_callable=None, **kwargs + ): + """ + patch.object(target, attribute, new=DEFAULT, spec=None, create=False, + spec_set=None, autospec=False, + new_callable=None, **kwargs) + + patch the named member (`attribute`) on an object (`target`) with a mock + object. + + `patch.object` can be used as a decorator, class decorator or a context + manager. Arguments `new`, `spec`, `create`, `spec_set`, + `autospec` and `new_callable` have the same meaning as for `patch`. Like + `patch`, `patch.object` takes arbitrary keyword arguments for configuring + the mock object it creates. + + When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + """ + getter = lambda: target + return _patch( + getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ) + + +def _patch_multiple(target, spec=None, create=False, + spec_set=None, autospec=False, + new_callable=None, **kwargs + ): + """Perform multiple patches in a single call. It takes the object to be + patched (either as an object or a string to fetch the object by importing) + and keyword arguments for the patches:: + + with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): + ... + + Use `DEFAULT` as the value if you want `patch.multiple` to create + mocks for you. In this case the created mocks are passed into a decorated + function by keyword, and a dictionary is returned when `patch.multiple` is + used as a context manager. + + `patch.multiple` can be used as a decorator, class decorator or a context + manager. The arguments `spec`, `spec_set`, `create`, + `autospec` and `new_callable` have the same meaning as for `patch`. These + arguments will be applied to *all* patches done by `patch.multiple`. + + When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + """ + if type(target) is str: + getter = lambda: _importer(target) + else: + getter = lambda: target + + if not kwargs: + raise ValueError( + 'Must supply at least one keyword argument with patch.multiple' + ) + # need to wrap in a list for python 3, where items is a view + items = list(kwargs.items()) + attribute, new = items[0] + patcher = _patch( + getter, attribute, new, spec, create, spec_set, + autospec, new_callable, {} + ) + patcher.attribute_name = attribute + for attribute, new in items[1:]: + this_patcher = _patch( + getter, attribute, new, spec, create, spec_set, + autospec, new_callable, {} + ) + this_patcher.attribute_name = attribute + patcher.additional_patchers.append(this_patcher) + return patcher + + +def patch( + target, new=DEFAULT, spec=None, create=False, + spec_set=None, autospec=False, + new_callable=None, **kwargs + ): + """ + `patch` acts as a function decorator, class decorator or a context + manager. Inside the body of the function or with statement, the `target` + (specified in the form `'package.module.ClassName'`) is patched + with a `new` object. When the function/with statement exits the patch is + undone. + + The `target` is imported and the specified attribute patched with the new + object, so it must be importable from the environment you are calling the + decorator from. The target is imported when the decorated function is + executed, not at decoration time. + + If `new` is omitted, then a new `MagicMock` is created and passed in as an + extra argument to the decorated function. + + The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` + if patch is creating one for you. + + In addition you can pass `spec=True` or `spec_set=True`, which causes + patch to pass in the object being mocked as the spec/spec_set object. + + `new_callable` allows you to specify a different class, or callable object, + that will be called to create the `new` object. By default `MagicMock` is + used. + + A more powerful form of `spec` is `autospec`. If you set `autospec=True` + then the mock with be created with a spec from the object being replaced. + All attributes of the mock will also have the spec of the corresponding + attribute of the object being replaced. Methods and functions being + mocked will have their arguments checked and will raise a `TypeError` if + they are called with the wrong signature. For mocks replacing a class, + their return value (the 'instance') will have the same spec as the class. + + Instead of `autospec=True` you can pass `autospec=some_object` to use an + arbitrary object as the spec instead of the one being replaced. + + By default `patch` will fail to replace attributes that don't exist. If + you pass in `create=True`, and the attribute doesn't exist, patch will + create the attribute for you when the patched function is called, and + delete it again afterwards. This is useful for writing tests against + attributes that your production code creates at runtime. It is off by by + default because it can be dangerous. With it switched on you can write + passing tests against APIs that don't actually exist! + + Patch can be used as a `TestCase` class decorator. It works by + decorating each test method in the class. This reduces the boilerplate + code when your test methods share a common patchings set. `patch` finds + tests by looking for method names that start with `patch.TEST_PREFIX`. + By default this is `test`, which matches the way `unittest` finds tests. + You can specify an alternative prefix by setting `patch.TEST_PREFIX`. + + Patch can be used as a context manager, with the with statement. Here the + patching applies to the indented block after the with statement. If you + use "as" then the patched object will be bound to the name after the + "as"; very useful if `patch` is creating a mock object for you. + + `patch` takes arbitrary keyword arguments. These will be passed to + the `Mock` (or `new_callable`) on construction. + + `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are + available for alternate use-cases. + """ + getter, attribute = _get_target(target) + return _patch( + getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ) + + +class _patch_dict(object): + """ + Patch a dictionary, or dictionary like object, and restore the dictionary + to its original state after the test. + + `in_dict` can be a dictionary or a mapping like container. If it is a + mapping then it must at least support getting, setting and deleting items + plus iterating over keys. + + `in_dict` can also be a string specifying the name of the dictionary, which + will then be fetched by importing it. + + `values` can be a dictionary of values to set in the dictionary. `values` + can also be an iterable of `(key, value)` pairs. + + If `clear` is True then the dictionary will be cleared before the new + values are set. + + `patch.dict` can also be called with arbitrary keyword arguments to set + values in the dictionary:: + + with patch.dict('sys.modules', mymodule=Mock(), other_module=Mock()): + ... + + `patch.dict` can be used as a context manager, decorator or class + decorator. When used as a class decorator `patch.dict` honours + `patch.TEST_PREFIX` for choosing which methods to wrap. + """ + + def __init__(self, in_dict, values=(), clear=False, **kwargs): + if isinstance(in_dict, str): + in_dict = _importer(in_dict) + self.in_dict = in_dict + # support any argument supported by dict(...) constructor + self.values = dict(values) + self.values.update(kwargs) + self.clear = clear + self._original = None + + + def __call__(self, f): + if isinstance(f, type): + return self.decorate_class(f) + @wraps(f) + def _inner(*args, **kw): + self._patch_dict() + try: + return f(*args, **kw) + finally: + self._unpatch_dict() + + return _inner + + + def decorate_class(self, klass): + for attr in dir(klass): + attr_value = getattr(klass, attr) + if (attr.startswith(patch.TEST_PREFIX) and + hasattr(attr_value, "__call__")): + decorator = _patch_dict(self.in_dict, self.values, self.clear) + decorated = decorator(attr_value) + setattr(klass, attr, decorated) + return klass + + + def __enter__(self): + """Patch the dict.""" + self._patch_dict() + + + def _patch_dict(self): + values = self.values + in_dict = self.in_dict + clear = self.clear + + try: + original = in_dict.copy() + except AttributeError: + # dict like object with no copy method + # must support iteration over keys + original = {} + for key in in_dict: + original[key] = in_dict[key] + self._original = original + + if clear: + _clear_dict(in_dict) + + try: + in_dict.update(values) + except AttributeError: + # dict like object with no update method + for key in values: + in_dict[key] = values[key] + + + def _unpatch_dict(self): + in_dict = self.in_dict + original = self._original + + _clear_dict(in_dict) + + try: + in_dict.update(original) + except AttributeError: + for key in original: + in_dict[key] = original[key] + + + def __exit__(self, *args): + """Unpatch the dict.""" + self._unpatch_dict() + return False + + start = __enter__ + stop = __exit__ + + +def _clear_dict(in_dict): + try: + in_dict.clear() + except AttributeError: + keys = list(in_dict) + for key in keys: + del in_dict[key] + + +patch.object = _patch_object +patch.dict = _patch_dict +patch.multiple = _patch_multiple +patch.TEST_PREFIX = 'test' + +magic_methods = ( + "lt le gt ge eq ne " + "getitem setitem delitem " + "len contains iter " + "hash str sizeof " + "enter exit " + "divmod neg pos abs invert " + "complex int float index " + "trunc floor ceil " + "bool next " +) + +numerics = "add sub mul div floordiv mod lshift rshift and xor or pow " +inplace = ' '.join('i%s' % n for n in numerics.split()) +right = ' '.join('r%s' % n for n in numerics.split()) + +# not including __prepare__, __instancecheck__, __subclasscheck__ +# (as they are metaclass methods) +# __del__ is not supported at all as it causes problems if it exists + +_non_defaults = set('__%s__' % method for method in [ + 'cmp', 'getslice', 'setslice', 'coerce', 'subclasses', + 'format', 'get', 'set', 'delete', 'reversed', + 'missing', 'reduce', 'reduce_ex', 'getinitargs', + 'getnewargs', 'getstate', 'setstate', 'getformat', + 'setformat', 'repr', 'dir' +]) + + +def _get_method(name, func): + "Turns a callable object (like a mock) into a real function" + def method(self, *args, **kw): + return func(self, *args, **kw) + method.__name__ = name + return method + + +_magics = set( + '__%s__' % method for method in + ' '.join([magic_methods, numerics, inplace, right]).split() +) + +_all_magics = _magics | _non_defaults + +_unsupported_magics = set([ + '__getattr__', '__setattr__', + '__init__', '__new__', '__prepare__' + '__instancecheck__', '__subclasscheck__', + '__del__' +]) + +_calculate_return_value = { + '__hash__': lambda self: object.__hash__(self), + '__str__': lambda self: object.__str__(self), + '__sizeof__': lambda self: object.__sizeof__(self), +} + +_return_values = { + '__int__': 1, + '__contains__': False, + '__len__': 0, + '__exit__': False, + '__complex__': 1j, + '__float__': 1.0, + '__bool__': True, + '__index__': 1, +} + + +def _get_eq(self): + def __eq__(other): + ret_val = self.__eq__._mock_return_value + if ret_val is not DEFAULT: + return ret_val + return self is other + return __eq__ + +def _get_ne(self): + def __ne__(other): + if self.__ne__._mock_return_value is not DEFAULT: + return DEFAULT + return self is not other + return __ne__ + +def _get_iter(self): + def __iter__(): + ret_val = self.__iter__._mock_return_value + if ret_val is DEFAULT: + return iter([]) + # if ret_val was already an iterator, then calling iter on it should + # return the iterator unchanged + return iter(ret_val) + return __iter__ + +_side_effect_methods = { + '__eq__': _get_eq, + '__ne__': _get_ne, + '__iter__': _get_iter, +} + + + +def _set_return_value(mock, method, name): + fixed = _return_values.get(name, DEFAULT) + if fixed is not DEFAULT: + method.return_value = fixed + return + + return_calulator = _calculate_return_value.get(name) + if return_calulator is not None: + try: + return_value = return_calulator(mock) + except AttributeError: + # XXXX why do we return AttributeError here? + # set it as a side_effect instead? + return_value = AttributeError(name) + method.return_value = return_value + return + + side_effector = _side_effect_methods.get(name) + if side_effector is not None: + method.side_effect = side_effector(mock) + + + +class MagicMixin(object): + def __init__(self, *args, **kw): + super(MagicMixin, self).__init__(*args, **kw) + self._mock_set_magics() + + + def _mock_set_magics(self): + these_magics = _magics + + if self._mock_methods is not None: + these_magics = _magics.intersection(self._mock_methods) + + remove_magics = set() + remove_magics = _magics - these_magics + + for entry in remove_magics: + if entry in type(self).__dict__: + # remove unneeded magic methods + delattr(self, entry) + + # don't overwrite existing attributes if called a second time + these_magics = these_magics - set(type(self).__dict__) + + _type = type(self) + for entry in these_magics: + setattr(_type, entry, MagicProxy(entry, self)) + + + +class NonCallableMagicMock(MagicMixin, NonCallableMock): + """A version of `MagicMock` that isn't callable.""" + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + self._mock_set_magics() + + + +class MagicMock(MagicMixin, Mock): + """ + MagicMock is a subclass of Mock with default implementations + of most of the magic methods. You can use MagicMock without having to + configure the magic methods yourself. + + If you use the `spec` or `spec_set` arguments then *only* magic + methods that exist in the spec will be created. + + Attributes and the return value of a `MagicMock` will also be `MagicMocks`. + """ + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + self._mock_set_magics() + + + +class MagicProxy(object): + def __init__(self, name, parent): + self.name = name + self.parent = parent + + def __call__(self, *args, **kwargs): + m = self.create_mock() + return m(*args, **kwargs) + + def create_mock(self): + entry = self.name + parent = self.parent + m = parent._get_child_mock(name=entry, _new_name=entry, + _new_parent=parent) + setattr(parent, entry, m) + _set_return_value(parent, m, entry) + return m + + def __get__(self, obj, _type=None): + return self.create_mock() + + + +class _ANY(object): + "A helper object that compares equal to everything." + + def __eq__(self, other): + return True + + def __ne__(self, other): + return False + + def __repr__(self): + return '' + +ANY = _ANY() + + + +def _format_call_signature(name, args, kwargs): + message = '%s(%%s)' % name + formatted_args = '' + args_string = ', '.join([repr(arg) for arg in args]) + kwargs_string = ', '.join([ + '%s=%r' % (key, value) for key, value in kwargs.items() + ]) + if args_string: + formatted_args = args_string + if kwargs_string: + if formatted_args: + formatted_args += ', ' + formatted_args += kwargs_string + + return message % formatted_args + + + +class _Call(tuple): + """ + A tuple for holding the results of a call to a mock, either in the form + `(args, kwargs)` or `(name, args, kwargs)`. + + If args or kwargs are empty then a call tuple will compare equal to + a tuple without those values. This makes comparisons less verbose:: + + _Call(('name', (), {})) == ('name',) + _Call(('name', (1,), {})) == ('name', (1,)) + _Call(((), {'a': 'b'})) == ({'a': 'b'},) + + The `_Call` object provides a useful shortcut for comparing with call:: + + _Call(((1, 2), {'a': 3})) == call(1, 2, a=3) + _Call(('foo', (1, 2), {'a': 3})) == call.foo(1, 2, a=3) + + If the _Call has no name then it will match any name. + """ + def __new__(cls, value=(), name=None, parent=None, two=False, + from_kall=True): + name = '' + args = () + kwargs = {} + _len = len(value) + if _len == 3: + name, args, kwargs = value + elif _len == 2: + first, second = value + if isinstance(first, str): + name = first + if isinstance(second, tuple): + args = second + else: + kwargs = second + else: + args, kwargs = first, second + elif _len == 1: + value, = value + if isinstance(value, str): + name = value + elif isinstance(value, tuple): + args = value + else: + kwargs = value + + if two: + return tuple.__new__(cls, (args, kwargs)) + + return tuple.__new__(cls, (name, args, kwargs)) + + + def __init__(self, value=(), name=None, parent=None, two=False, + from_kall=True): + self.name = name + self.parent = parent + self.from_kall = from_kall + + + def __eq__(self, other): + if other is ANY: + return True + try: + len_other = len(other) + except TypeError: + return False + + self_name = '' + if len(self) == 2: + self_args, self_kwargs = self + else: + self_name, self_args, self_kwargs = self + + other_name = '' + if len_other == 0: + other_args, other_kwargs = (), {} + elif len_other == 3: + other_name, other_args, other_kwargs = other + elif len_other == 1: + value, = other + if isinstance(value, tuple): + other_args = value + other_kwargs = {} + elif isinstance(value, str): + other_name = value + other_args, other_kwargs = (), {} + else: + other_args = () + other_kwargs = value + else: + # len 2 + # could be (name, args) or (name, kwargs) or (args, kwargs) + first, second = other + if isinstance(first, str): + other_name = first + if isinstance(second, tuple): + other_args, other_kwargs = second, {} + else: + other_args, other_kwargs = (), second + else: + other_args, other_kwargs = first, second + + if self_name and other_name != self_name: + return False + + # this order is important for ANY to work! + return (other_args, other_kwargs) == (self_args, self_kwargs) + + + def __ne__(self, other): + return not self.__eq__(other) + + + def __call__(self, *args, **kwargs): + if self.name is None: + return _Call(('', args, kwargs), name='()') + + name = self.name + '()' + return _Call((self.name, args, kwargs), name=name, parent=self) + + + def __getattr__(self, attr): + if self.name is None: + return _Call(name=attr, from_kall=False) + name = '%s.%s' % (self.name, attr) + return _Call(name=name, parent=self, from_kall=False) + + + def __repr__(self): + if not self.from_kall: + name = self.name or 'call' + if name.startswith('()'): + name = 'call%s' % name + return name + + if len(self) == 2: + name = 'call' + args, kwargs = self + else: + name, args, kwargs = self + if not name: + name = 'call' + elif not name.startswith('()'): + name = 'call.%s' % name + else: + name = 'call%s' % name + return _format_call_signature(name, args, kwargs) + + + def call_list(self): + """For a call object that represents multiple calls, `call_list` + returns a list of all the intermediate calls as well as the + final call.""" + vals = [] + thing = self + while thing is not None: + if thing.from_kall: + vals.append(thing) + thing = thing.parent + return _CallList(reversed(vals)) + + +call = _Call(from_kall=False) + + + +def create_autospec(spec, spec_set=False, instance=False, _parent=None, + _name=None, **kwargs): + """Create a mock object using another object as a spec. Attributes on the + mock will use the corresponding attribute on the `spec` object as their + spec. + + Functions or methods being mocked will have their arguments checked + to check that they are called with the correct signature. + + If `spec_set` is True then attempting to set attributes that don't exist + on the spec object will raise an `AttributeError`. + + If a class is used as a spec then the return value of the mock (the + instance of the class) will have the same spec. You can use a class as the + spec for an instance object by passing `instance=True`. The returned mock + will only be callable if instances of the mock are callable. + + `create_autospec` also takes arbitrary keyword arguments that are passed to + the constructor of the created mock.""" + if _is_list(spec): + # can't pass a list instance to the mock constructor as it will be + # interpreted as a list of strings + spec = type(spec) + + is_type = isinstance(spec, type) + + _kwargs = {'spec': spec} + if spec_set: + _kwargs = {'spec_set': spec} + elif spec is None: + # None we mock with a normal mock without a spec + _kwargs = {} + + _kwargs.update(kwargs) + + Klass = MagicMock + if type(spec) in DescriptorTypes: + # descriptors don't have a spec + # because we don't know what type they return + _kwargs = {} + elif not _callable(spec): + Klass = NonCallableMagicMock + elif is_type and instance and not _instance_callable(spec): + Klass = NonCallableMagicMock + + _new_name = _name + if _parent is None: + # for a top level object no _new_name should be set + _new_name = '' + + mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name, + name=_name, **_kwargs) + + if isinstance(spec, FunctionTypes): + # should only happen at the top level because we don't + # recurse for functions + mock = _set_signature(mock, spec) + else: + _check_signature(spec, mock, is_type, instance) + + if _parent is not None and not instance: + _parent._mock_children[_name] = mock + + if is_type and not instance and 'return_value' not in kwargs: + # XXXX could give a name to the return_value mock? + mock.return_value = create_autospec(spec, spec_set, instance=True, + _name='()', _parent=mock) + + for entry in dir(spec): + if _is_magic(entry): + # MagicMock already does the useful magic methods for us + continue + + if isinstance(spec, FunctionTypes) and entry in FunctionAttributes: + # allow a mock to actually be a function + continue + + # XXXX do we need a better way of getting attributes without + # triggering code execution (?) Probably not - we need the actual + # object to mock it so we would rather trigger a property than mock + # the property descriptor. Likewise we want to mock out dynamically + # provided attributes. + # XXXX what about attributes that raise exceptions on being fetched + # we could be resilient against it, or catch and propagate the + # exception when the attribute is fetched from the mock + original = getattr(spec, entry) + + kwargs = {'spec': original} + if spec_set: + kwargs = {'spec_set': original} + + if not isinstance(original, FunctionTypes): + new = _SpecState(original, spec_set, mock, entry, instance) + mock._mock_children[entry] = new + else: + parent = mock + if isinstance(spec, FunctionTypes): + parent = mock.mock + + new = MagicMock(parent=parent, name=entry, _new_name=entry, + _new_parent=parent, **kwargs) + mock._mock_children[entry] = new + skipfirst = _must_skip(spec, entry, is_type) + _check_signature(original, new, skipfirst=skipfirst) + + # so functions created with _set_signature become instance attributes, + # *plus* their underlying mock exists in _mock_children of the parent + # mock. Adding to _mock_children may be unnecessary where we are also + # setting as an instance attribute? + if isinstance(new, FunctionTypes): + setattr(mock, entry, new) + + return mock + + +def _must_skip(spec, entry, is_type): + if not isinstance(spec, type): + if entry in getattr(spec, '__dict__', {}): + # instance attribute - shouldn't skip + return False + # can't use type because of old style classes + spec = spec.__class__ + if not hasattr(spec, '__mro__'): + # old style class: can't have descriptors anyway + return is_type + + for klass in spec.__mro__: + result = klass.__dict__.get(entry, DEFAULT) + if result is DEFAULT: + continue + if isinstance(result, (staticmethod, classmethod)): + return False + return is_type + + # shouldn't get here unless function is a dynamically provided attribute + # XXXX untested behaviour + return is_type + + +def _get_class(obj): + try: + return obj.__class__ + except AttributeError: + # in Python 2, _sre.SRE_Pattern objects have no __class__ + return type(obj) + + +class _SpecState(object): + + def __init__(self, spec, spec_set=False, parent=None, + name=None, ids=None, instance=False): + self.spec = spec + self.ids = ids + self.spec_set = spec_set + self.parent = parent + self.instance = instance + self.name = name + + +FunctionTypes = ( + # python function + type(create_autospec), + # instance method + type(ANY.__eq__), + # unbound method + type(_ANY.__eq__), +) + +FunctionAttributes = set([ + 'func_closure', + 'func_code', + 'func_defaults', + 'func_dict', + 'func_doc', + 'func_globals', + 'func_name', +]) + +import _io +file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) + + +def mock_open(mock=None, read_data=None): + if mock is None: + mock = MagicMock(spec=file_spec) + + handle = MagicMock(spec=file_spec) + handle.write.return_value = None + handle.__enter__.return_value = handle + + if read_data is not None: + handle.read.return_value = read_data + + mock.return_value = handle + return mock + + +class PropertyMock(Mock): + """A Mock variant with __get__ and __set__ methods to act as a property""" + def __get__(self, obj, obj_type): + return self() + def __set__(self, obj, val): + self(val) diff --git a/Lib/unittest/test/__init__.py b/Lib/unittest/test/__init__.py --- a/Lib/unittest/test/__init__.py +++ b/Lib/unittest/test/__init__.py @@ -14,6 +14,7 @@ __import__(modname) module = sys.modules[modname] suite.addTest(loader.loadTestsFromModule(module)) + suite.addTest(loader.loadTestsFromName('unittest.test.testmock')) return suite diff --git a/Lib/unittest/test/testmock/__init__.py b/Lib/unittest/test/testmock/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/__init__.py @@ -0,0 +1,17 @@ +import os +import sys +import unittest + + +here = os.path.dirname(__file__) +loader = unittest.defaultTestLoader + +def load_tests(*args): + suite = unittest.TestSuite() + for fn in os.listdir(here): + if fn.startswith("test") and fn.endswith(".py"): + modname = "unittest.test.testmock." + fn[:-3] + __import__(modname) + module = sys.modules[modname] + suite.addTest(loader.loadTestsFromModule(module)) + return suite diff --git a/Lib/unittest/test/testmock/support.py b/Lib/unittest/test/testmock/support.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/support.py @@ -0,0 +1,23 @@ +import sys + +def is_instance(obj, klass): + """Version of is_instance that doesn't access __class__""" + return issubclass(type(obj), klass) + + +class SomeClass(object): + class_attribute = None + + def wibble(self): + pass + + +class X(object): + pass + + +def examine_warnings(func): + def wrapper(): + with catch_warnings(record=True) as ws: + func(ws) + return wrapper diff --git a/Lib/unittest/test/testmock/testcallable.py b/Lib/unittest/test/testmock/testcallable.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testcallable.py @@ -0,0 +1,159 @@ +# Copyright (C) 2007-2012 Michael Foord & the mock team +# E-mail: fuzzyman AT voidspace DOT org DOT uk +# http://www.voidspace.org.uk/python/mock/ + +import unittest +from unittest.test.testmock.support import is_instance, X, SomeClass + +from unittest.mock import ( + Mock, MagicMock, NonCallableMagicMock, + NonCallableMock, patch, create_autospec, + CallableMixin +) + + + +class TestCallable(unittest.TestCase): + + def assertNotCallable(self, mock): + self.assertTrue(is_instance(mock, NonCallableMagicMock)) + self.assertFalse(is_instance(mock, CallableMixin)) + + + def test_non_callable(self): + for mock in NonCallableMagicMock(), NonCallableMock(): + self.assertRaises(TypeError, mock) + self.assertFalse(hasattr(mock, '__call__')) + self.assertIn(mock.__class__.__name__, repr(mock)) + + + def test_heirarchy(self): + self.assertTrue(issubclass(MagicMock, Mock)) + self.assertTrue(issubclass(NonCallableMagicMock, NonCallableMock)) + + + def test_attributes(self): + one = NonCallableMock() + self.assertTrue(issubclass(type(one.one), Mock)) + + two = NonCallableMagicMock() + self.assertTrue(issubclass(type(two.two), MagicMock)) + + + def test_subclasses(self): + class MockSub(Mock): + pass + + one = MockSub() + self.assertTrue(issubclass(type(one.one), MockSub)) + + class MagicSub(MagicMock): + pass + + two = MagicSub() + self.assertTrue(issubclass(type(two.two), MagicSub)) + + + def test_patch_spec(self): + patcher = patch('%s.X' % __name__, spec=True) + mock = patcher.start() + self.addCleanup(patcher.stop) + + instance = mock() + mock.assert_called_once_with() + + self.assertNotCallable(instance) + self.assertRaises(TypeError, instance) + + + def test_patch_spec_set(self): + patcher = patch('%s.X' % __name__, spec_set=True) + mock = patcher.start() + self.addCleanup(patcher.stop) + + instance = mock() + mock.assert_called_once_with() + + self.assertNotCallable(instance) + self.assertRaises(TypeError, instance) + + + def test_patch_spec_instance(self): + patcher = patch('%s.X' % __name__, spec=X()) + mock = patcher.start() + self.addCleanup(patcher.stop) + + self.assertNotCallable(mock) + self.assertRaises(TypeError, mock) + + + def test_patch_spec_set_instance(self): + patcher = patch('%s.X' % __name__, spec_set=X()) + mock = patcher.start() + self.addCleanup(patcher.stop) + + self.assertNotCallable(mock) + self.assertRaises(TypeError, mock) + + + def test_patch_spec_callable_class(self): + class CallableX(X): + def __call__(self): + pass + + class Sub(CallableX): + pass + + class Multi(SomeClass, Sub): + pass + + class OldStyle: + def __call__(self): + pass + + class OldStyleSub(OldStyle): + pass + + for arg in 'spec', 'spec_set': + for Klass in CallableX, Sub, Multi, OldStyle, OldStyleSub: + patcher = patch('%s.X' % __name__, **{arg: Klass}) + mock = patcher.start() + + try: + instance = mock() + mock.assert_called_once_with() + + self.assertTrue(is_instance(instance, MagicMock)) + # inherited spec + self.assertRaises(AttributeError, getattr, instance, + 'foobarbaz') + + result = instance() + # instance is callable, result has no spec + instance.assert_called_once_with() + + result(3, 2, 1) + result.assert_called_once_with(3, 2, 1) + result.foo(3, 2, 1) + result.foo.assert_called_once_with(3, 2, 1) + finally: + patcher.stop() + + + def test_create_autopsec(self): + mock = create_autospec(X) + instance = mock() + self.assertRaises(TypeError, instance) + + mock = create_autospec(X()) + self.assertRaises(TypeError, mock) + + + def test_create_autospec_instance(self): + mock = create_autospec(SomeClass, instance=True) + + self.assertRaises(TypeError, mock) + mock.wibble() + mock.wibble.assert_called_once_with() + + self.assertRaises(TypeError, mock.wibble, 'some', 'args') diff --git a/Lib/unittest/test/testmock/testhelpers.py b/Lib/unittest/test/testmock/testhelpers.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testhelpers.py @@ -0,0 +1,835 @@ +import unittest + +from unittest.mock import ( + call, _Call, create_autospec, MagicMock, + Mock, ANY, _CallList, patch, PropertyMock +) + +from datetime import datetime + +class SomeClass(object): + def one(self, a, b): + pass + def two(self): + pass + def three(self, a=None): + pass + + + +class AnyTest(unittest.TestCase): + + def test_any(self): + self.assertEqual(ANY, object()) + + mock = Mock() + mock(ANY) + mock.assert_called_with(ANY) + + mock = Mock() + mock(foo=ANY) + mock.assert_called_with(foo=ANY) + + def test_repr(self): + self.assertEqual(repr(ANY), '') + self.assertEqual(str(ANY), '') + + + def test_any_and_datetime(self): + mock = Mock() + mock(datetime.now(), foo=datetime.now()) + + mock.assert_called_with(ANY, foo=ANY) + + + def test_any_mock_calls_comparison_order(self): + mock = Mock() + d = datetime.now() + class Foo(object): + def __eq__(self, other): + return False + def __ne__(self, other): + return True + + for d in datetime.now(), Foo(): + mock.reset_mock() + + mock(d, foo=d, bar=d) + mock.method(d, zinga=d, alpha=d) + mock().method(a1=d, z99=d) + + expected = [ + call(ANY, foo=ANY, bar=ANY), + call.method(ANY, zinga=ANY, alpha=ANY), + call(), call().method(a1=ANY, z99=ANY) + ] + self.assertEqual(expected, mock.mock_calls) + self.assertEqual(mock.mock_calls, expected) + + + +class CallTest(unittest.TestCase): + + def test_call_with_call(self): + kall = _Call() + self.assertEqual(kall, _Call()) + self.assertEqual(kall, _Call(('',))) + self.assertEqual(kall, _Call(((),))) + self.assertEqual(kall, _Call(({},))) + self.assertEqual(kall, _Call(('', ()))) + self.assertEqual(kall, _Call(('', {}))) + self.assertEqual(kall, _Call(('', (), {}))) + self.assertEqual(kall, _Call(('foo',))) + self.assertEqual(kall, _Call(('bar', ()))) + self.assertEqual(kall, _Call(('baz', {}))) + self.assertEqual(kall, _Call(('spam', (), {}))) + + kall = _Call(((1, 2, 3),)) + self.assertEqual(kall, _Call(((1, 2, 3),))) + self.assertEqual(kall, _Call(('', (1, 2, 3)))) + self.assertEqual(kall, _Call(((1, 2, 3), {}))) + self.assertEqual(kall, _Call(('', (1, 2, 3), {}))) + + kall = _Call(((1, 2, 4),)) + self.assertNotEqual(kall, _Call(('', (1, 2, 3)))) + self.assertNotEqual(kall, _Call(('', (1, 2, 3), {}))) + + kall = _Call(('foo', (1, 2, 4),)) + self.assertNotEqual(kall, _Call(('', (1, 2, 4)))) + self.assertNotEqual(kall, _Call(('', (1, 2, 4), {}))) + self.assertNotEqual(kall, _Call(('bar', (1, 2, 4)))) + self.assertNotEqual(kall, _Call(('bar', (1, 2, 4), {}))) + + kall = _Call(({'a': 3},)) + self.assertEqual(kall, _Call(('', (), {'a': 3}))) + self.assertEqual(kall, _Call(('', {'a': 3}))) + self.assertEqual(kall, _Call(((), {'a': 3}))) + self.assertEqual(kall, _Call(({'a': 3},))) + + + def test_empty__Call(self): + args = _Call() + + self.assertEqual(args, ()) + self.assertEqual(args, ('foo',)) + self.assertEqual(args, ((),)) + self.assertEqual(args, ('foo', ())) + self.assertEqual(args, ('foo',(), {})) + self.assertEqual(args, ('foo', {})) + self.assertEqual(args, ({},)) + + + def test_named_empty_call(self): + args = _Call(('foo', (), {})) + + self.assertEqual(args, ('foo',)) + self.assertEqual(args, ('foo', ())) + self.assertEqual(args, ('foo',(), {})) + self.assertEqual(args, ('foo', {})) + + self.assertNotEqual(args, ((),)) + self.assertNotEqual(args, ()) + self.assertNotEqual(args, ({},)) + self.assertNotEqual(args, ('bar',)) + self.assertNotEqual(args, ('bar', ())) + self.assertNotEqual(args, ('bar', {})) + + + def test_call_with_args(self): + args = _Call(((1, 2, 3), {})) + + self.assertEqual(args, ((1, 2, 3),)) + self.assertEqual(args, ('foo', (1, 2, 3))) + self.assertEqual(args, ('foo', (1, 2, 3), {})) + self.assertEqual(args, ((1, 2, 3), {})) + + + def test_named_call_with_args(self): + args = _Call(('foo', (1, 2, 3), {})) + + self.assertEqual(args, ('foo', (1, 2, 3))) + self.assertEqual(args, ('foo', (1, 2, 3), {})) + + self.assertNotEqual(args, ((1, 2, 3),)) + self.assertNotEqual(args, ((1, 2, 3), {})) + + + def test_call_with_kwargs(self): + args = _Call(((), dict(a=3, b=4))) + + self.assertEqual(args, (dict(a=3, b=4),)) + self.assertEqual(args, ('foo', dict(a=3, b=4))) + self.assertEqual(args, ('foo', (), dict(a=3, b=4))) + self.assertEqual(args, ((), dict(a=3, b=4))) + + + def test_named_call_with_kwargs(self): + args = _Call(('foo', (), dict(a=3, b=4))) + + self.assertEqual(args, ('foo', dict(a=3, b=4))) + self.assertEqual(args, ('foo', (), dict(a=3, b=4))) + + self.assertNotEqual(args, (dict(a=3, b=4),)) + self.assertNotEqual(args, ((), dict(a=3, b=4))) + + + def test_call_with_args_call_empty_name(self): + args = _Call(((1, 2, 3), {})) + self.assertEqual(args, call(1, 2, 3)) + self.assertEqual(call(1, 2, 3), args) + self.assertTrue(call(1, 2, 3) in [args]) + + + def test_call_ne(self): + self.assertNotEqual(_Call(((1, 2, 3),)), call(1, 2)) + self.assertFalse(_Call(((1, 2, 3),)) != call(1, 2, 3)) + self.assertTrue(_Call(((1, 2), {})) != call(1, 2, 3)) + + + def test_call_non_tuples(self): + kall = _Call(((1, 2, 3),)) + for value in 1, None, self, int: + self.assertNotEqual(kall, value) + self.assertFalse(kall == value) + + + def test_repr(self): + self.assertEqual(repr(_Call()), 'call()') + self.assertEqual(repr(_Call(('foo',))), 'call.foo()') + + self.assertEqual(repr(_Call(((1, 2, 3), {'a': 'b'}))), + "call(1, 2, 3, a='b')") + self.assertEqual(repr(_Call(('bar', (1, 2, 3), {'a': 'b'}))), + "call.bar(1, 2, 3, a='b')") + + self.assertEqual(repr(call), 'call') + self.assertEqual(str(call), 'call') + + self.assertEqual(repr(call()), 'call()') + self.assertEqual(repr(call(1)), 'call(1)') + self.assertEqual(repr(call(zz='thing')), "call(zz='thing')") + + self.assertEqual(repr(call().foo), 'call().foo') + self.assertEqual(repr(call(1).foo.bar(a=3).bing), + 'call().foo.bar().bing') + self.assertEqual( + repr(call().foo(1, 2, a=3)), + "call().foo(1, 2, a=3)" + ) + self.assertEqual(repr(call()()), "call()()") + self.assertEqual(repr(call(1)(2)), "call()(2)") + self.assertEqual( + repr(call()().bar().baz.beep(1)), + "call()().bar().baz.beep(1)" + ) + + + def test_call(self): + self.assertEqual(call(), ('', (), {})) + self.assertEqual(call('foo', 'bar', one=3, two=4), + ('', ('foo', 'bar'), {'one': 3, 'two': 4})) + + mock = Mock() + mock(1, 2, 3) + mock(a=3, b=6) + self.assertEqual(mock.call_args_list, + [call(1, 2, 3), call(a=3, b=6)]) + + def test_attribute_call(self): + self.assertEqual(call.foo(1), ('foo', (1,), {})) + self.assertEqual(call.bar.baz(fish='eggs'), + ('bar.baz', (), {'fish': 'eggs'})) + + mock = Mock() + mock.foo(1, 2 ,3) + mock.bar.baz(a=3, b=6) + self.assertEqual(mock.method_calls, + [call.foo(1, 2, 3), call.bar.baz(a=3, b=6)]) + + + def test_extended_call(self): + result = call(1).foo(2).bar(3, a=4) + self.assertEqual(result, ('().foo().bar', (3,), dict(a=4))) + + mock = MagicMock() + mock(1, 2, a=3, b=4) + self.assertEqual(mock.call_args, call(1, 2, a=3, b=4)) + self.assertNotEqual(mock.call_args, call(1, 2, 3)) + + self.assertEqual(mock.call_args_list, [call(1, 2, a=3, b=4)]) + self.assertEqual(mock.mock_calls, [call(1, 2, a=3, b=4)]) + + mock = MagicMock() + mock.foo(1).bar()().baz.beep(a=6) + + last_call = call.foo(1).bar()().baz.beep(a=6) + self.assertEqual(mock.mock_calls[-1], last_call) + self.assertEqual(mock.mock_calls, last_call.call_list()) + + + def test_call_list(self): + mock = MagicMock() + mock(1) + self.assertEqual(call(1).call_list(), mock.mock_calls) + + mock = MagicMock() + mock(1).method(2) + self.assertEqual(call(1).method(2).call_list(), + mock.mock_calls) + + mock = MagicMock() + mock(1).method(2)(3) + self.assertEqual(call(1).method(2)(3).call_list(), + mock.mock_calls) + + mock = MagicMock() + int(mock(1).method(2)(3).foo.bar.baz(4)(5)) + kall = call(1).method(2)(3).foo.bar.baz(4)(5).__int__() + self.assertEqual(kall.call_list(), mock.mock_calls) + + + def test_call_any(self): + self.assertEqual(call, ANY) + + m = MagicMock() + int(m) + self.assertEqual(m.mock_calls, [ANY]) + self.assertEqual([ANY], m.mock_calls) + + + def test_two_args_call(self): + args = _Call(((1, 2), {'a': 3}), two=True) + self.assertEqual(len(args), 2) + self.assertEqual(args[0], (1, 2)) + self.assertEqual(args[1], {'a': 3}) + + other_args = _Call(((1, 2), {'a': 3})) + self.assertEqual(args, other_args) + + +class SpecSignatureTest(unittest.TestCase): + + def _check_someclass_mock(self, mock): + self.assertRaises(AttributeError, getattr, mock, 'foo') + mock.one(1, 2) + mock.one.assert_called_with(1, 2) + self.assertRaises(AssertionError, + mock.one.assert_called_with, 3, 4) + self.assertRaises(TypeError, mock.one, 1) + + mock.two() + mock.two.assert_called_with() + self.assertRaises(AssertionError, + mock.two.assert_called_with, 3) + self.assertRaises(TypeError, mock.two, 1) + + mock.three() + mock.three.assert_called_with() + self.assertRaises(AssertionError, + mock.three.assert_called_with, 3) + self.assertRaises(TypeError, mock.three, 3, 2) + + mock.three(1) + mock.three.assert_called_with(1) + + mock.three(a=1) + mock.three.assert_called_with(a=1) + + + def test_basic(self): + for spec in (SomeClass, SomeClass()): + mock = create_autospec(spec) + self._check_someclass_mock(mock) + + + def test_create_autospec_return_value(self): + def f(): + pass + mock = create_autospec(f, return_value='foo') + self.assertEqual(mock(), 'foo') + + class Foo(object): + pass + + mock = create_autospec(Foo, return_value='foo') + self.assertEqual(mock(), 'foo') + + + def test_mocking_unbound_methods(self): + class Foo(object): + def foo(self, foo): + pass + p = patch.object(Foo, 'foo') + mock_foo = p.start() + Foo().foo(1) + + mock_foo.assert_called_with(1) + + + def test_create_autospec_unbound_methods(self): + # see issue 128 + # this is expected to fail until the issue is fixed + return + class Foo(object): + def foo(self): + pass + + klass = create_autospec(Foo) + instance = klass() + self.assertRaises(TypeError, instance.foo, 1) + + # Note: no type checking on the "self" parameter + klass.foo(1) + klass.foo.assert_called_with(1) + self.assertRaises(TypeError, klass.foo) + + + def test_create_autospec_keyword_arguments(self): + class Foo(object): + a = 3 + m = create_autospec(Foo, a='3') + self.assertEqual(m.a, '3') + + + def test_function_as_instance_attribute(self): + obj = SomeClass() + def f(a): + pass + obj.f = f + + mock = create_autospec(obj) + mock.f('bing') + mock.f.assert_called_with('bing') + + + def test_spec_as_list(self): + # because spec as a list of strings in the mock constructor means + # something very different we treat a list instance as the type. + mock = create_autospec([]) + mock.append('foo') + mock.append.assert_called_with('foo') + + self.assertRaises(AttributeError, getattr, mock, 'foo') + + class Foo(object): + foo = [] + + mock = create_autospec(Foo) + mock.foo.append(3) + mock.foo.append.assert_called_with(3) + self.assertRaises(AttributeError, getattr, mock.foo, 'foo') + + + def test_attributes(self): + class Sub(SomeClass): + attr = SomeClass() + + sub_mock = create_autospec(Sub) + + for mock in (sub_mock, sub_mock.attr): + self._check_someclass_mock(mock) + + + def test_builtin_functions_types(self): + # we could replace builtin functions / methods with a function + # with *args / **kwargs signature. Using the builtin method type + # as a spec seems to work fairly well though. + class BuiltinSubclass(list): + def bar(self, arg): + pass + sorted = sorted + attr = {} + + mock = create_autospec(BuiltinSubclass) + mock.append(3) + mock.append.assert_called_with(3) + self.assertRaises(AttributeError, getattr, mock.append, 'foo') + + mock.bar('foo') + mock.bar.assert_called_with('foo') + self.assertRaises(TypeError, mock.bar, 'foo', 'bar') + self.assertRaises(AttributeError, getattr, mock.bar, 'foo') + + mock.sorted([1, 2]) + mock.sorted.assert_called_with([1, 2]) + self.assertRaises(AttributeError, getattr, mock.sorted, 'foo') + + mock.attr.pop(3) + mock.attr.pop.assert_called_with(3) + self.assertRaises(AttributeError, getattr, mock.attr, 'foo') + + + def test_method_calls(self): + class Sub(SomeClass): + attr = SomeClass() + + mock = create_autospec(Sub) + mock.one(1, 2) + mock.two() + mock.three(3) + + expected = [call.one(1, 2), call.two(), call.three(3)] + self.assertEqual(mock.method_calls, expected) + + mock.attr.one(1, 2) + mock.attr.two() + mock.attr.three(3) + + expected.extend( + [call.attr.one(1, 2), call.attr.two(), call.attr.three(3)] + ) + self.assertEqual(mock.method_calls, expected) + + + def test_magic_methods(self): + class BuiltinSubclass(list): + attr = {} + + mock = create_autospec(BuiltinSubclass) + self.assertEqual(list(mock), []) + self.assertRaises(TypeError, int, mock) + self.assertRaises(TypeError, int, mock.attr) + self.assertEqual(list(mock), []) + + self.assertIsInstance(mock['foo'], MagicMock) + self.assertIsInstance(mock.attr['foo'], MagicMock) + + + def test_spec_set(self): + class Sub(SomeClass): + attr = SomeClass() + + for spec in (Sub, Sub()): + mock = create_autospec(spec, spec_set=True) + self._check_someclass_mock(mock) + + self.assertRaises(AttributeError, setattr, mock, 'foo', 'bar') + self.assertRaises(AttributeError, setattr, mock.attr, 'foo', 'bar') + + + def test_descriptors(self): + class Foo(object): + @classmethod + def f(cls, a, b): + pass + @staticmethod + def g(a, b): + pass + + class Bar(Foo): + pass + + class Baz(SomeClass, Bar): + pass + + for spec in (Foo, Foo(), Bar, Bar(), Baz, Baz()): + mock = create_autospec(spec) + mock.f(1, 2) + mock.f.assert_called_once_with(1, 2) + + mock.g(3, 4) + mock.g.assert_called_once_with(3, 4) + + + def test_recursive(self): + class A(object): + def a(self): + pass + foo = 'foo bar baz' + bar = foo + + A.B = A + mock = create_autospec(A) + + mock() + self.assertFalse(mock.B.called) + + mock.a() + mock.B.a() + self.assertEqual(mock.method_calls, [call.a(), call.B.a()]) + + self.assertIs(A.foo, A.bar) + self.assertIsNot(mock.foo, mock.bar) + mock.foo.lower() + self.assertRaises(AssertionError, mock.bar.lower.assert_called_with) + + + def test_spec_inheritance_for_classes(self): + class Foo(object): + def a(self): + pass + class Bar(object): + def f(self): + pass + + class_mock = create_autospec(Foo) + + self.assertIsNot(class_mock, class_mock()) + + for this_mock in class_mock, class_mock(): + this_mock.a() + this_mock.a.assert_called_with() + self.assertRaises(TypeError, this_mock.a, 'foo') + self.assertRaises(AttributeError, getattr, this_mock, 'b') + + instance_mock = create_autospec(Foo()) + instance_mock.a() + instance_mock.a.assert_called_with() + self.assertRaises(TypeError, instance_mock.a, 'foo') + self.assertRaises(AttributeError, getattr, instance_mock, 'b') + + # The return value isn't isn't callable + self.assertRaises(TypeError, instance_mock) + + instance_mock.Bar.f() + instance_mock.Bar.f.assert_called_with() + self.assertRaises(AttributeError, getattr, instance_mock.Bar, 'g') + + instance_mock.Bar().f() + instance_mock.Bar().f.assert_called_with() + self.assertRaises(AttributeError, getattr, instance_mock.Bar(), 'g') + + + def test_inherit(self): + class Foo(object): + a = 3 + + Foo.Foo = Foo + + # class + mock = create_autospec(Foo) + instance = mock() + self.assertRaises(AttributeError, getattr, instance, 'b') + + attr_instance = mock.Foo() + self.assertRaises(AttributeError, getattr, attr_instance, 'b') + + # instance + mock = create_autospec(Foo()) + self.assertRaises(AttributeError, getattr, mock, 'b') + self.assertRaises(TypeError, mock) + + # attribute instance + call_result = mock.Foo() + self.assertRaises(AttributeError, getattr, call_result, 'b') + + + def test_builtins(self): + # used to fail with infinite recursion + create_autospec(1) + + create_autospec(int) + create_autospec('foo') + create_autospec(str) + create_autospec({}) + create_autospec(dict) + create_autospec([]) + create_autospec(list) + create_autospec(set()) + create_autospec(set) + create_autospec(1.0) + create_autospec(float) + create_autospec(1j) + create_autospec(complex) + create_autospec(False) + create_autospec(True) + + + def test_function(self): + def f(a, b): + pass + + mock = create_autospec(f) + self.assertRaises(TypeError, mock) + mock(1, 2) + mock.assert_called_with(1, 2) + + f.f = f + mock = create_autospec(f) + self.assertRaises(TypeError, mock.f) + mock.f(3, 4) + mock.f.assert_called_with(3, 4) + + + def test_signature_class(self): + class Foo(object): + def __init__(self, a, b=3): + pass + + mock = create_autospec(Foo) + + self.assertRaises(TypeError, mock) + mock(1) + mock.assert_called_once_with(1) + + mock(4, 5) + mock.assert_called_with(4, 5) + + + def test_class_with_no_init(self): + # this used to raise an exception + # due to trying to get a signature from object.__init__ + class Foo(object): + pass + create_autospec(Foo) + + + def test_signature_callable(self): + class Callable(object): + def __init__(self): + pass + def __call__(self, a): + pass + + mock = create_autospec(Callable) + mock() + mock.assert_called_once_with() + self.assertRaises(TypeError, mock, 'a') + + instance = mock() + self.assertRaises(TypeError, instance) + instance(a='a') + instance.assert_called_once_with(a='a') + instance('a') + instance.assert_called_with('a') + + mock = create_autospec(Callable()) + mock(a='a') + mock.assert_called_once_with(a='a') + self.assertRaises(TypeError, mock) + mock('a') + mock.assert_called_with('a') + + + def test_signature_noncallable(self): + class NonCallable(object): + def __init__(self): + pass + + mock = create_autospec(NonCallable) + instance = mock() + mock.assert_called_once_with() + self.assertRaises(TypeError, mock, 'a') + self.assertRaises(TypeError, instance) + self.assertRaises(TypeError, instance, 'a') + + mock = create_autospec(NonCallable()) + self.assertRaises(TypeError, mock) + self.assertRaises(TypeError, mock, 'a') + + + def test_create_autospec_none(self): + class Foo(object): + bar = None + + mock = create_autospec(Foo) + none = mock.bar + self.assertNotIsInstance(none, type(None)) + + none.foo() + none.foo.assert_called_once_with() + + + def test_autospec_functions_with_self_in_odd_place(self): + class Foo(object): + def f(a, self): + pass + + a = create_autospec(Foo) + a.f(self=10) + a.f.assert_called_with(self=10) + + + def test_autospec_property(self): + class Foo(object): + @property + def foo(self): + return 3 + + foo = create_autospec(Foo) + mock_property = foo.foo + + # no spec on properties + self.assertTrue(isinstance(mock_property, MagicMock)) + mock_property(1, 2, 3) + mock_property.abc(4, 5, 6) + mock_property.assert_called_once_with(1, 2, 3) + mock_property.abc.assert_called_once_with(4, 5, 6) + + + def test_autospec_slots(self): + class Foo(object): + __slots__ = ['a'] + + foo = create_autospec(Foo) + mock_slot = foo.a + + # no spec on slots + mock_slot(1, 2, 3) + mock_slot.abc(4, 5, 6) + mock_slot.assert_called_once_with(1, 2, 3) + mock_slot.abc.assert_called_once_with(4, 5, 6) + + +class TestCallList(unittest.TestCase): + + def test_args_list_contains_call_list(self): + mock = Mock() + self.assertIsInstance(mock.call_args_list, _CallList) + + mock(1, 2) + mock(a=3) + mock(3, 4) + mock(b=6) + + for kall in call(1, 2), call(a=3), call(3, 4), call(b=6): + self.assertTrue(kall in mock.call_args_list) + + calls = [call(a=3), call(3, 4)] + self.assertTrue(calls in mock.call_args_list) + calls = [call(1, 2), call(a=3)] + self.assertTrue(calls in mock.call_args_list) + calls = [call(3, 4), call(b=6)] + self.assertTrue(calls in mock.call_args_list) + calls = [call(3, 4)] + self.assertTrue(calls in mock.call_args_list) + + self.assertFalse(call('fish') in mock.call_args_list) + self.assertFalse([call('fish')] in mock.call_args_list) + + + def test_call_list_str(self): + mock = Mock() + mock(1, 2) + mock.foo(a=3) + mock.foo.bar().baz('fish', cat='dog') + + expected = ( + "[call(1, 2),\n" + " call.foo(a=3),\n" + " call.foo.bar(),\n" + " call.foo.bar().baz('fish', cat='dog')]" + ) + self.assertEqual(str(mock.mock_calls), expected) + + + def test_propertymock(self): + p = patch('%s.SomeClass.one' % __name__, new_callable=PropertyMock) + mock = p.start() + try: + SomeClass.one + mock.assert_called_once_with() + + s = SomeClass() + s.one + mock.assert_called_with() + self.assertEqual(mock.mock_calls, [call(), call()]) + + s.one = 3 + self.assertEqual(mock.mock_calls, [call(), call(), call(3)]) + finally: + p.stop() + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testmagicmethods.py b/Lib/unittest/test/testmock/testmagicmethods.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testmagicmethods.py @@ -0,0 +1,382 @@ +import unittest +import inspect +import sys +from unittest.mock import Mock, MagicMock, _magics + + + +class TestMockingMagicMethods(unittest.TestCase): + + def test_deleting_magic_methods(self): + mock = Mock() + self.assertFalse(hasattr(mock, '__getitem__')) + + mock.__getitem__ = Mock() + self.assertTrue(hasattr(mock, '__getitem__')) + + del mock.__getitem__ + self.assertFalse(hasattr(mock, '__getitem__')) + + + def test_magicmock_del(self): + mock = MagicMock() + # before using getitem + del mock.__getitem__ + self.assertRaises(TypeError, lambda: mock['foo']) + + mock = MagicMock() + # this time use it first + mock['foo'] + del mock.__getitem__ + self.assertRaises(TypeError, lambda: mock['foo']) + + + def test_magic_method_wrapping(self): + mock = Mock() + def f(self, name): + return self, 'fish' + + mock.__getitem__ = f + self.assertFalse(mock.__getitem__ is f) + self.assertEqual(mock['foo'], (mock, 'fish')) + self.assertEqual(mock.__getitem__('foo'), (mock, 'fish')) + + mock.__getitem__ = mock + self.assertTrue(mock.__getitem__ is mock) + + + def test_magic_methods_isolated_between_mocks(self): + mock1 = Mock() + mock2 = Mock() + + mock1.__iter__ = Mock(return_value=iter([])) + self.assertEqual(list(mock1), []) + self.assertRaises(TypeError, lambda: list(mock2)) + + + def test_repr(self): + mock = Mock() + self.assertEqual(repr(mock), "" % id(mock)) + mock.__repr__ = lambda s: 'foo' + self.assertEqual(repr(mock), 'foo') + + + def test_str(self): + mock = Mock() + self.assertEqual(str(mock), object.__str__(mock)) + mock.__str__ = lambda s: 'foo' + self.assertEqual(str(mock), 'foo') + + + def test_dict_methods(self): + mock = Mock() + + self.assertRaises(TypeError, lambda: mock['foo']) + def _del(): + del mock['foo'] + def _set(): + mock['foo'] = 3 + self.assertRaises(TypeError, _del) + self.assertRaises(TypeError, _set) + + _dict = {} + def getitem(s, name): + return _dict[name] + def setitem(s, name, value): + _dict[name] = value + def delitem(s, name): + del _dict[name] + + mock.__setitem__ = setitem + mock.__getitem__ = getitem + mock.__delitem__ = delitem + + self.assertRaises(KeyError, lambda: mock['foo']) + mock['foo'] = 'bar' + self.assertEqual(_dict, {'foo': 'bar'}) + self.assertEqual(mock['foo'], 'bar') + del mock['foo'] + self.assertEqual(_dict, {}) + + + def test_numeric(self): + original = mock = Mock() + mock.value = 0 + + self.assertRaises(TypeError, lambda: mock + 3) + + def add(self, other): + mock.value += other + return self + mock.__add__ = add + self.assertEqual(mock + 3, mock) + self.assertEqual(mock.value, 3) + + del mock.__add__ + def iadd(mock): + mock += 3 + self.assertRaises(TypeError, iadd, mock) + mock.__iadd__ = add + mock += 6 + self.assertEqual(mock, original) + self.assertEqual(mock.value, 9) + + self.assertRaises(TypeError, lambda: 3 + mock) + mock.__radd__ = add + self.assertEqual(7 + mock, mock) + self.assertEqual(mock.value, 16) + + + def test_hash(self): + mock = Mock() + # test delegation + self.assertEqual(hash(mock), Mock.__hash__(mock)) + + def _hash(s): + return 3 + mock.__hash__ = _hash + self.assertEqual(hash(mock), 3) + + + def test_nonzero(self): + m = Mock() + self.assertTrue(bool(m)) + + m.__bool__ = lambda s: False + self.assertFalse(bool(m)) + + + def test_comparison(self): + mock = Mock() + def comp(s, o): + return True + mock.__lt__ = mock.__gt__ = mock.__le__ = mock.__ge__ = comp + self. assertTrue(mock < 3) + self. assertTrue(mock > 3) + self. assertTrue(mock <= 3) + self. assertTrue(mock >= 3) + + + def test_equality(self): + for mock in Mock(), MagicMock(): + self.assertEqual(mock == mock, True) + self.assertIsInstance(mock == mock, bool) + self.assertEqual(mock != mock, False) + self.assertIsInstance(mock != mock, bool) + self.assertEqual(mock == object(), False) + self.assertEqual(mock != object(), True) + + def eq(self, other): + return other == 3 + mock.__eq__ = eq + self.assertTrue(mock == 3) + self.assertFalse(mock == 4) + + def ne(self, other): + return other == 3 + mock.__ne__ = ne + self.assertTrue(mock != 3) + self.assertFalse(mock != 4) + + mock = MagicMock() + mock.__eq__.return_value = True + self.assertIsInstance(mock == 3, bool) + self.assertEqual(mock == 3, True) + + mock.__ne__.return_value = False + self.assertIsInstance(mock != 3, bool) + self.assertEqual(mock != 3, False) + + + def test_len_contains_iter(self): + mock = Mock() + + self.assertRaises(TypeError, len, mock) + self.assertRaises(TypeError, iter, mock) + self.assertRaises(TypeError, lambda: 'foo' in mock) + + mock.__len__ = lambda s: 6 + self.assertEqual(len(mock), 6) + + mock.__contains__ = lambda s, o: o == 3 + self.assertTrue(3 in mock) + self.assertFalse(6 in mock) + + mock.__iter__ = lambda s: iter('foobarbaz') + self.assertEqual(list(mock), list('foobarbaz')) + + + def test_magicmock(self): + mock = MagicMock() + + mock.__iter__.return_value = iter([1, 2, 3]) + self.assertEqual(list(mock), [1, 2, 3]) + + getattr(mock, '__bool__').return_value = False + self.assertFalse(hasattr(mock, '__nonzero__')) + self.assertFalse(bool(mock)) + + for entry in _magics: + self.assertTrue(hasattr(mock, entry)) + self.assertFalse(hasattr(mock, '__imaginery__')) + + + def test_magic_mock_equality(self): + mock = MagicMock() + self.assertIsInstance(mock == object(), bool) + self.assertIsInstance(mock != object(), bool) + + self.assertEqual(mock == object(), False) + self.assertEqual(mock != object(), True) + self.assertEqual(mock == mock, True) + self.assertEqual(mock != mock, False) + + + def test_magicmock_defaults(self): + mock = MagicMock() + self.assertEqual(int(mock), 1) + self.assertEqual(complex(mock), 1j) + self.assertEqual(float(mock), 1.0) + self.assertNotIn(object(), mock) + self.assertEqual(len(mock), 0) + self.assertEqual(list(mock), []) + self.assertEqual(hash(mock), object.__hash__(mock)) + self.assertEqual(str(mock), object.__str__(mock)) + self.assertTrue(bool(mock)) + + # in Python 3 oct and hex use __index__ + # so these tests are for __index__ in py3k + self.assertEqual(oct(mock), '0o1') + self.assertEqual(hex(mock), '0x1') + # how to test __sizeof__ ? + + + def test_magic_methods_and_spec(self): + class Iterable(object): + def __iter__(self): + pass + + mock = Mock(spec=Iterable) + self.assertRaises(AttributeError, lambda: mock.__iter__) + + mock.__iter__ = Mock(return_value=iter([])) + self.assertEqual(list(mock), []) + + class NonIterable(object): + pass + mock = Mock(spec=NonIterable) + self.assertRaises(AttributeError, lambda: mock.__iter__) + + def set_int(): + mock.__int__ = Mock(return_value=iter([])) + self.assertRaises(AttributeError, set_int) + + mock = MagicMock(spec=Iterable) + self.assertEqual(list(mock), []) + self.assertRaises(AttributeError, set_int) + + + def test_magic_methods_and_spec_set(self): + class Iterable(object): + def __iter__(self): + pass + + mock = Mock(spec_set=Iterable) + self.assertRaises(AttributeError, lambda: mock.__iter__) + + mock.__iter__ = Mock(return_value=iter([])) + self.assertEqual(list(mock), []) + + class NonIterable(object): + pass + mock = Mock(spec_set=NonIterable) + self.assertRaises(AttributeError, lambda: mock.__iter__) + + def set_int(): + mock.__int__ = Mock(return_value=iter([])) + self.assertRaises(AttributeError, set_int) + + mock = MagicMock(spec_set=Iterable) + self.assertEqual(list(mock), []) + self.assertRaises(AttributeError, set_int) + + + def test_setting_unsupported_magic_method(self): + mock = MagicMock() + def set_setattr(): + mock.__setattr__ = lambda self, name: None + self.assertRaisesRegex(AttributeError, + "Attempting to set unsupported magic method '__setattr__'.", + set_setattr + ) + + + def test_attributes_and_return_value(self): + mock = MagicMock() + attr = mock.foo + def _get_type(obj): + # the type of every mock (or magicmock) is a custom subclass + # so the real type is the second in the mro + return type(obj).__mro__[1] + self.assertEqual(_get_type(attr), MagicMock) + + returned = mock() + self.assertEqual(_get_type(returned), MagicMock) + + + def test_magic_methods_are_magic_mocks(self): + mock = MagicMock() + self.assertIsInstance(mock.__getitem__, MagicMock) + + mock[1][2].__getitem__.return_value = 3 + self.assertEqual(mock[1][2][3], 3) + + + def test_dir(self): + # overriding the default implementation + for mock in Mock(), MagicMock(): + def _dir(self): + return ['foo'] + mock.__dir__ = _dir + self.assertEqual(dir(mock), ['foo']) + + + @unittest.skipIf('PyPy' in sys.version, "This fails differently on pypy") + def test_bound_methods(self): + m = Mock() + + # XXXX should this be an expected failure instead? + + # this seems like it should work, but is hard to do without introducing + # other api inconsistencies. Failure message could be better though. + m.__iter__ = [3].__iter__ + self.assertRaises(TypeError, iter, m) + + + def test_magic_method_type(self): + class Foo(MagicMock): + pass + + foo = Foo() + self.assertIsInstance(foo.__int__, Foo) + + + def test_descriptor_from_class(self): + m = MagicMock() + type(m).__str__.return_value = 'foo' + self.assertEqual(str(m), 'foo') + + + def test_iterable_as_iter_return_value(self): + m = MagicMock() + m.__iter__.return_value = [1, 2, 3] + self.assertEqual(list(m), [1, 2, 3]) + self.assertEqual(list(m), [1, 2, 3]) + + m.__iter__.return_value = iter([4, 5, 6]) + self.assertEqual(list(m), [4, 5, 6]) + self.assertEqual(list(m), []) + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testmock.py @@ -0,0 +1,1258 @@ +import copy +import sys + +import unittest +from unittest.test.testmock.support import is_instance +from unittest import mock +from unittest.mock import ( + call, DEFAULT, patch, sentinel, + MagicMock, Mock, NonCallableMock, + NonCallableMagicMock, _CallList, + create_autospec +) + + +class Iter(object): + def __init__(self): + self.thing = iter(['this', 'is', 'an', 'iter']) + + def __iter__(self): + return self + + def next(self): + return next(self.thing) + + __next__ = next + + + +class MockTest(unittest.TestCase): + + def test_all(self): + # if __all__ is badly defined then import * will raise an error + # We have to exec it because you can't import * inside a method + # in Python 3 + exec("from mock import *") + + + def test_constructor(self): + mock = Mock() + + self.assertFalse(mock.called, "called not initialised correctly") + self.assertEqual(mock.call_count, 0, + "call_count not initialised correctly") + self.assertTrue(is_instance(mock.return_value, Mock), + "return_value not initialised correctly") + + self.assertEqual(mock.call_args, None, + "call_args not initialised correctly") + self.assertEqual(mock.call_args_list, [], + "call_args_list not initialised correctly") + self.assertEqual(mock.method_calls, [], + "method_calls not initialised correctly") + + # Can't use hasattr for this test as it always returns True on a mock + self.assertFalse('_items' in mock.__dict__, + "default mock should not have '_items' attribute") + + self.assertIsNone(mock._mock_parent, + "parent not initialised correctly") + self.assertIsNone(mock._mock_methods, + "methods not initialised correctly") + self.assertEqual(mock._mock_children, {}, + "children not initialised incorrectly") + + + def test_return_value_in_constructor(self): + mock = Mock(return_value=None) + self.assertIsNone(mock.return_value, + "return value in constructor not honoured") + + + def test_repr(self): + mock = Mock(name='foo') + self.assertIn('foo', repr(mock)) + self.assertIn("'%s'" % id(mock), repr(mock)) + + mocks = [(Mock(), 'mock'), (Mock(name='bar'), 'bar')] + for mock, name in mocks: + self.assertIn('%s.bar' % name, repr(mock.bar)) + self.assertIn('%s.foo()' % name, repr(mock.foo())) + self.assertIn('%s.foo().bing' % name, repr(mock.foo().bing)) + self.assertIn('%s()' % name, repr(mock())) + self.assertIn('%s()()' % name, repr(mock()())) + self.assertIn('%s()().foo.bar.baz().bing' % name, + repr(mock()().foo.bar.baz().bing)) + + + def test_repr_with_spec(self): + class X(object): + pass + + mock = Mock(spec=X) + self.assertIn(" spec='X' ", repr(mock)) + + mock = Mock(spec=X()) + self.assertIn(" spec='X' ", repr(mock)) + + mock = Mock(spec_set=X) + self.assertIn(" spec_set='X' ", repr(mock)) + + mock = Mock(spec_set=X()) + self.assertIn(" spec_set='X' ", repr(mock)) + + mock = Mock(spec=X, name='foo') + self.assertIn(" spec='X' ", repr(mock)) + self.assertIn(" name='foo' ", repr(mock)) + + mock = Mock(name='foo') + self.assertNotIn("spec", repr(mock)) + + mock = Mock() + self.assertNotIn("spec", repr(mock)) + + mock = Mock(spec=['foo']) + self.assertNotIn("spec", repr(mock)) + + + def test_side_effect(self): + mock = Mock() + + def effect(*args, **kwargs): + raise SystemError('kablooie') + + mock.side_effect = effect + self.assertRaises(SystemError, mock, 1, 2, fish=3) + mock.assert_called_with(1, 2, fish=3) + + results = [1, 2, 3] + def effect(): + return results.pop() + mock.side_effect = effect + + self.assertEqual([mock(), mock(), mock()], [3, 2, 1], + "side effect not used correctly") + + mock = Mock(side_effect=sentinel.SideEffect) + self.assertEqual(mock.side_effect, sentinel.SideEffect, + "side effect in constructor not used") + + def side_effect(): + return DEFAULT + mock = Mock(side_effect=side_effect, return_value=sentinel.RETURN) + self.assertEqual(mock(), sentinel.RETURN) + + + @unittest.skipUnless('java' in sys.platform, + 'This test only applies to Jython') + def test_java_exception_side_effect(self): + import java + mock = Mock(side_effect=java.lang.RuntimeException("Boom!")) + + # can't use assertRaises with java exceptions + try: + mock(1, 2, fish=3) + except java.lang.RuntimeException: + pass + else: + self.fail('java exception not raised') + mock.assert_called_with(1,2, fish=3) + + + def test_reset_mock(self): + parent = Mock() + spec = ["something"] + mock = Mock(name="child", parent=parent, spec=spec) + mock(sentinel.Something, something=sentinel.SomethingElse) + something = mock.something + mock.something() + mock.side_effect = sentinel.SideEffect + return_value = mock.return_value + return_value() + + mock.reset_mock() + + self.assertEqual(mock._mock_name, "child", + "name incorrectly reset") + self.assertEqual(mock._mock_parent, parent, + "parent incorrectly reset") + self.assertEqual(mock._mock_methods, spec, + "methods incorrectly reset") + + self.assertFalse(mock.called, "called not reset") + self.assertEqual(mock.call_count, 0, "call_count not reset") + self.assertEqual(mock.call_args, None, "call_args not reset") + self.assertEqual(mock.call_args_list, [], "call_args_list not reset") + self.assertEqual(mock.method_calls, [], + "method_calls not initialised correctly: %r != %r" % + (mock.method_calls, [])) + self.assertEqual(mock.mock_calls, []) + + self.assertEqual(mock.side_effect, sentinel.SideEffect, + "side_effect incorrectly reset") + self.assertEqual(mock.return_value, return_value, + "return_value incorrectly reset") + self.assertFalse(return_value.called, "return value mock not reset") + self.assertEqual(mock._mock_children, {'something': something}, + "children reset incorrectly") + self.assertEqual(mock.something, something, + "children incorrectly cleared") + self.assertFalse(mock.something.called, "child not reset") + + + def test_reset_mock_recursion(self): + mock = Mock() + mock.return_value = mock + + # used to cause recursion + mock.reset_mock() + + + def test_call(self): + mock = Mock() + self.assertTrue(is_instance(mock.return_value, Mock), + "Default return_value should be a Mock") + + result = mock() + self.assertEqual(mock(), result, + "different result from consecutive calls") + mock.reset_mock() + + ret_val = mock(sentinel.Arg) + self.assertTrue(mock.called, "called not set") + self.assertEqual(mock.call_count, 1, "call_count incoreect") + self.assertEqual(mock.call_args, ((sentinel.Arg,), {}), + "call_args not set") + self.assertEqual(mock.call_args_list, [((sentinel.Arg,), {})], + "call_args_list not initialised correctly") + + mock.return_value = sentinel.ReturnValue + ret_val = mock(sentinel.Arg, key=sentinel.KeyArg) + self.assertEqual(ret_val, sentinel.ReturnValue, + "incorrect return value") + + self.assertEqual(mock.call_count, 2, "call_count incorrect") + self.assertEqual(mock.call_args, + ((sentinel.Arg,), {'key': sentinel.KeyArg}), + "call_args not set") + self.assertEqual(mock.call_args_list, [ + ((sentinel.Arg,), {}), + ((sentinel.Arg,), {'key': sentinel.KeyArg}) + ], + "call_args_list not set") + + + def test_call_args_comparison(self): + mock = Mock() + mock() + mock(sentinel.Arg) + mock(kw=sentinel.Kwarg) + mock(sentinel.Arg, kw=sentinel.Kwarg) + self.assertEqual(mock.call_args_list, [ + (), + ((sentinel.Arg,),), + ({"kw": sentinel.Kwarg},), + ((sentinel.Arg,), {"kw": sentinel.Kwarg}) + ]) + self.assertEqual(mock.call_args, + ((sentinel.Arg,), {"kw": sentinel.Kwarg})) + + + def test_assert_called_with(self): + mock = Mock() + mock() + + # Will raise an exception if it fails + mock.assert_called_with() + self.assertRaises(AssertionError, mock.assert_called_with, 1) + + mock.reset_mock() + self.assertRaises(AssertionError, mock.assert_called_with) + + mock(1, 2, 3, a='fish', b='nothing') + mock.assert_called_with(1, 2, 3, a='fish', b='nothing') + + + def test_assert_called_once_with(self): + mock = Mock() + mock() + + # Will raise an exception if it fails + mock.assert_called_once_with() + + mock() + self.assertRaises(AssertionError, mock.assert_called_once_with) + + mock.reset_mock() + self.assertRaises(AssertionError, mock.assert_called_once_with) + + mock('foo', 'bar', baz=2) + mock.assert_called_once_with('foo', 'bar', baz=2) + + mock.reset_mock() + mock('foo', 'bar', baz=2) + self.assertRaises( + AssertionError, + lambda: mock.assert_called_once_with('bob', 'bar', baz=2) + ) + + + def test_attribute_access_returns_mocks(self): + mock = Mock() + something = mock.something + self.assertTrue(is_instance(something, Mock), "attribute isn't a mock") + self.assertEqual(mock.something, something, + "different attributes returned for same name") + + # Usage example + mock = Mock() + mock.something.return_value = 3 + + self.assertEqual(mock.something(), 3, "method returned wrong value") + self.assertTrue(mock.something.called, + "method didn't record being called") + + + def test_attributes_have_name_and_parent_set(self): + mock = Mock() + something = mock.something + + self.assertEqual(something._mock_name, "something", + "attribute name not set correctly") + self.assertEqual(something._mock_parent, mock, + "attribute parent not set correctly") + + + def test_method_calls_recorded(self): + mock = Mock() + mock.something(3, fish=None) + mock.something_else.something(6, cake=sentinel.Cake) + + self.assertEqual(mock.something_else.method_calls, + [("something", (6,), {'cake': sentinel.Cake})], + "method calls not recorded correctly") + self.assertEqual(mock.method_calls, [ + ("something", (3,), {'fish': None}), + ("something_else.something", (6,), {'cake': sentinel.Cake}) + ], + "method calls not recorded correctly") + + + def test_method_calls_compare_easily(self): + mock = Mock() + mock.something() + self.assertEqual(mock.method_calls, [('something',)]) + self.assertEqual(mock.method_calls, [('something', (), {})]) + + mock = Mock() + mock.something('different') + self.assertEqual(mock.method_calls, [('something', ('different',))]) + self.assertEqual(mock.method_calls, + [('something', ('different',), {})]) + + mock = Mock() + mock.something(x=1) + self.assertEqual(mock.method_calls, [('something', {'x': 1})]) + self.assertEqual(mock.method_calls, [('something', (), {'x': 1})]) + + mock = Mock() + mock.something('different', some='more') + self.assertEqual(mock.method_calls, [ + ('something', ('different',), {'some': 'more'}) + ]) + + + def test_only_allowed_methods_exist(self): + for spec in ['something'], ('something',): + for arg in 'spec', 'spec_set': + mock = Mock(**{arg: spec}) + + # this should be allowed + mock.something + self.assertRaisesRegex( + AttributeError, + "Mock object has no attribute 'something_else'", + getattr, mock, 'something_else' + ) + + + def test_from_spec(self): + class Something(object): + x = 3 + __something__ = None + def y(self): + pass + + def test_attributes(mock): + # should work + mock.x + mock.y + mock.__something__ + self.assertRaisesRegex( + AttributeError, + "Mock object has no attribute 'z'", + getattr, mock, 'z' + ) + self.assertRaisesRegex( + AttributeError, + "Mock object has no attribute '__foobar__'", + getattr, mock, '__foobar__' + ) + + test_attributes(Mock(spec=Something)) + test_attributes(Mock(spec=Something())) + + + def test_wraps_calls(self): + real = Mock() + + mock = Mock(wraps=real) + self.assertEqual(mock(), real()) + + real.reset_mock() + + mock(1, 2, fish=3) + real.assert_called_with(1, 2, fish=3) + + + def test_wraps_call_with_nondefault_return_value(self): + real = Mock() + + mock = Mock(wraps=real) + mock.return_value = 3 + + self.assertEqual(mock(), 3) + self.assertFalse(real.called) + + + def test_wraps_attributes(self): + class Real(object): + attribute = Mock() + + real = Real() + + mock = Mock(wraps=real) + self.assertEqual(mock.attribute(), real.attribute()) + self.assertRaises(AttributeError, lambda: mock.fish) + + self.assertNotEqual(mock.attribute, real.attribute) + result = mock.attribute.frog(1, 2, fish=3) + Real.attribute.frog.assert_called_with(1, 2, fish=3) + self.assertEqual(result, Real.attribute.frog()) + + + def test_exceptional_side_effect(self): + mock = Mock(side_effect=AttributeError) + self.assertRaises(AttributeError, mock) + + mock = Mock(side_effect=AttributeError('foo')) + self.assertRaises(AttributeError, mock) + + + def test_baseexceptional_side_effect(self): + mock = Mock(side_effect=KeyboardInterrupt) + self.assertRaises(KeyboardInterrupt, mock) + + mock = Mock(side_effect=KeyboardInterrupt('foo')) + self.assertRaises(KeyboardInterrupt, mock) + + + def test_assert_called_with_message(self): + mock = Mock() + self.assertRaisesRegex(AssertionError, 'Not called', + mock.assert_called_with) + + + def test__name__(self): + mock = Mock() + self.assertRaises(AttributeError, lambda: mock.__name__) + + mock.__name__ = 'foo' + self.assertEqual(mock.__name__, 'foo') + + + def test_spec_list_subclass(self): + class Sub(list): + pass + mock = Mock(spec=Sub(['foo'])) + + mock.append(3) + mock.append.assert_called_with(3) + self.assertRaises(AttributeError, getattr, mock, 'foo') + + + def test_spec_class(self): + class X(object): + pass + + mock = Mock(spec=X) + self.assertTrue(isinstance(mock, X)) + + mock = Mock(spec=X()) + self.assertTrue(isinstance(mock, X)) + + self.assertIs(mock.__class__, X) + self.assertEqual(Mock().__class__.__name__, 'Mock') + + mock = Mock(spec_set=X) + self.assertTrue(isinstance(mock, X)) + + mock = Mock(spec_set=X()) + self.assertTrue(isinstance(mock, X)) + + + def test_setting_attribute_with_spec_set(self): + class X(object): + y = 3 + + mock = Mock(spec=X) + mock.x = 'foo' + + mock = Mock(spec_set=X) + def set_attr(): + mock.x = 'foo' + + mock.y = 'foo' + self.assertRaises(AttributeError, set_attr) + + + def test_copy(self): + current = sys.getrecursionlimit() + self.addCleanup(sys.setrecursionlimit, current) + + # can't use sys.maxint as this doesn't exist in Python 3 + sys.setrecursionlimit(int(10e8)) + # this segfaults without the fix in place + copy.copy(Mock()) + + + def test_subclass_with_properties(self): + class SubClass(Mock): + def _get(self): + return 3 + def _set(self, value): + raise NameError('strange error') + some_attribute = property(_get, _set) + + s = SubClass(spec_set=SubClass) + self.assertEqual(s.some_attribute, 3) + + def test(): + s.some_attribute = 3 + self.assertRaises(NameError, test) + + def test(): + s.foo = 'bar' + self.assertRaises(AttributeError, test) + + + def test_setting_call(self): + mock = Mock() + def __call__(self, a): + return self._mock_call(a) + + type(mock).__call__ = __call__ + mock('one') + mock.assert_called_with('one') + + self.assertRaises(TypeError, mock, 'one', 'two') + + + def test_dir(self): + mock = Mock() + attrs = set(dir(mock)) + type_attrs = set([m for m in dir(Mock) if not m.startswith('_')]) + + # all public attributes from the type are included + self.assertEqual(set(), type_attrs - attrs) + + # creates these attributes + mock.a, mock.b + self.assertIn('a', dir(mock)) + self.assertIn('b', dir(mock)) + + # instance attributes + mock.c = mock.d = None + self.assertIn('c', dir(mock)) + self.assertIn('d', dir(mock)) + + # magic methods + mock.__iter__ = lambda s: iter([]) + self.assertIn('__iter__', dir(mock)) + + + def test_dir_from_spec(self): + mock = Mock(spec=unittest.TestCase) + testcase_attrs = set(dir(unittest.TestCase)) + attrs = set(dir(mock)) + + # all attributes from the spec are included + self.assertEqual(set(), testcase_attrs - attrs) + + # shadow a sys attribute + mock.version = 3 + self.assertEqual(dir(mock).count('version'), 1) + + + def test_filter_dir(self): + patcher = patch.object(mock, 'FILTER_DIR', False) + patcher.start() + try: + attrs = set(dir(Mock())) + type_attrs = set(dir(Mock)) + + # ALL attributes from the type are included + self.assertEqual(set(), type_attrs - attrs) + finally: + patcher.stop() + + + def test_configure_mock(self): + mock = Mock(foo='bar') + self.assertEqual(mock.foo, 'bar') + + mock = MagicMock(foo='bar') + self.assertEqual(mock.foo, 'bar') + + kwargs = {'side_effect': KeyError, 'foo.bar.return_value': 33, + 'foo': MagicMock()} + mock = Mock(**kwargs) + self.assertRaises(KeyError, mock) + self.assertEqual(mock.foo.bar(), 33) + self.assertIsInstance(mock.foo, MagicMock) + + mock = Mock() + mock.configure_mock(**kwargs) + self.assertRaises(KeyError, mock) + self.assertEqual(mock.foo.bar(), 33) + self.assertIsInstance(mock.foo, MagicMock) + + + def assertRaisesWithMsg(self, exception, message, func, *args, **kwargs): + # needed because assertRaisesRegex doesn't work easily with newlines + try: + func(*args, **kwargs) + except: + instance = sys.exc_info()[1] + self.assertIsInstance(instance, exception) + else: + self.fail('Exception %r not raised' % (exception,)) + + msg = str(instance) + self.assertEqual(msg, message) + + + def test_assert_called_with_failure_message(self): + mock = NonCallableMock() + + expected = "mock(1, '2', 3, bar='foo')" + message = 'Expected call: %s\nNot called' + self.assertRaisesWithMsg( + AssertionError, message % (expected,), + mock.assert_called_with, 1, '2', 3, bar='foo' + ) + + mock.foo(1, '2', 3, foo='foo') + + + asserters = [ + mock.foo.assert_called_with, mock.foo.assert_called_once_with + ] + for meth in asserters: + actual = "foo(1, '2', 3, foo='foo')" + expected = "foo(1, '2', 3, bar='foo')" + message = 'Expected call: %s\nActual call: %s' + self.assertRaisesWithMsg( + AssertionError, message % (expected, actual), + meth, 1, '2', 3, bar='foo' + ) + + # just kwargs + for meth in asserters: + actual = "foo(1, '2', 3, foo='foo')" + expected = "foo(bar='foo')" + message = 'Expected call: %s\nActual call: %s' + self.assertRaisesWithMsg( + AssertionError, message % (expected, actual), + meth, bar='foo' + ) + + # just args + for meth in asserters: + actual = "foo(1, '2', 3, foo='foo')" + expected = "foo(1, 2, 3)" + message = 'Expected call: %s\nActual call: %s' + self.assertRaisesWithMsg( + AssertionError, message % (expected, actual), + meth, 1, 2, 3 + ) + + # empty + for meth in asserters: + actual = "foo(1, '2', 3, foo='foo')" + expected = "foo()" + message = 'Expected call: %s\nActual call: %s' + self.assertRaisesWithMsg( + AssertionError, message % (expected, actual), meth + ) + + + def test_mock_calls(self): + mock = MagicMock() + + # need to do this because MagicMock.mock_calls used to just return + # a MagicMock which also returned a MagicMock when __eq__ was called + self.assertIs(mock.mock_calls == [], True) + + mock = MagicMock() + mock() + expected = [('', (), {})] + self.assertEqual(mock.mock_calls, expected) + + mock.foo() + expected.append(call.foo()) + self.assertEqual(mock.mock_calls, expected) + # intermediate mock_calls work too + self.assertEqual(mock.foo.mock_calls, [('', (), {})]) + + mock = MagicMock() + mock().foo(1, 2, 3, a=4, b=5) + expected = [ + ('', (), {}), ('().foo', (1, 2, 3), dict(a=4, b=5)) + ] + self.assertEqual(mock.mock_calls, expected) + self.assertEqual(mock.return_value.foo.mock_calls, + [('', (1, 2, 3), dict(a=4, b=5))]) + self.assertEqual(mock.return_value.mock_calls, + [('foo', (1, 2, 3), dict(a=4, b=5))]) + + mock = MagicMock() + mock().foo.bar().baz() + expected = [ + ('', (), {}), ('().foo.bar', (), {}), + ('().foo.bar().baz', (), {}) + ] + self.assertEqual(mock.mock_calls, expected) + self.assertEqual(mock().mock_calls, + call.foo.bar().baz().call_list()) + + for kwargs in dict(), dict(name='bar'): + mock = MagicMock(**kwargs) + int(mock.foo) + expected = [('foo.__int__', (), {})] + self.assertEqual(mock.mock_calls, expected) + + mock = MagicMock(**kwargs) + mock.a()() + expected = [('a', (), {}), ('a()', (), {})] + self.assertEqual(mock.mock_calls, expected) + self.assertEqual(mock.a().mock_calls, [call()]) + + mock = MagicMock(**kwargs) + mock(1)(2)(3) + self.assertEqual(mock.mock_calls, call(1)(2)(3).call_list()) + self.assertEqual(mock().mock_calls, call(2)(3).call_list()) + self.assertEqual(mock()().mock_calls, call(3).call_list()) + + mock = MagicMock(**kwargs) + mock(1)(2)(3).a.b.c(4) + self.assertEqual(mock.mock_calls, + call(1)(2)(3).a.b.c(4).call_list()) + self.assertEqual(mock().mock_calls, + call(2)(3).a.b.c(4).call_list()) + self.assertEqual(mock()().mock_calls, + call(3).a.b.c(4).call_list()) + + mock = MagicMock(**kwargs) + int(mock().foo.bar().baz()) + last_call = ('().foo.bar().baz().__int__', (), {}) + self.assertEqual(mock.mock_calls[-1], last_call) + self.assertEqual(mock().mock_calls, + call.foo.bar().baz().__int__().call_list()) + self.assertEqual(mock().foo.bar().mock_calls, + call.baz().__int__().call_list()) + self.assertEqual(mock().foo.bar().baz.mock_calls, + call().__int__().call_list()) + + + def test_subclassing(self): + class Subclass(Mock): + pass + + mock = Subclass() + self.assertIsInstance(mock.foo, Subclass) + self.assertIsInstance(mock(), Subclass) + + class Subclass(Mock): + def _get_child_mock(self, **kwargs): + return Mock(**kwargs) + + mock = Subclass() + self.assertNotIsInstance(mock.foo, Subclass) + self.assertNotIsInstance(mock(), Subclass) + + + def test_arg_lists(self): + mocks = [ + Mock(), + MagicMock(), + NonCallableMock(), + NonCallableMagicMock() + ] + + def assert_attrs(mock): + names = 'call_args_list', 'method_calls', 'mock_calls' + for name in names: + attr = getattr(mock, name) + self.assertIsInstance(attr, _CallList) + self.assertIsInstance(attr, list) + self.assertEqual(attr, []) + + for mock in mocks: + assert_attrs(mock) + + if callable(mock): + mock() + mock(1, 2) + mock(a=3) + + mock.reset_mock() + assert_attrs(mock) + + mock.foo() + mock.foo.bar(1, a=3) + mock.foo(1).bar().baz(3) + + mock.reset_mock() + assert_attrs(mock) + + + def test_call_args_two_tuple(self): + mock = Mock() + mock(1, a=3) + mock(2, b=4) + + self.assertEqual(len(mock.call_args), 2) + args, kwargs = mock.call_args + self.assertEqual(args, (2,)) + self.assertEqual(kwargs, dict(b=4)) + + expected_list = [((1,), dict(a=3)), ((2,), dict(b=4))] + for expected, call_args in zip(expected_list, mock.call_args_list): + self.assertEqual(len(call_args), 2) + self.assertEqual(expected[0], call_args[0]) + self.assertEqual(expected[1], call_args[1]) + + + def test_side_effect_iterator(self): + mock = Mock(side_effect=iter([1, 2, 3])) + self.assertEqual([mock(), mock(), mock()], [1, 2, 3]) + self.assertRaises(StopIteration, mock) + + mock = MagicMock(side_effect=['a', 'b', 'c']) + self.assertEqual([mock(), mock(), mock()], ['a', 'b', 'c']) + self.assertRaises(StopIteration, mock) + + mock = Mock(side_effect='ghi') + self.assertEqual([mock(), mock(), mock()], ['g', 'h', 'i']) + self.assertRaises(StopIteration, mock) + + class Foo(object): + pass + mock = MagicMock(side_effect=Foo) + self.assertIsInstance(mock(), Foo) + + mock = Mock(side_effect=Iter()) + self.assertEqual([mock(), mock(), mock(), mock()], + ['this', 'is', 'an', 'iter']) + self.assertRaises(StopIteration, mock) + + + def test_side_effect_setting_iterator(self): + mock = Mock() + mock.side_effect = iter([1, 2, 3]) + self.assertEqual([mock(), mock(), mock()], [1, 2, 3]) + self.assertRaises(StopIteration, mock) + side_effect = mock.side_effect + self.assertIsInstance(side_effect, type(iter([]))) + + mock.side_effect = ['a', 'b', 'c'] + self.assertEqual([mock(), mock(), mock()], ['a', 'b', 'c']) + self.assertRaises(StopIteration, mock) + side_effect = mock.side_effect + self.assertIsInstance(side_effect, type(iter([]))) + + this_iter = Iter() + mock.side_effect = this_iter + self.assertEqual([mock(), mock(), mock(), mock()], + ['this', 'is', 'an', 'iter']) + self.assertRaises(StopIteration, mock) + self.assertIs(mock.side_effect, this_iter) + + + def test_assert_has_calls_any_order(self): + mock = Mock() + mock(1, 2) + mock(a=3) + mock(3, 4) + mock(b=6) + mock(b=6) + + kalls = [ + call(1, 2), ({'a': 3},), + ((3, 4),), ((), {'a': 3}), + ('', (1, 2)), ('', {'a': 3}), + ('', (1, 2), {}), ('', (), {'a': 3}) + ] + for kall in kalls: + mock.assert_has_calls([kall], any_order=True) + + for kall in call(1, '2'), call(b=3), call(), 3, None, 'foo': + self.assertRaises( + AssertionError, mock.assert_has_calls, + [kall], any_order=True + ) + + kall_lists = [ + [call(1, 2), call(b=6)], + [call(3, 4), call(1, 2)], + [call(b=6), call(b=6)], + ] + + for kall_list in kall_lists: + mock.assert_has_calls(kall_list, any_order=True) + + kall_lists = [ + [call(b=6), call(b=6), call(b=6)], + [call(1, 2), call(1, 2)], + [call(3, 4), call(1, 2), call(5, 7)], + [call(b=6), call(3, 4), call(b=6), call(1, 2), call(b=6)], + ] + for kall_list in kall_lists: + self.assertRaises( + AssertionError, mock.assert_has_calls, + kall_list, any_order=True + ) + + def test_assert_has_calls(self): + kalls1 = [ + call(1, 2), ({'a': 3},), + ((3, 4),), call(b=6), + ('', (1,), {'b': 6}), + ] + kalls2 = [call.foo(), call.bar(1)] + kalls2.extend(call.spam().baz(a=3).call_list()) + kalls2.extend(call.bam(set(), foo={}).fish([1]).call_list()) + + mocks = [] + for mock in Mock(), MagicMock(): + mock(1, 2) + mock(a=3) + mock(3, 4) + mock(b=6) + mock(1, b=6) + mocks.append((mock, kalls1)) + + mock = Mock() + mock.foo() + mock.bar(1) + mock.spam().baz(a=3) + mock.bam(set(), foo={}).fish([1]) + mocks.append((mock, kalls2)) + + for mock, kalls in mocks: + for i in range(len(kalls)): + for step in 1, 2, 3: + these = kalls[i:i+step] + mock.assert_has_calls(these) + + if len(these) > 1: + self.assertRaises( + AssertionError, + mock.assert_has_calls, + list(reversed(these)) + ) + + + def test_assert_any_call(self): + mock = Mock() + mock(1, 2) + mock(a=3) + mock(1, b=6) + + mock.assert_any_call(1, 2) + mock.assert_any_call(a=3) + mock.assert_any_call(1, b=6) + + self.assertRaises( + AssertionError, + mock.assert_any_call + ) + self.assertRaises( + AssertionError, + mock.assert_any_call, + 1, 3 + ) + self.assertRaises( + AssertionError, + mock.assert_any_call, + a=4 + ) + + + def test_mock_calls_create_autospec(self): + def f(a, b): + pass + obj = Iter() + obj.f = f + + funcs = [ + create_autospec(f), + create_autospec(obj).f + ] + for func in funcs: + func(1, 2) + func(3, 4) + + self.assertEqual( + func.mock_calls, [call(1, 2), call(3, 4)] + ) + + + def test_mock_add_spec(self): + class _One(object): + one = 1 + class _Two(object): + two = 2 + class Anything(object): + one = two = three = 'four' + + klasses = [ + Mock, MagicMock, NonCallableMock, NonCallableMagicMock + ] + for Klass in list(klasses): + klasses.append(lambda K=Klass: K(spec=Anything)) + klasses.append(lambda K=Klass: K(spec_set=Anything)) + + for Klass in klasses: + for kwargs in dict(), dict(spec_set=True): + mock = Klass() + #no error + mock.one, mock.two, mock.three + + for One, Two in [(_One, _Two), (['one'], ['two'])]: + for kwargs in dict(), dict(spec_set=True): + mock.mock_add_spec(One, **kwargs) + + mock.one + self.assertRaises( + AttributeError, getattr, mock, 'two' + ) + self.assertRaises( + AttributeError, getattr, mock, 'three' + ) + if 'spec_set' in kwargs: + self.assertRaises( + AttributeError, setattr, mock, 'three', None + ) + + mock.mock_add_spec(Two, **kwargs) + self.assertRaises( + AttributeError, getattr, mock, 'one' + ) + mock.two + self.assertRaises( + AttributeError, getattr, mock, 'three' + ) + if 'spec_set' in kwargs: + self.assertRaises( + AttributeError, setattr, mock, 'three', None + ) + # note that creating a mock, setting an instance attribute, and + # *then* setting a spec doesn't work. Not the intended use case + + + def test_mock_add_spec_magic_methods(self): + for Klass in MagicMock, NonCallableMagicMock: + mock = Klass() + int(mock) + + mock.mock_add_spec(object) + self.assertRaises(TypeError, int, mock) + + mock = Klass() + mock['foo'] + mock.__int__.return_value =4 + + mock.mock_add_spec(int) + self.assertEqual(int(mock), 4) + self.assertRaises(TypeError, lambda: mock['foo']) + + + def test_adding_child_mock(self): + for Klass in NonCallableMock, Mock, MagicMock, NonCallableMagicMock: + mock = Klass() + + mock.foo = Mock() + mock.foo() + + self.assertEqual(mock.method_calls, [call.foo()]) + self.assertEqual(mock.mock_calls, [call.foo()]) + + mock = Klass() + mock.bar = Mock(name='name') + mock.bar() + self.assertEqual(mock.method_calls, []) + self.assertEqual(mock.mock_calls, []) + + # mock with an existing _new_parent but no name + mock = Klass() + mock.baz = MagicMock()() + mock.baz() + self.assertEqual(mock.method_calls, []) + self.assertEqual(mock.mock_calls, []) + + + def test_adding_return_value_mock(self): + for Klass in Mock, MagicMock: + mock = Klass() + mock.return_value = MagicMock() + + mock()() + self.assertEqual(mock.mock_calls, [call(), call()()]) + + + def test_manager_mock(self): + class Foo(object): + one = 'one' + two = 'two' + manager = Mock() + p1 = patch.object(Foo, 'one') + p2 = patch.object(Foo, 'two') + + mock_one = p1.start() + self.addCleanup(p1.stop) + mock_two = p2.start() + self.addCleanup(p2.stop) + + manager.attach_mock(mock_one, 'one') + manager.attach_mock(mock_two, 'two') + + Foo.two() + Foo.one() + + self.assertEqual(manager.mock_calls, [call.two(), call.one()]) + + + def test_magic_methods_mock_calls(self): + for Klass in Mock, MagicMock: + m = Klass() + m.__int__ = Mock(return_value=3) + m.__float__ = MagicMock(return_value=3.0) + int(m) + float(m) + + self.assertEqual(m.mock_calls, [call.__int__(), call.__float__()]) + self.assertEqual(m.method_calls, []) + + + def test_attribute_deletion(self): + # this behaviour isn't *useful*, but at least it's now tested... + for Klass in Mock, MagicMock, NonCallableMagicMock, NonCallableMock: + m = Klass() + original = m.foo + m.foo = 3 + del m.foo + self.assertEqual(m.foo, original) + + new = m.foo = Mock() + del m.foo + self.assertEqual(m.foo, new) + + + def test_mock_parents(self): + for Klass in Mock, MagicMock: + m = Klass() + original_repr = repr(m) + m.return_value = m + self.assertIs(m(), m) + self.assertEqual(repr(m), original_repr) + + m.reset_mock() + self.assertIs(m(), m) + self.assertEqual(repr(m), original_repr) + + m = Klass() + m.b = m.a + self.assertIn("name='mock.a'", repr(m.b)) + self.assertIn("name='mock.a'", repr(m.a)) + m.reset_mock() + self.assertIn("name='mock.a'", repr(m.b)) + self.assertIn("name='mock.a'", repr(m.a)) + + m = Klass() + original_repr = repr(m) + m.a = m() + m.a.return_value = m + + self.assertEqual(repr(m), original_repr) + self.assertEqual(repr(m.a()), original_repr) + + + def test_attach_mock(self): + classes = Mock, MagicMock, NonCallableMagicMock, NonCallableMock + for Klass in classes: + for Klass2 in classes: + m = Klass() + + m2 = Klass2(name='foo') + m.attach_mock(m2, 'bar') + + self.assertIs(m.bar, m2) + self.assertIn("name='mock.bar'", repr(m2)) + + m.bar.baz(1) + self.assertEqual(m.mock_calls, [call.bar.baz(1)]) + self.assertEqual(m.method_calls, [call.bar.baz(1)]) + + + def test_attach_mock_return_value(self): + classes = Mock, MagicMock, NonCallableMagicMock, NonCallableMock + for Klass in Mock, MagicMock: + for Klass2 in classes: + m = Klass() + + m2 = Klass2(name='foo') + m.attach_mock(m2, 'return_value') + + self.assertIs(m(), m2) + self.assertIn("name='mock()'", repr(m2)) + + m2.foo() + self.assertEqual(m.mock_calls, call().foo().call_list()) + + + def test_attribute_deletion(self): + for mock in Mock(), MagicMock(): + self.assertTrue(hasattr(mock, 'm')) + + del mock.m + self.assertFalse(hasattr(mock, 'm')) + + del mock.f + self.assertFalse(hasattr(mock, 'f')) + self.assertRaises(AttributeError, getattr, mock, 'f') + + + def test_class_assignable(self): + for mock in Mock(), MagicMock(): + self.assertNotIsInstance(mock, int) + + mock.__class__ = int + self.assertIsInstance(mock, int) + mock.foo + + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testpatch.py @@ -0,0 +1,1652 @@ +# Copyright (C) 2007-2012 Michael Foord & the mock team +# E-mail: fuzzyman AT voidspace DOT org DOT uk +# http://www.voidspace.org.uk/python/mock/ + +import os +import sys + +import unittest +from unittest.test.testmock import support +from unittest.test.testmock.support import SomeClass, is_instance + +from mock import ( + NonCallableMock, CallableMixin, patch, sentinel, + MagicMock, Mock, NonCallableMagicMock, patch, + DEFAULT, call +) + + +builtin_string = 'builtins' + +PTModule = sys.modules[__name__] + + +def _get_proxy(obj, get_only=True): + class Proxy(object): + def __getattr__(self, name): + return getattr(obj, name) + if not get_only: + def __setattr__(self, name, value): + setattr(obj, name, value) + def __delattr__(self, name): + delattr(obj, name) + Proxy.__setattr__ = __setattr__ + Proxy.__delattr__ = __delattr__ + return Proxy() + + +# for use in the test +something = sentinel.Something +something_else = sentinel.SomethingElse + + +class Foo(object): + def __init__(self, a): + pass + def f(self, a): + pass + def g(self): + pass + foo = 'bar' + + class Bar(object): + def a(self): + pass + +foo_name = '%s.Foo' % __name__ + + +def function(a, b=Foo): + pass + + +class Container(object): + def __init__(self): + self.values = {} + + def __getitem__(self, name): + return self.values[name] + + def __setitem__(self, name, value): + self.values[name] = value + + def __delitem__(self, name): + del self.values[name] + + def __iter__(self): + return iter(self.values) + + + +class PatchTest(unittest.TestCase): + + def assertNotCallable(self, obj, magic=True): + MockClass = NonCallableMagicMock + if not magic: + MockClass = NonCallableMock + + self.assertRaises(TypeError, obj) + self.assertTrue(is_instance(obj, MockClass)) + self.assertFalse(is_instance(obj, CallableMixin)) + + + def test_single_patchobject(self): + class Something(object): + attribute = sentinel.Original + + @patch.object(Something, 'attribute', sentinel.Patched) + def test(): + self.assertEqual(Something.attribute, sentinel.Patched, "unpatched") + + test() + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + + + def test_patchobject_with_none(self): + class Something(object): + attribute = sentinel.Original + + @patch.object(Something, 'attribute', None) + def test(): + self.assertIsNone(Something.attribute, "unpatched") + + test() + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + + + def test_multiple_patchobject(self): + class Something(object): + attribute = sentinel.Original + next_attribute = sentinel.Original2 + + @patch.object(Something, 'attribute', sentinel.Patched) + @patch.object(Something, 'next_attribute', sentinel.Patched2) + def test(): + self.assertEqual(Something.attribute, sentinel.Patched, + "unpatched") + self.assertEqual(Something.next_attribute, sentinel.Patched2, + "unpatched") + + test() + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + self.assertEqual(Something.next_attribute, sentinel.Original2, + "patch not restored") + + + def test_object_lookup_is_quite_lazy(self): + global something + original = something + @patch('%s.something' % __name__, sentinel.Something2) + def test(): + pass + + try: + something = sentinel.replacement_value + test() + self.assertEqual(something, sentinel.replacement_value) + finally: + something = original + + + def test_patch(self): + @patch('%s.something' % __name__, sentinel.Something2) + def test(): + self.assertEqual(PTModule.something, sentinel.Something2, + "unpatched") + + test() + self.assertEqual(PTModule.something, sentinel.Something, + "patch not restored") + + @patch('%s.something' % __name__, sentinel.Something2) + @patch('%s.something_else' % __name__, sentinel.SomethingElse) + def test(): + self.assertEqual(PTModule.something, sentinel.Something2, + "unpatched") + self.assertEqual(PTModule.something_else, sentinel.SomethingElse, + "unpatched") + + self.assertEqual(PTModule.something, sentinel.Something, + "patch not restored") + self.assertEqual(PTModule.something_else, sentinel.SomethingElse, + "patch not restored") + + # Test the patching and restoring works a second time + test() + + self.assertEqual(PTModule.something, sentinel.Something, + "patch not restored") + self.assertEqual(PTModule.something_else, sentinel.SomethingElse, + "patch not restored") + + mock = Mock() + mock.return_value = sentinel.Handle + @patch('%s.open' % builtin_string, mock) + def test(): + self.assertEqual(open('filename', 'r'), sentinel.Handle, + "open not patched") + test() + test() + + self.assertNotEqual(open, mock, "patch not restored") + + + def test_patch_class_attribute(self): + @patch('%s.SomeClass.class_attribute' % __name__, + sentinel.ClassAttribute) + def test(): + self.assertEqual(PTModule.SomeClass.class_attribute, + sentinel.ClassAttribute, "unpatched") + test() + + self.assertIsNone(PTModule.SomeClass.class_attribute, + "patch not restored") + + + def test_patchobject_with_default_mock(self): + class Test(object): + something = sentinel.Original + something2 = sentinel.Original2 + + @patch.object(Test, 'something') + def test(mock): + self.assertEqual(mock, Test.something, + "Mock not passed into test function") + self.assertIsInstance(mock, MagicMock, + "patch with two arguments did not create a mock") + + test() + + @patch.object(Test, 'something') + @patch.object(Test, 'something2') + def test(this1, this2, mock1, mock2): + self.assertEqual(this1, sentinel.this1, + "Patched function didn't receive initial argument") + self.assertEqual(this2, sentinel.this2, + "Patched function didn't receive second argument") + self.assertEqual(mock1, Test.something2, + "Mock not passed into test function") + self.assertEqual(mock2, Test.something, + "Second Mock not passed into test function") + self.assertIsInstance(mock2, MagicMock, + "patch with two arguments did not create a mock") + self.assertIsInstance(mock2, MagicMock, + "patch with two arguments did not create a mock") + + # A hack to test that new mocks are passed the second time + self.assertNotEqual(outerMock1, mock1, "unexpected value for mock1") + self.assertNotEqual(outerMock2, mock2, "unexpected value for mock1") + return mock1, mock2 + + outerMock1 = outerMock2 = None + outerMock1, outerMock2 = test(sentinel.this1, sentinel.this2) + + # Test that executing a second time creates new mocks + test(sentinel.this1, sentinel.this2) + + + def test_patch_with_spec(self): + @patch('%s.SomeClass' % __name__, spec=SomeClass) + def test(MockSomeClass): + self.assertEqual(SomeClass, MockSomeClass) + self.assertTrue(is_instance(SomeClass.wibble, MagicMock)) + self.assertRaises(AttributeError, lambda: SomeClass.not_wibble) + + test() + + + def test_patchobject_with_spec(self): + @patch.object(SomeClass, 'class_attribute', spec=SomeClass) + def test(MockAttribute): + self.assertEqual(SomeClass.class_attribute, MockAttribute) + self.assertTrue(is_instance(SomeClass.class_attribute.wibble, + MagicMock)) + self.assertRaises(AttributeError, + lambda: SomeClass.class_attribute.not_wibble) + + test() + + + def test_patch_with_spec_as_list(self): + @patch('%s.SomeClass' % __name__, spec=['wibble']) + def test(MockSomeClass): + self.assertEqual(SomeClass, MockSomeClass) + self.assertTrue(is_instance(SomeClass.wibble, MagicMock)) + self.assertRaises(AttributeError, lambda: SomeClass.not_wibble) + + test() + + + def test_patchobject_with_spec_as_list(self): + @patch.object(SomeClass, 'class_attribute', spec=['wibble']) + def test(MockAttribute): + self.assertEqual(SomeClass.class_attribute, MockAttribute) + self.assertTrue(is_instance(SomeClass.class_attribute.wibble, + MagicMock)) + self.assertRaises(AttributeError, + lambda: SomeClass.class_attribute.not_wibble) + + test() + + + def test_nested_patch_with_spec_as_list(self): + # regression test for nested decorators + @patch('%s.open' % builtin_string) + @patch('%s.SomeClass' % __name__, spec=['wibble']) + def test(MockSomeClass, MockOpen): + self.assertEqual(SomeClass, MockSomeClass) + self.assertTrue(is_instance(SomeClass.wibble, MagicMock)) + self.assertRaises(AttributeError, lambda: SomeClass.not_wibble) + test() + + + def test_patch_with_spec_as_boolean(self): + @patch('%s.SomeClass' % __name__, spec=True) + def test(MockSomeClass): + self.assertEqual(SomeClass, MockSomeClass) + # Should not raise attribute error + MockSomeClass.wibble + + self.assertRaises(AttributeError, lambda: MockSomeClass.not_wibble) + + test() + + + def test_patch_object_with_spec_as_boolean(self): + @patch.object(PTModule, 'SomeClass', spec=True) + def test(MockSomeClass): + self.assertEqual(SomeClass, MockSomeClass) + # Should not raise attribute error + MockSomeClass.wibble + + self.assertRaises(AttributeError, lambda: MockSomeClass.not_wibble) + + test() + + + def test_patch_class_acts_with_spec_is_inherited(self): + @patch('%s.SomeClass' % __name__, spec=True) + def test(MockSomeClass): + self.assertTrue(is_instance(MockSomeClass, MagicMock)) + instance = MockSomeClass() + self.assertNotCallable(instance) + # Should not raise attribute error + instance.wibble + + self.assertRaises(AttributeError, lambda: instance.not_wibble) + + test() + + + def test_patch_with_create_mocks_non_existent_attributes(self): + @patch('%s.frooble' % builtin_string, sentinel.Frooble, create=True) + def test(): + self.assertEqual(frooble, sentinel.Frooble) + + test() + self.assertRaises(NameError, lambda: frooble) + + + def test_patchobject_with_create_mocks_non_existent_attributes(self): + @patch.object(SomeClass, 'frooble', sentinel.Frooble, create=True) + def test(): + self.assertEqual(SomeClass.frooble, sentinel.Frooble) + + test() + self.assertFalse(hasattr(SomeClass, 'frooble')) + + + def test_patch_wont_create_by_default(self): + try: + @patch('%s.frooble' % builtin_string, sentinel.Frooble) + def test(): + self.assertEqual(frooble, sentinel.Frooble) + + test() + except AttributeError: + pass + else: + self.fail('Patching non existent attributes should fail') + + self.assertRaises(NameError, lambda: frooble) + + + def test_patchobject_wont_create_by_default(self): + try: + @patch.object(SomeClass, 'frooble', sentinel.Frooble) + def test(): + self.fail('Patching non existent attributes should fail') + + test() + except AttributeError: + pass + else: + self.fail('Patching non existent attributes should fail') + self.assertFalse(hasattr(SomeClass, 'frooble')) + + + def test_patch_with_static_methods(self): + class Foo(object): + @staticmethod + def woot(): + return sentinel.Static + + @patch.object(Foo, 'woot', staticmethod(lambda: sentinel.Patched)) + def anonymous(): + self.assertEqual(Foo.woot(), sentinel.Patched) + anonymous() + + self.assertEqual(Foo.woot(), sentinel.Static) + + + def test_patch_local(self): + foo = sentinel.Foo + @patch.object(sentinel, 'Foo', 'Foo') + def anonymous(): + self.assertEqual(sentinel.Foo, 'Foo') + anonymous() + + self.assertEqual(sentinel.Foo, foo) + + + def test_patch_slots(self): + class Foo(object): + __slots__ = ('Foo',) + + foo = Foo() + foo.Foo = sentinel.Foo + + @patch.object(foo, 'Foo', 'Foo') + def anonymous(): + self.assertEqual(foo.Foo, 'Foo') + anonymous() + + self.assertEqual(foo.Foo, sentinel.Foo) + + + def test_patchobject_class_decorator(self): + class Something(object): + attribute = sentinel.Original + + class Foo(object): + def test_method(other_self): + self.assertEqual(Something.attribute, sentinel.Patched, + "unpatched") + def not_test_method(other_self): + self.assertEqual(Something.attribute, sentinel.Original, + "non-test method patched") + + Foo = patch.object(Something, 'attribute', sentinel.Patched)(Foo) + + f = Foo() + f.test_method() + f.not_test_method() + + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + + + def test_patch_class_decorator(self): + class Something(object): + attribute = sentinel.Original + + class Foo(object): + def test_method(other_self, mock_something): + self.assertEqual(PTModule.something, mock_something, + "unpatched") + def not_test_method(other_self): + self.assertEqual(PTModule.something, sentinel.Something, + "non-test method patched") + Foo = patch('%s.something' % __name__)(Foo) + + f = Foo() + f.test_method() + f.not_test_method() + + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + self.assertEqual(PTModule.something, sentinel.Something, + "patch not restored") + + + def test_patchobject_twice(self): + class Something(object): + attribute = sentinel.Original + next_attribute = sentinel.Original2 + + @patch.object(Something, 'attribute', sentinel.Patched) + @patch.object(Something, 'attribute', sentinel.Patched) + def test(): + self.assertEqual(Something.attribute, sentinel.Patched, "unpatched") + + test() + + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + + + def test_patch_dict(self): + foo = {'initial': object(), 'other': 'something'} + original = foo.copy() + + @patch.dict(foo) + def test(): + foo['a'] = 3 + del foo['initial'] + foo['other'] = 'something else' + + test() + + self.assertEqual(foo, original) + + @patch.dict(foo, {'a': 'b'}) + def test(): + self.assertEqual(len(foo), 3) + self.assertEqual(foo['a'], 'b') + + test() + + self.assertEqual(foo, original) + + @patch.dict(foo, [('a', 'b')]) + def test(): + self.assertEqual(len(foo), 3) + self.assertEqual(foo['a'], 'b') + + test() + + self.assertEqual(foo, original) + + + def test_patch_dict_with_container_object(self): + foo = Container() + foo['initial'] = object() + foo['other'] = 'something' + + original = foo.values.copy() + + @patch.dict(foo) + def test(): + foo['a'] = 3 + del foo['initial'] + foo['other'] = 'something else' + + test() + + self.assertEqual(foo.values, original) + + @patch.dict(foo, {'a': 'b'}) + def test(): + self.assertEqual(len(foo.values), 3) + self.assertEqual(foo['a'], 'b') + + test() + + self.assertEqual(foo.values, original) + + + def test_patch_dict_with_clear(self): + foo = {'initial': object(), 'other': 'something'} + original = foo.copy() + + @patch.dict(foo, clear=True) + def test(): + self.assertEqual(foo, {}) + foo['a'] = 3 + foo['other'] = 'something else' + + test() + + self.assertEqual(foo, original) + + @patch.dict(foo, {'a': 'b'}, clear=True) + def test(): + self.assertEqual(foo, {'a': 'b'}) + + test() + + self.assertEqual(foo, original) + + @patch.dict(foo, [('a', 'b')], clear=True) + def test(): + self.assertEqual(foo, {'a': 'b'}) + + test() + + self.assertEqual(foo, original) + + + def test_patch_dict_with_container_object_and_clear(self): + foo = Container() + foo['initial'] = object() + foo['other'] = 'something' + + original = foo.values.copy() + + @patch.dict(foo, clear=True) + def test(): + self.assertEqual(foo.values, {}) + foo['a'] = 3 + foo['other'] = 'something else' + + test() + + self.assertEqual(foo.values, original) + + @patch.dict(foo, {'a': 'b'}, clear=True) + def test(): + self.assertEqual(foo.values, {'a': 'b'}) + + test() + + self.assertEqual(foo.values, original) + + + def test_name_preserved(self): + foo = {} + + @patch('%s.SomeClass' % __name__, object()) + @patch('%s.SomeClass' % __name__, object(), autospec=True) + @patch.object(SomeClass, object()) + @patch.dict(foo) + def some_name(): + pass + + self.assertEqual(some_name.__name__, 'some_name') + + + def test_patch_with_exception(self): + foo = {} + + @patch.dict(foo, {'a': 'b'}) + def test(): + raise NameError('Konrad') + try: + test() + except NameError: + pass + else: + self.fail('NameError not raised by test') + + self.assertEqual(foo, {}) + + + def test_patch_dict_with_string(self): + @patch.dict('os.environ', {'konrad_delong': 'some value'}) + def test(): + self.assertIn('konrad_delong', os.environ) + + test() + + + def test_patch_descriptor(self): + # would be some effort to fix this - we could special case the + # builtin descriptors: classmethod, property, staticmethod + return + class Nothing(object): + foo = None + + class Something(object): + foo = {} + + @patch.object(Nothing, 'foo', 2) + @classmethod + def klass(cls): + self.assertIs(cls, Something) + + @patch.object(Nothing, 'foo', 2) + @staticmethod + def static(arg): + return arg + + @patch.dict(foo) + @classmethod + def klass_dict(cls): + self.assertIs(cls, Something) + + @patch.dict(foo) + @staticmethod + def static_dict(arg): + return arg + + # these will raise exceptions if patching descriptors is broken + self.assertEqual(Something.static('f00'), 'f00') + Something.klass() + self.assertEqual(Something.static_dict('f00'), 'f00') + Something.klass_dict() + + something = Something() + self.assertEqual(something.static('f00'), 'f00') + something.klass() + self.assertEqual(something.static_dict('f00'), 'f00') + something.klass_dict() + + + def test_patch_spec_set(self): + @patch('%s.SomeClass' % __name__, spec=SomeClass, spec_set=True) + def test(MockClass): + MockClass.z = 'foo' + + self.assertRaises(AttributeError, test) + + @patch.object(support, 'SomeClass', spec=SomeClass, spec_set=True) + def test(MockClass): + MockClass.z = 'foo' + + self.assertRaises(AttributeError, test) + @patch('%s.SomeClass' % __name__, spec_set=True) + def test(MockClass): + MockClass.z = 'foo' + + self.assertRaises(AttributeError, test) + + @patch.object(support, 'SomeClass', spec_set=True) + def test(MockClass): + MockClass.z = 'foo' + + self.assertRaises(AttributeError, test) + + + def test_spec_set_inherit(self): + @patch('%s.SomeClass' % __name__, spec_set=True) + def test(MockClass): + instance = MockClass() + instance.z = 'foo' + + self.assertRaises(AttributeError, test) + + + def test_patch_start_stop(self): + original = something + patcher = patch('%s.something' % __name__) + self.assertIs(something, original) + mock = patcher.start() + self.assertIsNot(mock, original) + try: + self.assertIs(something, mock) + finally: + patcher.stop() + self.assertIs(something, original) + + + def test_stop_without_start(self): + patcher = patch(foo_name, 'bar', 3) + + # calling stop without start used to produce a very obscure error + self.assertRaises(RuntimeError, patcher.stop) + + + def test_patchobject_start_stop(self): + original = something + patcher = patch.object(PTModule, 'something', 'foo') + self.assertIs(something, original) + replaced = patcher.start() + self.assertEqual(replaced, 'foo') + try: + self.assertIs(something, replaced) + finally: + patcher.stop() + self.assertIs(something, original) + + + def test_patch_dict_start_stop(self): + d = {'foo': 'bar'} + original = d.copy() + patcher = patch.dict(d, [('spam', 'eggs')], clear=True) + self.assertEqual(d, original) + + patcher.start() + self.assertEqual(d, {'spam': 'eggs'}) + + patcher.stop() + self.assertEqual(d, original) + + + def test_patch_dict_class_decorator(self): + this = self + d = {'spam': 'eggs'} + original = d.copy() + + class Test(object): + def test_first(self): + this.assertEqual(d, {'foo': 'bar'}) + def test_second(self): + this.assertEqual(d, {'foo': 'bar'}) + + Test = patch.dict(d, {'foo': 'bar'}, clear=True)(Test) + self.assertEqual(d, original) + + test = Test() + + test.test_first() + self.assertEqual(d, original) + + test.test_second() + self.assertEqual(d, original) + + test = Test() + + test.test_first() + self.assertEqual(d, original) + + test.test_second() + self.assertEqual(d, original) + + + def test_get_only_proxy(self): + class Something(object): + foo = 'foo' + class SomethingElse: + foo = 'foo' + + for thing in Something, SomethingElse, Something(), SomethingElse: + proxy = _get_proxy(thing) + + @patch.object(proxy, 'foo', 'bar') + def test(): + self.assertEqual(proxy.foo, 'bar') + test() + self.assertEqual(proxy.foo, 'foo') + self.assertEqual(thing.foo, 'foo') + self.assertNotIn('foo', proxy.__dict__) + + + def test_get_set_delete_proxy(self): + class Something(object): + foo = 'foo' + class SomethingElse: + foo = 'foo' + + for thing in Something, SomethingElse, Something(), SomethingElse: + proxy = _get_proxy(Something, get_only=False) + + @patch.object(proxy, 'foo', 'bar') + def test(): + self.assertEqual(proxy.foo, 'bar') + test() + self.assertEqual(proxy.foo, 'foo') + self.assertEqual(thing.foo, 'foo') + self.assertNotIn('foo', proxy.__dict__) + + + def test_patch_keyword_args(self): + kwargs = {'side_effect': KeyError, 'foo.bar.return_value': 33, + 'foo': MagicMock()} + + patcher = patch(foo_name, **kwargs) + mock = patcher.start() + patcher.stop() + + self.assertRaises(KeyError, mock) + self.assertEqual(mock.foo.bar(), 33) + self.assertIsInstance(mock.foo, MagicMock) + + + def test_patch_object_keyword_args(self): + kwargs = {'side_effect': KeyError, 'foo.bar.return_value': 33, + 'foo': MagicMock()} + + patcher = patch.object(Foo, 'f', **kwargs) + mock = patcher.start() + patcher.stop() + + self.assertRaises(KeyError, mock) + self.assertEqual(mock.foo.bar(), 33) + self.assertIsInstance(mock.foo, MagicMock) + + + def test_patch_dict_keyword_args(self): + original = {'foo': 'bar'} + copy = original.copy() + + patcher = patch.dict(original, foo=3, bar=4, baz=5) + patcher.start() + + try: + self.assertEqual(original, dict(foo=3, bar=4, baz=5)) + finally: + patcher.stop() + + self.assertEqual(original, copy) + + + def test_autospec(self): + class Boo(object): + def __init__(self, a): + pass + def f(self, a): + pass + def g(self): + pass + foo = 'bar' + + class Bar(object): + def a(self): + pass + + def _test(mock): + mock(1) + mock.assert_called_with(1) + self.assertRaises(TypeError, mock) + + def _test2(mock): + mock.f(1) + mock.f.assert_called_with(1) + self.assertRaises(TypeError, mock.f) + + mock.g() + mock.g.assert_called_with() + self.assertRaises(TypeError, mock.g, 1) + + self.assertRaises(AttributeError, getattr, mock, 'h') + + mock.foo.lower() + mock.foo.lower.assert_called_with() + self.assertRaises(AttributeError, getattr, mock.foo, 'bar') + + mock.Bar() + mock.Bar.assert_called_with() + + mock.Bar.a() + mock.Bar.a.assert_called_with() + self.assertRaises(TypeError, mock.Bar.a, 1) + + mock.Bar().a() + mock.Bar().a.assert_called_with() + self.assertRaises(TypeError, mock.Bar().a, 1) + + self.assertRaises(AttributeError, getattr, mock.Bar, 'b') + self.assertRaises(AttributeError, getattr, mock.Bar(), 'b') + + def function(mock): + _test(mock) + _test2(mock) + _test2(mock(1)) + self.assertIs(mock, Foo) + return mock + + test = patch(foo_name, autospec=True)(function) + + mock = test() + self.assertIsNot(Foo, mock) + # test patching a second time works + test() + + module = sys.modules[__name__] + test = patch.object(module, 'Foo', autospec=True)(function) + + mock = test() + self.assertIsNot(Foo, mock) + # test patching a second time works + test() + + + def test_autospec_function(self): + @patch('%s.function' % __name__, autospec=True) + def test(mock): + function(1) + function.assert_called_with(1) + function(2, 3) + function.assert_called_with(2, 3) + + self.assertRaises(TypeError, function) + self.assertRaises(AttributeError, getattr, function, 'foo') + + test() + + + def test_autospec_keywords(self): + @patch('%s.function' % __name__, autospec=True, + return_value=3) + def test(mock_function): + #self.assertEqual(function.abc, 'foo') + return function(1, 2) + + result = test() + self.assertEqual(result, 3) + + + def test_autospec_with_new(self): + patcher = patch('%s.function' % __name__, new=3, autospec=True) + self.assertRaises(TypeError, patcher.start) + + module = sys.modules[__name__] + patcher = patch.object(module, 'function', new=3, autospec=True) + self.assertRaises(TypeError, patcher.start) + + + def test_autospec_with_object(self): + class Bar(Foo): + extra = [] + + patcher = patch(foo_name, autospec=Bar) + mock = patcher.start() + try: + self.assertIsInstance(mock, Bar) + self.assertIsInstance(mock.extra, list) + finally: + patcher.stop() + + + def test_autospec_inherits(self): + FooClass = Foo + patcher = patch(foo_name, autospec=True) + mock = patcher.start() + try: + self.assertIsInstance(mock, FooClass) + self.assertIsInstance(mock(3), FooClass) + finally: + patcher.stop() + + + def test_autospec_name(self): + patcher = patch(foo_name, autospec=True) + mock = patcher.start() + + try: + self.assertIn(" name='Foo'", repr(mock)) + self.assertIn(" name='Foo.f'", repr(mock.f)) + self.assertIn(" name='Foo()'", repr(mock(None))) + self.assertIn(" name='Foo().f'", repr(mock(None).f)) + finally: + patcher.stop() + + + def test_tracebacks(self): + @patch.object(Foo, 'f', object()) + def test(): + raise AssertionError + try: + test() + except: + err = sys.exc_info() + + result = unittest.TextTestResult(None, None, 0) + traceback = result._exc_info_to_string(err, self) + self.assertIn('raise AssertionError', traceback) + + + def test_new_callable_patch(self): + patcher = patch(foo_name, new_callable=NonCallableMagicMock) + + m1 = patcher.start() + patcher.stop() + m2 = patcher.start() + patcher.stop() + + self.assertIsNot(m1, m2) + for mock in m1, m2: + self.assertNotCallable(m1) + + + def test_new_callable_patch_object(self): + patcher = patch.object(Foo, 'f', new_callable=NonCallableMagicMock) + + m1 = patcher.start() + patcher.stop() + m2 = patcher.start() + patcher.stop() + + self.assertIsNot(m1, m2) + for mock in m1, m2: + self.assertNotCallable(m1) + + + def test_new_callable_keyword_arguments(self): + class Bar(object): + kwargs = None + def __init__(self, **kwargs): + Bar.kwargs = kwargs + + patcher = patch(foo_name, new_callable=Bar, arg1=1, arg2=2) + m = patcher.start() + try: + self.assertIs(type(m), Bar) + self.assertEqual(Bar.kwargs, dict(arg1=1, arg2=2)) + finally: + patcher.stop() + + + def test_new_callable_spec(self): + class Bar(object): + kwargs = None + def __init__(self, **kwargs): + Bar.kwargs = kwargs + + patcher = patch(foo_name, new_callable=Bar, spec=Bar) + patcher.start() + try: + self.assertEqual(Bar.kwargs, dict(spec=Bar)) + finally: + patcher.stop() + + patcher = patch(foo_name, new_callable=Bar, spec_set=Bar) + patcher.start() + try: + self.assertEqual(Bar.kwargs, dict(spec_set=Bar)) + finally: + patcher.stop() + + + def test_new_callable_create(self): + non_existent_attr = '%s.weeeee' % foo_name + p = patch(non_existent_attr, new_callable=NonCallableMock) + self.assertRaises(AttributeError, p.start) + + p = patch(non_existent_attr, new_callable=NonCallableMock, + create=True) + m = p.start() + try: + self.assertNotCallable(m, magic=False) + finally: + p.stop() + + + def test_new_callable_incompatible_with_new(self): + self.assertRaises( + ValueError, patch, foo_name, new=object(), new_callable=MagicMock + ) + self.assertRaises( + ValueError, patch.object, Foo, 'f', new=object(), + new_callable=MagicMock + ) + + + def test_new_callable_incompatible_with_autospec(self): + self.assertRaises( + ValueError, patch, foo_name, new_callable=MagicMock, + autospec=True + ) + self.assertRaises( + ValueError, patch.object, Foo, 'f', new_callable=MagicMock, + autospec=True + ) + + + def test_new_callable_inherit_for_mocks(self): + class MockSub(Mock): + pass + + MockClasses = ( + NonCallableMock, NonCallableMagicMock, MagicMock, Mock, MockSub + ) + for Klass in MockClasses: + for arg in 'spec', 'spec_set': + kwargs = {arg: True} + p = patch(foo_name, new_callable=Klass, **kwargs) + m = p.start() + try: + instance = m.return_value + self.assertRaises(AttributeError, getattr, instance, 'x') + finally: + p.stop() + + + def test_new_callable_inherit_non_mock(self): + class NotAMock(object): + def __init__(self, spec): + self.spec = spec + + p = patch(foo_name, new_callable=NotAMock, spec=True) + m = p.start() + try: + self.assertTrue(is_instance(m, NotAMock)) + self.assertRaises(AttributeError, getattr, m, 'return_value') + finally: + p.stop() + + self.assertEqual(m.spec, Foo) + + + def test_new_callable_class_decorating(self): + test = self + original = Foo + class SomeTest(object): + + def _test(self, mock_foo): + test.assertIsNot(Foo, original) + test.assertIs(Foo, mock_foo) + test.assertIsInstance(Foo, SomeClass) + + def test_two(self, mock_foo): + self._test(mock_foo) + def test_one(self, mock_foo): + self._test(mock_foo) + + SomeTest = patch(foo_name, new_callable=SomeClass)(SomeTest) + SomeTest().test_one() + SomeTest().test_two() + self.assertIs(Foo, original) + + + def test_patch_multiple(self): + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + patcher1 = patch.multiple(foo_name, f=1, g=2) + patcher2 = patch.multiple(Foo, f=1, g=2) + + for patcher in patcher1, patcher2: + patcher.start() + try: + self.assertIs(Foo, original_foo) + self.assertEqual(Foo.f, 1) + self.assertEqual(Foo.g, 2) + finally: + patcher.stop() + + self.assertIs(Foo, original_foo) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + @patch.multiple(foo_name, f=3, g=4) + def test(): + self.assertIs(Foo, original_foo) + self.assertEqual(Foo.f, 3) + self.assertEqual(Foo.g, 4) + + test() + + + def test_patch_multiple_no_kwargs(self): + self.assertRaises(ValueError, patch.multiple, foo_name) + self.assertRaises(ValueError, patch.multiple, Foo) + + + def test_patch_multiple_create_mocks(self): + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + @patch.multiple(foo_name, f=DEFAULT, g=3, foo=DEFAULT) + def test(f, foo): + self.assertIs(Foo, original_foo) + self.assertIs(Foo.f, f) + self.assertEqual(Foo.g, 3) + self.assertIs(Foo.foo, foo) + self.assertTrue(is_instance(f, MagicMock)) + self.assertTrue(is_instance(foo, MagicMock)) + + test() + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_create_mocks_different_order(self): + # bug revealed by Jython! + original_f = Foo.f + original_g = Foo.g + + patcher = patch.object(Foo, 'f', 3) + patcher.attribute_name = 'f' + + other = patch.object(Foo, 'g', DEFAULT) + other.attribute_name = 'g' + patcher.additional_patchers = [other] + + @patcher + def test(g): + self.assertIs(Foo.g, g) + self.assertEqual(Foo.f, 3) + + test() + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_stacked_decorators(self): + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + @patch.multiple(foo_name, f=DEFAULT) + @patch.multiple(foo_name, foo=DEFAULT) + @patch(foo_name + '.g') + def test1(g, **kwargs): + _test(g, **kwargs) + + @patch.multiple(foo_name, f=DEFAULT) + @patch(foo_name + '.g') + @patch.multiple(foo_name, foo=DEFAULT) + def test2(g, **kwargs): + _test(g, **kwargs) + + @patch(foo_name + '.g') + @patch.multiple(foo_name, f=DEFAULT) + @patch.multiple(foo_name, foo=DEFAULT) + def test3(g, **kwargs): + _test(g, **kwargs) + + def _test(g, **kwargs): + f = kwargs.pop('f') + foo = kwargs.pop('foo') + self.assertFalse(kwargs) + + self.assertIs(Foo, original_foo) + self.assertIs(Foo.f, f) + self.assertIs(Foo.g, g) + self.assertIs(Foo.foo, foo) + self.assertTrue(is_instance(f, MagicMock)) + self.assertTrue(is_instance(g, MagicMock)) + self.assertTrue(is_instance(foo, MagicMock)) + + test1() + test2() + test3() + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_create_mocks_patcher(self): + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + patcher = patch.multiple(foo_name, f=DEFAULT, g=3, foo=DEFAULT) + + result = patcher.start() + try: + f = result['f'] + foo = result['foo'] + self.assertEqual(set(result), set(['f', 'foo'])) + + self.assertIs(Foo, original_foo) + self.assertIs(Foo.f, f) + self.assertIs(Foo.foo, foo) + self.assertTrue(is_instance(f, MagicMock)) + self.assertTrue(is_instance(foo, MagicMock)) + finally: + patcher.stop() + + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_decorating_class(self): + test = self + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + class SomeTest(object): + + def _test(self, f, foo): + test.assertIs(Foo, original_foo) + test.assertIs(Foo.f, f) + test.assertEqual(Foo.g, 3) + test.assertIs(Foo.foo, foo) + test.assertTrue(is_instance(f, MagicMock)) + test.assertTrue(is_instance(foo, MagicMock)) + + def test_two(self, f, foo): + self._test(f, foo) + def test_one(self, f, foo): + self._test(f, foo) + + SomeTest = patch.multiple( + foo_name, f=DEFAULT, g=3, foo=DEFAULT + )(SomeTest) + + thing = SomeTest() + thing.test_one() + thing.test_two() + + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_create(self): + patcher = patch.multiple(Foo, blam='blam') + self.assertRaises(AttributeError, patcher.start) + + patcher = patch.multiple(Foo, blam='blam', create=True) + patcher.start() + try: + self.assertEqual(Foo.blam, 'blam') + finally: + patcher.stop() + + self.assertFalse(hasattr(Foo, 'blam')) + + + def test_patch_multiple_spec_set(self): + # if spec_set works then we can assume that spec and autospec also + # work as the underlying machinery is the same + patcher = patch.multiple(Foo, foo=DEFAULT, spec_set=['a', 'b']) + result = patcher.start() + try: + self.assertEqual(Foo.foo, result['foo']) + Foo.foo.a(1) + Foo.foo.b(2) + Foo.foo.a.assert_called_with(1) + Foo.foo.b.assert_called_with(2) + self.assertRaises(AttributeError, setattr, Foo.foo, 'c', None) + finally: + patcher.stop() + + + def test_patch_multiple_new_callable(self): + class Thing(object): + pass + + patcher = patch.multiple( + Foo, f=DEFAULT, g=DEFAULT, new_callable=Thing + ) + result = patcher.start() + try: + self.assertIs(Foo.f, result['f']) + self.assertIs(Foo.g, result['g']) + self.assertIsInstance(Foo.f, Thing) + self.assertIsInstance(Foo.g, Thing) + self.assertIsNot(Foo.f, Foo.g) + finally: + patcher.stop() + + + def test_nested_patch_failure(self): + original_f = Foo.f + original_g = Foo.g + + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'missing', 1) + @patch.object(Foo, 'f', 1) + def thing1(): + pass + + @patch.object(Foo, 'missing', 1) + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'f', 1) + def thing2(): + pass + + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'f', 1) + @patch.object(Foo, 'missing', 1) + def thing3(): + pass + + for func in thing1, thing2, thing3: + self.assertRaises(AttributeError, func) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_new_callable_failure(self): + original_f = Foo.f + original_g = Foo.g + original_foo = Foo.foo + + def crasher(): + raise NameError('crasher') + + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'foo', new_callable=crasher) + @patch.object(Foo, 'f', 1) + def thing1(): + pass + + @patch.object(Foo, 'foo', new_callable=crasher) + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'f', 1) + def thing2(): + pass + + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'f', 1) + @patch.object(Foo, 'foo', new_callable=crasher) + def thing3(): + pass + + for func in thing1, thing2, thing3: + self.assertRaises(NameError, func) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + self.assertEqual(Foo.foo, original_foo) + + + def test_patch_multiple_failure(self): + original_f = Foo.f + original_g = Foo.g + + patcher = patch.object(Foo, 'f', 1) + patcher.attribute_name = 'f' + + good = patch.object(Foo, 'g', 1) + good.attribute_name = 'g' + + bad = patch.object(Foo, 'missing', 1) + bad.attribute_name = 'missing' + + for additionals in [good, bad], [bad, good]: + patcher.additional_patchers = additionals + + @patcher + def func(): + pass + + self.assertRaises(AttributeError, func) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_new_callable_failure(self): + original_f = Foo.f + original_g = Foo.g + original_foo = Foo.foo + + def crasher(): + raise NameError('crasher') + + patcher = patch.object(Foo, 'f', 1) + patcher.attribute_name = 'f' + + good = patch.object(Foo, 'g', 1) + good.attribute_name = 'g' + + bad = patch.object(Foo, 'foo', new_callable=crasher) + bad.attribute_name = 'foo' + + for additionals in [good, bad], [bad, good]: + patcher.additional_patchers = additionals + + @patcher + def func(): + pass + + self.assertRaises(NameError, func) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + self.assertEqual(Foo.foo, original_foo) + + + def test_patch_multiple_string_subclasses(self): + Foo = type('Foo', (str,), {'fish': 'tasty'}) + foo = Foo() + @patch.multiple(foo, fish='nearly gone') + def test(): + self.assertEqual(foo.fish, 'nearly gone') + + test() + self.assertEqual(foo.fish, 'tasty') + + + @patch('mock.patch.TEST_PREFIX', 'foo') + def test_patch_test_prefix(self): + class Foo(object): + thing = 'original' + + def foo_one(self): + return self.thing + def foo_two(self): + return self.thing + def test_one(self): + return self.thing + def test_two(self): + return self.thing + + Foo = patch.object(Foo, 'thing', 'changed')(Foo) + + foo = Foo() + self.assertEqual(foo.foo_one(), 'changed') + self.assertEqual(foo.foo_two(), 'changed') + self.assertEqual(foo.test_one(), 'original') + self.assertEqual(foo.test_two(), 'original') + + + @patch('mock.patch.TEST_PREFIX', 'bar') + def test_patch_dict_test_prefix(self): + class Foo(object): + def bar_one(self): + return dict(the_dict) + def bar_two(self): + return dict(the_dict) + def test_one(self): + return dict(the_dict) + def test_two(self): + return dict(the_dict) + + the_dict = {'key': 'original'} + Foo = patch.dict(the_dict, key='changed')(Foo) + + foo =Foo() + self.assertEqual(foo.bar_one(), {'key': 'changed'}) + self.assertEqual(foo.bar_two(), {'key': 'changed'}) + self.assertEqual(foo.test_one(), {'key': 'original'}) + self.assertEqual(foo.test_two(), {'key': 'original'}) + + + def test_patch_with_spec_mock_repr(self): + for arg in ('spec', 'autospec', 'spec_set'): + p = patch('%s.SomeClass' % __name__, **{arg: True}) + m = p.start() + try: + self.assertIn(" name='SomeClass'", repr(m)) + self.assertIn(" name='SomeClass.class_attribute'", + repr(m.class_attribute)) + self.assertIn(" name='SomeClass()'", repr(m())) + self.assertIn(" name='SomeClass().class_attribute'", + repr(m().class_attribute)) + finally: + p.stop() + + + def test_patch_nested_autospec_repr(self): + with patch('unittest.test.testmock.support', autospec=True) as m: + self.assertIn(" name='support.SomeClass.wibble()'", + repr(m.SomeClass.wibble())) + self.assertIn(" name='support.SomeClass().wibble()'", + repr(m.SomeClass().wibble())) + + + + def test_mock_calls_with_patch(self): + for arg in ('spec', 'autospec', 'spec_set'): + p = patch('%s.SomeClass' % __name__, **{arg: True}) + m = p.start() + try: + m.wibble() + + kalls = [call.wibble()] + self.assertEqual(m.mock_calls, kalls) + self.assertEqual(m.method_calls, kalls) + self.assertEqual(m.wibble.mock_calls, [call()]) + + result = m() + kalls.append(call()) + self.assertEqual(m.mock_calls, kalls) + + result.wibble() + kalls.append(call().wibble()) + self.assertEqual(m.mock_calls, kalls) + + self.assertEqual(result.mock_calls, [call.wibble()]) + self.assertEqual(result.wibble.mock_calls, [call()]) + self.assertEqual(result.method_calls, [call.wibble()]) + finally: + p.stop() + + + def test_patch_imports_lazily(self): + sys.modules.pop('squizz', None) + + p1 = patch('squizz.squozz') + self.assertRaises(ImportError, p1.start) + + squizz = Mock() + squizz.squozz = 6 + sys.modules['squizz'] = squizz + p1 = patch('squizz.squozz') + squizz.squozz = 3 + p1.start() + p1.stop() + self.assertEqual(squizz.squozz, 3) + + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testsentinel.py b/Lib/unittest/test/testmock/testsentinel.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testsentinel.py @@ -0,0 +1,28 @@ +import unittest +from unittest.mock import sentinel, DEFAULT + + +class SentinelTest(unittest.TestCase): + + def testSentinels(self): + self.assertEqual(sentinel.whatever, sentinel.whatever, + 'sentinel not stored') + self.assertNotEqual(sentinel.whatever, sentinel.whateverelse, + 'sentinel should be unique') + + + def testSentinelName(self): + self.assertEqual(str(sentinel.whatever), 'sentinel.whatever', + 'sentinel name incorrect') + + + def testDEFAULT(self): + self.assertTrue(DEFAULT is sentinel.DEFAULT) + + def testBases(self): + # If this doesn't raise an AttributeError then help(mock) is broken + self.assertRaises(AttributeError, lambda: sentinel.__bases__) + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testwith.py b/Lib/unittest/test/testmock/testwith.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testwith.py @@ -0,0 +1,176 @@ +import unittest +from warnings import catch_warnings + +from unittest.test.testmock.support import is_instance +from unittest.mock import MagicMock, Mock, patch, sentinel, mock_open, call + + + +something = sentinel.Something +something_else = sentinel.SomethingElse + + + +class WithTest(unittest.TestCase): + + def test_with_statement(self): + with patch('%s.something' % __name__, sentinel.Something2): + self.assertEqual(something, sentinel.Something2, "unpatched") + self.assertEqual(something, sentinel.Something) + + + def test_with_statement_exception(self): + try: + with patch('%s.something' % __name__, sentinel.Something2): + self.assertEqual(something, sentinel.Something2, "unpatched") + raise Exception('pow') + except Exception: + pass + else: + self.fail("patch swallowed exception") + self.assertEqual(something, sentinel.Something) + + + def test_with_statement_as(self): + with patch('%s.something' % __name__) as mock_something: + self.assertEqual(something, mock_something, "unpatched") + self.assertTrue(is_instance(mock_something, MagicMock), + "patching wrong type") + self.assertEqual(something, sentinel.Something) + + + def test_patch_object_with_statement(self): + class Foo(object): + something = 'foo' + original = Foo.something + with patch.object(Foo, 'something'): + self.assertNotEqual(Foo.something, original, "unpatched") + self.assertEqual(Foo.something, original) + + + def test_with_statement_nested(self): + with catch_warnings(record=True): + with patch('%s.something' % __name__) as mock_something, patch('%s.something_else' % __name__) as mock_something_else: + self.assertEqual(something, mock_something, "unpatched") + self.assertEqual(something_else, mock_something_else, + "unpatched") + + self.assertEqual(something, sentinel.Something) + self.assertEqual(something_else, sentinel.SomethingElse) + + + def test_with_statement_specified(self): + with patch('%s.something' % __name__, sentinel.Patched) as mock_something: + self.assertEqual(something, mock_something, "unpatched") + self.assertEqual(mock_something, sentinel.Patched, "wrong patch") + self.assertEqual(something, sentinel.Something) + + + def testContextManagerMocking(self): + mock = Mock() + mock.__enter__ = Mock() + mock.__exit__ = Mock() + mock.__exit__.return_value = False + + with mock as m: + self.assertEqual(m, mock.__enter__.return_value) + mock.__enter__.assert_called_with() + mock.__exit__.assert_called_with(None, None, None) + + + def test_context_manager_with_magic_mock(self): + mock = MagicMock() + + with self.assertRaises(TypeError): + with mock: + 'foo' + 3 + mock.__enter__.assert_called_with() + self.assertTrue(mock.__exit__.called) + + + def test_with_statement_same_attribute(self): + with patch('%s.something' % __name__, sentinel.Patched) as mock_something: + self.assertEqual(something, mock_something, "unpatched") + + with patch('%s.something' % __name__) as mock_again: + self.assertEqual(something, mock_again, "unpatched") + + self.assertEqual(something, mock_something, + "restored with wrong instance") + + self.assertEqual(something, sentinel.Something, "not restored") + + + def test_with_statement_imbricated(self): + with patch('%s.something' % __name__) as mock_something: + self.assertEqual(something, mock_something, "unpatched") + + with patch('%s.something_else' % __name__) as mock_something_else: + self.assertEqual(something_else, mock_something_else, + "unpatched") + + self.assertEqual(something, sentinel.Something) + self.assertEqual(something_else, sentinel.SomethingElse) + + + def test_dict_context_manager(self): + foo = {} + with patch.dict(foo, {'a': 'b'}): + self.assertEqual(foo, {'a': 'b'}) + self.assertEqual(foo, {}) + + with self.assertRaises(NameError): + with patch.dict(foo, {'a': 'b'}): + self.assertEqual(foo, {'a': 'b'}) + raise NameError('Konrad') + + self.assertEqual(foo, {}) + + + +class TestMockOpen(unittest.TestCase): + + def test_mock_open(self): + mock = mock_open() + with patch('%s.open' % __name__, mock, create=True) as patched: + self.assertIs(patched, mock) + open('foo') + + mock.assert_called_once_with('foo') + + + def test_mock_open_context_manager(self): + mock = mock_open() + handle = mock.return_value + with patch('%s.open' % __name__, mock, create=True): + with open('foo') as f: + f.read() + + expected_calls = [call('foo'), call().__enter__(), call().read(), + call().__exit__(None, None, None)] + self.assertEqual(mock.mock_calls, expected_calls) + self.assertIs(f, handle) + + + def test_explicit_mock(self): + mock = MagicMock() + mock_open(mock) + + with patch('%s.open' % __name__, mock, create=True) as patched: + self.assertIs(patched, mock) + open('foo') + + mock.assert_called_once_with('foo') + + + def test_read_data(self): + mock = mock_open(read_data='foo') + with patch('%s.open' % __name__, mock, create=True): + h = open('bar') + result = h.read() + + self.assertEqual(result, 'foo') + + +if __name__ == '__main__': + unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 20:32:50 2012 From: python-checkins at python.org (r.david.murray) Date: Wed, 14 Mar 2012 20:32:50 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=2312818=3A_remove_escaping?= =?utf8?q?_of_=28=29_in_quoted_strings_in_formataddr?= Message-ID: http://hg.python.org/cpython/rev/ec191c51a15f changeset: 75633:ec191c51a15f user: R David Murray date: Wed Mar 14 15:31:47 2012 -0400 summary: #12818: remove escaping of () in quoted strings in formataddr The quoting of ()s inside quoted strings is allowed by the RFC, but is not needed. There seems to be no reason to add needless escapes. files: Lib/email/utils.py | 2 +- Lib/test/test_email/test_email.py | 14 +++++++++++++- Misc/NEWS | 3 +++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Lib/email/utils.py b/Lib/email/utils.py --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -55,7 +55,7 @@ TICK = "'" specialsre = re.compile(r'[][\\()<>@,:;".]') -escapesre = re.compile(r'[][\\()"]') +escapesre = re.compile(r'[\\"]') diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -2702,7 +2702,10 @@ def test_escape_dump(self): self.assertEqual( utils.formataddr(('A (Very) Silly Person', 'person at dom.ain')), - r'"A \(Very\) Silly Person" ') + r'"A (Very) Silly Person" ') + self.assertEqual( + utils.parseaddr(r'"A \(Very\) Silly Person" '), + ('A (Very) Silly Person', 'person at dom.ain')) a = r'A \(Special\) Person' b = 'person at dom.ain' self.assertEqual(utils.parseaddr(utils.formataddr((a, b))), (a, b)) @@ -2800,6 +2803,15 @@ self.assertEqual(('', 'merwok.wok.wok at xample.com'), utils.parseaddr('merwok. wok . wok at xample.com')) + def test_formataddr_does_not_quote_parens_in_quoted_string(self): + addr = ("'foo at example.com' (foo at example.com)", + 'foo at example.com') + addrstr = ('"\'foo at example.com\' ' + '(foo at example.com)" ') + self.assertEqual(utils.parseaddr(addrstr), addr) + self.assertEqual(utils.formataddr(addr), addrstr) + + def test_multiline_from_comment(self): x = """\ Foo diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #12818: format address no longer needlessly \ escapes ()s in names when + the name ends up being quoted. + - Issue #14062: BytesGenerator now correctly folds Header objects, including using linesep when folding. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 20:38:14 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 14 Mar 2012 20:38:14 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_import_failure_in_mock_?= =?utf8?q?test?= Message-ID: http://hg.python.org/cpython/rev/82d670c8268d changeset: 75634:82d670c8268d user: Michael Foord date: Wed Mar 14 12:38:06 2012 -0700 summary: Fix import failure in mock test files: Lib/unittest/test/testmock/testpatch.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -9,7 +9,7 @@ from unittest.test.testmock import support from unittest.test.testmock.support import SomeClass, is_instance -from mock import ( +from unittest.mock import ( NonCallableMock, CallableMixin, patch, sentinel, MagicMock, Mock, NonCallableMagicMock, patch, DEFAULT, call -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 20:55:02 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 20:55:02 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Avoid_main=5Fwindow_unused_?= =?utf8?q?compiler_warning=2E?= Message-ID: http://hg.python.org/cpython/rev/a7a9e0f46b8a changeset: 75635:a7a9e0f46b8a user: Gregory P. Smith date: Tue Mar 13 23:21:53 2012 -0700 summary: Avoid main_window unused compiler warning. files: Modules/tkappinit.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c --- a/Modules/tkappinit.c +++ b/Modules/tkappinit.c @@ -26,7 +26,9 @@ int Tcl_AppInit(Tcl_Interp *interp) { +#ifdef WITH_MOREBUTTONS Tk_Window main_window; +#endif const char *_tkinter_skip_tk_init; #ifdef TKINTER_PROTECT_LOADTK const char *_tkinter_tk_failed; @@ -111,7 +113,11 @@ return TCL_ERROR; } +#ifdef WITH_MOREBUTTONS main_window = Tk_MainWindow(interp); +#else + Tk_MainWindow(interp); +#endif #ifdef TK_AQUA TkMacOSXInitAppleEvents(interp); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 20:59:14 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 14 Mar 2012 20:59:14 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_another_mock_import?= Message-ID: http://hg.python.org/cpython/rev/6493f091b401 changeset: 75636:6493f091b401 parent: 75634:82d670c8268d user: Michael Foord date: Wed Mar 14 12:58:46 2012 -0700 summary: Fix another mock import files: Lib/unittest/test/testmock/testmock.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -32,7 +32,7 @@ # if __all__ is badly defined then import * will raise an error # We have to exec it because you can't import * inside a method # in Python 3 - exec("from mock import *") + exec("from unittest.mock import *") def test_constructor(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 20:59:15 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 14 Mar 2012 20:59:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merge?= Message-ID: http://hg.python.org/cpython/rev/4925efb9f9f6 changeset: 75637:4925efb9f9f6 parent: 75636:6493f091b401 parent: 75635:a7a9e0f46b8a user: Michael Foord date: Wed Mar 14 12:59:08 2012 -0700 summary: Merge files: Modules/tkappinit.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c --- a/Modules/tkappinit.c +++ b/Modules/tkappinit.c @@ -26,7 +26,9 @@ int Tcl_AppInit(Tcl_Interp *interp) { +#ifdef WITH_MOREBUTTONS Tk_Window main_window; +#endif const char *_tkinter_skip_tk_init; #ifdef TKINTER_PROTECT_LOADTK const char *_tkinter_tk_failed; @@ -111,7 +113,11 @@ return TCL_ERROR; } +#ifdef WITH_MOREBUTTONS main_window = Tk_MainWindow(interp); +#else + Tk_MainWindow(interp); +#endif #ifdef TK_AQUA TkMacOSXInitAppleEvents(interp); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 21:01:39 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 14 Mar 2012 21:01:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_And_another_one=2E=2E=2E_mo?= =?utf8?q?ck_import_fix=2E?= Message-ID: http://hg.python.org/cpython/rev/bf1fb7afc947 changeset: 75638:bf1fb7afc947 user: Michael Foord date: Wed Mar 14 13:01:31 2012 -0700 summary: And another one... mock import fix. files: Lib/unittest/test/testmock/testpatch.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -1535,7 +1535,7 @@ self.assertEqual(foo.fish, 'tasty') - @patch('mock.patch.TEST_PREFIX', 'foo') + @patch('unittest.mock.patch.TEST_PREFIX', 'foo') def test_patch_test_prefix(self): class Foo(object): thing = 'original' @@ -1558,7 +1558,7 @@ self.assertEqual(foo.test_two(), 'original') - @patch('mock.patch.TEST_PREFIX', 'bar') + @patch('unittest.mock.patch.TEST_PREFIX', 'bar') def test_patch_dict_test_prefix(self): class Foo(object): def bar_one(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 21:30:42 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 14 Mar 2012 21:30:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_Python_2_compatibili?= =?utf8?q?ty_cruft_from_unittest=2Emock?= Message-ID: http://hg.python.org/cpython/rev/6700fd345835 changeset: 75639:6700fd345835 user: Michael Foord date: Wed Mar 14 13:30:29 2012 -0700 summary: Remove Python 2 compatibility cruft from unittest.mock files: Lib/unittest/mock.py | 8 +++----- 1 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1,5 +1,8 @@ # mock.py # Test tools for mocking and patching. +# Maintained by Michael Foord +# Backport for other versions of Python available from +# http://pypi.python.org/pypi/mock __all__ = ( 'Mock', @@ -259,11 +262,6 @@ _deleted = sentinel.DELETED -class OldStyleClass: - pass -ClassType = type(OldStyleClass) - - def _copy(value): if type(value) in (dict, list, tuple, set): return type(value)(value) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 21:44:03 2012 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 14 Mar 2012 21:44:03 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_deprecated_the_old_urllib_p?= =?utf8?q?rimitives_in_3=2E3_urllib_package_-_issue_10050?= Message-ID: http://hg.python.org/cpython/rev/eab274c7d456 changeset: 75640:eab274c7d456 user: Senthil Kumaran date: Wed Mar 14 13:43:53 2012 -0700 summary: deprecated the old urllib primitives in 3.3 urllib package - issue 10050 files: Doc/library/urllib.request.rst | 92 +++++++++++++-------- Lib/test/test_urllib.py | 4 + Lib/test/test_urllib2.py | 23 ++++- Lib/urllib/request.py | 44 +++++++--- 4 files changed, 112 insertions(+), 51 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -385,12 +385,6 @@ .. versionadded:: 3.3 -.. method:: Request.add_data(data) - - Set the :class:`Request` data to *data*. This is ignored by all handlers except - HTTP handlers --- and there it should be a byte string, and will change the - request to be ``POST`` rather than ``GET``. - .. method:: Request.get_method() @@ -403,16 +397,6 @@ get_method now looks at the value of :attr:`Request.method`. -.. method:: Request.has_data() - - Return whether the instance has a non-\ ``None`` data. - - -.. method:: Request.get_data() - - Return the instance's data. - - .. method:: Request.add_header(key, val) Add another header to the request. Headers are currently ignored by all @@ -440,21 +424,6 @@ Return the URL given in the constructor. -.. method:: Request.get_type() - - Return the type of the URL --- also known as the scheme. - - -.. method:: Request.get_host() - - Return the host to which a connection will be made. - - -.. method:: Request.get_selector() - - Return the selector --- the part of the URL that is sent to the server. - - .. method:: Request.set_proxy(host, type) Prepare the request by connecting to a proxy server. The *host* and *type* will @@ -462,16 +431,71 @@ URL given in the constructor. +.. method:: Request.add_data(data) + + Set the :class:`Request` data to *data*. This is ignored by all handlers except + HTTP handlers --- and there it should be a byte string, and will change the + request to be ``POST`` rather than ``GET``. Deprecated in 3.3, use + :attr:`Request.data`. + + .. deprecated:: 3.3 + + +.. method:: Request.has_data() + + Return whether the instance has a non-\ ``None`` data. Deprecated in 3.3, + use :attr:`Request.data`. + + .. deprecated:: 3.3 + + +.. method:: Request.get_data() + + Return the instance's data. Deprecated in 3.3, use :attr:`Request.data`. + + .. deprecated:: 3.3 + + +.. method:: Request.get_type() + + Return the type of the URL --- also known as the scheme. Deprecated in 3.3, + use :attr:`Request.type`. + + .. deprecated:: 3.3 + + +.. method:: Request.get_host() + + Return the host to which a connection will be made. Deprecated in 3.3, use + :attr:`Request.host`. + + .. deprecated:: 3.3 + + +.. method:: Request.get_selector() + + Return the selector --- the part of the URL that is sent to the server. + Deprecated in 3.3, use :attr:`Request.selector`. + + .. deprecated:: 3.3 + + .. method:: Request.get_origin_req_host() - Return the request-host of the origin transaction, as defined by :rfc:`2965`. - See the documentation for the :class:`Request` constructor. + Return the request-host of the origin transaction, as defined by + :rfc:`2965`. See the documentation for the :class:`Request` constructor. + Deprecated in 3.3, use :attr:`Request.origin_req_host`. + + .. deprecated:: 3.3 .. method:: Request.is_unverifiable() Return whether the request is unverifiable, as defined by RFC 2965. See the - documentation for the :class:`Request` constructor. + documentation for the :class:`Request` constructor. Deprecated in 3.3, use + :attr:`Request.is_unverifiable`. + + .. deprecated:: 3.3 .. _opener-director-objects: diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -298,6 +298,10 @@ finally: self.unfakehttp() + def test_URLopener_deprecation(self): + with support.check_warnings(('',DeprecationWarning)): + warn = urllib.request.URLopener() + class urlretrieve_FileTests(unittest.TestCase): """Test urllib.urlretrieve() on local files""" diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -553,10 +553,6 @@ self.assertRaises(urllib.error.URLError, o.open, req) self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})]) -## def test_error(self): -## # XXX this doesn't actually seem to be used in standard library, -## # but should really be tested anyway... - def test_http_error(self): # XXX http_error_default # http errors are a special case @@ -584,6 +580,7 @@ self.assertEqual((handler, method_name), got[:2]) self.assertEqual(args, got[2]) + def test_processors(self): # *_request / *_response methods get called appropriately o = OpenerDirector() @@ -619,6 +616,24 @@ self.assertTrue(args[1] is None or isinstance(args[1], MockResponse)) + def test_method_deprecations(self): + req = Request("http://www.example.com") + with support.check_warnings(('', DeprecationWarning)): + req.add_data("data") + with support.check_warnings(('', DeprecationWarning)): + req.has_data() + with support.check_warnings(('', DeprecationWarning)): + req.get_data() + with support.check_warnings(('', DeprecationWarning)): + req.get_full_url() + with support.check_warnings(('', DeprecationWarning)): + req.get_host() + with support.check_warnings(('', DeprecationWarning)): + req.get_selector() + with support.check_warnings(('', DeprecationWarning)): + req.is_unverifiable() + with support.check_warnings(('', DeprecationWarning)): + req.get_origin_req_host() def sanepathname2url(path): try: diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -96,6 +96,7 @@ import collections import tempfile import contextlib +import warnings from urllib.error import URLError, HTTPError, ContentTooShortError @@ -291,36 +292,52 @@ else: return "GET" - # Begin deprecated methods - - def add_data(self, data): - self.data = data - - def has_data(self): - return self.data is not None - - def get_data(self): - return self.data - def get_full_url(self): if self.fragment: return '%s#%s' % (self.full_url, self.fragment) else: return self.full_url + # Begin deprecated methods + + def add_data(self, data): + msg = "Request.add_data method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) + self.data = data + + def has_data(self): + msg = "Request.has_data method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) + return self.data is not None + + def get_data(self): + msg = "Request.get_data method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) + return self.data + def get_type(self): + msg = "Request.get_type method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.type def get_host(self): + msg = "Request.get_host method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.host def get_selector(self): + msg = "Request.get_selector method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.selector def is_unverifiable(self): + msg = "Request.is_unverifiable method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.unverifiable def get_origin_req_host(self): + msg = "Request.get_origin_req_host method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.origin_req_host # End deprecated methods @@ -1552,6 +1569,9 @@ # Constructor def __init__(self, proxies=None, **x509): + msg = "%(class)s style of invoking requests is deprecated."\ + "Use newer urlopen functions/methods" % {'class': self.__class__.__name__} + warnings.warn(msg, DeprecationWarning, stacklevel=3) if proxies is None: proxies = getproxies() assert hasattr(proxies, 'keys'), "proxies must be a mapping" @@ -1753,7 +1773,6 @@ if proxy_bypass(realhost): host = realhost - #print "proxy via http:", host, selector if not host: raise IOError('http error', 'no host given') if proxy_passwd: @@ -2554,7 +2573,6 @@ test = test.replace("*", r".*") # change glob sequence test = test.replace("?", r".") # change glob char for val in host: - # print "%s <--> %s" %( test, val ) if re.match(test, val, re.I): return 1 return 0 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 21:46:17 2012 From: python-checkins at python.org (andrew.svetlov) Date: Wed, 14 Mar 2012 21:46:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314200=3A_Idle_shel?= =?utf8?q?l_crash_on_printing_non-BMP_unicode_character=2E?= Message-ID: http://hg.python.org/cpython/rev/c06b94c5c609 changeset: 75641:c06b94c5c609 parent: 75628:7cbc48324938 user: Andrew Svetlov date: Wed Mar 14 13:22:12 2012 -0700 summary: Issue #14200: Idle shell crash on printing non-BMP unicode character. UnicodeEncodeError is raised for strings contains non-BMP characters. For eval results unicode escaping is used, print() calls display exception with traceback as usual. files: Lib/idlelib/PyShell.py | 10 ++++++++++ Lib/idlelib/rpc.py | 7 +++++++ Lib/idlelib/run.py | 21 +++++++++++++++++++++ Misc/NEWS | 2 ++ 4 files changed, 40 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1221,6 +1221,16 @@ self.set_line_and_column() def write(self, s, tags=()): + if isinstance(s, str) and len(s) and max(s) > '\uffff': + # Tk doesn't support outputting non-BMP characters + # Let's assume what printed string is not very long, + # find first non-BMP character and construct informative + # UnicodeEncodeError exception. + for start, char in enumerate(s): + if char > '\uffff': + break + raise UnicodeEncodeError("UCS-2", char, start, start+1, + 'Non-BMP character not supported in Tk') try: self.text.mark_gravity("iomark", "right") OutputWindow.write(self, s, tags, "iomark") diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py --- a/Lib/idlelib/rpc.py +++ b/Lib/idlelib/rpc.py @@ -196,8 +196,12 @@ return ("ERROR", "Unsupported message type: %s" % how) except SystemExit: raise + except KeyboardInterrupt: + raise except socket.error: raise + except Exception as ex: + return ("CALLEXC", ex) except: msg = "*** Internal Error: rpc.py:SocketIO.localcall()\n\n"\ " Object: %s \n Method: %s \n Args: %s\n" @@ -257,6 +261,9 @@ if how == "ERROR": self.debug("decoderesponse: Internal ERROR:", what) raise RuntimeError(what) + if how == "CALLEXC": + self.debug("decoderesponse: Call Exception:", what) + raise what raise SystemError(how, what) def decode_interrupthook(self): diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -6,6 +6,7 @@ import _thread as thread import threading import queue +import builtins from idlelib import CallTips from idlelib import AutoComplete @@ -261,6 +262,25 @@ thread.interrupt_main() +def displayhook(value): + """Override standard display hook to use non-locale encoding""" + if value is None: + return + # Set '_' to None to avoid recursion + builtins._ = None + text = repr(value) + try: + sys.stdout.write(text) + except UnicodeEncodeError: + # let's use ascii while utf8-bmp codec doesn't present + encoding = 'ascii' + bytes = text.encode(encoding, 'backslashreplace') + text = bytes.decode(encoding, 'strict') + sys.stdout.write(text) + sys.stdout.write("\n") + builtins._ = value + + class MyHandler(rpc.RPCHandler): def handle(self): @@ -270,6 +290,7 @@ sys.stdin = self.console = self.get_remote_proxy("stdin") sys.stdout = self.get_remote_proxy("stdout") sys.stderr = self.get_remote_proxy("stderr") + sys.displayhook = displayhook # page help() text to shell. import pydoc # import must be done here to capture i/o binding pydoc.pager = pydoc.plainpager diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #14200: Idle shell crash on printing non-BMP unicode character. + - Issue #14291: Email now defaults to utf-8 for non-ASCII unicode headers instead of raising an error. This fixes a regression relative to 2.7. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 21:46:18 2012 From: python-checkins at python.org (andrew.svetlov) Date: Wed, 14 Mar 2012 21:46:18 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merge_from_tip?= Message-ID: http://hg.python.org/cpython/rev/e6baf63f2f15 changeset: 75642:e6baf63f2f15 parent: 75641:c06b94c5c609 parent: 75638:bf1fb7afc947 user: Andrew Svetlov date: Wed Mar 14 13:44:02 2012 -0700 summary: Merge from tip files: Lib/email/generator.py | 3 + Lib/email/utils.py | 2 +- Lib/pstats.py | 2 + Lib/test/test_email/test_email.py | 38 +- Lib/unittest/mock.py | 2151 ++++++++++ Lib/unittest/test/__init__.py | 1 + Lib/unittest/test/testmock/__init__.py | 17 + Lib/unittest/test/testmock/support.py | 23 + Lib/unittest/test/testmock/testcallable.py | 159 + Lib/unittest/test/testmock/testhelpers.py | 835 +++ Lib/unittest/test/testmock/testmagicmethods.py | 382 + Lib/unittest/test/testmock/testmock.py | 1258 +++++ Lib/unittest/test/testmock/testpatch.py | 1652 +++++++ Lib/unittest/test/testmock/testsentinel.py | 28 + Lib/unittest/test/testmock/testwith.py | 176 + Misc/NEWS | 10 + Modules/tkappinit.c | 6 + 17 files changed, 6741 insertions(+), 2 deletions(-) diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -386,6 +386,9 @@ h = Header(v, charset=_charset.UNKNOWN8BIT, header_name=h) else: h = Header(v, header_name=h) + else: + # Assume it is a Header-like object. + h = v self.write(h.encode(linesep=self._NL, maxlinelen=self._maxheaderlen)+self._NL) # A blank line always separates headers from body diff --git a/Lib/email/utils.py b/Lib/email/utils.py --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -55,7 +55,7 @@ TICK = "'" specialsre = re.compile(r'[][\\()<>@,:;".]') -escapesre = re.compile(r'[][\\()"]') +escapesre = re.compile(r'[\\"]') diff --git a/Lib/pstats.py b/Lib/pstats.py --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -680,6 +680,8 @@ initprofile = None try: browser = ProfileBrowser(initprofile) + for profile in sys.argv[2:]: + browser.do_add(profile) print("Welcome to the profile statistics browser.", file=browser.stream) browser.cmdloop() print("Goodbye.", file=browser.stream) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -2702,7 +2702,10 @@ def test_escape_dump(self): self.assertEqual( utils.formataddr(('A (Very) Silly Person', 'person at dom.ain')), - r'"A \(Very\) Silly Person" ') + r'"A (Very) Silly Person" ') + self.assertEqual( + utils.parseaddr(r'"A \(Very\) Silly Person" '), + ('A (Very) Silly Person', 'person at dom.ain')) a = r'A \(Special\) Person' b = 'person at dom.ain' self.assertEqual(utils.parseaddr(utils.formataddr((a, b))), (a, b)) @@ -2800,6 +2803,15 @@ self.assertEqual(('', 'merwok.wok.wok at xample.com'), utils.parseaddr('merwok. wok . wok at xample.com')) + def test_formataddr_does_not_quote_parens_in_quoted_string(self): + addr = ("'foo at example.com' (foo at example.com)", + 'foo at example.com') + addrstr = ('"\'foo at example.com\' ' + '(foo at example.com)" ') + self.assertEqual(utils.parseaddr(addrstr), addr) + self.assertEqual(utils.formataddr(addr), addrstr) + + def test_multiline_from_comment(self): x = """\ Foo @@ -3601,6 +3613,30 @@ g.flatten(msg) self.assertEqual(s.getvalue(), source) + def test_bytes_generator_b_encoding_linesep(self): + # Issue 14062: b encoding was tacking on an extra \n. + m = Message() + # This has enough non-ascii that it should always end up b encoded. + m['Subject'] = Header('?lu?ou?k? k??') + s = BytesIO() + g = email.generator.BytesGenerator(s) + g.flatten(m, linesep='\r\n') + self.assertEqual( + s.getvalue(), + b'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n') + + def test_generator_b_encoding_linesep(self): + # Since this broke in ByteGenerator, test Generator for completeness. + m = Message() + # This has enough non-ascii that it should always end up b encoded. + m['Subject'] = Header('?lu?ou?k? k??') + s = StringIO() + g = email.generator.Generator(s) + g.flatten(m, linesep='\r\n') + self.assertEqual( + s.getvalue(), + 'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n') + def test_crlf_control_via_policy(self): # msg_26 is crlf terminated with openfile('msg_26.txt', 'rb') as fp: diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/mock.py @@ -0,0 +1,2151 @@ +# mock.py +# Test tools for mocking and patching. + +__all__ = ( + 'Mock', + 'MagicMock', + 'patch', + 'sentinel', + 'DEFAULT', + 'ANY', + 'call', + 'create_autospec', + 'FILTER_DIR', + 'NonCallableMock', + 'NonCallableMagicMock', + 'mock_open', + 'PropertyMock', +) + + +__version__ = '1.0' + + +import inspect +import pprint +import sys +from functools import wraps + + +BaseExceptions = (BaseException,) +if 'java' in sys.platform: + # jython + import java + BaseExceptions = (BaseException, java.lang.Throwable) + + +FILTER_DIR = True + + +def _is_instance_mock(obj): + # can't use isinstance on Mock objects because they override __class__ + # The base class for all mocks is NonCallableMock + return issubclass(type(obj), NonCallableMock) + + +def _is_exception(obj): + return ( + isinstance(obj, BaseExceptions) or + isinstance(obj, type) and issubclass(obj, BaseExceptions) + ) + + +class _slotted(object): + __slots__ = ['a'] + + +DescriptorTypes = ( + type(_slotted.a), + property, +) + + +def _getsignature(func, skipfirst, instance=False): + if isinstance(func, type) and not instance: + try: + func = func.__init__ + except AttributeError: + return + skipfirst = True + elif not isinstance(func, FunctionTypes): + # for classes where instance is True we end up here too + try: + func = func.__call__ + except AttributeError: + return + + try: + regargs, varargs, varkwargs, defaults = inspect.getargspec(func) + except TypeError: + # C function / method, possibly inherited object().__init__ + return + + # instance methods and classmethods need to lose the self argument + if getattr(func, '__self__', None) is not None: + regargs = regargs[1:] + if skipfirst: + # this condition and the above one are never both True - why? + regargs = regargs[1:] + + signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults, + formatvalue=lambda value: "") + return signature[1:-1], func + + +def _check_signature(func, mock, skipfirst, instance=False): + if not _callable(func): + return + + result = _getsignature(func, skipfirst, instance) + if result is None: + return + signature, func = result + + # can't use self because "self" is common as an argument name + # unfortunately even not in the first place + src = "lambda _mock_self, %s: None" % signature + checksig = eval(src, {}) + _copy_func_details(func, checksig) + type(mock)._mock_check_sig = checksig + + +def _copy_func_details(func, funcopy): + funcopy.__name__ = func.__name__ + funcopy.__doc__ = func.__doc__ + # we explicitly don't copy func.__dict__ into this copy as it would + # expose original attributes that should be mocked + funcopy.__module__ = func.__module__ + funcopy.__defaults__ = func.__defaults__ + funcopy.__kwdefaults__ = func.__kwdefaults__ + + +def _callable(obj): + if isinstance(obj, type): + return True + if getattr(obj, '__call__', None) is not None: + return True + return False + + +def _is_list(obj): + # checks for list or tuples + # XXXX badly named! + return type(obj) in (list, tuple) + + +def _instance_callable(obj): + """Given an object, return True if the object is callable. + For classes, return True if instances would be callable.""" + if not isinstance(obj, type): + # already an instance + return getattr(obj, '__call__', None) is not None + + klass = obj + # uses __bases__ instead of __mro__ so that we work with old style classes + if klass.__dict__.get('__call__') is not None: + return True + + for base in klass.__bases__: + if _instance_callable(base): + return True + return False + + +def _set_signature(mock, original, instance=False): + # creates a function with signature (*args, **kwargs) that delegates to a + # mock. It still does signature checking by calling a lambda with the same + # signature as the original. + if not _callable(original): + return + + skipfirst = isinstance(original, type) + result = _getsignature(original, skipfirst, instance) + if result is None: + # was a C function (e.g. object().__init__ ) that can't be mocked + return + + signature, func = result + + src = "lambda %s: None" % signature + context = {'_mock_': mock} + checksig = eval(src, context) + _copy_func_details(func, checksig) + + name = original.__name__ + if not name.isidentifier(): + name = 'funcopy' + context = {'checksig': checksig, 'mock': mock} + src = """def %s(*args, **kwargs): + checksig(*args, **kwargs) + return mock(*args, **kwargs)""" % name + exec (src, context) + funcopy = context[name] + _setup_func(funcopy, mock) + return funcopy + + +def _setup_func(funcopy, mock): + funcopy.mock = mock + + # can't use isinstance with mocks + if not _is_instance_mock(mock): + return + + def assert_called_with(*args, **kwargs): + return mock.assert_called_with(*args, **kwargs) + def assert_called_once_with(*args, **kwargs): + return mock.assert_called_once_with(*args, **kwargs) + def assert_has_calls(*args, **kwargs): + return mock.assert_has_calls(*args, **kwargs) + def assert_any_call(*args, **kwargs): + return mock.assert_any_call(*args, **kwargs) + def reset_mock(): + funcopy.method_calls = _CallList() + funcopy.mock_calls = _CallList() + mock.reset_mock() + ret = funcopy.return_value + if _is_instance_mock(ret) and not ret is mock: + ret.reset_mock() + + funcopy.called = False + funcopy.call_count = 0 + funcopy.call_args = None + funcopy.call_args_list = _CallList() + funcopy.method_calls = _CallList() + funcopy.mock_calls = _CallList() + + funcopy.return_value = mock.return_value + funcopy.side_effect = mock.side_effect + funcopy._mock_children = mock._mock_children + + funcopy.assert_called_with = assert_called_with + funcopy.assert_called_once_with = assert_called_once_with + funcopy.assert_has_calls = assert_has_calls + funcopy.assert_any_call = assert_any_call + funcopy.reset_mock = reset_mock + + mock._mock_delegate = funcopy + + +def _is_magic(name): + return '__%s__' % name[2:-2] == name + + +class _SentinelObject(object): + "A unique, named, sentinel object." + def __init__(self, name): + self.name = name + + def __repr__(self): + return 'sentinel.%s' % self.name + + +class _Sentinel(object): + """Access attributes to return a named object, usable as a sentinel.""" + def __init__(self): + self._sentinels = {} + + def __getattr__(self, name): + if name == '__bases__': + # Without this help(unittest.mock) raises an exception + raise AttributeError + return self._sentinels.setdefault(name, _SentinelObject(name)) + + +sentinel = _Sentinel() + +DEFAULT = sentinel.DEFAULT +_missing = sentinel.MISSING +_deleted = sentinel.DELETED + + +class OldStyleClass: + pass +ClassType = type(OldStyleClass) + + +def _copy(value): + if type(value) in (dict, list, tuple, set): + return type(value)(value) + return value + + +_allowed_names = set( + [ + 'return_value', '_mock_return_value', 'side_effect', + '_mock_side_effect', '_mock_parent', '_mock_new_parent', + '_mock_name', '_mock_new_name' + ] +) + + +def _delegating_property(name): + _allowed_names.add(name) + _the_name = '_mock_' + name + def _get(self, name=name, _the_name=_the_name): + sig = self._mock_delegate + if sig is None: + return getattr(self, _the_name) + return getattr(sig, name) + def _set(self, value, name=name, _the_name=_the_name): + sig = self._mock_delegate + if sig is None: + self.__dict__[_the_name] = value + else: + setattr(sig, name, value) + + return property(_get, _set) + + + +class _CallList(list): + + def __contains__(self, value): + if not isinstance(value, list): + return list.__contains__(self, value) + len_value = len(value) + len_self = len(self) + if len_value > len_self: + return False + + for i in range(0, len_self - len_value + 1): + sub_list = self[i:i+len_value] + if sub_list == value: + return True + return False + + def __repr__(self): + return pprint.pformat(list(self)) + + +def _check_and_set_parent(parent, value, name, new_name): + if not _is_instance_mock(value): + return False + if ((value._mock_name or value._mock_new_name) or + (value._mock_parent is not None) or + (value._mock_new_parent is not None)): + return False + + _parent = parent + while _parent is not None: + # setting a mock (value) as a child or return value of itself + # should not modify the mock + if _parent is value: + return False + _parent = _parent._mock_new_parent + + if new_name: + value._mock_new_parent = parent + value._mock_new_name = new_name + if name: + value._mock_parent = parent + value._mock_name = name + return True + + + +class Base(object): + _mock_return_value = DEFAULT + _mock_side_effect = None + def __init__(self, *args, **kwargs): + pass + + + +class NonCallableMock(Base): + """A non-callable version of `Mock`""" + + def __new__(cls, *args, **kw): + # every instance has its own class + # so we can create magic methods on the + # class without stomping on other mocks + new = type(cls.__name__, (cls,), {'__doc__': cls.__doc__}) + instance = object.__new__(new) + return instance + + + def __init__( + self, spec=None, wraps=None, name=None, spec_set=None, + parent=None, _spec_state=None, _new_name='', _new_parent=None, + **kwargs + ): + if _new_parent is None: + _new_parent = parent + + __dict__ = self.__dict__ + __dict__['_mock_parent'] = parent + __dict__['_mock_name'] = name + __dict__['_mock_new_name'] = _new_name + __dict__['_mock_new_parent'] = _new_parent + + if spec_set is not None: + spec = spec_set + spec_set = True + + self._mock_add_spec(spec, spec_set) + + __dict__['_mock_children'] = {} + __dict__['_mock_wraps'] = wraps + __dict__['_mock_delegate'] = None + + __dict__['_mock_called'] = False + __dict__['_mock_call_args'] = None + __dict__['_mock_call_count'] = 0 + __dict__['_mock_call_args_list'] = _CallList() + __dict__['_mock_mock_calls'] = _CallList() + + __dict__['method_calls'] = _CallList() + + if kwargs: + self.configure_mock(**kwargs) + + super(NonCallableMock, self).__init__( + spec, wraps, name, spec_set, parent, + _spec_state + ) + + + def attach_mock(self, mock, attribute): + """ + Attach a mock as an attribute of this one, replacing its name and + parent. Calls to the attached mock will be recorded in the + `method_calls` and `mock_calls` attributes of this one.""" + mock._mock_parent = None + mock._mock_new_parent = None + mock._mock_name = '' + mock._mock_new_name = None + + setattr(self, attribute, mock) + + + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + + + def _mock_add_spec(self, spec, spec_set): + _spec_class = None + + if spec is not None and not _is_list(spec): + if isinstance(spec, type): + _spec_class = spec + else: + _spec_class = _get_class(spec) + + spec = dir(spec) + + __dict__ = self.__dict__ + __dict__['_spec_class'] = _spec_class + __dict__['_spec_set'] = spec_set + __dict__['_mock_methods'] = spec + + + def __get_return_value(self): + ret = self._mock_return_value + if self._mock_delegate is not None: + ret = self._mock_delegate.return_value + + if ret is DEFAULT: + ret = self._get_child_mock( + _new_parent=self, _new_name='()' + ) + self.return_value = ret + return ret + + + def __set_return_value(self, value): + if self._mock_delegate is not None: + self._mock_delegate.return_value = value + else: + self._mock_return_value = value + _check_and_set_parent(self, value, None, '()') + + __return_value_doc = "The value to be returned when the mock is called." + return_value = property(__get_return_value, __set_return_value, + __return_value_doc) + + + @property + def __class__(self): + if self._spec_class is None: + return type(self) + return self._spec_class + + called = _delegating_property('called') + call_count = _delegating_property('call_count') + call_args = _delegating_property('call_args') + call_args_list = _delegating_property('call_args_list') + mock_calls = _delegating_property('mock_calls') + + + def __get_side_effect(self): + delegated = self._mock_delegate + if delegated is None: + return self._mock_side_effect + return delegated.side_effect + + def __set_side_effect(self, value): + value = _try_iter(value) + delegated = self._mock_delegate + if delegated is None: + self._mock_side_effect = value + else: + delegated.side_effect = value + + side_effect = property(__get_side_effect, __set_side_effect) + + + def reset_mock(self): + "Restore the mock object to its initial state." + self.called = False + self.call_args = None + self.call_count = 0 + self.mock_calls = _CallList() + self.call_args_list = _CallList() + self.method_calls = _CallList() + + for child in self._mock_children.values(): + child.reset_mock() + + ret = self._mock_return_value + if _is_instance_mock(ret) and ret is not self: + ret.reset_mock() + + + def configure_mock(self, **kwargs): + """Set attributes on the mock through keyword arguments. + + Attributes plus return values and side effects can be set on child + mocks using standard dot notation and unpacking a dictionary in the + method call: + + >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> mock.configure_mock(**attrs)""" + for arg, val in sorted(kwargs.items(), + # we sort on the number of dots so that + # attributes are set before we set attributes on + # attributes + key=lambda entry: entry[0].count('.')): + args = arg.split('.') + final = args.pop() + obj = self + for entry in args: + obj = getattr(obj, entry) + setattr(obj, final, val) + + + def __getattr__(self, name): + if name == '_mock_methods': + raise AttributeError(name) + elif self._mock_methods is not None: + if name not in self._mock_methods or name in _all_magics: + raise AttributeError("Mock object has no attribute %r" % name) + elif _is_magic(name): + raise AttributeError(name) + + result = self._mock_children.get(name) + if result is _deleted: + raise AttributeError(name) + elif result is None: + wraps = None + if self._mock_wraps is not None: + # XXXX should we get the attribute without triggering code + # execution? + wraps = getattr(self._mock_wraps, name) + + result = self._get_child_mock( + parent=self, name=name, wraps=wraps, _new_name=name, + _new_parent=self + ) + self._mock_children[name] = result + + elif isinstance(result, _SpecState): + result = create_autospec( + result.spec, result.spec_set, result.instance, + result.parent, result.name + ) + self._mock_children[name] = result + + return result + + + def __repr__(self): + _name_list = [self._mock_new_name] + _parent = self._mock_new_parent + last = self + + dot = '.' + if _name_list == ['()']: + dot = '' + seen = set() + while _parent is not None: + last = _parent + + _name_list.append(_parent._mock_new_name + dot) + dot = '.' + if _parent._mock_new_name == '()': + dot = '' + + _parent = _parent._mock_new_parent + + # use ids here so as not to call __hash__ on the mocks + if id(_parent) in seen: + break + seen.add(id(_parent)) + + _name_list = list(reversed(_name_list)) + _first = last._mock_name or 'mock' + if len(_name_list) > 1: + if _name_list[1] not in ('()', '().'): + _first += '.' + _name_list[0] = _first + name = ''.join(_name_list) + + name_string = '' + if name not in ('mock', 'mock.'): + name_string = ' name=%r' % name + + spec_string = '' + if self._spec_class is not None: + spec_string = ' spec=%r' + if self._spec_set: + spec_string = ' spec_set=%r' + spec_string = spec_string % self._spec_class.__name__ + return "<%s%s%s id='%s'>" % ( + type(self).__name__, + name_string, + spec_string, + id(self) + ) + + + def __dir__(self): + """Filter the output of `dir(mock)` to only useful members. + XXXX + """ + extras = self._mock_methods or [] + from_type = dir(type(self)) + from_dict = list(self.__dict__) + + if FILTER_DIR: + from_type = [e for e in from_type if not e.startswith('_')] + from_dict = [e for e in from_dict if not e.startswith('_') or + _is_magic(e)] + return sorted(set(extras + from_type + from_dict + + list(self._mock_children))) + + + def __setattr__(self, name, value): + if name in _allowed_names: + # property setters go through here + return object.__setattr__(self, name, value) + elif (self._spec_set and self._mock_methods is not None and + name not in self._mock_methods and + name not in self.__dict__): + raise AttributeError("Mock object has no attribute '%s'" % name) + elif name in _unsupported_magics: + msg = 'Attempting to set unsupported magic method %r.' % name + raise AttributeError(msg) + elif name in _all_magics: + if self._mock_methods is not None and name not in self._mock_methods: + raise AttributeError("Mock object has no attribute '%s'" % name) + + if not _is_instance_mock(value): + setattr(type(self), name, _get_method(name, value)) + original = value + value = lambda *args, **kw: original(self, *args, **kw) + else: + # only set _new_name and not name so that mock_calls is tracked + # but not method calls + _check_and_set_parent(self, value, None, name) + setattr(type(self), name, value) + elif name == '__class__': + self._spec_class = value + return + else: + if _check_and_set_parent(self, value, name, name): + self._mock_children[name] = value + return object.__setattr__(self, name, value) + + + def __delattr__(self, name): + if name in _all_magics and name in type(self).__dict__: + delattr(type(self), name) + if name not in self.__dict__: + # for magic methods that are still MagicProxy objects and + # not set on the instance itself + return + + if name in self.__dict__: + object.__delattr__(self, name) + + obj = self._mock_children.get(name, _missing) + if obj is _deleted: + raise AttributeError(name) + if obj is not _missing: + del self._mock_children[name] + self._mock_children[name] = _deleted + + + + def _format_mock_call_signature(self, args, kwargs): + name = self._mock_name or 'mock' + return _format_call_signature(name, args, kwargs) + + + def _format_mock_failure_message(self, args, kwargs): + message = 'Expected call: %s\nActual call: %s' + expected_string = self._format_mock_call_signature(args, kwargs) + call_args = self.call_args + if len(call_args) == 3: + call_args = call_args[1:] + actual_string = self._format_mock_call_signature(*call_args) + return message % (expected_string, actual_string) + + + def assert_called_with(_mock_self, *args, **kwargs): + """assert that the mock was called with the specified arguments. + + Raises an AssertionError if the args and keyword args passed in are + different to the last call to the mock.""" + self = _mock_self + if self.call_args is None: + expected = self._format_mock_call_signature(args, kwargs) + raise AssertionError('Expected call: %s\nNot called' % (expected,)) + + if self.call_args != (args, kwargs): + msg = self._format_mock_failure_message(args, kwargs) + raise AssertionError(msg) + + + def assert_called_once_with(_mock_self, *args, **kwargs): + """assert that the mock was called exactly once and with the specified + arguments.""" + self = _mock_self + if not self.call_count == 1: + msg = ("Expected to be called once. Called %s times." % + self.call_count) + raise AssertionError(msg) + return self.assert_called_with(*args, **kwargs) + + + def assert_has_calls(self, calls, any_order=False): + """assert the mock has been called with the specified calls. + The `mock_calls` list is checked for the calls. + + If `any_order` is False (the default) then the calls must be + sequential. There can be extra calls before or after the + specified calls. + + If `any_order` is True then the calls can be in any order, but + they must all appear in `mock_calls`.""" + if not any_order: + if calls not in self.mock_calls: + raise AssertionError( + 'Calls not found.\nExpected: %r\n' + 'Actual: %r' % (calls, self.mock_calls) + ) + return + + all_calls = list(self.mock_calls) + + not_found = [] + for kall in calls: + try: + all_calls.remove(kall) + except ValueError: + not_found.append(kall) + if not_found: + raise AssertionError( + '%r not all found in call list' % (tuple(not_found),) + ) + + + def assert_any_call(self, *args, **kwargs): + """assert the mock has been called with the specified arguments. + + The assert passes if the mock has *ever* been called, unlike + `assert_called_with` and `assert_called_once_with` that only pass if + the call is the most recent one.""" + kall = call(*args, **kwargs) + if kall not in self.call_args_list: + expected_string = self._format_mock_call_signature(args, kwargs) + raise AssertionError( + '%s call not found' % expected_string + ) + + + def _get_child_mock(self, **kw): + """Create the child mocks for attributes and return value. + By default child mocks will be the same type as the parent. + Subclasses of Mock may want to override this to customize the way + child mocks are made. + + For non-callable mocks the callable variant will be used (rather than + any custom subclass).""" + _type = type(self) + if not issubclass(_type, CallableMixin): + if issubclass(_type, NonCallableMagicMock): + klass = MagicMock + elif issubclass(_type, NonCallableMock) : + klass = Mock + else: + klass = _type.__mro__[1] + return klass(**kw) + + + +def _try_iter(obj): + if obj is None: + return obj + if _is_exception(obj): + return obj + if _callable(obj): + return obj + try: + return iter(obj) + except TypeError: + # XXXX backwards compatibility + # but this will blow up on first call - so maybe we should fail early? + return obj + + + +class CallableMixin(Base): + + def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, + wraps=None, name=None, spec_set=None, parent=None, + _spec_state=None, _new_name='', _new_parent=None, **kwargs): + self.__dict__['_mock_return_value'] = return_value + + super(CallableMixin, self).__init__( + spec, wraps, name, spec_set, parent, + _spec_state, _new_name, _new_parent, **kwargs + ) + + self.side_effect = side_effect + + + def _mock_check_sig(self, *args, **kwargs): + # stub method that can be replaced with one with a specific signature + pass + + + def __call__(_mock_self, *args, **kwargs): + # can't use self in-case a function / method we are mocking uses self + # in the signature + _mock_self._mock_check_sig(*args, **kwargs) + return _mock_self._mock_call(*args, **kwargs) + + + def _mock_call(_mock_self, *args, **kwargs): + self = _mock_self + self.called = True + self.call_count += 1 + self.call_args = _Call((args, kwargs), two=True) + self.call_args_list.append(_Call((args, kwargs), two=True)) + + _new_name = self._mock_new_name + _new_parent = self._mock_new_parent + self.mock_calls.append(_Call(('', args, kwargs))) + + seen = set() + skip_next_dot = _new_name == '()' + do_method_calls = self._mock_parent is not None + name = self._mock_name + while _new_parent is not None: + this_mock_call = _Call((_new_name, args, kwargs)) + if _new_parent._mock_new_name: + dot = '.' + if skip_next_dot: + dot = '' + + skip_next_dot = False + if _new_parent._mock_new_name == '()': + skip_next_dot = True + + _new_name = _new_parent._mock_new_name + dot + _new_name + + if do_method_calls: + if _new_name == name: + this_method_call = this_mock_call + else: + this_method_call = _Call((name, args, kwargs)) + _new_parent.method_calls.append(this_method_call) + + do_method_calls = _new_parent._mock_parent is not None + if do_method_calls: + name = _new_parent._mock_name + '.' + name + + _new_parent.mock_calls.append(this_mock_call) + _new_parent = _new_parent._mock_new_parent + + # use ids here so as not to call __hash__ on the mocks + _new_parent_id = id(_new_parent) + if _new_parent_id in seen: + break + seen.add(_new_parent_id) + + ret_val = DEFAULT + effect = self.side_effect + if effect is not None: + if _is_exception(effect): + raise effect + + if not _callable(effect): + return next(effect) + + ret_val = effect(*args, **kwargs) + if ret_val is DEFAULT: + ret_val = self.return_value + + if (self._mock_wraps is not None and + self._mock_return_value is DEFAULT): + return self._mock_wraps(*args, **kwargs) + if ret_val is DEFAULT: + ret_val = self.return_value + return ret_val + + + +class Mock(CallableMixin, NonCallableMock): + """ + Create a new `Mock` object. `Mock` takes several optional arguments + that specify the behaviour of the Mock object: + + * `spec`: This can be either a list of strings or an existing object (a + class or instance) that acts as the specification for the mock object. If + you pass in an object then a list of strings is formed by calling dir on + the object (excluding unsupported magic attributes and methods). Accessing + any attribute not in this list will raise an `AttributeError`. + + If `spec` is an object (rather than a list of strings) then + `mock.__class__` returns the class of the spec object. This allows mocks + to pass `isinstance` tests. + + * `spec_set`: A stricter variant of `spec`. If used, attempting to *set* + or get an attribute on the mock that isn't on the object passed as + `spec_set` will raise an `AttributeError`. + + * `side_effect`: A function to be called whenever the Mock is called. See + the `side_effect` attribute. Useful for raising exceptions or + dynamically changing return values. The function is called with the same + arguments as the mock, and unless it returns `DEFAULT`, the return + value of this function is used as the return value. + + Alternatively `side_effect` can be an exception class or instance. In + this case the exception will be raised when the mock is called. + + If `side_effect` is an iterable then each call to the mock will return + the next value from the iterable. + + * `return_value`: The value returned when the mock is called. By default + this is a new Mock (created on first access). See the + `return_value` attribute. + + * `wraps`: Item for the mock object to wrap. If `wraps` is not None + then calling the Mock will pass the call through to the wrapped object + (returning the real result and ignoring `return_value`). Attribute + access on the mock will return a Mock object that wraps the corresponding + attribute of the wrapped object (so attempting to access an attribute that + doesn't exist will raise an `AttributeError`). + + If the mock has an explicit `return_value` set then calls are not passed + to the wrapped object and the `return_value` is returned instead. + + * `name`: If the mock has a name then it will be used in the repr of the + mock. This can be useful for debugging. The name is propagated to child + mocks. + + Mocks can also be called with arbitrary keyword arguments. These will be + used to set attributes on the mock after it is created. + """ + + + +def _dot_lookup(thing, comp, import_path): + try: + return getattr(thing, comp) + except AttributeError: + __import__(import_path) + return getattr(thing, comp) + + +def _importer(target): + components = target.split('.') + import_path = components.pop(0) + thing = __import__(import_path) + + for comp in components: + import_path += ".%s" % comp + thing = _dot_lookup(thing, comp, import_path) + return thing + + +def _is_started(patcher): + # XXXX horrible + return hasattr(patcher, 'is_local') + + +class _patch(object): + + attribute_name = None + + def __init__( + self, getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ): + if new_callable is not None: + if new is not DEFAULT: + raise ValueError( + "Cannot use 'new' and 'new_callable' together" + ) + if autospec is not False: + raise ValueError( + "Cannot use 'autospec' and 'new_callable' together" + ) + + self.getter = getter + self.attribute = attribute + self.new = new + self.new_callable = new_callable + self.spec = spec + self.create = create + self.has_local = False + self.spec_set = spec_set + self.autospec = autospec + self.kwargs = kwargs + self.additional_patchers = [] + + + def copy(self): + patcher = _patch( + self.getter, self.attribute, self.new, self.spec, + self.create, self.spec_set, + self.autospec, self.new_callable, self.kwargs + ) + patcher.attribute_name = self.attribute_name + patcher.additional_patchers = [ + p.copy() for p in self.additional_patchers + ] + return patcher + + + def __call__(self, func): + if isinstance(func, type): + return self.decorate_class(func) + return self.decorate_callable(func) + + + def decorate_class(self, klass): + for attr in dir(klass): + if not attr.startswith(patch.TEST_PREFIX): + continue + + attr_value = getattr(klass, attr) + if not hasattr(attr_value, "__call__"): + continue + + patcher = self.copy() + setattr(klass, attr, patcher(attr_value)) + return klass + + + def decorate_callable(self, func): + if hasattr(func, 'patchings'): + func.patchings.append(self) + return func + + @wraps(func) + def patched(*args, **keywargs): + # could use with statement here + extra_args = [] + entered_patchers = [] + + # could use try..except...finally here + try: + try: + for patching in patched.patchings: + arg = patching.__enter__() + entered_patchers.append(patching) + if patching.attribute_name is not None: + keywargs.update(arg) + elif patching.new is DEFAULT: + extra_args.append(arg) + + args += tuple(extra_args) + return func(*args, **keywargs) + except: + if (patching not in entered_patchers and + _is_started(patching)): + # the patcher may have been started, but an exception + # raised whilst entering one of its additional_patchers + entered_patchers.append(patching) + # re-raise the exception + raise + finally: + for patching in reversed(entered_patchers): + patching.__exit__() + + patched.patchings = [self] + if hasattr(func, 'func_code'): + # not in Python 3 + patched.compat_co_firstlineno = getattr( + func, "compat_co_firstlineno", + func.func_code.co_firstlineno + ) + return patched + + + def get_original(self): + target = self.getter() + name = self.attribute + + original = DEFAULT + local = False + + try: + original = target.__dict__[name] + except (AttributeError, KeyError): + original = getattr(target, name, DEFAULT) + else: + local = True + + if not self.create and original is DEFAULT: + raise AttributeError( + "%s does not have the attribute %r" % (target, name) + ) + return original, local + + + def __enter__(self): + """Perform the patch.""" + new, spec, spec_set = self.new, self.spec, self.spec_set + autospec, kwargs = self.autospec, self.kwargs + new_callable = self.new_callable + self.target = self.getter() + + original, local = self.get_original() + + if new is DEFAULT and autospec is False: + inherit = False + if spec_set == True: + spec_set = original + elif spec == True: + # set spec to the object we are replacing + spec = original + + if (spec or spec_set) is not None: + if isinstance(original, type): + # If we're patching out a class and there is a spec + inherit = True + + Klass = MagicMock + _kwargs = {} + if new_callable is not None: + Klass = new_callable + elif (spec or spec_set) is not None: + if not _callable(spec or spec_set): + Klass = NonCallableMagicMock + + if spec is not None: + _kwargs['spec'] = spec + if spec_set is not None: + _kwargs['spec_set'] = spec_set + + # add a name to mocks + if (isinstance(Klass, type) and + issubclass(Klass, NonCallableMock) and self.attribute): + _kwargs['name'] = self.attribute + + _kwargs.update(kwargs) + new = Klass(**_kwargs) + + if inherit and _is_instance_mock(new): + # we can only tell if the instance should be callable if the + # spec is not a list + if (not _is_list(spec or spec_set) and not + _instance_callable(spec or spec_set)): + Klass = NonCallableMagicMock + + _kwargs.pop('name') + new.return_value = Klass(_new_parent=new, _new_name='()', + **_kwargs) + elif autospec is not False: + # spec is ignored, new *must* be default, spec_set is treated + # as a boolean. Should we check spec is not None and that spec_set + # is a bool? + if new is not DEFAULT: + raise TypeError( + "autospec creates the mock for you. Can't specify " + "autospec and new." + ) + spec_set = bool(spec_set) + if autospec is True: + autospec = original + + new = create_autospec(autospec, spec_set=spec_set, + _name=self.attribute, **kwargs) + elif kwargs: + # can't set keyword args when we aren't creating the mock + # XXXX If new is a Mock we could call new.configure_mock(**kwargs) + raise TypeError("Can't pass kwargs to a mock we aren't creating") + + new_attr = new + + self.temp_original = original + self.is_local = local + setattr(self.target, self.attribute, new_attr) + if self.attribute_name is not None: + extra_args = {} + if self.new is DEFAULT: + extra_args[self.attribute_name] = new + for patching in self.additional_patchers: + arg = patching.__enter__() + if patching.new is DEFAULT: + extra_args.update(arg) + return extra_args + + return new + + + def __exit__(self, *_): + """Undo the patch.""" + if not _is_started(self): + raise RuntimeError('stop called on unstarted patcher') + + if self.is_local and self.temp_original is not DEFAULT: + setattr(self.target, self.attribute, self.temp_original) + else: + delattr(self.target, self.attribute) + if not self.create and not hasattr(self.target, self.attribute): + # needed for proxy objects like django settings + setattr(self.target, self.attribute, self.temp_original) + + del self.temp_original + del self.is_local + del self.target + for patcher in reversed(self.additional_patchers): + if _is_started(patcher): + patcher.__exit__() + + start = __enter__ + stop = __exit__ + + + +def _get_target(target): + try: + target, attribute = target.rsplit('.', 1) + except (TypeError, ValueError): + raise TypeError("Need a valid target to patch. You supplied: %r" % + (target,)) + getter = lambda: _importer(target) + return getter, attribute + + +def _patch_object( + target, attribute, new=DEFAULT, spec=None, + create=False, spec_set=None, autospec=False, + new_callable=None, **kwargs + ): + """ + patch.object(target, attribute, new=DEFAULT, spec=None, create=False, + spec_set=None, autospec=False, + new_callable=None, **kwargs) + + patch the named member (`attribute`) on an object (`target`) with a mock + object. + + `patch.object` can be used as a decorator, class decorator or a context + manager. Arguments `new`, `spec`, `create`, `spec_set`, + `autospec` and `new_callable` have the same meaning as for `patch`. Like + `patch`, `patch.object` takes arbitrary keyword arguments for configuring + the mock object it creates. + + When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + """ + getter = lambda: target + return _patch( + getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ) + + +def _patch_multiple(target, spec=None, create=False, + spec_set=None, autospec=False, + new_callable=None, **kwargs + ): + """Perform multiple patches in a single call. It takes the object to be + patched (either as an object or a string to fetch the object by importing) + and keyword arguments for the patches:: + + with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): + ... + + Use `DEFAULT` as the value if you want `patch.multiple` to create + mocks for you. In this case the created mocks are passed into a decorated + function by keyword, and a dictionary is returned when `patch.multiple` is + used as a context manager. + + `patch.multiple` can be used as a decorator, class decorator or a context + manager. The arguments `spec`, `spec_set`, `create`, + `autospec` and `new_callable` have the same meaning as for `patch`. These + arguments will be applied to *all* patches done by `patch.multiple`. + + When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + """ + if type(target) is str: + getter = lambda: _importer(target) + else: + getter = lambda: target + + if not kwargs: + raise ValueError( + 'Must supply at least one keyword argument with patch.multiple' + ) + # need to wrap in a list for python 3, where items is a view + items = list(kwargs.items()) + attribute, new = items[0] + patcher = _patch( + getter, attribute, new, spec, create, spec_set, + autospec, new_callable, {} + ) + patcher.attribute_name = attribute + for attribute, new in items[1:]: + this_patcher = _patch( + getter, attribute, new, spec, create, spec_set, + autospec, new_callable, {} + ) + this_patcher.attribute_name = attribute + patcher.additional_patchers.append(this_patcher) + return patcher + + +def patch( + target, new=DEFAULT, spec=None, create=False, + spec_set=None, autospec=False, + new_callable=None, **kwargs + ): + """ + `patch` acts as a function decorator, class decorator or a context + manager. Inside the body of the function or with statement, the `target` + (specified in the form `'package.module.ClassName'`) is patched + with a `new` object. When the function/with statement exits the patch is + undone. + + The `target` is imported and the specified attribute patched with the new + object, so it must be importable from the environment you are calling the + decorator from. The target is imported when the decorated function is + executed, not at decoration time. + + If `new` is omitted, then a new `MagicMock` is created and passed in as an + extra argument to the decorated function. + + The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` + if patch is creating one for you. + + In addition you can pass `spec=True` or `spec_set=True`, which causes + patch to pass in the object being mocked as the spec/spec_set object. + + `new_callable` allows you to specify a different class, or callable object, + that will be called to create the `new` object. By default `MagicMock` is + used. + + A more powerful form of `spec` is `autospec`. If you set `autospec=True` + then the mock with be created with a spec from the object being replaced. + All attributes of the mock will also have the spec of the corresponding + attribute of the object being replaced. Methods and functions being + mocked will have their arguments checked and will raise a `TypeError` if + they are called with the wrong signature. For mocks replacing a class, + their return value (the 'instance') will have the same spec as the class. + + Instead of `autospec=True` you can pass `autospec=some_object` to use an + arbitrary object as the spec instead of the one being replaced. + + By default `patch` will fail to replace attributes that don't exist. If + you pass in `create=True`, and the attribute doesn't exist, patch will + create the attribute for you when the patched function is called, and + delete it again afterwards. This is useful for writing tests against + attributes that your production code creates at runtime. It is off by by + default because it can be dangerous. With it switched on you can write + passing tests against APIs that don't actually exist! + + Patch can be used as a `TestCase` class decorator. It works by + decorating each test method in the class. This reduces the boilerplate + code when your test methods share a common patchings set. `patch` finds + tests by looking for method names that start with `patch.TEST_PREFIX`. + By default this is `test`, which matches the way `unittest` finds tests. + You can specify an alternative prefix by setting `patch.TEST_PREFIX`. + + Patch can be used as a context manager, with the with statement. Here the + patching applies to the indented block after the with statement. If you + use "as" then the patched object will be bound to the name after the + "as"; very useful if `patch` is creating a mock object for you. + + `patch` takes arbitrary keyword arguments. These will be passed to + the `Mock` (or `new_callable`) on construction. + + `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are + available for alternate use-cases. + """ + getter, attribute = _get_target(target) + return _patch( + getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ) + + +class _patch_dict(object): + """ + Patch a dictionary, or dictionary like object, and restore the dictionary + to its original state after the test. + + `in_dict` can be a dictionary or a mapping like container. If it is a + mapping then it must at least support getting, setting and deleting items + plus iterating over keys. + + `in_dict` can also be a string specifying the name of the dictionary, which + will then be fetched by importing it. + + `values` can be a dictionary of values to set in the dictionary. `values` + can also be an iterable of `(key, value)` pairs. + + If `clear` is True then the dictionary will be cleared before the new + values are set. + + `patch.dict` can also be called with arbitrary keyword arguments to set + values in the dictionary:: + + with patch.dict('sys.modules', mymodule=Mock(), other_module=Mock()): + ... + + `patch.dict` can be used as a context manager, decorator or class + decorator. When used as a class decorator `patch.dict` honours + `patch.TEST_PREFIX` for choosing which methods to wrap. + """ + + def __init__(self, in_dict, values=(), clear=False, **kwargs): + if isinstance(in_dict, str): + in_dict = _importer(in_dict) + self.in_dict = in_dict + # support any argument supported by dict(...) constructor + self.values = dict(values) + self.values.update(kwargs) + self.clear = clear + self._original = None + + + def __call__(self, f): + if isinstance(f, type): + return self.decorate_class(f) + @wraps(f) + def _inner(*args, **kw): + self._patch_dict() + try: + return f(*args, **kw) + finally: + self._unpatch_dict() + + return _inner + + + def decorate_class(self, klass): + for attr in dir(klass): + attr_value = getattr(klass, attr) + if (attr.startswith(patch.TEST_PREFIX) and + hasattr(attr_value, "__call__")): + decorator = _patch_dict(self.in_dict, self.values, self.clear) + decorated = decorator(attr_value) + setattr(klass, attr, decorated) + return klass + + + def __enter__(self): + """Patch the dict.""" + self._patch_dict() + + + def _patch_dict(self): + values = self.values + in_dict = self.in_dict + clear = self.clear + + try: + original = in_dict.copy() + except AttributeError: + # dict like object with no copy method + # must support iteration over keys + original = {} + for key in in_dict: + original[key] = in_dict[key] + self._original = original + + if clear: + _clear_dict(in_dict) + + try: + in_dict.update(values) + except AttributeError: + # dict like object with no update method + for key in values: + in_dict[key] = values[key] + + + def _unpatch_dict(self): + in_dict = self.in_dict + original = self._original + + _clear_dict(in_dict) + + try: + in_dict.update(original) + except AttributeError: + for key in original: + in_dict[key] = original[key] + + + def __exit__(self, *args): + """Unpatch the dict.""" + self._unpatch_dict() + return False + + start = __enter__ + stop = __exit__ + + +def _clear_dict(in_dict): + try: + in_dict.clear() + except AttributeError: + keys = list(in_dict) + for key in keys: + del in_dict[key] + + +patch.object = _patch_object +patch.dict = _patch_dict +patch.multiple = _patch_multiple +patch.TEST_PREFIX = 'test' + +magic_methods = ( + "lt le gt ge eq ne " + "getitem setitem delitem " + "len contains iter " + "hash str sizeof " + "enter exit " + "divmod neg pos abs invert " + "complex int float index " + "trunc floor ceil " + "bool next " +) + +numerics = "add sub mul div floordiv mod lshift rshift and xor or pow " +inplace = ' '.join('i%s' % n for n in numerics.split()) +right = ' '.join('r%s' % n for n in numerics.split()) + +# not including __prepare__, __instancecheck__, __subclasscheck__ +# (as they are metaclass methods) +# __del__ is not supported at all as it causes problems if it exists + +_non_defaults = set('__%s__' % method for method in [ + 'cmp', 'getslice', 'setslice', 'coerce', 'subclasses', + 'format', 'get', 'set', 'delete', 'reversed', + 'missing', 'reduce', 'reduce_ex', 'getinitargs', + 'getnewargs', 'getstate', 'setstate', 'getformat', + 'setformat', 'repr', 'dir' +]) + + +def _get_method(name, func): + "Turns a callable object (like a mock) into a real function" + def method(self, *args, **kw): + return func(self, *args, **kw) + method.__name__ = name + return method + + +_magics = set( + '__%s__' % method for method in + ' '.join([magic_methods, numerics, inplace, right]).split() +) + +_all_magics = _magics | _non_defaults + +_unsupported_magics = set([ + '__getattr__', '__setattr__', + '__init__', '__new__', '__prepare__' + '__instancecheck__', '__subclasscheck__', + '__del__' +]) + +_calculate_return_value = { + '__hash__': lambda self: object.__hash__(self), + '__str__': lambda self: object.__str__(self), + '__sizeof__': lambda self: object.__sizeof__(self), +} + +_return_values = { + '__int__': 1, + '__contains__': False, + '__len__': 0, + '__exit__': False, + '__complex__': 1j, + '__float__': 1.0, + '__bool__': True, + '__index__': 1, +} + + +def _get_eq(self): + def __eq__(other): + ret_val = self.__eq__._mock_return_value + if ret_val is not DEFAULT: + return ret_val + return self is other + return __eq__ + +def _get_ne(self): + def __ne__(other): + if self.__ne__._mock_return_value is not DEFAULT: + return DEFAULT + return self is not other + return __ne__ + +def _get_iter(self): + def __iter__(): + ret_val = self.__iter__._mock_return_value + if ret_val is DEFAULT: + return iter([]) + # if ret_val was already an iterator, then calling iter on it should + # return the iterator unchanged + return iter(ret_val) + return __iter__ + +_side_effect_methods = { + '__eq__': _get_eq, + '__ne__': _get_ne, + '__iter__': _get_iter, +} + + + +def _set_return_value(mock, method, name): + fixed = _return_values.get(name, DEFAULT) + if fixed is not DEFAULT: + method.return_value = fixed + return + + return_calulator = _calculate_return_value.get(name) + if return_calulator is not None: + try: + return_value = return_calulator(mock) + except AttributeError: + # XXXX why do we return AttributeError here? + # set it as a side_effect instead? + return_value = AttributeError(name) + method.return_value = return_value + return + + side_effector = _side_effect_methods.get(name) + if side_effector is not None: + method.side_effect = side_effector(mock) + + + +class MagicMixin(object): + def __init__(self, *args, **kw): + super(MagicMixin, self).__init__(*args, **kw) + self._mock_set_magics() + + + def _mock_set_magics(self): + these_magics = _magics + + if self._mock_methods is not None: + these_magics = _magics.intersection(self._mock_methods) + + remove_magics = set() + remove_magics = _magics - these_magics + + for entry in remove_magics: + if entry in type(self).__dict__: + # remove unneeded magic methods + delattr(self, entry) + + # don't overwrite existing attributes if called a second time + these_magics = these_magics - set(type(self).__dict__) + + _type = type(self) + for entry in these_magics: + setattr(_type, entry, MagicProxy(entry, self)) + + + +class NonCallableMagicMock(MagicMixin, NonCallableMock): + """A version of `MagicMock` that isn't callable.""" + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + self._mock_set_magics() + + + +class MagicMock(MagicMixin, Mock): + """ + MagicMock is a subclass of Mock with default implementations + of most of the magic methods. You can use MagicMock without having to + configure the magic methods yourself. + + If you use the `spec` or `spec_set` arguments then *only* magic + methods that exist in the spec will be created. + + Attributes and the return value of a `MagicMock` will also be `MagicMocks`. + """ + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + self._mock_set_magics() + + + +class MagicProxy(object): + def __init__(self, name, parent): + self.name = name + self.parent = parent + + def __call__(self, *args, **kwargs): + m = self.create_mock() + return m(*args, **kwargs) + + def create_mock(self): + entry = self.name + parent = self.parent + m = parent._get_child_mock(name=entry, _new_name=entry, + _new_parent=parent) + setattr(parent, entry, m) + _set_return_value(parent, m, entry) + return m + + def __get__(self, obj, _type=None): + return self.create_mock() + + + +class _ANY(object): + "A helper object that compares equal to everything." + + def __eq__(self, other): + return True + + def __ne__(self, other): + return False + + def __repr__(self): + return '' + +ANY = _ANY() + + + +def _format_call_signature(name, args, kwargs): + message = '%s(%%s)' % name + formatted_args = '' + args_string = ', '.join([repr(arg) for arg in args]) + kwargs_string = ', '.join([ + '%s=%r' % (key, value) for key, value in kwargs.items() + ]) + if args_string: + formatted_args = args_string + if kwargs_string: + if formatted_args: + formatted_args += ', ' + formatted_args += kwargs_string + + return message % formatted_args + + + +class _Call(tuple): + """ + A tuple for holding the results of a call to a mock, either in the form + `(args, kwargs)` or `(name, args, kwargs)`. + + If args or kwargs are empty then a call tuple will compare equal to + a tuple without those values. This makes comparisons less verbose:: + + _Call(('name', (), {})) == ('name',) + _Call(('name', (1,), {})) == ('name', (1,)) + _Call(((), {'a': 'b'})) == ({'a': 'b'},) + + The `_Call` object provides a useful shortcut for comparing with call:: + + _Call(((1, 2), {'a': 3})) == call(1, 2, a=3) + _Call(('foo', (1, 2), {'a': 3})) == call.foo(1, 2, a=3) + + If the _Call has no name then it will match any name. + """ + def __new__(cls, value=(), name=None, parent=None, two=False, + from_kall=True): + name = '' + args = () + kwargs = {} + _len = len(value) + if _len == 3: + name, args, kwargs = value + elif _len == 2: + first, second = value + if isinstance(first, str): + name = first + if isinstance(second, tuple): + args = second + else: + kwargs = second + else: + args, kwargs = first, second + elif _len == 1: + value, = value + if isinstance(value, str): + name = value + elif isinstance(value, tuple): + args = value + else: + kwargs = value + + if two: + return tuple.__new__(cls, (args, kwargs)) + + return tuple.__new__(cls, (name, args, kwargs)) + + + def __init__(self, value=(), name=None, parent=None, two=False, + from_kall=True): + self.name = name + self.parent = parent + self.from_kall = from_kall + + + def __eq__(self, other): + if other is ANY: + return True + try: + len_other = len(other) + except TypeError: + return False + + self_name = '' + if len(self) == 2: + self_args, self_kwargs = self + else: + self_name, self_args, self_kwargs = self + + other_name = '' + if len_other == 0: + other_args, other_kwargs = (), {} + elif len_other == 3: + other_name, other_args, other_kwargs = other + elif len_other == 1: + value, = other + if isinstance(value, tuple): + other_args = value + other_kwargs = {} + elif isinstance(value, str): + other_name = value + other_args, other_kwargs = (), {} + else: + other_args = () + other_kwargs = value + else: + # len 2 + # could be (name, args) or (name, kwargs) or (args, kwargs) + first, second = other + if isinstance(first, str): + other_name = first + if isinstance(second, tuple): + other_args, other_kwargs = second, {} + else: + other_args, other_kwargs = (), second + else: + other_args, other_kwargs = first, second + + if self_name and other_name != self_name: + return False + + # this order is important for ANY to work! + return (other_args, other_kwargs) == (self_args, self_kwargs) + + + def __ne__(self, other): + return not self.__eq__(other) + + + def __call__(self, *args, **kwargs): + if self.name is None: + return _Call(('', args, kwargs), name='()') + + name = self.name + '()' + return _Call((self.name, args, kwargs), name=name, parent=self) + + + def __getattr__(self, attr): + if self.name is None: + return _Call(name=attr, from_kall=False) + name = '%s.%s' % (self.name, attr) + return _Call(name=name, parent=self, from_kall=False) + + + def __repr__(self): + if not self.from_kall: + name = self.name or 'call' + if name.startswith('()'): + name = 'call%s' % name + return name + + if len(self) == 2: + name = 'call' + args, kwargs = self + else: + name, args, kwargs = self + if not name: + name = 'call' + elif not name.startswith('()'): + name = 'call.%s' % name + else: + name = 'call%s' % name + return _format_call_signature(name, args, kwargs) + + + def call_list(self): + """For a call object that represents multiple calls, `call_list` + returns a list of all the intermediate calls as well as the + final call.""" + vals = [] + thing = self + while thing is not None: + if thing.from_kall: + vals.append(thing) + thing = thing.parent + return _CallList(reversed(vals)) + + +call = _Call(from_kall=False) + + + +def create_autospec(spec, spec_set=False, instance=False, _parent=None, + _name=None, **kwargs): + """Create a mock object using another object as a spec. Attributes on the + mock will use the corresponding attribute on the `spec` object as their + spec. + + Functions or methods being mocked will have their arguments checked + to check that they are called with the correct signature. + + If `spec_set` is True then attempting to set attributes that don't exist + on the spec object will raise an `AttributeError`. + + If a class is used as a spec then the return value of the mock (the + instance of the class) will have the same spec. You can use a class as the + spec for an instance object by passing `instance=True`. The returned mock + will only be callable if instances of the mock are callable. + + `create_autospec` also takes arbitrary keyword arguments that are passed to + the constructor of the created mock.""" + if _is_list(spec): + # can't pass a list instance to the mock constructor as it will be + # interpreted as a list of strings + spec = type(spec) + + is_type = isinstance(spec, type) + + _kwargs = {'spec': spec} + if spec_set: + _kwargs = {'spec_set': spec} + elif spec is None: + # None we mock with a normal mock without a spec + _kwargs = {} + + _kwargs.update(kwargs) + + Klass = MagicMock + if type(spec) in DescriptorTypes: + # descriptors don't have a spec + # because we don't know what type they return + _kwargs = {} + elif not _callable(spec): + Klass = NonCallableMagicMock + elif is_type and instance and not _instance_callable(spec): + Klass = NonCallableMagicMock + + _new_name = _name + if _parent is None: + # for a top level object no _new_name should be set + _new_name = '' + + mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name, + name=_name, **_kwargs) + + if isinstance(spec, FunctionTypes): + # should only happen at the top level because we don't + # recurse for functions + mock = _set_signature(mock, spec) + else: + _check_signature(spec, mock, is_type, instance) + + if _parent is not None and not instance: + _parent._mock_children[_name] = mock + + if is_type and not instance and 'return_value' not in kwargs: + # XXXX could give a name to the return_value mock? + mock.return_value = create_autospec(spec, spec_set, instance=True, + _name='()', _parent=mock) + + for entry in dir(spec): + if _is_magic(entry): + # MagicMock already does the useful magic methods for us + continue + + if isinstance(spec, FunctionTypes) and entry in FunctionAttributes: + # allow a mock to actually be a function + continue + + # XXXX do we need a better way of getting attributes without + # triggering code execution (?) Probably not - we need the actual + # object to mock it so we would rather trigger a property than mock + # the property descriptor. Likewise we want to mock out dynamically + # provided attributes. + # XXXX what about attributes that raise exceptions on being fetched + # we could be resilient against it, or catch and propagate the + # exception when the attribute is fetched from the mock + original = getattr(spec, entry) + + kwargs = {'spec': original} + if spec_set: + kwargs = {'spec_set': original} + + if not isinstance(original, FunctionTypes): + new = _SpecState(original, spec_set, mock, entry, instance) + mock._mock_children[entry] = new + else: + parent = mock + if isinstance(spec, FunctionTypes): + parent = mock.mock + + new = MagicMock(parent=parent, name=entry, _new_name=entry, + _new_parent=parent, **kwargs) + mock._mock_children[entry] = new + skipfirst = _must_skip(spec, entry, is_type) + _check_signature(original, new, skipfirst=skipfirst) + + # so functions created with _set_signature become instance attributes, + # *plus* their underlying mock exists in _mock_children of the parent + # mock. Adding to _mock_children may be unnecessary where we are also + # setting as an instance attribute? + if isinstance(new, FunctionTypes): + setattr(mock, entry, new) + + return mock + + +def _must_skip(spec, entry, is_type): + if not isinstance(spec, type): + if entry in getattr(spec, '__dict__', {}): + # instance attribute - shouldn't skip + return False + # can't use type because of old style classes + spec = spec.__class__ + if not hasattr(spec, '__mro__'): + # old style class: can't have descriptors anyway + return is_type + + for klass in spec.__mro__: + result = klass.__dict__.get(entry, DEFAULT) + if result is DEFAULT: + continue + if isinstance(result, (staticmethod, classmethod)): + return False + return is_type + + # shouldn't get here unless function is a dynamically provided attribute + # XXXX untested behaviour + return is_type + + +def _get_class(obj): + try: + return obj.__class__ + except AttributeError: + # in Python 2, _sre.SRE_Pattern objects have no __class__ + return type(obj) + + +class _SpecState(object): + + def __init__(self, spec, spec_set=False, parent=None, + name=None, ids=None, instance=False): + self.spec = spec + self.ids = ids + self.spec_set = spec_set + self.parent = parent + self.instance = instance + self.name = name + + +FunctionTypes = ( + # python function + type(create_autospec), + # instance method + type(ANY.__eq__), + # unbound method + type(_ANY.__eq__), +) + +FunctionAttributes = set([ + 'func_closure', + 'func_code', + 'func_defaults', + 'func_dict', + 'func_doc', + 'func_globals', + 'func_name', +]) + +import _io +file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) + + +def mock_open(mock=None, read_data=None): + if mock is None: + mock = MagicMock(spec=file_spec) + + handle = MagicMock(spec=file_spec) + handle.write.return_value = None + handle.__enter__.return_value = handle + + if read_data is not None: + handle.read.return_value = read_data + + mock.return_value = handle + return mock + + +class PropertyMock(Mock): + """A Mock variant with __get__ and __set__ methods to act as a property""" + def __get__(self, obj, obj_type): + return self() + def __set__(self, obj, val): + self(val) diff --git a/Lib/unittest/test/__init__.py b/Lib/unittest/test/__init__.py --- a/Lib/unittest/test/__init__.py +++ b/Lib/unittest/test/__init__.py @@ -14,6 +14,7 @@ __import__(modname) module = sys.modules[modname] suite.addTest(loader.loadTestsFromModule(module)) + suite.addTest(loader.loadTestsFromName('unittest.test.testmock')) return suite diff --git a/Lib/unittest/test/testmock/__init__.py b/Lib/unittest/test/testmock/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/__init__.py @@ -0,0 +1,17 @@ +import os +import sys +import unittest + + +here = os.path.dirname(__file__) +loader = unittest.defaultTestLoader + +def load_tests(*args): + suite = unittest.TestSuite() + for fn in os.listdir(here): + if fn.startswith("test") and fn.endswith(".py"): + modname = "unittest.test.testmock." + fn[:-3] + __import__(modname) + module = sys.modules[modname] + suite.addTest(loader.loadTestsFromModule(module)) + return suite diff --git a/Lib/unittest/test/testmock/support.py b/Lib/unittest/test/testmock/support.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/support.py @@ -0,0 +1,23 @@ +import sys + +def is_instance(obj, klass): + """Version of is_instance that doesn't access __class__""" + return issubclass(type(obj), klass) + + +class SomeClass(object): + class_attribute = None + + def wibble(self): + pass + + +class X(object): + pass + + +def examine_warnings(func): + def wrapper(): + with catch_warnings(record=True) as ws: + func(ws) + return wrapper diff --git a/Lib/unittest/test/testmock/testcallable.py b/Lib/unittest/test/testmock/testcallable.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testcallable.py @@ -0,0 +1,159 @@ +# Copyright (C) 2007-2012 Michael Foord & the mock team +# E-mail: fuzzyman AT voidspace DOT org DOT uk +# http://www.voidspace.org.uk/python/mock/ + +import unittest +from unittest.test.testmock.support import is_instance, X, SomeClass + +from unittest.mock import ( + Mock, MagicMock, NonCallableMagicMock, + NonCallableMock, patch, create_autospec, + CallableMixin +) + + + +class TestCallable(unittest.TestCase): + + def assertNotCallable(self, mock): + self.assertTrue(is_instance(mock, NonCallableMagicMock)) + self.assertFalse(is_instance(mock, CallableMixin)) + + + def test_non_callable(self): + for mock in NonCallableMagicMock(), NonCallableMock(): + self.assertRaises(TypeError, mock) + self.assertFalse(hasattr(mock, '__call__')) + self.assertIn(mock.__class__.__name__, repr(mock)) + + + def test_heirarchy(self): + self.assertTrue(issubclass(MagicMock, Mock)) + self.assertTrue(issubclass(NonCallableMagicMock, NonCallableMock)) + + + def test_attributes(self): + one = NonCallableMock() + self.assertTrue(issubclass(type(one.one), Mock)) + + two = NonCallableMagicMock() + self.assertTrue(issubclass(type(two.two), MagicMock)) + + + def test_subclasses(self): + class MockSub(Mock): + pass + + one = MockSub() + self.assertTrue(issubclass(type(one.one), MockSub)) + + class MagicSub(MagicMock): + pass + + two = MagicSub() + self.assertTrue(issubclass(type(two.two), MagicSub)) + + + def test_patch_spec(self): + patcher = patch('%s.X' % __name__, spec=True) + mock = patcher.start() + self.addCleanup(patcher.stop) + + instance = mock() + mock.assert_called_once_with() + + self.assertNotCallable(instance) + self.assertRaises(TypeError, instance) + + + def test_patch_spec_set(self): + patcher = patch('%s.X' % __name__, spec_set=True) + mock = patcher.start() + self.addCleanup(patcher.stop) + + instance = mock() + mock.assert_called_once_with() + + self.assertNotCallable(instance) + self.assertRaises(TypeError, instance) + + + def test_patch_spec_instance(self): + patcher = patch('%s.X' % __name__, spec=X()) + mock = patcher.start() + self.addCleanup(patcher.stop) + + self.assertNotCallable(mock) + self.assertRaises(TypeError, mock) + + + def test_patch_spec_set_instance(self): + patcher = patch('%s.X' % __name__, spec_set=X()) + mock = patcher.start() + self.addCleanup(patcher.stop) + + self.assertNotCallable(mock) + self.assertRaises(TypeError, mock) + + + def test_patch_spec_callable_class(self): + class CallableX(X): + def __call__(self): + pass + + class Sub(CallableX): + pass + + class Multi(SomeClass, Sub): + pass + + class OldStyle: + def __call__(self): + pass + + class OldStyleSub(OldStyle): + pass + + for arg in 'spec', 'spec_set': + for Klass in CallableX, Sub, Multi, OldStyle, OldStyleSub: + patcher = patch('%s.X' % __name__, **{arg: Klass}) + mock = patcher.start() + + try: + instance = mock() + mock.assert_called_once_with() + + self.assertTrue(is_instance(instance, MagicMock)) + # inherited spec + self.assertRaises(AttributeError, getattr, instance, + 'foobarbaz') + + result = instance() + # instance is callable, result has no spec + instance.assert_called_once_with() + + result(3, 2, 1) + result.assert_called_once_with(3, 2, 1) + result.foo(3, 2, 1) + result.foo.assert_called_once_with(3, 2, 1) + finally: + patcher.stop() + + + def test_create_autopsec(self): + mock = create_autospec(X) + instance = mock() + self.assertRaises(TypeError, instance) + + mock = create_autospec(X()) + self.assertRaises(TypeError, mock) + + + def test_create_autospec_instance(self): + mock = create_autospec(SomeClass, instance=True) + + self.assertRaises(TypeError, mock) + mock.wibble() + mock.wibble.assert_called_once_with() + + self.assertRaises(TypeError, mock.wibble, 'some', 'args') diff --git a/Lib/unittest/test/testmock/testhelpers.py b/Lib/unittest/test/testmock/testhelpers.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testhelpers.py @@ -0,0 +1,835 @@ +import unittest + +from unittest.mock import ( + call, _Call, create_autospec, MagicMock, + Mock, ANY, _CallList, patch, PropertyMock +) + +from datetime import datetime + +class SomeClass(object): + def one(self, a, b): + pass + def two(self): + pass + def three(self, a=None): + pass + + + +class AnyTest(unittest.TestCase): + + def test_any(self): + self.assertEqual(ANY, object()) + + mock = Mock() + mock(ANY) + mock.assert_called_with(ANY) + + mock = Mock() + mock(foo=ANY) + mock.assert_called_with(foo=ANY) + + def test_repr(self): + self.assertEqual(repr(ANY), '') + self.assertEqual(str(ANY), '') + + + def test_any_and_datetime(self): + mock = Mock() + mock(datetime.now(), foo=datetime.now()) + + mock.assert_called_with(ANY, foo=ANY) + + + def test_any_mock_calls_comparison_order(self): + mock = Mock() + d = datetime.now() + class Foo(object): + def __eq__(self, other): + return False + def __ne__(self, other): + return True + + for d in datetime.now(), Foo(): + mock.reset_mock() + + mock(d, foo=d, bar=d) + mock.method(d, zinga=d, alpha=d) + mock().method(a1=d, z99=d) + + expected = [ + call(ANY, foo=ANY, bar=ANY), + call.method(ANY, zinga=ANY, alpha=ANY), + call(), call().method(a1=ANY, z99=ANY) + ] + self.assertEqual(expected, mock.mock_calls) + self.assertEqual(mock.mock_calls, expected) + + + +class CallTest(unittest.TestCase): + + def test_call_with_call(self): + kall = _Call() + self.assertEqual(kall, _Call()) + self.assertEqual(kall, _Call(('',))) + self.assertEqual(kall, _Call(((),))) + self.assertEqual(kall, _Call(({},))) + self.assertEqual(kall, _Call(('', ()))) + self.assertEqual(kall, _Call(('', {}))) + self.assertEqual(kall, _Call(('', (), {}))) + self.assertEqual(kall, _Call(('foo',))) + self.assertEqual(kall, _Call(('bar', ()))) + self.assertEqual(kall, _Call(('baz', {}))) + self.assertEqual(kall, _Call(('spam', (), {}))) + + kall = _Call(((1, 2, 3),)) + self.assertEqual(kall, _Call(((1, 2, 3),))) + self.assertEqual(kall, _Call(('', (1, 2, 3)))) + self.assertEqual(kall, _Call(((1, 2, 3), {}))) + self.assertEqual(kall, _Call(('', (1, 2, 3), {}))) + + kall = _Call(((1, 2, 4),)) + self.assertNotEqual(kall, _Call(('', (1, 2, 3)))) + self.assertNotEqual(kall, _Call(('', (1, 2, 3), {}))) + + kall = _Call(('foo', (1, 2, 4),)) + self.assertNotEqual(kall, _Call(('', (1, 2, 4)))) + self.assertNotEqual(kall, _Call(('', (1, 2, 4), {}))) + self.assertNotEqual(kall, _Call(('bar', (1, 2, 4)))) + self.assertNotEqual(kall, _Call(('bar', (1, 2, 4), {}))) + + kall = _Call(({'a': 3},)) + self.assertEqual(kall, _Call(('', (), {'a': 3}))) + self.assertEqual(kall, _Call(('', {'a': 3}))) + self.assertEqual(kall, _Call(((), {'a': 3}))) + self.assertEqual(kall, _Call(({'a': 3},))) + + + def test_empty__Call(self): + args = _Call() + + self.assertEqual(args, ()) + self.assertEqual(args, ('foo',)) + self.assertEqual(args, ((),)) + self.assertEqual(args, ('foo', ())) + self.assertEqual(args, ('foo',(), {})) + self.assertEqual(args, ('foo', {})) + self.assertEqual(args, ({},)) + + + def test_named_empty_call(self): + args = _Call(('foo', (), {})) + + self.assertEqual(args, ('foo',)) + self.assertEqual(args, ('foo', ())) + self.assertEqual(args, ('foo',(), {})) + self.assertEqual(args, ('foo', {})) + + self.assertNotEqual(args, ((),)) + self.assertNotEqual(args, ()) + self.assertNotEqual(args, ({},)) + self.assertNotEqual(args, ('bar',)) + self.assertNotEqual(args, ('bar', ())) + self.assertNotEqual(args, ('bar', {})) + + + def test_call_with_args(self): + args = _Call(((1, 2, 3), {})) + + self.assertEqual(args, ((1, 2, 3),)) + self.assertEqual(args, ('foo', (1, 2, 3))) + self.assertEqual(args, ('foo', (1, 2, 3), {})) + self.assertEqual(args, ((1, 2, 3), {})) + + + def test_named_call_with_args(self): + args = _Call(('foo', (1, 2, 3), {})) + + self.assertEqual(args, ('foo', (1, 2, 3))) + self.assertEqual(args, ('foo', (1, 2, 3), {})) + + self.assertNotEqual(args, ((1, 2, 3),)) + self.assertNotEqual(args, ((1, 2, 3), {})) + + + def test_call_with_kwargs(self): + args = _Call(((), dict(a=3, b=4))) + + self.assertEqual(args, (dict(a=3, b=4),)) + self.assertEqual(args, ('foo', dict(a=3, b=4))) + self.assertEqual(args, ('foo', (), dict(a=3, b=4))) + self.assertEqual(args, ((), dict(a=3, b=4))) + + + def test_named_call_with_kwargs(self): + args = _Call(('foo', (), dict(a=3, b=4))) + + self.assertEqual(args, ('foo', dict(a=3, b=4))) + self.assertEqual(args, ('foo', (), dict(a=3, b=4))) + + self.assertNotEqual(args, (dict(a=3, b=4),)) + self.assertNotEqual(args, ((), dict(a=3, b=4))) + + + def test_call_with_args_call_empty_name(self): + args = _Call(((1, 2, 3), {})) + self.assertEqual(args, call(1, 2, 3)) + self.assertEqual(call(1, 2, 3), args) + self.assertTrue(call(1, 2, 3) in [args]) + + + def test_call_ne(self): + self.assertNotEqual(_Call(((1, 2, 3),)), call(1, 2)) + self.assertFalse(_Call(((1, 2, 3),)) != call(1, 2, 3)) + self.assertTrue(_Call(((1, 2), {})) != call(1, 2, 3)) + + + def test_call_non_tuples(self): + kall = _Call(((1, 2, 3),)) + for value in 1, None, self, int: + self.assertNotEqual(kall, value) + self.assertFalse(kall == value) + + + def test_repr(self): + self.assertEqual(repr(_Call()), 'call()') + self.assertEqual(repr(_Call(('foo',))), 'call.foo()') + + self.assertEqual(repr(_Call(((1, 2, 3), {'a': 'b'}))), + "call(1, 2, 3, a='b')") + self.assertEqual(repr(_Call(('bar', (1, 2, 3), {'a': 'b'}))), + "call.bar(1, 2, 3, a='b')") + + self.assertEqual(repr(call), 'call') + self.assertEqual(str(call), 'call') + + self.assertEqual(repr(call()), 'call()') + self.assertEqual(repr(call(1)), 'call(1)') + self.assertEqual(repr(call(zz='thing')), "call(zz='thing')") + + self.assertEqual(repr(call().foo), 'call().foo') + self.assertEqual(repr(call(1).foo.bar(a=3).bing), + 'call().foo.bar().bing') + self.assertEqual( + repr(call().foo(1, 2, a=3)), + "call().foo(1, 2, a=3)" + ) + self.assertEqual(repr(call()()), "call()()") + self.assertEqual(repr(call(1)(2)), "call()(2)") + self.assertEqual( + repr(call()().bar().baz.beep(1)), + "call()().bar().baz.beep(1)" + ) + + + def test_call(self): + self.assertEqual(call(), ('', (), {})) + self.assertEqual(call('foo', 'bar', one=3, two=4), + ('', ('foo', 'bar'), {'one': 3, 'two': 4})) + + mock = Mock() + mock(1, 2, 3) + mock(a=3, b=6) + self.assertEqual(mock.call_args_list, + [call(1, 2, 3), call(a=3, b=6)]) + + def test_attribute_call(self): + self.assertEqual(call.foo(1), ('foo', (1,), {})) + self.assertEqual(call.bar.baz(fish='eggs'), + ('bar.baz', (), {'fish': 'eggs'})) + + mock = Mock() + mock.foo(1, 2 ,3) + mock.bar.baz(a=3, b=6) + self.assertEqual(mock.method_calls, + [call.foo(1, 2, 3), call.bar.baz(a=3, b=6)]) + + + def test_extended_call(self): + result = call(1).foo(2).bar(3, a=4) + self.assertEqual(result, ('().foo().bar', (3,), dict(a=4))) + + mock = MagicMock() + mock(1, 2, a=3, b=4) + self.assertEqual(mock.call_args, call(1, 2, a=3, b=4)) + self.assertNotEqual(mock.call_args, call(1, 2, 3)) + + self.assertEqual(mock.call_args_list, [call(1, 2, a=3, b=4)]) + self.assertEqual(mock.mock_calls, [call(1, 2, a=3, b=4)]) + + mock = MagicMock() + mock.foo(1).bar()().baz.beep(a=6) + + last_call = call.foo(1).bar()().baz.beep(a=6) + self.assertEqual(mock.mock_calls[-1], last_call) + self.assertEqual(mock.mock_calls, last_call.call_list()) + + + def test_call_list(self): + mock = MagicMock() + mock(1) + self.assertEqual(call(1).call_list(), mock.mock_calls) + + mock = MagicMock() + mock(1).method(2) + self.assertEqual(call(1).method(2).call_list(), + mock.mock_calls) + + mock = MagicMock() + mock(1).method(2)(3) + self.assertEqual(call(1).method(2)(3).call_list(), + mock.mock_calls) + + mock = MagicMock() + int(mock(1).method(2)(3).foo.bar.baz(4)(5)) + kall = call(1).method(2)(3).foo.bar.baz(4)(5).__int__() + self.assertEqual(kall.call_list(), mock.mock_calls) + + + def test_call_any(self): + self.assertEqual(call, ANY) + + m = MagicMock() + int(m) + self.assertEqual(m.mock_calls, [ANY]) + self.assertEqual([ANY], m.mock_calls) + + + def test_two_args_call(self): + args = _Call(((1, 2), {'a': 3}), two=True) + self.assertEqual(len(args), 2) + self.assertEqual(args[0], (1, 2)) + self.assertEqual(args[1], {'a': 3}) + + other_args = _Call(((1, 2), {'a': 3})) + self.assertEqual(args, other_args) + + +class SpecSignatureTest(unittest.TestCase): + + def _check_someclass_mock(self, mock): + self.assertRaises(AttributeError, getattr, mock, 'foo') + mock.one(1, 2) + mock.one.assert_called_with(1, 2) + self.assertRaises(AssertionError, + mock.one.assert_called_with, 3, 4) + self.assertRaises(TypeError, mock.one, 1) + + mock.two() + mock.two.assert_called_with() + self.assertRaises(AssertionError, + mock.two.assert_called_with, 3) + self.assertRaises(TypeError, mock.two, 1) + + mock.three() + mock.three.assert_called_with() + self.assertRaises(AssertionError, + mock.three.assert_called_with, 3) + self.assertRaises(TypeError, mock.three, 3, 2) + + mock.three(1) + mock.three.assert_called_with(1) + + mock.three(a=1) + mock.three.assert_called_with(a=1) + + + def test_basic(self): + for spec in (SomeClass, SomeClass()): + mock = create_autospec(spec) + self._check_someclass_mock(mock) + + + def test_create_autospec_return_value(self): + def f(): + pass + mock = create_autospec(f, return_value='foo') + self.assertEqual(mock(), 'foo') + + class Foo(object): + pass + + mock = create_autospec(Foo, return_value='foo') + self.assertEqual(mock(), 'foo') + + + def test_mocking_unbound_methods(self): + class Foo(object): + def foo(self, foo): + pass + p = patch.object(Foo, 'foo') + mock_foo = p.start() + Foo().foo(1) + + mock_foo.assert_called_with(1) + + + def test_create_autospec_unbound_methods(self): + # see issue 128 + # this is expected to fail until the issue is fixed + return + class Foo(object): + def foo(self): + pass + + klass = create_autospec(Foo) + instance = klass() + self.assertRaises(TypeError, instance.foo, 1) + + # Note: no type checking on the "self" parameter + klass.foo(1) + klass.foo.assert_called_with(1) + self.assertRaises(TypeError, klass.foo) + + + def test_create_autospec_keyword_arguments(self): + class Foo(object): + a = 3 + m = create_autospec(Foo, a='3') + self.assertEqual(m.a, '3') + + + def test_function_as_instance_attribute(self): + obj = SomeClass() + def f(a): + pass + obj.f = f + + mock = create_autospec(obj) + mock.f('bing') + mock.f.assert_called_with('bing') + + + def test_spec_as_list(self): + # because spec as a list of strings in the mock constructor means + # something very different we treat a list instance as the type. + mock = create_autospec([]) + mock.append('foo') + mock.append.assert_called_with('foo') + + self.assertRaises(AttributeError, getattr, mock, 'foo') + + class Foo(object): + foo = [] + + mock = create_autospec(Foo) + mock.foo.append(3) + mock.foo.append.assert_called_with(3) + self.assertRaises(AttributeError, getattr, mock.foo, 'foo') + + + def test_attributes(self): + class Sub(SomeClass): + attr = SomeClass() + + sub_mock = create_autospec(Sub) + + for mock in (sub_mock, sub_mock.attr): + self._check_someclass_mock(mock) + + + def test_builtin_functions_types(self): + # we could replace builtin functions / methods with a function + # with *args / **kwargs signature. Using the builtin method type + # as a spec seems to work fairly well though. + class BuiltinSubclass(list): + def bar(self, arg): + pass + sorted = sorted + attr = {} + + mock = create_autospec(BuiltinSubclass) + mock.append(3) + mock.append.assert_called_with(3) + self.assertRaises(AttributeError, getattr, mock.append, 'foo') + + mock.bar('foo') + mock.bar.assert_called_with('foo') + self.assertRaises(TypeError, mock.bar, 'foo', 'bar') + self.assertRaises(AttributeError, getattr, mock.bar, 'foo') + + mock.sorted([1, 2]) + mock.sorted.assert_called_with([1, 2]) + self.assertRaises(AttributeError, getattr, mock.sorted, 'foo') + + mock.attr.pop(3) + mock.attr.pop.assert_called_with(3) + self.assertRaises(AttributeError, getattr, mock.attr, 'foo') + + + def test_method_calls(self): + class Sub(SomeClass): + attr = SomeClass() + + mock = create_autospec(Sub) + mock.one(1, 2) + mock.two() + mock.three(3) + + expected = [call.one(1, 2), call.two(), call.three(3)] + self.assertEqual(mock.method_calls, expected) + + mock.attr.one(1, 2) + mock.attr.two() + mock.attr.three(3) + + expected.extend( + [call.attr.one(1, 2), call.attr.two(), call.attr.three(3)] + ) + self.assertEqual(mock.method_calls, expected) + + + def test_magic_methods(self): + class BuiltinSubclass(list): + attr = {} + + mock = create_autospec(BuiltinSubclass) + self.assertEqual(list(mock), []) + self.assertRaises(TypeError, int, mock) + self.assertRaises(TypeError, int, mock.attr) + self.assertEqual(list(mock), []) + + self.assertIsInstance(mock['foo'], MagicMock) + self.assertIsInstance(mock.attr['foo'], MagicMock) + + + def test_spec_set(self): + class Sub(SomeClass): + attr = SomeClass() + + for spec in (Sub, Sub()): + mock = create_autospec(spec, spec_set=True) + self._check_someclass_mock(mock) + + self.assertRaises(AttributeError, setattr, mock, 'foo', 'bar') + self.assertRaises(AttributeError, setattr, mock.attr, 'foo', 'bar') + + + def test_descriptors(self): + class Foo(object): + @classmethod + def f(cls, a, b): + pass + @staticmethod + def g(a, b): + pass + + class Bar(Foo): + pass + + class Baz(SomeClass, Bar): + pass + + for spec in (Foo, Foo(), Bar, Bar(), Baz, Baz()): + mock = create_autospec(spec) + mock.f(1, 2) + mock.f.assert_called_once_with(1, 2) + + mock.g(3, 4) + mock.g.assert_called_once_with(3, 4) + + + def test_recursive(self): + class A(object): + def a(self): + pass + foo = 'foo bar baz' + bar = foo + + A.B = A + mock = create_autospec(A) + + mock() + self.assertFalse(mock.B.called) + + mock.a() + mock.B.a() + self.assertEqual(mock.method_calls, [call.a(), call.B.a()]) + + self.assertIs(A.foo, A.bar) + self.assertIsNot(mock.foo, mock.bar) + mock.foo.lower() + self.assertRaises(AssertionError, mock.bar.lower.assert_called_with) + + + def test_spec_inheritance_for_classes(self): + class Foo(object): + def a(self): + pass + class Bar(object): + def f(self): + pass + + class_mock = create_autospec(Foo) + + self.assertIsNot(class_mock, class_mock()) + + for this_mock in class_mock, class_mock(): + this_mock.a() + this_mock.a.assert_called_with() + self.assertRaises(TypeError, this_mock.a, 'foo') + self.assertRaises(AttributeError, getattr, this_mock, 'b') + + instance_mock = create_autospec(Foo()) + instance_mock.a() + instance_mock.a.assert_called_with() + self.assertRaises(TypeError, instance_mock.a, 'foo') + self.assertRaises(AttributeError, getattr, instance_mock, 'b') + + # The return value isn't isn't callable + self.assertRaises(TypeError, instance_mock) + + instance_mock.Bar.f() + instance_mock.Bar.f.assert_called_with() + self.assertRaises(AttributeError, getattr, instance_mock.Bar, 'g') + + instance_mock.Bar().f() + instance_mock.Bar().f.assert_called_with() + self.assertRaises(AttributeError, getattr, instance_mock.Bar(), 'g') + + + def test_inherit(self): + class Foo(object): + a = 3 + + Foo.Foo = Foo + + # class + mock = create_autospec(Foo) + instance = mock() + self.assertRaises(AttributeError, getattr, instance, 'b') + + attr_instance = mock.Foo() + self.assertRaises(AttributeError, getattr, attr_instance, 'b') + + # instance + mock = create_autospec(Foo()) + self.assertRaises(AttributeError, getattr, mock, 'b') + self.assertRaises(TypeError, mock) + + # attribute instance + call_result = mock.Foo() + self.assertRaises(AttributeError, getattr, call_result, 'b') + + + def test_builtins(self): + # used to fail with infinite recursion + create_autospec(1) + + create_autospec(int) + create_autospec('foo') + create_autospec(str) + create_autospec({}) + create_autospec(dict) + create_autospec([]) + create_autospec(list) + create_autospec(set()) + create_autospec(set) + create_autospec(1.0) + create_autospec(float) + create_autospec(1j) + create_autospec(complex) + create_autospec(False) + create_autospec(True) + + + def test_function(self): + def f(a, b): + pass + + mock = create_autospec(f) + self.assertRaises(TypeError, mock) + mock(1, 2) + mock.assert_called_with(1, 2) + + f.f = f + mock = create_autospec(f) + self.assertRaises(TypeError, mock.f) + mock.f(3, 4) + mock.f.assert_called_with(3, 4) + + + def test_signature_class(self): + class Foo(object): + def __init__(self, a, b=3): + pass + + mock = create_autospec(Foo) + + self.assertRaises(TypeError, mock) + mock(1) + mock.assert_called_once_with(1) + + mock(4, 5) + mock.assert_called_with(4, 5) + + + def test_class_with_no_init(self): + # this used to raise an exception + # due to trying to get a signature from object.__init__ + class Foo(object): + pass + create_autospec(Foo) + + + def test_signature_callable(self): + class Callable(object): + def __init__(self): + pass + def __call__(self, a): + pass + + mock = create_autospec(Callable) + mock() + mock.assert_called_once_with() + self.assertRaises(TypeError, mock, 'a') + + instance = mock() + self.assertRaises(TypeError, instance) + instance(a='a') + instance.assert_called_once_with(a='a') + instance('a') + instance.assert_called_with('a') + + mock = create_autospec(Callable()) + mock(a='a') + mock.assert_called_once_with(a='a') + self.assertRaises(TypeError, mock) + mock('a') + mock.assert_called_with('a') + + + def test_signature_noncallable(self): + class NonCallable(object): + def __init__(self): + pass + + mock = create_autospec(NonCallable) + instance = mock() + mock.assert_called_once_with() + self.assertRaises(TypeError, mock, 'a') + self.assertRaises(TypeError, instance) + self.assertRaises(TypeError, instance, 'a') + + mock = create_autospec(NonCallable()) + self.assertRaises(TypeError, mock) + self.assertRaises(TypeError, mock, 'a') + + + def test_create_autospec_none(self): + class Foo(object): + bar = None + + mock = create_autospec(Foo) + none = mock.bar + self.assertNotIsInstance(none, type(None)) + + none.foo() + none.foo.assert_called_once_with() + + + def test_autospec_functions_with_self_in_odd_place(self): + class Foo(object): + def f(a, self): + pass + + a = create_autospec(Foo) + a.f(self=10) + a.f.assert_called_with(self=10) + + + def test_autospec_property(self): + class Foo(object): + @property + def foo(self): + return 3 + + foo = create_autospec(Foo) + mock_property = foo.foo + + # no spec on properties + self.assertTrue(isinstance(mock_property, MagicMock)) + mock_property(1, 2, 3) + mock_property.abc(4, 5, 6) + mock_property.assert_called_once_with(1, 2, 3) + mock_property.abc.assert_called_once_with(4, 5, 6) + + + def test_autospec_slots(self): + class Foo(object): + __slots__ = ['a'] + + foo = create_autospec(Foo) + mock_slot = foo.a + + # no spec on slots + mock_slot(1, 2, 3) + mock_slot.abc(4, 5, 6) + mock_slot.assert_called_once_with(1, 2, 3) + mock_slot.abc.assert_called_once_with(4, 5, 6) + + +class TestCallList(unittest.TestCase): + + def test_args_list_contains_call_list(self): + mock = Mock() + self.assertIsInstance(mock.call_args_list, _CallList) + + mock(1, 2) + mock(a=3) + mock(3, 4) + mock(b=6) + + for kall in call(1, 2), call(a=3), call(3, 4), call(b=6): + self.assertTrue(kall in mock.call_args_list) + + calls = [call(a=3), call(3, 4)] + self.assertTrue(calls in mock.call_args_list) + calls = [call(1, 2), call(a=3)] + self.assertTrue(calls in mock.call_args_list) + calls = [call(3, 4), call(b=6)] + self.assertTrue(calls in mock.call_args_list) + calls = [call(3, 4)] + self.assertTrue(calls in mock.call_args_list) + + self.assertFalse(call('fish') in mock.call_args_list) + self.assertFalse([call('fish')] in mock.call_args_list) + + + def test_call_list_str(self): + mock = Mock() + mock(1, 2) + mock.foo(a=3) + mock.foo.bar().baz('fish', cat='dog') + + expected = ( + "[call(1, 2),\n" + " call.foo(a=3),\n" + " call.foo.bar(),\n" + " call.foo.bar().baz('fish', cat='dog')]" + ) + self.assertEqual(str(mock.mock_calls), expected) + + + def test_propertymock(self): + p = patch('%s.SomeClass.one' % __name__, new_callable=PropertyMock) + mock = p.start() + try: + SomeClass.one + mock.assert_called_once_with() + + s = SomeClass() + s.one + mock.assert_called_with() + self.assertEqual(mock.mock_calls, [call(), call()]) + + s.one = 3 + self.assertEqual(mock.mock_calls, [call(), call(), call(3)]) + finally: + p.stop() + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testmagicmethods.py b/Lib/unittest/test/testmock/testmagicmethods.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testmagicmethods.py @@ -0,0 +1,382 @@ +import unittest +import inspect +import sys +from unittest.mock import Mock, MagicMock, _magics + + + +class TestMockingMagicMethods(unittest.TestCase): + + def test_deleting_magic_methods(self): + mock = Mock() + self.assertFalse(hasattr(mock, '__getitem__')) + + mock.__getitem__ = Mock() + self.assertTrue(hasattr(mock, '__getitem__')) + + del mock.__getitem__ + self.assertFalse(hasattr(mock, '__getitem__')) + + + def test_magicmock_del(self): + mock = MagicMock() + # before using getitem + del mock.__getitem__ + self.assertRaises(TypeError, lambda: mock['foo']) + + mock = MagicMock() + # this time use it first + mock['foo'] + del mock.__getitem__ + self.assertRaises(TypeError, lambda: mock['foo']) + + + def test_magic_method_wrapping(self): + mock = Mock() + def f(self, name): + return self, 'fish' + + mock.__getitem__ = f + self.assertFalse(mock.__getitem__ is f) + self.assertEqual(mock['foo'], (mock, 'fish')) + self.assertEqual(mock.__getitem__('foo'), (mock, 'fish')) + + mock.__getitem__ = mock + self.assertTrue(mock.__getitem__ is mock) + + + def test_magic_methods_isolated_between_mocks(self): + mock1 = Mock() + mock2 = Mock() + + mock1.__iter__ = Mock(return_value=iter([])) + self.assertEqual(list(mock1), []) + self.assertRaises(TypeError, lambda: list(mock2)) + + + def test_repr(self): + mock = Mock() + self.assertEqual(repr(mock), "" % id(mock)) + mock.__repr__ = lambda s: 'foo' + self.assertEqual(repr(mock), 'foo') + + + def test_str(self): + mock = Mock() + self.assertEqual(str(mock), object.__str__(mock)) + mock.__str__ = lambda s: 'foo' + self.assertEqual(str(mock), 'foo') + + + def test_dict_methods(self): + mock = Mock() + + self.assertRaises(TypeError, lambda: mock['foo']) + def _del(): + del mock['foo'] + def _set(): + mock['foo'] = 3 + self.assertRaises(TypeError, _del) + self.assertRaises(TypeError, _set) + + _dict = {} + def getitem(s, name): + return _dict[name] + def setitem(s, name, value): + _dict[name] = value + def delitem(s, name): + del _dict[name] + + mock.__setitem__ = setitem + mock.__getitem__ = getitem + mock.__delitem__ = delitem + + self.assertRaises(KeyError, lambda: mock['foo']) + mock['foo'] = 'bar' + self.assertEqual(_dict, {'foo': 'bar'}) + self.assertEqual(mock['foo'], 'bar') + del mock['foo'] + self.assertEqual(_dict, {}) + + + def test_numeric(self): + original = mock = Mock() + mock.value = 0 + + self.assertRaises(TypeError, lambda: mock + 3) + + def add(self, other): + mock.value += other + return self + mock.__add__ = add + self.assertEqual(mock + 3, mock) + self.assertEqual(mock.value, 3) + + del mock.__add__ + def iadd(mock): + mock += 3 + self.assertRaises(TypeError, iadd, mock) + mock.__iadd__ = add + mock += 6 + self.assertEqual(mock, original) + self.assertEqual(mock.value, 9) + + self.assertRaises(TypeError, lambda: 3 + mock) + mock.__radd__ = add + self.assertEqual(7 + mock, mock) + self.assertEqual(mock.value, 16) + + + def test_hash(self): + mock = Mock() + # test delegation + self.assertEqual(hash(mock), Mock.__hash__(mock)) + + def _hash(s): + return 3 + mock.__hash__ = _hash + self.assertEqual(hash(mock), 3) + + + def test_nonzero(self): + m = Mock() + self.assertTrue(bool(m)) + + m.__bool__ = lambda s: False + self.assertFalse(bool(m)) + + + def test_comparison(self): + mock = Mock() + def comp(s, o): + return True + mock.__lt__ = mock.__gt__ = mock.__le__ = mock.__ge__ = comp + self. assertTrue(mock < 3) + self. assertTrue(mock > 3) + self. assertTrue(mock <= 3) + self. assertTrue(mock >= 3) + + + def test_equality(self): + for mock in Mock(), MagicMock(): + self.assertEqual(mock == mock, True) + self.assertIsInstance(mock == mock, bool) + self.assertEqual(mock != mock, False) + self.assertIsInstance(mock != mock, bool) + self.assertEqual(mock == object(), False) + self.assertEqual(mock != object(), True) + + def eq(self, other): + return other == 3 + mock.__eq__ = eq + self.assertTrue(mock == 3) + self.assertFalse(mock == 4) + + def ne(self, other): + return other == 3 + mock.__ne__ = ne + self.assertTrue(mock != 3) + self.assertFalse(mock != 4) + + mock = MagicMock() + mock.__eq__.return_value = True + self.assertIsInstance(mock == 3, bool) + self.assertEqual(mock == 3, True) + + mock.__ne__.return_value = False + self.assertIsInstance(mock != 3, bool) + self.assertEqual(mock != 3, False) + + + def test_len_contains_iter(self): + mock = Mock() + + self.assertRaises(TypeError, len, mock) + self.assertRaises(TypeError, iter, mock) + self.assertRaises(TypeError, lambda: 'foo' in mock) + + mock.__len__ = lambda s: 6 + self.assertEqual(len(mock), 6) + + mock.__contains__ = lambda s, o: o == 3 + self.assertTrue(3 in mock) + self.assertFalse(6 in mock) + + mock.__iter__ = lambda s: iter('foobarbaz') + self.assertEqual(list(mock), list('foobarbaz')) + + + def test_magicmock(self): + mock = MagicMock() + + mock.__iter__.return_value = iter([1, 2, 3]) + self.assertEqual(list(mock), [1, 2, 3]) + + getattr(mock, '__bool__').return_value = False + self.assertFalse(hasattr(mock, '__nonzero__')) + self.assertFalse(bool(mock)) + + for entry in _magics: + self.assertTrue(hasattr(mock, entry)) + self.assertFalse(hasattr(mock, '__imaginery__')) + + + def test_magic_mock_equality(self): + mock = MagicMock() + self.assertIsInstance(mock == object(), bool) + self.assertIsInstance(mock != object(), bool) + + self.assertEqual(mock == object(), False) + self.assertEqual(mock != object(), True) + self.assertEqual(mock == mock, True) + self.assertEqual(mock != mock, False) + + + def test_magicmock_defaults(self): + mock = MagicMock() + self.assertEqual(int(mock), 1) + self.assertEqual(complex(mock), 1j) + self.assertEqual(float(mock), 1.0) + self.assertNotIn(object(), mock) + self.assertEqual(len(mock), 0) + self.assertEqual(list(mock), []) + self.assertEqual(hash(mock), object.__hash__(mock)) + self.assertEqual(str(mock), object.__str__(mock)) + self.assertTrue(bool(mock)) + + # in Python 3 oct and hex use __index__ + # so these tests are for __index__ in py3k + self.assertEqual(oct(mock), '0o1') + self.assertEqual(hex(mock), '0x1') + # how to test __sizeof__ ? + + + def test_magic_methods_and_spec(self): + class Iterable(object): + def __iter__(self): + pass + + mock = Mock(spec=Iterable) + self.assertRaises(AttributeError, lambda: mock.__iter__) + + mock.__iter__ = Mock(return_value=iter([])) + self.assertEqual(list(mock), []) + + class NonIterable(object): + pass + mock = Mock(spec=NonIterable) + self.assertRaises(AttributeError, lambda: mock.__iter__) + + def set_int(): + mock.__int__ = Mock(return_value=iter([])) + self.assertRaises(AttributeError, set_int) + + mock = MagicMock(spec=Iterable) + self.assertEqual(list(mock), []) + self.assertRaises(AttributeError, set_int) + + + def test_magic_methods_and_spec_set(self): + class Iterable(object): + def __iter__(self): + pass + + mock = Mock(spec_set=Iterable) + self.assertRaises(AttributeError, lambda: mock.__iter__) + + mock.__iter__ = Mock(return_value=iter([])) + self.assertEqual(list(mock), []) + + class NonIterable(object): + pass + mock = Mock(spec_set=NonIterable) + self.assertRaises(AttributeError, lambda: mock.__iter__) + + def set_int(): + mock.__int__ = Mock(return_value=iter([])) + self.assertRaises(AttributeError, set_int) + + mock = MagicMock(spec_set=Iterable) + self.assertEqual(list(mock), []) + self.assertRaises(AttributeError, set_int) + + + def test_setting_unsupported_magic_method(self): + mock = MagicMock() + def set_setattr(): + mock.__setattr__ = lambda self, name: None + self.assertRaisesRegex(AttributeError, + "Attempting to set unsupported magic method '__setattr__'.", + set_setattr + ) + + + def test_attributes_and_return_value(self): + mock = MagicMock() + attr = mock.foo + def _get_type(obj): + # the type of every mock (or magicmock) is a custom subclass + # so the real type is the second in the mro + return type(obj).__mro__[1] + self.assertEqual(_get_type(attr), MagicMock) + + returned = mock() + self.assertEqual(_get_type(returned), MagicMock) + + + def test_magic_methods_are_magic_mocks(self): + mock = MagicMock() + self.assertIsInstance(mock.__getitem__, MagicMock) + + mock[1][2].__getitem__.return_value = 3 + self.assertEqual(mock[1][2][3], 3) + + + def test_dir(self): + # overriding the default implementation + for mock in Mock(), MagicMock(): + def _dir(self): + return ['foo'] + mock.__dir__ = _dir + self.assertEqual(dir(mock), ['foo']) + + + @unittest.skipIf('PyPy' in sys.version, "This fails differently on pypy") + def test_bound_methods(self): + m = Mock() + + # XXXX should this be an expected failure instead? + + # this seems like it should work, but is hard to do without introducing + # other api inconsistencies. Failure message could be better though. + m.__iter__ = [3].__iter__ + self.assertRaises(TypeError, iter, m) + + + def test_magic_method_type(self): + class Foo(MagicMock): + pass + + foo = Foo() + self.assertIsInstance(foo.__int__, Foo) + + + def test_descriptor_from_class(self): + m = MagicMock() + type(m).__str__.return_value = 'foo' + self.assertEqual(str(m), 'foo') + + + def test_iterable_as_iter_return_value(self): + m = MagicMock() + m.__iter__.return_value = [1, 2, 3] + self.assertEqual(list(m), [1, 2, 3]) + self.assertEqual(list(m), [1, 2, 3]) + + m.__iter__.return_value = iter([4, 5, 6]) + self.assertEqual(list(m), [4, 5, 6]) + self.assertEqual(list(m), []) + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testmock.py @@ -0,0 +1,1258 @@ +import copy +import sys + +import unittest +from unittest.test.testmock.support import is_instance +from unittest import mock +from unittest.mock import ( + call, DEFAULT, patch, sentinel, + MagicMock, Mock, NonCallableMock, + NonCallableMagicMock, _CallList, + create_autospec +) + + +class Iter(object): + def __init__(self): + self.thing = iter(['this', 'is', 'an', 'iter']) + + def __iter__(self): + return self + + def next(self): + return next(self.thing) + + __next__ = next + + + +class MockTest(unittest.TestCase): + + def test_all(self): + # if __all__ is badly defined then import * will raise an error + # We have to exec it because you can't import * inside a method + # in Python 3 + exec("from unittest.mock import *") + + + def test_constructor(self): + mock = Mock() + + self.assertFalse(mock.called, "called not initialised correctly") + self.assertEqual(mock.call_count, 0, + "call_count not initialised correctly") + self.assertTrue(is_instance(mock.return_value, Mock), + "return_value not initialised correctly") + + self.assertEqual(mock.call_args, None, + "call_args not initialised correctly") + self.assertEqual(mock.call_args_list, [], + "call_args_list not initialised correctly") + self.assertEqual(mock.method_calls, [], + "method_calls not initialised correctly") + + # Can't use hasattr for this test as it always returns True on a mock + self.assertFalse('_items' in mock.__dict__, + "default mock should not have '_items' attribute") + + self.assertIsNone(mock._mock_parent, + "parent not initialised correctly") + self.assertIsNone(mock._mock_methods, + "methods not initialised correctly") + self.assertEqual(mock._mock_children, {}, + "children not initialised incorrectly") + + + def test_return_value_in_constructor(self): + mock = Mock(return_value=None) + self.assertIsNone(mock.return_value, + "return value in constructor not honoured") + + + def test_repr(self): + mock = Mock(name='foo') + self.assertIn('foo', repr(mock)) + self.assertIn("'%s'" % id(mock), repr(mock)) + + mocks = [(Mock(), 'mock'), (Mock(name='bar'), 'bar')] + for mock, name in mocks: + self.assertIn('%s.bar' % name, repr(mock.bar)) + self.assertIn('%s.foo()' % name, repr(mock.foo())) + self.assertIn('%s.foo().bing' % name, repr(mock.foo().bing)) + self.assertIn('%s()' % name, repr(mock())) + self.assertIn('%s()()' % name, repr(mock()())) + self.assertIn('%s()().foo.bar.baz().bing' % name, + repr(mock()().foo.bar.baz().bing)) + + + def test_repr_with_spec(self): + class X(object): + pass + + mock = Mock(spec=X) + self.assertIn(" spec='X' ", repr(mock)) + + mock = Mock(spec=X()) + self.assertIn(" spec='X' ", repr(mock)) + + mock = Mock(spec_set=X) + self.assertIn(" spec_set='X' ", repr(mock)) + + mock = Mock(spec_set=X()) + self.assertIn(" spec_set='X' ", repr(mock)) + + mock = Mock(spec=X, name='foo') + self.assertIn(" spec='X' ", repr(mock)) + self.assertIn(" name='foo' ", repr(mock)) + + mock = Mock(name='foo') + self.assertNotIn("spec", repr(mock)) + + mock = Mock() + self.assertNotIn("spec", repr(mock)) + + mock = Mock(spec=['foo']) + self.assertNotIn("spec", repr(mock)) + + + def test_side_effect(self): + mock = Mock() + + def effect(*args, **kwargs): + raise SystemError('kablooie') + + mock.side_effect = effect + self.assertRaises(SystemError, mock, 1, 2, fish=3) + mock.assert_called_with(1, 2, fish=3) + + results = [1, 2, 3] + def effect(): + return results.pop() + mock.side_effect = effect + + self.assertEqual([mock(), mock(), mock()], [3, 2, 1], + "side effect not used correctly") + + mock = Mock(side_effect=sentinel.SideEffect) + self.assertEqual(mock.side_effect, sentinel.SideEffect, + "side effect in constructor not used") + + def side_effect(): + return DEFAULT + mock = Mock(side_effect=side_effect, return_value=sentinel.RETURN) + self.assertEqual(mock(), sentinel.RETURN) + + + @unittest.skipUnless('java' in sys.platform, + 'This test only applies to Jython') + def test_java_exception_side_effect(self): + import java + mock = Mock(side_effect=java.lang.RuntimeException("Boom!")) + + # can't use assertRaises with java exceptions + try: + mock(1, 2, fish=3) + except java.lang.RuntimeException: + pass + else: + self.fail('java exception not raised') + mock.assert_called_with(1,2, fish=3) + + + def test_reset_mock(self): + parent = Mock() + spec = ["something"] + mock = Mock(name="child", parent=parent, spec=spec) + mock(sentinel.Something, something=sentinel.SomethingElse) + something = mock.something + mock.something() + mock.side_effect = sentinel.SideEffect + return_value = mock.return_value + return_value() + + mock.reset_mock() + + self.assertEqual(mock._mock_name, "child", + "name incorrectly reset") + self.assertEqual(mock._mock_parent, parent, + "parent incorrectly reset") + self.assertEqual(mock._mock_methods, spec, + "methods incorrectly reset") + + self.assertFalse(mock.called, "called not reset") + self.assertEqual(mock.call_count, 0, "call_count not reset") + self.assertEqual(mock.call_args, None, "call_args not reset") + self.assertEqual(mock.call_args_list, [], "call_args_list not reset") + self.assertEqual(mock.method_calls, [], + "method_calls not initialised correctly: %r != %r" % + (mock.method_calls, [])) + self.assertEqual(mock.mock_calls, []) + + self.assertEqual(mock.side_effect, sentinel.SideEffect, + "side_effect incorrectly reset") + self.assertEqual(mock.return_value, return_value, + "return_value incorrectly reset") + self.assertFalse(return_value.called, "return value mock not reset") + self.assertEqual(mock._mock_children, {'something': something}, + "children reset incorrectly") + self.assertEqual(mock.something, something, + "children incorrectly cleared") + self.assertFalse(mock.something.called, "child not reset") + + + def test_reset_mock_recursion(self): + mock = Mock() + mock.return_value = mock + + # used to cause recursion + mock.reset_mock() + + + def test_call(self): + mock = Mock() + self.assertTrue(is_instance(mock.return_value, Mock), + "Default return_value should be a Mock") + + result = mock() + self.assertEqual(mock(), result, + "different result from consecutive calls") + mock.reset_mock() + + ret_val = mock(sentinel.Arg) + self.assertTrue(mock.called, "called not set") + self.assertEqual(mock.call_count, 1, "call_count incoreect") + self.assertEqual(mock.call_args, ((sentinel.Arg,), {}), + "call_args not set") + self.assertEqual(mock.call_args_list, [((sentinel.Arg,), {})], + "call_args_list not initialised correctly") + + mock.return_value = sentinel.ReturnValue + ret_val = mock(sentinel.Arg, key=sentinel.KeyArg) + self.assertEqual(ret_val, sentinel.ReturnValue, + "incorrect return value") + + self.assertEqual(mock.call_count, 2, "call_count incorrect") + self.assertEqual(mock.call_args, + ((sentinel.Arg,), {'key': sentinel.KeyArg}), + "call_args not set") + self.assertEqual(mock.call_args_list, [ + ((sentinel.Arg,), {}), + ((sentinel.Arg,), {'key': sentinel.KeyArg}) + ], + "call_args_list not set") + + + def test_call_args_comparison(self): + mock = Mock() + mock() + mock(sentinel.Arg) + mock(kw=sentinel.Kwarg) + mock(sentinel.Arg, kw=sentinel.Kwarg) + self.assertEqual(mock.call_args_list, [ + (), + ((sentinel.Arg,),), + ({"kw": sentinel.Kwarg},), + ((sentinel.Arg,), {"kw": sentinel.Kwarg}) + ]) + self.assertEqual(mock.call_args, + ((sentinel.Arg,), {"kw": sentinel.Kwarg})) + + + def test_assert_called_with(self): + mock = Mock() + mock() + + # Will raise an exception if it fails + mock.assert_called_with() + self.assertRaises(AssertionError, mock.assert_called_with, 1) + + mock.reset_mock() + self.assertRaises(AssertionError, mock.assert_called_with) + + mock(1, 2, 3, a='fish', b='nothing') + mock.assert_called_with(1, 2, 3, a='fish', b='nothing') + + + def test_assert_called_once_with(self): + mock = Mock() + mock() + + # Will raise an exception if it fails + mock.assert_called_once_with() + + mock() + self.assertRaises(AssertionError, mock.assert_called_once_with) + + mock.reset_mock() + self.assertRaises(AssertionError, mock.assert_called_once_with) + + mock('foo', 'bar', baz=2) + mock.assert_called_once_with('foo', 'bar', baz=2) + + mock.reset_mock() + mock('foo', 'bar', baz=2) + self.assertRaises( + AssertionError, + lambda: mock.assert_called_once_with('bob', 'bar', baz=2) + ) + + + def test_attribute_access_returns_mocks(self): + mock = Mock() + something = mock.something + self.assertTrue(is_instance(something, Mock), "attribute isn't a mock") + self.assertEqual(mock.something, something, + "different attributes returned for same name") + + # Usage example + mock = Mock() + mock.something.return_value = 3 + + self.assertEqual(mock.something(), 3, "method returned wrong value") + self.assertTrue(mock.something.called, + "method didn't record being called") + + + def test_attributes_have_name_and_parent_set(self): + mock = Mock() + something = mock.something + + self.assertEqual(something._mock_name, "something", + "attribute name not set correctly") + self.assertEqual(something._mock_parent, mock, + "attribute parent not set correctly") + + + def test_method_calls_recorded(self): + mock = Mock() + mock.something(3, fish=None) + mock.something_else.something(6, cake=sentinel.Cake) + + self.assertEqual(mock.something_else.method_calls, + [("something", (6,), {'cake': sentinel.Cake})], + "method calls not recorded correctly") + self.assertEqual(mock.method_calls, [ + ("something", (3,), {'fish': None}), + ("something_else.something", (6,), {'cake': sentinel.Cake}) + ], + "method calls not recorded correctly") + + + def test_method_calls_compare_easily(self): + mock = Mock() + mock.something() + self.assertEqual(mock.method_calls, [('something',)]) + self.assertEqual(mock.method_calls, [('something', (), {})]) + + mock = Mock() + mock.something('different') + self.assertEqual(mock.method_calls, [('something', ('different',))]) + self.assertEqual(mock.method_calls, + [('something', ('different',), {})]) + + mock = Mock() + mock.something(x=1) + self.assertEqual(mock.method_calls, [('something', {'x': 1})]) + self.assertEqual(mock.method_calls, [('something', (), {'x': 1})]) + + mock = Mock() + mock.something('different', some='more') + self.assertEqual(mock.method_calls, [ + ('something', ('different',), {'some': 'more'}) + ]) + + + def test_only_allowed_methods_exist(self): + for spec in ['something'], ('something',): + for arg in 'spec', 'spec_set': + mock = Mock(**{arg: spec}) + + # this should be allowed + mock.something + self.assertRaisesRegex( + AttributeError, + "Mock object has no attribute 'something_else'", + getattr, mock, 'something_else' + ) + + + def test_from_spec(self): + class Something(object): + x = 3 + __something__ = None + def y(self): + pass + + def test_attributes(mock): + # should work + mock.x + mock.y + mock.__something__ + self.assertRaisesRegex( + AttributeError, + "Mock object has no attribute 'z'", + getattr, mock, 'z' + ) + self.assertRaisesRegex( + AttributeError, + "Mock object has no attribute '__foobar__'", + getattr, mock, '__foobar__' + ) + + test_attributes(Mock(spec=Something)) + test_attributes(Mock(spec=Something())) + + + def test_wraps_calls(self): + real = Mock() + + mock = Mock(wraps=real) + self.assertEqual(mock(), real()) + + real.reset_mock() + + mock(1, 2, fish=3) + real.assert_called_with(1, 2, fish=3) + + + def test_wraps_call_with_nondefault_return_value(self): + real = Mock() + + mock = Mock(wraps=real) + mock.return_value = 3 + + self.assertEqual(mock(), 3) + self.assertFalse(real.called) + + + def test_wraps_attributes(self): + class Real(object): + attribute = Mock() + + real = Real() + + mock = Mock(wraps=real) + self.assertEqual(mock.attribute(), real.attribute()) + self.assertRaises(AttributeError, lambda: mock.fish) + + self.assertNotEqual(mock.attribute, real.attribute) + result = mock.attribute.frog(1, 2, fish=3) + Real.attribute.frog.assert_called_with(1, 2, fish=3) + self.assertEqual(result, Real.attribute.frog()) + + + def test_exceptional_side_effect(self): + mock = Mock(side_effect=AttributeError) + self.assertRaises(AttributeError, mock) + + mock = Mock(side_effect=AttributeError('foo')) + self.assertRaises(AttributeError, mock) + + + def test_baseexceptional_side_effect(self): + mock = Mock(side_effect=KeyboardInterrupt) + self.assertRaises(KeyboardInterrupt, mock) + + mock = Mock(side_effect=KeyboardInterrupt('foo')) + self.assertRaises(KeyboardInterrupt, mock) + + + def test_assert_called_with_message(self): + mock = Mock() + self.assertRaisesRegex(AssertionError, 'Not called', + mock.assert_called_with) + + + def test__name__(self): + mock = Mock() + self.assertRaises(AttributeError, lambda: mock.__name__) + + mock.__name__ = 'foo' + self.assertEqual(mock.__name__, 'foo') + + + def test_spec_list_subclass(self): + class Sub(list): + pass + mock = Mock(spec=Sub(['foo'])) + + mock.append(3) + mock.append.assert_called_with(3) + self.assertRaises(AttributeError, getattr, mock, 'foo') + + + def test_spec_class(self): + class X(object): + pass + + mock = Mock(spec=X) + self.assertTrue(isinstance(mock, X)) + + mock = Mock(spec=X()) + self.assertTrue(isinstance(mock, X)) + + self.assertIs(mock.__class__, X) + self.assertEqual(Mock().__class__.__name__, 'Mock') + + mock = Mock(spec_set=X) + self.assertTrue(isinstance(mock, X)) + + mock = Mock(spec_set=X()) + self.assertTrue(isinstance(mock, X)) + + + def test_setting_attribute_with_spec_set(self): + class X(object): + y = 3 + + mock = Mock(spec=X) + mock.x = 'foo' + + mock = Mock(spec_set=X) + def set_attr(): + mock.x = 'foo' + + mock.y = 'foo' + self.assertRaises(AttributeError, set_attr) + + + def test_copy(self): + current = sys.getrecursionlimit() + self.addCleanup(sys.setrecursionlimit, current) + + # can't use sys.maxint as this doesn't exist in Python 3 + sys.setrecursionlimit(int(10e8)) + # this segfaults without the fix in place + copy.copy(Mock()) + + + def test_subclass_with_properties(self): + class SubClass(Mock): + def _get(self): + return 3 + def _set(self, value): + raise NameError('strange error') + some_attribute = property(_get, _set) + + s = SubClass(spec_set=SubClass) + self.assertEqual(s.some_attribute, 3) + + def test(): + s.some_attribute = 3 + self.assertRaises(NameError, test) + + def test(): + s.foo = 'bar' + self.assertRaises(AttributeError, test) + + + def test_setting_call(self): + mock = Mock() + def __call__(self, a): + return self._mock_call(a) + + type(mock).__call__ = __call__ + mock('one') + mock.assert_called_with('one') + + self.assertRaises(TypeError, mock, 'one', 'two') + + + def test_dir(self): + mock = Mock() + attrs = set(dir(mock)) + type_attrs = set([m for m in dir(Mock) if not m.startswith('_')]) + + # all public attributes from the type are included + self.assertEqual(set(), type_attrs - attrs) + + # creates these attributes + mock.a, mock.b + self.assertIn('a', dir(mock)) + self.assertIn('b', dir(mock)) + + # instance attributes + mock.c = mock.d = None + self.assertIn('c', dir(mock)) + self.assertIn('d', dir(mock)) + + # magic methods + mock.__iter__ = lambda s: iter([]) + self.assertIn('__iter__', dir(mock)) + + + def test_dir_from_spec(self): + mock = Mock(spec=unittest.TestCase) + testcase_attrs = set(dir(unittest.TestCase)) + attrs = set(dir(mock)) + + # all attributes from the spec are included + self.assertEqual(set(), testcase_attrs - attrs) + + # shadow a sys attribute + mock.version = 3 + self.assertEqual(dir(mock).count('version'), 1) + + + def test_filter_dir(self): + patcher = patch.object(mock, 'FILTER_DIR', False) + patcher.start() + try: + attrs = set(dir(Mock())) + type_attrs = set(dir(Mock)) + + # ALL attributes from the type are included + self.assertEqual(set(), type_attrs - attrs) + finally: + patcher.stop() + + + def test_configure_mock(self): + mock = Mock(foo='bar') + self.assertEqual(mock.foo, 'bar') + + mock = MagicMock(foo='bar') + self.assertEqual(mock.foo, 'bar') + + kwargs = {'side_effect': KeyError, 'foo.bar.return_value': 33, + 'foo': MagicMock()} + mock = Mock(**kwargs) + self.assertRaises(KeyError, mock) + self.assertEqual(mock.foo.bar(), 33) + self.assertIsInstance(mock.foo, MagicMock) + + mock = Mock() + mock.configure_mock(**kwargs) + self.assertRaises(KeyError, mock) + self.assertEqual(mock.foo.bar(), 33) + self.assertIsInstance(mock.foo, MagicMock) + + + def assertRaisesWithMsg(self, exception, message, func, *args, **kwargs): + # needed because assertRaisesRegex doesn't work easily with newlines + try: + func(*args, **kwargs) + except: + instance = sys.exc_info()[1] + self.assertIsInstance(instance, exception) + else: + self.fail('Exception %r not raised' % (exception,)) + + msg = str(instance) + self.assertEqual(msg, message) + + + def test_assert_called_with_failure_message(self): + mock = NonCallableMock() + + expected = "mock(1, '2', 3, bar='foo')" + message = 'Expected call: %s\nNot called' + self.assertRaisesWithMsg( + AssertionError, message % (expected,), + mock.assert_called_with, 1, '2', 3, bar='foo' + ) + + mock.foo(1, '2', 3, foo='foo') + + + asserters = [ + mock.foo.assert_called_with, mock.foo.assert_called_once_with + ] + for meth in asserters: + actual = "foo(1, '2', 3, foo='foo')" + expected = "foo(1, '2', 3, bar='foo')" + message = 'Expected call: %s\nActual call: %s' + self.assertRaisesWithMsg( + AssertionError, message % (expected, actual), + meth, 1, '2', 3, bar='foo' + ) + + # just kwargs + for meth in asserters: + actual = "foo(1, '2', 3, foo='foo')" + expected = "foo(bar='foo')" + message = 'Expected call: %s\nActual call: %s' + self.assertRaisesWithMsg( + AssertionError, message % (expected, actual), + meth, bar='foo' + ) + + # just args + for meth in asserters: + actual = "foo(1, '2', 3, foo='foo')" + expected = "foo(1, 2, 3)" + message = 'Expected call: %s\nActual call: %s' + self.assertRaisesWithMsg( + AssertionError, message % (expected, actual), + meth, 1, 2, 3 + ) + + # empty + for meth in asserters: + actual = "foo(1, '2', 3, foo='foo')" + expected = "foo()" + message = 'Expected call: %s\nActual call: %s' + self.assertRaisesWithMsg( + AssertionError, message % (expected, actual), meth + ) + + + def test_mock_calls(self): + mock = MagicMock() + + # need to do this because MagicMock.mock_calls used to just return + # a MagicMock which also returned a MagicMock when __eq__ was called + self.assertIs(mock.mock_calls == [], True) + + mock = MagicMock() + mock() + expected = [('', (), {})] + self.assertEqual(mock.mock_calls, expected) + + mock.foo() + expected.append(call.foo()) + self.assertEqual(mock.mock_calls, expected) + # intermediate mock_calls work too + self.assertEqual(mock.foo.mock_calls, [('', (), {})]) + + mock = MagicMock() + mock().foo(1, 2, 3, a=4, b=5) + expected = [ + ('', (), {}), ('().foo', (1, 2, 3), dict(a=4, b=5)) + ] + self.assertEqual(mock.mock_calls, expected) + self.assertEqual(mock.return_value.foo.mock_calls, + [('', (1, 2, 3), dict(a=4, b=5))]) + self.assertEqual(mock.return_value.mock_calls, + [('foo', (1, 2, 3), dict(a=4, b=5))]) + + mock = MagicMock() + mock().foo.bar().baz() + expected = [ + ('', (), {}), ('().foo.bar', (), {}), + ('().foo.bar().baz', (), {}) + ] + self.assertEqual(mock.mock_calls, expected) + self.assertEqual(mock().mock_calls, + call.foo.bar().baz().call_list()) + + for kwargs in dict(), dict(name='bar'): + mock = MagicMock(**kwargs) + int(mock.foo) + expected = [('foo.__int__', (), {})] + self.assertEqual(mock.mock_calls, expected) + + mock = MagicMock(**kwargs) + mock.a()() + expected = [('a', (), {}), ('a()', (), {})] + self.assertEqual(mock.mock_calls, expected) + self.assertEqual(mock.a().mock_calls, [call()]) + + mock = MagicMock(**kwargs) + mock(1)(2)(3) + self.assertEqual(mock.mock_calls, call(1)(2)(3).call_list()) + self.assertEqual(mock().mock_calls, call(2)(3).call_list()) + self.assertEqual(mock()().mock_calls, call(3).call_list()) + + mock = MagicMock(**kwargs) + mock(1)(2)(3).a.b.c(4) + self.assertEqual(mock.mock_calls, + call(1)(2)(3).a.b.c(4).call_list()) + self.assertEqual(mock().mock_calls, + call(2)(3).a.b.c(4).call_list()) + self.assertEqual(mock()().mock_calls, + call(3).a.b.c(4).call_list()) + + mock = MagicMock(**kwargs) + int(mock().foo.bar().baz()) + last_call = ('().foo.bar().baz().__int__', (), {}) + self.assertEqual(mock.mock_calls[-1], last_call) + self.assertEqual(mock().mock_calls, + call.foo.bar().baz().__int__().call_list()) + self.assertEqual(mock().foo.bar().mock_calls, + call.baz().__int__().call_list()) + self.assertEqual(mock().foo.bar().baz.mock_calls, + call().__int__().call_list()) + + + def test_subclassing(self): + class Subclass(Mock): + pass + + mock = Subclass() + self.assertIsInstance(mock.foo, Subclass) + self.assertIsInstance(mock(), Subclass) + + class Subclass(Mock): + def _get_child_mock(self, **kwargs): + return Mock(**kwargs) + + mock = Subclass() + self.assertNotIsInstance(mock.foo, Subclass) + self.assertNotIsInstance(mock(), Subclass) + + + def test_arg_lists(self): + mocks = [ + Mock(), + MagicMock(), + NonCallableMock(), + NonCallableMagicMock() + ] + + def assert_attrs(mock): + names = 'call_args_list', 'method_calls', 'mock_calls' + for name in names: + attr = getattr(mock, name) + self.assertIsInstance(attr, _CallList) + self.assertIsInstance(attr, list) + self.assertEqual(attr, []) + + for mock in mocks: + assert_attrs(mock) + + if callable(mock): + mock() + mock(1, 2) + mock(a=3) + + mock.reset_mock() + assert_attrs(mock) + + mock.foo() + mock.foo.bar(1, a=3) + mock.foo(1).bar().baz(3) + + mock.reset_mock() + assert_attrs(mock) + + + def test_call_args_two_tuple(self): + mock = Mock() + mock(1, a=3) + mock(2, b=4) + + self.assertEqual(len(mock.call_args), 2) + args, kwargs = mock.call_args + self.assertEqual(args, (2,)) + self.assertEqual(kwargs, dict(b=4)) + + expected_list = [((1,), dict(a=3)), ((2,), dict(b=4))] + for expected, call_args in zip(expected_list, mock.call_args_list): + self.assertEqual(len(call_args), 2) + self.assertEqual(expected[0], call_args[0]) + self.assertEqual(expected[1], call_args[1]) + + + def test_side_effect_iterator(self): + mock = Mock(side_effect=iter([1, 2, 3])) + self.assertEqual([mock(), mock(), mock()], [1, 2, 3]) + self.assertRaises(StopIteration, mock) + + mock = MagicMock(side_effect=['a', 'b', 'c']) + self.assertEqual([mock(), mock(), mock()], ['a', 'b', 'c']) + self.assertRaises(StopIteration, mock) + + mock = Mock(side_effect='ghi') + self.assertEqual([mock(), mock(), mock()], ['g', 'h', 'i']) + self.assertRaises(StopIteration, mock) + + class Foo(object): + pass + mock = MagicMock(side_effect=Foo) + self.assertIsInstance(mock(), Foo) + + mock = Mock(side_effect=Iter()) + self.assertEqual([mock(), mock(), mock(), mock()], + ['this', 'is', 'an', 'iter']) + self.assertRaises(StopIteration, mock) + + + def test_side_effect_setting_iterator(self): + mock = Mock() + mock.side_effect = iter([1, 2, 3]) + self.assertEqual([mock(), mock(), mock()], [1, 2, 3]) + self.assertRaises(StopIteration, mock) + side_effect = mock.side_effect + self.assertIsInstance(side_effect, type(iter([]))) + + mock.side_effect = ['a', 'b', 'c'] + self.assertEqual([mock(), mock(), mock()], ['a', 'b', 'c']) + self.assertRaises(StopIteration, mock) + side_effect = mock.side_effect + self.assertIsInstance(side_effect, type(iter([]))) + + this_iter = Iter() + mock.side_effect = this_iter + self.assertEqual([mock(), mock(), mock(), mock()], + ['this', 'is', 'an', 'iter']) + self.assertRaises(StopIteration, mock) + self.assertIs(mock.side_effect, this_iter) + + + def test_assert_has_calls_any_order(self): + mock = Mock() + mock(1, 2) + mock(a=3) + mock(3, 4) + mock(b=6) + mock(b=6) + + kalls = [ + call(1, 2), ({'a': 3},), + ((3, 4),), ((), {'a': 3}), + ('', (1, 2)), ('', {'a': 3}), + ('', (1, 2), {}), ('', (), {'a': 3}) + ] + for kall in kalls: + mock.assert_has_calls([kall], any_order=True) + + for kall in call(1, '2'), call(b=3), call(), 3, None, 'foo': + self.assertRaises( + AssertionError, mock.assert_has_calls, + [kall], any_order=True + ) + + kall_lists = [ + [call(1, 2), call(b=6)], + [call(3, 4), call(1, 2)], + [call(b=6), call(b=6)], + ] + + for kall_list in kall_lists: + mock.assert_has_calls(kall_list, any_order=True) + + kall_lists = [ + [call(b=6), call(b=6), call(b=6)], + [call(1, 2), call(1, 2)], + [call(3, 4), call(1, 2), call(5, 7)], + [call(b=6), call(3, 4), call(b=6), call(1, 2), call(b=6)], + ] + for kall_list in kall_lists: + self.assertRaises( + AssertionError, mock.assert_has_calls, + kall_list, any_order=True + ) + + def test_assert_has_calls(self): + kalls1 = [ + call(1, 2), ({'a': 3},), + ((3, 4),), call(b=6), + ('', (1,), {'b': 6}), + ] + kalls2 = [call.foo(), call.bar(1)] + kalls2.extend(call.spam().baz(a=3).call_list()) + kalls2.extend(call.bam(set(), foo={}).fish([1]).call_list()) + + mocks = [] + for mock in Mock(), MagicMock(): + mock(1, 2) + mock(a=3) + mock(3, 4) + mock(b=6) + mock(1, b=6) + mocks.append((mock, kalls1)) + + mock = Mock() + mock.foo() + mock.bar(1) + mock.spam().baz(a=3) + mock.bam(set(), foo={}).fish([1]) + mocks.append((mock, kalls2)) + + for mock, kalls in mocks: + for i in range(len(kalls)): + for step in 1, 2, 3: + these = kalls[i:i+step] + mock.assert_has_calls(these) + + if len(these) > 1: + self.assertRaises( + AssertionError, + mock.assert_has_calls, + list(reversed(these)) + ) + + + def test_assert_any_call(self): + mock = Mock() + mock(1, 2) + mock(a=3) + mock(1, b=6) + + mock.assert_any_call(1, 2) + mock.assert_any_call(a=3) + mock.assert_any_call(1, b=6) + + self.assertRaises( + AssertionError, + mock.assert_any_call + ) + self.assertRaises( + AssertionError, + mock.assert_any_call, + 1, 3 + ) + self.assertRaises( + AssertionError, + mock.assert_any_call, + a=4 + ) + + + def test_mock_calls_create_autospec(self): + def f(a, b): + pass + obj = Iter() + obj.f = f + + funcs = [ + create_autospec(f), + create_autospec(obj).f + ] + for func in funcs: + func(1, 2) + func(3, 4) + + self.assertEqual( + func.mock_calls, [call(1, 2), call(3, 4)] + ) + + + def test_mock_add_spec(self): + class _One(object): + one = 1 + class _Two(object): + two = 2 + class Anything(object): + one = two = three = 'four' + + klasses = [ + Mock, MagicMock, NonCallableMock, NonCallableMagicMock + ] + for Klass in list(klasses): + klasses.append(lambda K=Klass: K(spec=Anything)) + klasses.append(lambda K=Klass: K(spec_set=Anything)) + + for Klass in klasses: + for kwargs in dict(), dict(spec_set=True): + mock = Klass() + #no error + mock.one, mock.two, mock.three + + for One, Two in [(_One, _Two), (['one'], ['two'])]: + for kwargs in dict(), dict(spec_set=True): + mock.mock_add_spec(One, **kwargs) + + mock.one + self.assertRaises( + AttributeError, getattr, mock, 'two' + ) + self.assertRaises( + AttributeError, getattr, mock, 'three' + ) + if 'spec_set' in kwargs: + self.assertRaises( + AttributeError, setattr, mock, 'three', None + ) + + mock.mock_add_spec(Two, **kwargs) + self.assertRaises( + AttributeError, getattr, mock, 'one' + ) + mock.two + self.assertRaises( + AttributeError, getattr, mock, 'three' + ) + if 'spec_set' in kwargs: + self.assertRaises( + AttributeError, setattr, mock, 'three', None + ) + # note that creating a mock, setting an instance attribute, and + # *then* setting a spec doesn't work. Not the intended use case + + + def test_mock_add_spec_magic_methods(self): + for Klass in MagicMock, NonCallableMagicMock: + mock = Klass() + int(mock) + + mock.mock_add_spec(object) + self.assertRaises(TypeError, int, mock) + + mock = Klass() + mock['foo'] + mock.__int__.return_value =4 + + mock.mock_add_spec(int) + self.assertEqual(int(mock), 4) + self.assertRaises(TypeError, lambda: mock['foo']) + + + def test_adding_child_mock(self): + for Klass in NonCallableMock, Mock, MagicMock, NonCallableMagicMock: + mock = Klass() + + mock.foo = Mock() + mock.foo() + + self.assertEqual(mock.method_calls, [call.foo()]) + self.assertEqual(mock.mock_calls, [call.foo()]) + + mock = Klass() + mock.bar = Mock(name='name') + mock.bar() + self.assertEqual(mock.method_calls, []) + self.assertEqual(mock.mock_calls, []) + + # mock with an existing _new_parent but no name + mock = Klass() + mock.baz = MagicMock()() + mock.baz() + self.assertEqual(mock.method_calls, []) + self.assertEqual(mock.mock_calls, []) + + + def test_adding_return_value_mock(self): + for Klass in Mock, MagicMock: + mock = Klass() + mock.return_value = MagicMock() + + mock()() + self.assertEqual(mock.mock_calls, [call(), call()()]) + + + def test_manager_mock(self): + class Foo(object): + one = 'one' + two = 'two' + manager = Mock() + p1 = patch.object(Foo, 'one') + p2 = patch.object(Foo, 'two') + + mock_one = p1.start() + self.addCleanup(p1.stop) + mock_two = p2.start() + self.addCleanup(p2.stop) + + manager.attach_mock(mock_one, 'one') + manager.attach_mock(mock_two, 'two') + + Foo.two() + Foo.one() + + self.assertEqual(manager.mock_calls, [call.two(), call.one()]) + + + def test_magic_methods_mock_calls(self): + for Klass in Mock, MagicMock: + m = Klass() + m.__int__ = Mock(return_value=3) + m.__float__ = MagicMock(return_value=3.0) + int(m) + float(m) + + self.assertEqual(m.mock_calls, [call.__int__(), call.__float__()]) + self.assertEqual(m.method_calls, []) + + + def test_attribute_deletion(self): + # this behaviour isn't *useful*, but at least it's now tested... + for Klass in Mock, MagicMock, NonCallableMagicMock, NonCallableMock: + m = Klass() + original = m.foo + m.foo = 3 + del m.foo + self.assertEqual(m.foo, original) + + new = m.foo = Mock() + del m.foo + self.assertEqual(m.foo, new) + + + def test_mock_parents(self): + for Klass in Mock, MagicMock: + m = Klass() + original_repr = repr(m) + m.return_value = m + self.assertIs(m(), m) + self.assertEqual(repr(m), original_repr) + + m.reset_mock() + self.assertIs(m(), m) + self.assertEqual(repr(m), original_repr) + + m = Klass() + m.b = m.a + self.assertIn("name='mock.a'", repr(m.b)) + self.assertIn("name='mock.a'", repr(m.a)) + m.reset_mock() + self.assertIn("name='mock.a'", repr(m.b)) + self.assertIn("name='mock.a'", repr(m.a)) + + m = Klass() + original_repr = repr(m) + m.a = m() + m.a.return_value = m + + self.assertEqual(repr(m), original_repr) + self.assertEqual(repr(m.a()), original_repr) + + + def test_attach_mock(self): + classes = Mock, MagicMock, NonCallableMagicMock, NonCallableMock + for Klass in classes: + for Klass2 in classes: + m = Klass() + + m2 = Klass2(name='foo') + m.attach_mock(m2, 'bar') + + self.assertIs(m.bar, m2) + self.assertIn("name='mock.bar'", repr(m2)) + + m.bar.baz(1) + self.assertEqual(m.mock_calls, [call.bar.baz(1)]) + self.assertEqual(m.method_calls, [call.bar.baz(1)]) + + + def test_attach_mock_return_value(self): + classes = Mock, MagicMock, NonCallableMagicMock, NonCallableMock + for Klass in Mock, MagicMock: + for Klass2 in classes: + m = Klass() + + m2 = Klass2(name='foo') + m.attach_mock(m2, 'return_value') + + self.assertIs(m(), m2) + self.assertIn("name='mock()'", repr(m2)) + + m2.foo() + self.assertEqual(m.mock_calls, call().foo().call_list()) + + + def test_attribute_deletion(self): + for mock in Mock(), MagicMock(): + self.assertTrue(hasattr(mock, 'm')) + + del mock.m + self.assertFalse(hasattr(mock, 'm')) + + del mock.f + self.assertFalse(hasattr(mock, 'f')) + self.assertRaises(AttributeError, getattr, mock, 'f') + + + def test_class_assignable(self): + for mock in Mock(), MagicMock(): + self.assertNotIsInstance(mock, int) + + mock.__class__ = int + self.assertIsInstance(mock, int) + mock.foo + + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testpatch.py @@ -0,0 +1,1652 @@ +# Copyright (C) 2007-2012 Michael Foord & the mock team +# E-mail: fuzzyman AT voidspace DOT org DOT uk +# http://www.voidspace.org.uk/python/mock/ + +import os +import sys + +import unittest +from unittest.test.testmock import support +from unittest.test.testmock.support import SomeClass, is_instance + +from unittest.mock import ( + NonCallableMock, CallableMixin, patch, sentinel, + MagicMock, Mock, NonCallableMagicMock, patch, + DEFAULT, call +) + + +builtin_string = 'builtins' + +PTModule = sys.modules[__name__] + + +def _get_proxy(obj, get_only=True): + class Proxy(object): + def __getattr__(self, name): + return getattr(obj, name) + if not get_only: + def __setattr__(self, name, value): + setattr(obj, name, value) + def __delattr__(self, name): + delattr(obj, name) + Proxy.__setattr__ = __setattr__ + Proxy.__delattr__ = __delattr__ + return Proxy() + + +# for use in the test +something = sentinel.Something +something_else = sentinel.SomethingElse + + +class Foo(object): + def __init__(self, a): + pass + def f(self, a): + pass + def g(self): + pass + foo = 'bar' + + class Bar(object): + def a(self): + pass + +foo_name = '%s.Foo' % __name__ + + +def function(a, b=Foo): + pass + + +class Container(object): + def __init__(self): + self.values = {} + + def __getitem__(self, name): + return self.values[name] + + def __setitem__(self, name, value): + self.values[name] = value + + def __delitem__(self, name): + del self.values[name] + + def __iter__(self): + return iter(self.values) + + + +class PatchTest(unittest.TestCase): + + def assertNotCallable(self, obj, magic=True): + MockClass = NonCallableMagicMock + if not magic: + MockClass = NonCallableMock + + self.assertRaises(TypeError, obj) + self.assertTrue(is_instance(obj, MockClass)) + self.assertFalse(is_instance(obj, CallableMixin)) + + + def test_single_patchobject(self): + class Something(object): + attribute = sentinel.Original + + @patch.object(Something, 'attribute', sentinel.Patched) + def test(): + self.assertEqual(Something.attribute, sentinel.Patched, "unpatched") + + test() + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + + + def test_patchobject_with_none(self): + class Something(object): + attribute = sentinel.Original + + @patch.object(Something, 'attribute', None) + def test(): + self.assertIsNone(Something.attribute, "unpatched") + + test() + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + + + def test_multiple_patchobject(self): + class Something(object): + attribute = sentinel.Original + next_attribute = sentinel.Original2 + + @patch.object(Something, 'attribute', sentinel.Patched) + @patch.object(Something, 'next_attribute', sentinel.Patched2) + def test(): + self.assertEqual(Something.attribute, sentinel.Patched, + "unpatched") + self.assertEqual(Something.next_attribute, sentinel.Patched2, + "unpatched") + + test() + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + self.assertEqual(Something.next_attribute, sentinel.Original2, + "patch not restored") + + + def test_object_lookup_is_quite_lazy(self): + global something + original = something + @patch('%s.something' % __name__, sentinel.Something2) + def test(): + pass + + try: + something = sentinel.replacement_value + test() + self.assertEqual(something, sentinel.replacement_value) + finally: + something = original + + + def test_patch(self): + @patch('%s.something' % __name__, sentinel.Something2) + def test(): + self.assertEqual(PTModule.something, sentinel.Something2, + "unpatched") + + test() + self.assertEqual(PTModule.something, sentinel.Something, + "patch not restored") + + @patch('%s.something' % __name__, sentinel.Something2) + @patch('%s.something_else' % __name__, sentinel.SomethingElse) + def test(): + self.assertEqual(PTModule.something, sentinel.Something2, + "unpatched") + self.assertEqual(PTModule.something_else, sentinel.SomethingElse, + "unpatched") + + self.assertEqual(PTModule.something, sentinel.Something, + "patch not restored") + self.assertEqual(PTModule.something_else, sentinel.SomethingElse, + "patch not restored") + + # Test the patching and restoring works a second time + test() + + self.assertEqual(PTModule.something, sentinel.Something, + "patch not restored") + self.assertEqual(PTModule.something_else, sentinel.SomethingElse, + "patch not restored") + + mock = Mock() + mock.return_value = sentinel.Handle + @patch('%s.open' % builtin_string, mock) + def test(): + self.assertEqual(open('filename', 'r'), sentinel.Handle, + "open not patched") + test() + test() + + self.assertNotEqual(open, mock, "patch not restored") + + + def test_patch_class_attribute(self): + @patch('%s.SomeClass.class_attribute' % __name__, + sentinel.ClassAttribute) + def test(): + self.assertEqual(PTModule.SomeClass.class_attribute, + sentinel.ClassAttribute, "unpatched") + test() + + self.assertIsNone(PTModule.SomeClass.class_attribute, + "patch not restored") + + + def test_patchobject_with_default_mock(self): + class Test(object): + something = sentinel.Original + something2 = sentinel.Original2 + + @patch.object(Test, 'something') + def test(mock): + self.assertEqual(mock, Test.something, + "Mock not passed into test function") + self.assertIsInstance(mock, MagicMock, + "patch with two arguments did not create a mock") + + test() + + @patch.object(Test, 'something') + @patch.object(Test, 'something2') + def test(this1, this2, mock1, mock2): + self.assertEqual(this1, sentinel.this1, + "Patched function didn't receive initial argument") + self.assertEqual(this2, sentinel.this2, + "Patched function didn't receive second argument") + self.assertEqual(mock1, Test.something2, + "Mock not passed into test function") + self.assertEqual(mock2, Test.something, + "Second Mock not passed into test function") + self.assertIsInstance(mock2, MagicMock, + "patch with two arguments did not create a mock") + self.assertIsInstance(mock2, MagicMock, + "patch with two arguments did not create a mock") + + # A hack to test that new mocks are passed the second time + self.assertNotEqual(outerMock1, mock1, "unexpected value for mock1") + self.assertNotEqual(outerMock2, mock2, "unexpected value for mock1") + return mock1, mock2 + + outerMock1 = outerMock2 = None + outerMock1, outerMock2 = test(sentinel.this1, sentinel.this2) + + # Test that executing a second time creates new mocks + test(sentinel.this1, sentinel.this2) + + + def test_patch_with_spec(self): + @patch('%s.SomeClass' % __name__, spec=SomeClass) + def test(MockSomeClass): + self.assertEqual(SomeClass, MockSomeClass) + self.assertTrue(is_instance(SomeClass.wibble, MagicMock)) + self.assertRaises(AttributeError, lambda: SomeClass.not_wibble) + + test() + + + def test_patchobject_with_spec(self): + @patch.object(SomeClass, 'class_attribute', spec=SomeClass) + def test(MockAttribute): + self.assertEqual(SomeClass.class_attribute, MockAttribute) + self.assertTrue(is_instance(SomeClass.class_attribute.wibble, + MagicMock)) + self.assertRaises(AttributeError, + lambda: SomeClass.class_attribute.not_wibble) + + test() + + + def test_patch_with_spec_as_list(self): + @patch('%s.SomeClass' % __name__, spec=['wibble']) + def test(MockSomeClass): + self.assertEqual(SomeClass, MockSomeClass) + self.assertTrue(is_instance(SomeClass.wibble, MagicMock)) + self.assertRaises(AttributeError, lambda: SomeClass.not_wibble) + + test() + + + def test_patchobject_with_spec_as_list(self): + @patch.object(SomeClass, 'class_attribute', spec=['wibble']) + def test(MockAttribute): + self.assertEqual(SomeClass.class_attribute, MockAttribute) + self.assertTrue(is_instance(SomeClass.class_attribute.wibble, + MagicMock)) + self.assertRaises(AttributeError, + lambda: SomeClass.class_attribute.not_wibble) + + test() + + + def test_nested_patch_with_spec_as_list(self): + # regression test for nested decorators + @patch('%s.open' % builtin_string) + @patch('%s.SomeClass' % __name__, spec=['wibble']) + def test(MockSomeClass, MockOpen): + self.assertEqual(SomeClass, MockSomeClass) + self.assertTrue(is_instance(SomeClass.wibble, MagicMock)) + self.assertRaises(AttributeError, lambda: SomeClass.not_wibble) + test() + + + def test_patch_with_spec_as_boolean(self): + @patch('%s.SomeClass' % __name__, spec=True) + def test(MockSomeClass): + self.assertEqual(SomeClass, MockSomeClass) + # Should not raise attribute error + MockSomeClass.wibble + + self.assertRaises(AttributeError, lambda: MockSomeClass.not_wibble) + + test() + + + def test_patch_object_with_spec_as_boolean(self): + @patch.object(PTModule, 'SomeClass', spec=True) + def test(MockSomeClass): + self.assertEqual(SomeClass, MockSomeClass) + # Should not raise attribute error + MockSomeClass.wibble + + self.assertRaises(AttributeError, lambda: MockSomeClass.not_wibble) + + test() + + + def test_patch_class_acts_with_spec_is_inherited(self): + @patch('%s.SomeClass' % __name__, spec=True) + def test(MockSomeClass): + self.assertTrue(is_instance(MockSomeClass, MagicMock)) + instance = MockSomeClass() + self.assertNotCallable(instance) + # Should not raise attribute error + instance.wibble + + self.assertRaises(AttributeError, lambda: instance.not_wibble) + + test() + + + def test_patch_with_create_mocks_non_existent_attributes(self): + @patch('%s.frooble' % builtin_string, sentinel.Frooble, create=True) + def test(): + self.assertEqual(frooble, sentinel.Frooble) + + test() + self.assertRaises(NameError, lambda: frooble) + + + def test_patchobject_with_create_mocks_non_existent_attributes(self): + @patch.object(SomeClass, 'frooble', sentinel.Frooble, create=True) + def test(): + self.assertEqual(SomeClass.frooble, sentinel.Frooble) + + test() + self.assertFalse(hasattr(SomeClass, 'frooble')) + + + def test_patch_wont_create_by_default(self): + try: + @patch('%s.frooble' % builtin_string, sentinel.Frooble) + def test(): + self.assertEqual(frooble, sentinel.Frooble) + + test() + except AttributeError: + pass + else: + self.fail('Patching non existent attributes should fail') + + self.assertRaises(NameError, lambda: frooble) + + + def test_patchobject_wont_create_by_default(self): + try: + @patch.object(SomeClass, 'frooble', sentinel.Frooble) + def test(): + self.fail('Patching non existent attributes should fail') + + test() + except AttributeError: + pass + else: + self.fail('Patching non existent attributes should fail') + self.assertFalse(hasattr(SomeClass, 'frooble')) + + + def test_patch_with_static_methods(self): + class Foo(object): + @staticmethod + def woot(): + return sentinel.Static + + @patch.object(Foo, 'woot', staticmethod(lambda: sentinel.Patched)) + def anonymous(): + self.assertEqual(Foo.woot(), sentinel.Patched) + anonymous() + + self.assertEqual(Foo.woot(), sentinel.Static) + + + def test_patch_local(self): + foo = sentinel.Foo + @patch.object(sentinel, 'Foo', 'Foo') + def anonymous(): + self.assertEqual(sentinel.Foo, 'Foo') + anonymous() + + self.assertEqual(sentinel.Foo, foo) + + + def test_patch_slots(self): + class Foo(object): + __slots__ = ('Foo',) + + foo = Foo() + foo.Foo = sentinel.Foo + + @patch.object(foo, 'Foo', 'Foo') + def anonymous(): + self.assertEqual(foo.Foo, 'Foo') + anonymous() + + self.assertEqual(foo.Foo, sentinel.Foo) + + + def test_patchobject_class_decorator(self): + class Something(object): + attribute = sentinel.Original + + class Foo(object): + def test_method(other_self): + self.assertEqual(Something.attribute, sentinel.Patched, + "unpatched") + def not_test_method(other_self): + self.assertEqual(Something.attribute, sentinel.Original, + "non-test method patched") + + Foo = patch.object(Something, 'attribute', sentinel.Patched)(Foo) + + f = Foo() + f.test_method() + f.not_test_method() + + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + + + def test_patch_class_decorator(self): + class Something(object): + attribute = sentinel.Original + + class Foo(object): + def test_method(other_self, mock_something): + self.assertEqual(PTModule.something, mock_something, + "unpatched") + def not_test_method(other_self): + self.assertEqual(PTModule.something, sentinel.Something, + "non-test method patched") + Foo = patch('%s.something' % __name__)(Foo) + + f = Foo() + f.test_method() + f.not_test_method() + + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + self.assertEqual(PTModule.something, sentinel.Something, + "patch not restored") + + + def test_patchobject_twice(self): + class Something(object): + attribute = sentinel.Original + next_attribute = sentinel.Original2 + + @patch.object(Something, 'attribute', sentinel.Patched) + @patch.object(Something, 'attribute', sentinel.Patched) + def test(): + self.assertEqual(Something.attribute, sentinel.Patched, "unpatched") + + test() + + self.assertEqual(Something.attribute, sentinel.Original, + "patch not restored") + + + def test_patch_dict(self): + foo = {'initial': object(), 'other': 'something'} + original = foo.copy() + + @patch.dict(foo) + def test(): + foo['a'] = 3 + del foo['initial'] + foo['other'] = 'something else' + + test() + + self.assertEqual(foo, original) + + @patch.dict(foo, {'a': 'b'}) + def test(): + self.assertEqual(len(foo), 3) + self.assertEqual(foo['a'], 'b') + + test() + + self.assertEqual(foo, original) + + @patch.dict(foo, [('a', 'b')]) + def test(): + self.assertEqual(len(foo), 3) + self.assertEqual(foo['a'], 'b') + + test() + + self.assertEqual(foo, original) + + + def test_patch_dict_with_container_object(self): + foo = Container() + foo['initial'] = object() + foo['other'] = 'something' + + original = foo.values.copy() + + @patch.dict(foo) + def test(): + foo['a'] = 3 + del foo['initial'] + foo['other'] = 'something else' + + test() + + self.assertEqual(foo.values, original) + + @patch.dict(foo, {'a': 'b'}) + def test(): + self.assertEqual(len(foo.values), 3) + self.assertEqual(foo['a'], 'b') + + test() + + self.assertEqual(foo.values, original) + + + def test_patch_dict_with_clear(self): + foo = {'initial': object(), 'other': 'something'} + original = foo.copy() + + @patch.dict(foo, clear=True) + def test(): + self.assertEqual(foo, {}) + foo['a'] = 3 + foo['other'] = 'something else' + + test() + + self.assertEqual(foo, original) + + @patch.dict(foo, {'a': 'b'}, clear=True) + def test(): + self.assertEqual(foo, {'a': 'b'}) + + test() + + self.assertEqual(foo, original) + + @patch.dict(foo, [('a', 'b')], clear=True) + def test(): + self.assertEqual(foo, {'a': 'b'}) + + test() + + self.assertEqual(foo, original) + + + def test_patch_dict_with_container_object_and_clear(self): + foo = Container() + foo['initial'] = object() + foo['other'] = 'something' + + original = foo.values.copy() + + @patch.dict(foo, clear=True) + def test(): + self.assertEqual(foo.values, {}) + foo['a'] = 3 + foo['other'] = 'something else' + + test() + + self.assertEqual(foo.values, original) + + @patch.dict(foo, {'a': 'b'}, clear=True) + def test(): + self.assertEqual(foo.values, {'a': 'b'}) + + test() + + self.assertEqual(foo.values, original) + + + def test_name_preserved(self): + foo = {} + + @patch('%s.SomeClass' % __name__, object()) + @patch('%s.SomeClass' % __name__, object(), autospec=True) + @patch.object(SomeClass, object()) + @patch.dict(foo) + def some_name(): + pass + + self.assertEqual(some_name.__name__, 'some_name') + + + def test_patch_with_exception(self): + foo = {} + + @patch.dict(foo, {'a': 'b'}) + def test(): + raise NameError('Konrad') + try: + test() + except NameError: + pass + else: + self.fail('NameError not raised by test') + + self.assertEqual(foo, {}) + + + def test_patch_dict_with_string(self): + @patch.dict('os.environ', {'konrad_delong': 'some value'}) + def test(): + self.assertIn('konrad_delong', os.environ) + + test() + + + def test_patch_descriptor(self): + # would be some effort to fix this - we could special case the + # builtin descriptors: classmethod, property, staticmethod + return + class Nothing(object): + foo = None + + class Something(object): + foo = {} + + @patch.object(Nothing, 'foo', 2) + @classmethod + def klass(cls): + self.assertIs(cls, Something) + + @patch.object(Nothing, 'foo', 2) + @staticmethod + def static(arg): + return arg + + @patch.dict(foo) + @classmethod + def klass_dict(cls): + self.assertIs(cls, Something) + + @patch.dict(foo) + @staticmethod + def static_dict(arg): + return arg + + # these will raise exceptions if patching descriptors is broken + self.assertEqual(Something.static('f00'), 'f00') + Something.klass() + self.assertEqual(Something.static_dict('f00'), 'f00') + Something.klass_dict() + + something = Something() + self.assertEqual(something.static('f00'), 'f00') + something.klass() + self.assertEqual(something.static_dict('f00'), 'f00') + something.klass_dict() + + + def test_patch_spec_set(self): + @patch('%s.SomeClass' % __name__, spec=SomeClass, spec_set=True) + def test(MockClass): + MockClass.z = 'foo' + + self.assertRaises(AttributeError, test) + + @patch.object(support, 'SomeClass', spec=SomeClass, spec_set=True) + def test(MockClass): + MockClass.z = 'foo' + + self.assertRaises(AttributeError, test) + @patch('%s.SomeClass' % __name__, spec_set=True) + def test(MockClass): + MockClass.z = 'foo' + + self.assertRaises(AttributeError, test) + + @patch.object(support, 'SomeClass', spec_set=True) + def test(MockClass): + MockClass.z = 'foo' + + self.assertRaises(AttributeError, test) + + + def test_spec_set_inherit(self): + @patch('%s.SomeClass' % __name__, spec_set=True) + def test(MockClass): + instance = MockClass() + instance.z = 'foo' + + self.assertRaises(AttributeError, test) + + + def test_patch_start_stop(self): + original = something + patcher = patch('%s.something' % __name__) + self.assertIs(something, original) + mock = patcher.start() + self.assertIsNot(mock, original) + try: + self.assertIs(something, mock) + finally: + patcher.stop() + self.assertIs(something, original) + + + def test_stop_without_start(self): + patcher = patch(foo_name, 'bar', 3) + + # calling stop without start used to produce a very obscure error + self.assertRaises(RuntimeError, patcher.stop) + + + def test_patchobject_start_stop(self): + original = something + patcher = patch.object(PTModule, 'something', 'foo') + self.assertIs(something, original) + replaced = patcher.start() + self.assertEqual(replaced, 'foo') + try: + self.assertIs(something, replaced) + finally: + patcher.stop() + self.assertIs(something, original) + + + def test_patch_dict_start_stop(self): + d = {'foo': 'bar'} + original = d.copy() + patcher = patch.dict(d, [('spam', 'eggs')], clear=True) + self.assertEqual(d, original) + + patcher.start() + self.assertEqual(d, {'spam': 'eggs'}) + + patcher.stop() + self.assertEqual(d, original) + + + def test_patch_dict_class_decorator(self): + this = self + d = {'spam': 'eggs'} + original = d.copy() + + class Test(object): + def test_first(self): + this.assertEqual(d, {'foo': 'bar'}) + def test_second(self): + this.assertEqual(d, {'foo': 'bar'}) + + Test = patch.dict(d, {'foo': 'bar'}, clear=True)(Test) + self.assertEqual(d, original) + + test = Test() + + test.test_first() + self.assertEqual(d, original) + + test.test_second() + self.assertEqual(d, original) + + test = Test() + + test.test_first() + self.assertEqual(d, original) + + test.test_second() + self.assertEqual(d, original) + + + def test_get_only_proxy(self): + class Something(object): + foo = 'foo' + class SomethingElse: + foo = 'foo' + + for thing in Something, SomethingElse, Something(), SomethingElse: + proxy = _get_proxy(thing) + + @patch.object(proxy, 'foo', 'bar') + def test(): + self.assertEqual(proxy.foo, 'bar') + test() + self.assertEqual(proxy.foo, 'foo') + self.assertEqual(thing.foo, 'foo') + self.assertNotIn('foo', proxy.__dict__) + + + def test_get_set_delete_proxy(self): + class Something(object): + foo = 'foo' + class SomethingElse: + foo = 'foo' + + for thing in Something, SomethingElse, Something(), SomethingElse: + proxy = _get_proxy(Something, get_only=False) + + @patch.object(proxy, 'foo', 'bar') + def test(): + self.assertEqual(proxy.foo, 'bar') + test() + self.assertEqual(proxy.foo, 'foo') + self.assertEqual(thing.foo, 'foo') + self.assertNotIn('foo', proxy.__dict__) + + + def test_patch_keyword_args(self): + kwargs = {'side_effect': KeyError, 'foo.bar.return_value': 33, + 'foo': MagicMock()} + + patcher = patch(foo_name, **kwargs) + mock = patcher.start() + patcher.stop() + + self.assertRaises(KeyError, mock) + self.assertEqual(mock.foo.bar(), 33) + self.assertIsInstance(mock.foo, MagicMock) + + + def test_patch_object_keyword_args(self): + kwargs = {'side_effect': KeyError, 'foo.bar.return_value': 33, + 'foo': MagicMock()} + + patcher = patch.object(Foo, 'f', **kwargs) + mock = patcher.start() + patcher.stop() + + self.assertRaises(KeyError, mock) + self.assertEqual(mock.foo.bar(), 33) + self.assertIsInstance(mock.foo, MagicMock) + + + def test_patch_dict_keyword_args(self): + original = {'foo': 'bar'} + copy = original.copy() + + patcher = patch.dict(original, foo=3, bar=4, baz=5) + patcher.start() + + try: + self.assertEqual(original, dict(foo=3, bar=4, baz=5)) + finally: + patcher.stop() + + self.assertEqual(original, copy) + + + def test_autospec(self): + class Boo(object): + def __init__(self, a): + pass + def f(self, a): + pass + def g(self): + pass + foo = 'bar' + + class Bar(object): + def a(self): + pass + + def _test(mock): + mock(1) + mock.assert_called_with(1) + self.assertRaises(TypeError, mock) + + def _test2(mock): + mock.f(1) + mock.f.assert_called_with(1) + self.assertRaises(TypeError, mock.f) + + mock.g() + mock.g.assert_called_with() + self.assertRaises(TypeError, mock.g, 1) + + self.assertRaises(AttributeError, getattr, mock, 'h') + + mock.foo.lower() + mock.foo.lower.assert_called_with() + self.assertRaises(AttributeError, getattr, mock.foo, 'bar') + + mock.Bar() + mock.Bar.assert_called_with() + + mock.Bar.a() + mock.Bar.a.assert_called_with() + self.assertRaises(TypeError, mock.Bar.a, 1) + + mock.Bar().a() + mock.Bar().a.assert_called_with() + self.assertRaises(TypeError, mock.Bar().a, 1) + + self.assertRaises(AttributeError, getattr, mock.Bar, 'b') + self.assertRaises(AttributeError, getattr, mock.Bar(), 'b') + + def function(mock): + _test(mock) + _test2(mock) + _test2(mock(1)) + self.assertIs(mock, Foo) + return mock + + test = patch(foo_name, autospec=True)(function) + + mock = test() + self.assertIsNot(Foo, mock) + # test patching a second time works + test() + + module = sys.modules[__name__] + test = patch.object(module, 'Foo', autospec=True)(function) + + mock = test() + self.assertIsNot(Foo, mock) + # test patching a second time works + test() + + + def test_autospec_function(self): + @patch('%s.function' % __name__, autospec=True) + def test(mock): + function(1) + function.assert_called_with(1) + function(2, 3) + function.assert_called_with(2, 3) + + self.assertRaises(TypeError, function) + self.assertRaises(AttributeError, getattr, function, 'foo') + + test() + + + def test_autospec_keywords(self): + @patch('%s.function' % __name__, autospec=True, + return_value=3) + def test(mock_function): + #self.assertEqual(function.abc, 'foo') + return function(1, 2) + + result = test() + self.assertEqual(result, 3) + + + def test_autospec_with_new(self): + patcher = patch('%s.function' % __name__, new=3, autospec=True) + self.assertRaises(TypeError, patcher.start) + + module = sys.modules[__name__] + patcher = patch.object(module, 'function', new=3, autospec=True) + self.assertRaises(TypeError, patcher.start) + + + def test_autospec_with_object(self): + class Bar(Foo): + extra = [] + + patcher = patch(foo_name, autospec=Bar) + mock = patcher.start() + try: + self.assertIsInstance(mock, Bar) + self.assertIsInstance(mock.extra, list) + finally: + patcher.stop() + + + def test_autospec_inherits(self): + FooClass = Foo + patcher = patch(foo_name, autospec=True) + mock = patcher.start() + try: + self.assertIsInstance(mock, FooClass) + self.assertIsInstance(mock(3), FooClass) + finally: + patcher.stop() + + + def test_autospec_name(self): + patcher = patch(foo_name, autospec=True) + mock = patcher.start() + + try: + self.assertIn(" name='Foo'", repr(mock)) + self.assertIn(" name='Foo.f'", repr(mock.f)) + self.assertIn(" name='Foo()'", repr(mock(None))) + self.assertIn(" name='Foo().f'", repr(mock(None).f)) + finally: + patcher.stop() + + + def test_tracebacks(self): + @patch.object(Foo, 'f', object()) + def test(): + raise AssertionError + try: + test() + except: + err = sys.exc_info() + + result = unittest.TextTestResult(None, None, 0) + traceback = result._exc_info_to_string(err, self) + self.assertIn('raise AssertionError', traceback) + + + def test_new_callable_patch(self): + patcher = patch(foo_name, new_callable=NonCallableMagicMock) + + m1 = patcher.start() + patcher.stop() + m2 = patcher.start() + patcher.stop() + + self.assertIsNot(m1, m2) + for mock in m1, m2: + self.assertNotCallable(m1) + + + def test_new_callable_patch_object(self): + patcher = patch.object(Foo, 'f', new_callable=NonCallableMagicMock) + + m1 = patcher.start() + patcher.stop() + m2 = patcher.start() + patcher.stop() + + self.assertIsNot(m1, m2) + for mock in m1, m2: + self.assertNotCallable(m1) + + + def test_new_callable_keyword_arguments(self): + class Bar(object): + kwargs = None + def __init__(self, **kwargs): + Bar.kwargs = kwargs + + patcher = patch(foo_name, new_callable=Bar, arg1=1, arg2=2) + m = patcher.start() + try: + self.assertIs(type(m), Bar) + self.assertEqual(Bar.kwargs, dict(arg1=1, arg2=2)) + finally: + patcher.stop() + + + def test_new_callable_spec(self): + class Bar(object): + kwargs = None + def __init__(self, **kwargs): + Bar.kwargs = kwargs + + patcher = patch(foo_name, new_callable=Bar, spec=Bar) + patcher.start() + try: + self.assertEqual(Bar.kwargs, dict(spec=Bar)) + finally: + patcher.stop() + + patcher = patch(foo_name, new_callable=Bar, spec_set=Bar) + patcher.start() + try: + self.assertEqual(Bar.kwargs, dict(spec_set=Bar)) + finally: + patcher.stop() + + + def test_new_callable_create(self): + non_existent_attr = '%s.weeeee' % foo_name + p = patch(non_existent_attr, new_callable=NonCallableMock) + self.assertRaises(AttributeError, p.start) + + p = patch(non_existent_attr, new_callable=NonCallableMock, + create=True) + m = p.start() + try: + self.assertNotCallable(m, magic=False) + finally: + p.stop() + + + def test_new_callable_incompatible_with_new(self): + self.assertRaises( + ValueError, patch, foo_name, new=object(), new_callable=MagicMock + ) + self.assertRaises( + ValueError, patch.object, Foo, 'f', new=object(), + new_callable=MagicMock + ) + + + def test_new_callable_incompatible_with_autospec(self): + self.assertRaises( + ValueError, patch, foo_name, new_callable=MagicMock, + autospec=True + ) + self.assertRaises( + ValueError, patch.object, Foo, 'f', new_callable=MagicMock, + autospec=True + ) + + + def test_new_callable_inherit_for_mocks(self): + class MockSub(Mock): + pass + + MockClasses = ( + NonCallableMock, NonCallableMagicMock, MagicMock, Mock, MockSub + ) + for Klass in MockClasses: + for arg in 'spec', 'spec_set': + kwargs = {arg: True} + p = patch(foo_name, new_callable=Klass, **kwargs) + m = p.start() + try: + instance = m.return_value + self.assertRaises(AttributeError, getattr, instance, 'x') + finally: + p.stop() + + + def test_new_callable_inherit_non_mock(self): + class NotAMock(object): + def __init__(self, spec): + self.spec = spec + + p = patch(foo_name, new_callable=NotAMock, spec=True) + m = p.start() + try: + self.assertTrue(is_instance(m, NotAMock)) + self.assertRaises(AttributeError, getattr, m, 'return_value') + finally: + p.stop() + + self.assertEqual(m.spec, Foo) + + + def test_new_callable_class_decorating(self): + test = self + original = Foo + class SomeTest(object): + + def _test(self, mock_foo): + test.assertIsNot(Foo, original) + test.assertIs(Foo, mock_foo) + test.assertIsInstance(Foo, SomeClass) + + def test_two(self, mock_foo): + self._test(mock_foo) + def test_one(self, mock_foo): + self._test(mock_foo) + + SomeTest = patch(foo_name, new_callable=SomeClass)(SomeTest) + SomeTest().test_one() + SomeTest().test_two() + self.assertIs(Foo, original) + + + def test_patch_multiple(self): + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + patcher1 = patch.multiple(foo_name, f=1, g=2) + patcher2 = patch.multiple(Foo, f=1, g=2) + + for patcher in patcher1, patcher2: + patcher.start() + try: + self.assertIs(Foo, original_foo) + self.assertEqual(Foo.f, 1) + self.assertEqual(Foo.g, 2) + finally: + patcher.stop() + + self.assertIs(Foo, original_foo) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + @patch.multiple(foo_name, f=3, g=4) + def test(): + self.assertIs(Foo, original_foo) + self.assertEqual(Foo.f, 3) + self.assertEqual(Foo.g, 4) + + test() + + + def test_patch_multiple_no_kwargs(self): + self.assertRaises(ValueError, patch.multiple, foo_name) + self.assertRaises(ValueError, patch.multiple, Foo) + + + def test_patch_multiple_create_mocks(self): + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + @patch.multiple(foo_name, f=DEFAULT, g=3, foo=DEFAULT) + def test(f, foo): + self.assertIs(Foo, original_foo) + self.assertIs(Foo.f, f) + self.assertEqual(Foo.g, 3) + self.assertIs(Foo.foo, foo) + self.assertTrue(is_instance(f, MagicMock)) + self.assertTrue(is_instance(foo, MagicMock)) + + test() + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_create_mocks_different_order(self): + # bug revealed by Jython! + original_f = Foo.f + original_g = Foo.g + + patcher = patch.object(Foo, 'f', 3) + patcher.attribute_name = 'f' + + other = patch.object(Foo, 'g', DEFAULT) + other.attribute_name = 'g' + patcher.additional_patchers = [other] + + @patcher + def test(g): + self.assertIs(Foo.g, g) + self.assertEqual(Foo.f, 3) + + test() + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_stacked_decorators(self): + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + @patch.multiple(foo_name, f=DEFAULT) + @patch.multiple(foo_name, foo=DEFAULT) + @patch(foo_name + '.g') + def test1(g, **kwargs): + _test(g, **kwargs) + + @patch.multiple(foo_name, f=DEFAULT) + @patch(foo_name + '.g') + @patch.multiple(foo_name, foo=DEFAULT) + def test2(g, **kwargs): + _test(g, **kwargs) + + @patch(foo_name + '.g') + @patch.multiple(foo_name, f=DEFAULT) + @patch.multiple(foo_name, foo=DEFAULT) + def test3(g, **kwargs): + _test(g, **kwargs) + + def _test(g, **kwargs): + f = kwargs.pop('f') + foo = kwargs.pop('foo') + self.assertFalse(kwargs) + + self.assertIs(Foo, original_foo) + self.assertIs(Foo.f, f) + self.assertIs(Foo.g, g) + self.assertIs(Foo.foo, foo) + self.assertTrue(is_instance(f, MagicMock)) + self.assertTrue(is_instance(g, MagicMock)) + self.assertTrue(is_instance(foo, MagicMock)) + + test1() + test2() + test3() + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_create_mocks_patcher(self): + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + patcher = patch.multiple(foo_name, f=DEFAULT, g=3, foo=DEFAULT) + + result = patcher.start() + try: + f = result['f'] + foo = result['foo'] + self.assertEqual(set(result), set(['f', 'foo'])) + + self.assertIs(Foo, original_foo) + self.assertIs(Foo.f, f) + self.assertIs(Foo.foo, foo) + self.assertTrue(is_instance(f, MagicMock)) + self.assertTrue(is_instance(foo, MagicMock)) + finally: + patcher.stop() + + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_decorating_class(self): + test = self + original_foo = Foo + original_f = Foo.f + original_g = Foo.g + + class SomeTest(object): + + def _test(self, f, foo): + test.assertIs(Foo, original_foo) + test.assertIs(Foo.f, f) + test.assertEqual(Foo.g, 3) + test.assertIs(Foo.foo, foo) + test.assertTrue(is_instance(f, MagicMock)) + test.assertTrue(is_instance(foo, MagicMock)) + + def test_two(self, f, foo): + self._test(f, foo) + def test_one(self, f, foo): + self._test(f, foo) + + SomeTest = patch.multiple( + foo_name, f=DEFAULT, g=3, foo=DEFAULT + )(SomeTest) + + thing = SomeTest() + thing.test_one() + thing.test_two() + + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_create(self): + patcher = patch.multiple(Foo, blam='blam') + self.assertRaises(AttributeError, patcher.start) + + patcher = patch.multiple(Foo, blam='blam', create=True) + patcher.start() + try: + self.assertEqual(Foo.blam, 'blam') + finally: + patcher.stop() + + self.assertFalse(hasattr(Foo, 'blam')) + + + def test_patch_multiple_spec_set(self): + # if spec_set works then we can assume that spec and autospec also + # work as the underlying machinery is the same + patcher = patch.multiple(Foo, foo=DEFAULT, spec_set=['a', 'b']) + result = patcher.start() + try: + self.assertEqual(Foo.foo, result['foo']) + Foo.foo.a(1) + Foo.foo.b(2) + Foo.foo.a.assert_called_with(1) + Foo.foo.b.assert_called_with(2) + self.assertRaises(AttributeError, setattr, Foo.foo, 'c', None) + finally: + patcher.stop() + + + def test_patch_multiple_new_callable(self): + class Thing(object): + pass + + patcher = patch.multiple( + Foo, f=DEFAULT, g=DEFAULT, new_callable=Thing + ) + result = patcher.start() + try: + self.assertIs(Foo.f, result['f']) + self.assertIs(Foo.g, result['g']) + self.assertIsInstance(Foo.f, Thing) + self.assertIsInstance(Foo.g, Thing) + self.assertIsNot(Foo.f, Foo.g) + finally: + patcher.stop() + + + def test_nested_patch_failure(self): + original_f = Foo.f + original_g = Foo.g + + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'missing', 1) + @patch.object(Foo, 'f', 1) + def thing1(): + pass + + @patch.object(Foo, 'missing', 1) + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'f', 1) + def thing2(): + pass + + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'f', 1) + @patch.object(Foo, 'missing', 1) + def thing3(): + pass + + for func in thing1, thing2, thing3: + self.assertRaises(AttributeError, func) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_new_callable_failure(self): + original_f = Foo.f + original_g = Foo.g + original_foo = Foo.foo + + def crasher(): + raise NameError('crasher') + + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'foo', new_callable=crasher) + @patch.object(Foo, 'f', 1) + def thing1(): + pass + + @patch.object(Foo, 'foo', new_callable=crasher) + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'f', 1) + def thing2(): + pass + + @patch.object(Foo, 'g', 1) + @patch.object(Foo, 'f', 1) + @patch.object(Foo, 'foo', new_callable=crasher) + def thing3(): + pass + + for func in thing1, thing2, thing3: + self.assertRaises(NameError, func) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + self.assertEqual(Foo.foo, original_foo) + + + def test_patch_multiple_failure(self): + original_f = Foo.f + original_g = Foo.g + + patcher = patch.object(Foo, 'f', 1) + patcher.attribute_name = 'f' + + good = patch.object(Foo, 'g', 1) + good.attribute_name = 'g' + + bad = patch.object(Foo, 'missing', 1) + bad.attribute_name = 'missing' + + for additionals in [good, bad], [bad, good]: + patcher.additional_patchers = additionals + + @patcher + def func(): + pass + + self.assertRaises(AttributeError, func) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + + + def test_patch_multiple_new_callable_failure(self): + original_f = Foo.f + original_g = Foo.g + original_foo = Foo.foo + + def crasher(): + raise NameError('crasher') + + patcher = patch.object(Foo, 'f', 1) + patcher.attribute_name = 'f' + + good = patch.object(Foo, 'g', 1) + good.attribute_name = 'g' + + bad = patch.object(Foo, 'foo', new_callable=crasher) + bad.attribute_name = 'foo' + + for additionals in [good, bad], [bad, good]: + patcher.additional_patchers = additionals + + @patcher + def func(): + pass + + self.assertRaises(NameError, func) + self.assertEqual(Foo.f, original_f) + self.assertEqual(Foo.g, original_g) + self.assertEqual(Foo.foo, original_foo) + + + def test_patch_multiple_string_subclasses(self): + Foo = type('Foo', (str,), {'fish': 'tasty'}) + foo = Foo() + @patch.multiple(foo, fish='nearly gone') + def test(): + self.assertEqual(foo.fish, 'nearly gone') + + test() + self.assertEqual(foo.fish, 'tasty') + + + @patch('unittest.mock.patch.TEST_PREFIX', 'foo') + def test_patch_test_prefix(self): + class Foo(object): + thing = 'original' + + def foo_one(self): + return self.thing + def foo_two(self): + return self.thing + def test_one(self): + return self.thing + def test_two(self): + return self.thing + + Foo = patch.object(Foo, 'thing', 'changed')(Foo) + + foo = Foo() + self.assertEqual(foo.foo_one(), 'changed') + self.assertEqual(foo.foo_two(), 'changed') + self.assertEqual(foo.test_one(), 'original') + self.assertEqual(foo.test_two(), 'original') + + + @patch('unittest.mock.patch.TEST_PREFIX', 'bar') + def test_patch_dict_test_prefix(self): + class Foo(object): + def bar_one(self): + return dict(the_dict) + def bar_two(self): + return dict(the_dict) + def test_one(self): + return dict(the_dict) + def test_two(self): + return dict(the_dict) + + the_dict = {'key': 'original'} + Foo = patch.dict(the_dict, key='changed')(Foo) + + foo =Foo() + self.assertEqual(foo.bar_one(), {'key': 'changed'}) + self.assertEqual(foo.bar_two(), {'key': 'changed'}) + self.assertEqual(foo.test_one(), {'key': 'original'}) + self.assertEqual(foo.test_two(), {'key': 'original'}) + + + def test_patch_with_spec_mock_repr(self): + for arg in ('spec', 'autospec', 'spec_set'): + p = patch('%s.SomeClass' % __name__, **{arg: True}) + m = p.start() + try: + self.assertIn(" name='SomeClass'", repr(m)) + self.assertIn(" name='SomeClass.class_attribute'", + repr(m.class_attribute)) + self.assertIn(" name='SomeClass()'", repr(m())) + self.assertIn(" name='SomeClass().class_attribute'", + repr(m().class_attribute)) + finally: + p.stop() + + + def test_patch_nested_autospec_repr(self): + with patch('unittest.test.testmock.support', autospec=True) as m: + self.assertIn(" name='support.SomeClass.wibble()'", + repr(m.SomeClass.wibble())) + self.assertIn(" name='support.SomeClass().wibble()'", + repr(m.SomeClass().wibble())) + + + + def test_mock_calls_with_patch(self): + for arg in ('spec', 'autospec', 'spec_set'): + p = patch('%s.SomeClass' % __name__, **{arg: True}) + m = p.start() + try: + m.wibble() + + kalls = [call.wibble()] + self.assertEqual(m.mock_calls, kalls) + self.assertEqual(m.method_calls, kalls) + self.assertEqual(m.wibble.mock_calls, [call()]) + + result = m() + kalls.append(call()) + self.assertEqual(m.mock_calls, kalls) + + result.wibble() + kalls.append(call().wibble()) + self.assertEqual(m.mock_calls, kalls) + + self.assertEqual(result.mock_calls, [call.wibble()]) + self.assertEqual(result.wibble.mock_calls, [call()]) + self.assertEqual(result.method_calls, [call.wibble()]) + finally: + p.stop() + + + def test_patch_imports_lazily(self): + sys.modules.pop('squizz', None) + + p1 = patch('squizz.squozz') + self.assertRaises(ImportError, p1.start) + + squizz = Mock() + squizz.squozz = 6 + sys.modules['squizz'] = squizz + p1 = patch('squizz.squozz') + squizz.squozz = 3 + p1.start() + p1.stop() + self.assertEqual(squizz.squozz, 3) + + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testsentinel.py b/Lib/unittest/test/testmock/testsentinel.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testsentinel.py @@ -0,0 +1,28 @@ +import unittest +from unittest.mock import sentinel, DEFAULT + + +class SentinelTest(unittest.TestCase): + + def testSentinels(self): + self.assertEqual(sentinel.whatever, sentinel.whatever, + 'sentinel not stored') + self.assertNotEqual(sentinel.whatever, sentinel.whateverelse, + 'sentinel should be unique') + + + def testSentinelName(self): + self.assertEqual(str(sentinel.whatever), 'sentinel.whatever', + 'sentinel name incorrect') + + + def testDEFAULT(self): + self.assertTrue(DEFAULT is sentinel.DEFAULT) + + def testBases(self): + # If this doesn't raise an AttributeError then help(mock) is broken + self.assertRaises(AttributeError, lambda: sentinel.__bases__) + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/unittest/test/testmock/testwith.py b/Lib/unittest/test/testmock/testwith.py new file mode 100644 --- /dev/null +++ b/Lib/unittest/test/testmock/testwith.py @@ -0,0 +1,176 @@ +import unittest +from warnings import catch_warnings + +from unittest.test.testmock.support import is_instance +from unittest.mock import MagicMock, Mock, patch, sentinel, mock_open, call + + + +something = sentinel.Something +something_else = sentinel.SomethingElse + + + +class WithTest(unittest.TestCase): + + def test_with_statement(self): + with patch('%s.something' % __name__, sentinel.Something2): + self.assertEqual(something, sentinel.Something2, "unpatched") + self.assertEqual(something, sentinel.Something) + + + def test_with_statement_exception(self): + try: + with patch('%s.something' % __name__, sentinel.Something2): + self.assertEqual(something, sentinel.Something2, "unpatched") + raise Exception('pow') + except Exception: + pass + else: + self.fail("patch swallowed exception") + self.assertEqual(something, sentinel.Something) + + + def test_with_statement_as(self): + with patch('%s.something' % __name__) as mock_something: + self.assertEqual(something, mock_something, "unpatched") + self.assertTrue(is_instance(mock_something, MagicMock), + "patching wrong type") + self.assertEqual(something, sentinel.Something) + + + def test_patch_object_with_statement(self): + class Foo(object): + something = 'foo' + original = Foo.something + with patch.object(Foo, 'something'): + self.assertNotEqual(Foo.something, original, "unpatched") + self.assertEqual(Foo.something, original) + + + def test_with_statement_nested(self): + with catch_warnings(record=True): + with patch('%s.something' % __name__) as mock_something, patch('%s.something_else' % __name__) as mock_something_else: + self.assertEqual(something, mock_something, "unpatched") + self.assertEqual(something_else, mock_something_else, + "unpatched") + + self.assertEqual(something, sentinel.Something) + self.assertEqual(something_else, sentinel.SomethingElse) + + + def test_with_statement_specified(self): + with patch('%s.something' % __name__, sentinel.Patched) as mock_something: + self.assertEqual(something, mock_something, "unpatched") + self.assertEqual(mock_something, sentinel.Patched, "wrong patch") + self.assertEqual(something, sentinel.Something) + + + def testContextManagerMocking(self): + mock = Mock() + mock.__enter__ = Mock() + mock.__exit__ = Mock() + mock.__exit__.return_value = False + + with mock as m: + self.assertEqual(m, mock.__enter__.return_value) + mock.__enter__.assert_called_with() + mock.__exit__.assert_called_with(None, None, None) + + + def test_context_manager_with_magic_mock(self): + mock = MagicMock() + + with self.assertRaises(TypeError): + with mock: + 'foo' + 3 + mock.__enter__.assert_called_with() + self.assertTrue(mock.__exit__.called) + + + def test_with_statement_same_attribute(self): + with patch('%s.something' % __name__, sentinel.Patched) as mock_something: + self.assertEqual(something, mock_something, "unpatched") + + with patch('%s.something' % __name__) as mock_again: + self.assertEqual(something, mock_again, "unpatched") + + self.assertEqual(something, mock_something, + "restored with wrong instance") + + self.assertEqual(something, sentinel.Something, "not restored") + + + def test_with_statement_imbricated(self): + with patch('%s.something' % __name__) as mock_something: + self.assertEqual(something, mock_something, "unpatched") + + with patch('%s.something_else' % __name__) as mock_something_else: + self.assertEqual(something_else, mock_something_else, + "unpatched") + + self.assertEqual(something, sentinel.Something) + self.assertEqual(something_else, sentinel.SomethingElse) + + + def test_dict_context_manager(self): + foo = {} + with patch.dict(foo, {'a': 'b'}): + self.assertEqual(foo, {'a': 'b'}) + self.assertEqual(foo, {}) + + with self.assertRaises(NameError): + with patch.dict(foo, {'a': 'b'}): + self.assertEqual(foo, {'a': 'b'}) + raise NameError('Konrad') + + self.assertEqual(foo, {}) + + + +class TestMockOpen(unittest.TestCase): + + def test_mock_open(self): + mock = mock_open() + with patch('%s.open' % __name__, mock, create=True) as patched: + self.assertIs(patched, mock) + open('foo') + + mock.assert_called_once_with('foo') + + + def test_mock_open_context_manager(self): + mock = mock_open() + handle = mock.return_value + with patch('%s.open' % __name__, mock, create=True): + with open('foo') as f: + f.read() + + expected_calls = [call('foo'), call().__enter__(), call().read(), + call().__exit__(None, None, None)] + self.assertEqual(mock.mock_calls, expected_calls) + self.assertIs(f, handle) + + + def test_explicit_mock(self): + mock = MagicMock() + mock_open(mock) + + with patch('%s.open' % __name__, mock, create=True) as patched: + self.assertIs(patched, mock) + open('foo') + + mock.assert_called_once_with('foo') + + + def test_read_data(self): + mock = mock_open(read_data='foo') + with patch('%s.open' % __name__, mock, create=True): + h = open('bar') + result = h.read() + + self.assertEqual(result, 'foo') + + +if __name__ == '__main__': + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,6 +26,16 @@ - Issue #14200: Idle shell crash on printing non-BMP unicode character. +- Issue #12818: format address no longer needlessly \ escapes ()s in names when + the name ends up being quoted. + +- Issue #14062: BytesGenerator now correctly folds Header objects, + including using linesep when folding. + +- Issue #13839: When invoked on the command-line, the pstats module now + accepts several filenames of profile stat files and merges them all. + Patch by Matt Joiner. + - Issue #14291: Email now defaults to utf-8 for non-ASCII unicode headers instead of raising an error. This fixes a regression relative to 2.7. diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c --- a/Modules/tkappinit.c +++ b/Modules/tkappinit.c @@ -26,7 +26,9 @@ int Tcl_AppInit(Tcl_Interp *interp) { +#ifdef WITH_MOREBUTTONS Tk_Window main_window; +#endif const char *_tkinter_skip_tk_init; #ifdef TKINTER_PROTECT_LOADTK const char *_tkinter_tk_failed; @@ -111,7 +113,11 @@ return TCL_ERROR; } +#ifdef WITH_MOREBUTTONS main_window = Tk_MainWindow(interp); +#else + Tk_MainWindow(interp); +#endif #ifdef TK_AQUA TkMacOSXInitAppleEvents(interp); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 21:46:19 2012 From: python-checkins at python.org (andrew.svetlov) Date: Wed, 14 Mar 2012 21:46:19 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Megre_from_tip?= Message-ID: http://hg.python.org/cpython/rev/f1829281fdc8 changeset: 75643:f1829281fdc8 parent: 75642:e6baf63f2f15 parent: 75640:eab274c7d456 user: Andrew Svetlov date: Wed Mar 14 13:46:08 2012 -0700 summary: Megre from tip files: Doc/library/urllib.request.rst | 92 +++++++++++++-------- Lib/test/test_urllib.py | 4 + Lib/test/test_urllib2.py | 23 ++++- Lib/unittest/mock.py | 8 +- Lib/urllib/request.py | 44 +++++++--- 5 files changed, 115 insertions(+), 56 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -385,12 +385,6 @@ .. versionadded:: 3.3 -.. method:: Request.add_data(data) - - Set the :class:`Request` data to *data*. This is ignored by all handlers except - HTTP handlers --- and there it should be a byte string, and will change the - request to be ``POST`` rather than ``GET``. - .. method:: Request.get_method() @@ -403,16 +397,6 @@ get_method now looks at the value of :attr:`Request.method`. -.. method:: Request.has_data() - - Return whether the instance has a non-\ ``None`` data. - - -.. method:: Request.get_data() - - Return the instance's data. - - .. method:: Request.add_header(key, val) Add another header to the request. Headers are currently ignored by all @@ -440,21 +424,6 @@ Return the URL given in the constructor. -.. method:: Request.get_type() - - Return the type of the URL --- also known as the scheme. - - -.. method:: Request.get_host() - - Return the host to which a connection will be made. - - -.. method:: Request.get_selector() - - Return the selector --- the part of the URL that is sent to the server. - - .. method:: Request.set_proxy(host, type) Prepare the request by connecting to a proxy server. The *host* and *type* will @@ -462,16 +431,71 @@ URL given in the constructor. +.. method:: Request.add_data(data) + + Set the :class:`Request` data to *data*. This is ignored by all handlers except + HTTP handlers --- and there it should be a byte string, and will change the + request to be ``POST`` rather than ``GET``. Deprecated in 3.3, use + :attr:`Request.data`. + + .. deprecated:: 3.3 + + +.. method:: Request.has_data() + + Return whether the instance has a non-\ ``None`` data. Deprecated in 3.3, + use :attr:`Request.data`. + + .. deprecated:: 3.3 + + +.. method:: Request.get_data() + + Return the instance's data. Deprecated in 3.3, use :attr:`Request.data`. + + .. deprecated:: 3.3 + + +.. method:: Request.get_type() + + Return the type of the URL --- also known as the scheme. Deprecated in 3.3, + use :attr:`Request.type`. + + .. deprecated:: 3.3 + + +.. method:: Request.get_host() + + Return the host to which a connection will be made. Deprecated in 3.3, use + :attr:`Request.host`. + + .. deprecated:: 3.3 + + +.. method:: Request.get_selector() + + Return the selector --- the part of the URL that is sent to the server. + Deprecated in 3.3, use :attr:`Request.selector`. + + .. deprecated:: 3.3 + + .. method:: Request.get_origin_req_host() - Return the request-host of the origin transaction, as defined by :rfc:`2965`. - See the documentation for the :class:`Request` constructor. + Return the request-host of the origin transaction, as defined by + :rfc:`2965`. See the documentation for the :class:`Request` constructor. + Deprecated in 3.3, use :attr:`Request.origin_req_host`. + + .. deprecated:: 3.3 .. method:: Request.is_unverifiable() Return whether the request is unverifiable, as defined by RFC 2965. See the - documentation for the :class:`Request` constructor. + documentation for the :class:`Request` constructor. Deprecated in 3.3, use + :attr:`Request.is_unverifiable`. + + .. deprecated:: 3.3 .. _opener-director-objects: diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -298,6 +298,10 @@ finally: self.unfakehttp() + def test_URLopener_deprecation(self): + with support.check_warnings(('',DeprecationWarning)): + warn = urllib.request.URLopener() + class urlretrieve_FileTests(unittest.TestCase): """Test urllib.urlretrieve() on local files""" diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -553,10 +553,6 @@ self.assertRaises(urllib.error.URLError, o.open, req) self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})]) -## def test_error(self): -## # XXX this doesn't actually seem to be used in standard library, -## # but should really be tested anyway... - def test_http_error(self): # XXX http_error_default # http errors are a special case @@ -584,6 +580,7 @@ self.assertEqual((handler, method_name), got[:2]) self.assertEqual(args, got[2]) + def test_processors(self): # *_request / *_response methods get called appropriately o = OpenerDirector() @@ -619,6 +616,24 @@ self.assertTrue(args[1] is None or isinstance(args[1], MockResponse)) + def test_method_deprecations(self): + req = Request("http://www.example.com") + with support.check_warnings(('', DeprecationWarning)): + req.add_data("data") + with support.check_warnings(('', DeprecationWarning)): + req.has_data() + with support.check_warnings(('', DeprecationWarning)): + req.get_data() + with support.check_warnings(('', DeprecationWarning)): + req.get_full_url() + with support.check_warnings(('', DeprecationWarning)): + req.get_host() + with support.check_warnings(('', DeprecationWarning)): + req.get_selector() + with support.check_warnings(('', DeprecationWarning)): + req.is_unverifiable() + with support.check_warnings(('', DeprecationWarning)): + req.get_origin_req_host() def sanepathname2url(path): try: diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1,5 +1,8 @@ # mock.py # Test tools for mocking and patching. +# Maintained by Michael Foord +# Backport for other versions of Python available from +# http://pypi.python.org/pypi/mock __all__ = ( 'Mock', @@ -259,11 +262,6 @@ _deleted = sentinel.DELETED -class OldStyleClass: - pass -ClassType = type(OldStyleClass) - - def _copy(value): if type(value) in (dict, list, tuple, set): return type(value)(value) diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -96,6 +96,7 @@ import collections import tempfile import contextlib +import warnings from urllib.error import URLError, HTTPError, ContentTooShortError @@ -291,36 +292,52 @@ else: return "GET" - # Begin deprecated methods - - def add_data(self, data): - self.data = data - - def has_data(self): - return self.data is not None - - def get_data(self): - return self.data - def get_full_url(self): if self.fragment: return '%s#%s' % (self.full_url, self.fragment) else: return self.full_url + # Begin deprecated methods + + def add_data(self, data): + msg = "Request.add_data method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) + self.data = data + + def has_data(self): + msg = "Request.has_data method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) + return self.data is not None + + def get_data(self): + msg = "Request.get_data method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) + return self.data + def get_type(self): + msg = "Request.get_type method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.type def get_host(self): + msg = "Request.get_host method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.host def get_selector(self): + msg = "Request.get_selector method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.selector def is_unverifiable(self): + msg = "Request.is_unverifiable method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.unverifiable def get_origin_req_host(self): + msg = "Request.get_origin_req_host method is deprecated." + warnings.warn(msg, DeprecationWarning, stacklevel=1) return self.origin_req_host # End deprecated methods @@ -1552,6 +1569,9 @@ # Constructor def __init__(self, proxies=None, **x509): + msg = "%(class)s style of invoking requests is deprecated."\ + "Use newer urlopen functions/methods" % {'class': self.__class__.__name__} + warnings.warn(msg, DeprecationWarning, stacklevel=3) if proxies is None: proxies = getproxies() assert hasattr(proxies, 'keys'), "proxies must be a mapping" @@ -1753,7 +1773,6 @@ if proxy_bypass(realhost): host = realhost - #print "proxy via http:", host, selector if not host: raise IOError('http error', 'no host given') if proxy_passwd: @@ -2554,7 +2573,6 @@ test = test.replace("*", r".*") # change glob sequence test = test.replace("?", r".") # change glob char for val in host: - # print "%s <--> %s" %( test, val ) if re.match(test, val, re.I): return 1 return 0 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 22:00:44 2012 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 14 Mar 2012 22:00:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_the_buildbot_breakdown_?= =?utf8?q?-_issue_10050?= Message-ID: http://hg.python.org/cpython/rev/30f13d7fecd0 changeset: 75644:30f13d7fecd0 parent: 75640:eab274c7d456 user: Senthil Kumaran date: Wed Mar 14 13:59:56 2012 -0700 summary: Fix the buildbot breakdown - issue 10050 files: Lib/test/test_urllib2.py | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -625,8 +625,6 @@ with support.check_warnings(('', DeprecationWarning)): req.get_data() with support.check_warnings(('', DeprecationWarning)): - req.get_full_url() - with support.check_warnings(('', DeprecationWarning)): req.get_host() with support.check_warnings(('', DeprecationWarning)): req.get_selector() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 22:00:45 2012 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 14 Mar 2012 22:00:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/8943649201c5 changeset: 75645:8943649201c5 parent: 75644:30f13d7fecd0 parent: 75643:f1829281fdc8 user: Senthil Kumaran date: Wed Mar 14 14:00:31 2012 -0700 summary: merge heads files: Lib/idlelib/PyShell.py | 10 ++++++++++ Lib/idlelib/rpc.py | 7 +++++++ Lib/idlelib/run.py | 21 +++++++++++++++++++++ Misc/NEWS | 2 ++ 4 files changed, 40 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1221,6 +1221,16 @@ self.set_line_and_column() def write(self, s, tags=()): + if isinstance(s, str) and len(s) and max(s) > '\uffff': + # Tk doesn't support outputting non-BMP characters + # Let's assume what printed string is not very long, + # find first non-BMP character and construct informative + # UnicodeEncodeError exception. + for start, char in enumerate(s): + if char > '\uffff': + break + raise UnicodeEncodeError("UCS-2", char, start, start+1, + 'Non-BMP character not supported in Tk') try: self.text.mark_gravity("iomark", "right") OutputWindow.write(self, s, tags, "iomark") diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py --- a/Lib/idlelib/rpc.py +++ b/Lib/idlelib/rpc.py @@ -196,8 +196,12 @@ return ("ERROR", "Unsupported message type: %s" % how) except SystemExit: raise + except KeyboardInterrupt: + raise except socket.error: raise + except Exception as ex: + return ("CALLEXC", ex) except: msg = "*** Internal Error: rpc.py:SocketIO.localcall()\n\n"\ " Object: %s \n Method: %s \n Args: %s\n" @@ -257,6 +261,9 @@ if how == "ERROR": self.debug("decoderesponse: Internal ERROR:", what) raise RuntimeError(what) + if how == "CALLEXC": + self.debug("decoderesponse: Call Exception:", what) + raise what raise SystemError(how, what) def decode_interrupthook(self): diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -6,6 +6,7 @@ import _thread as thread import threading import queue +import builtins from idlelib import CallTips from idlelib import AutoComplete @@ -261,6 +262,25 @@ thread.interrupt_main() +def displayhook(value): + """Override standard display hook to use non-locale encoding""" + if value is None: + return + # Set '_' to None to avoid recursion + builtins._ = None + text = repr(value) + try: + sys.stdout.write(text) + except UnicodeEncodeError: + # let's use ascii while utf8-bmp codec doesn't present + encoding = 'ascii' + bytes = text.encode(encoding, 'backslashreplace') + text = bytes.decode(encoding, 'strict') + sys.stdout.write(text) + sys.stdout.write("\n") + builtins._ = value + + class MyHandler(rpc.RPCHandler): def handle(self): @@ -270,6 +290,7 @@ sys.stdin = self.console = self.get_remote_proxy("stdin") sys.stdout = self.get_remote_proxy("stdout") sys.stderr = self.get_remote_proxy("stderr") + sys.displayhook = displayhook # page help() text to shell. import pydoc # import must be done here to capture i/o binding pydoc.pager = pydoc.plainpager diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #14200: Idle shell crash on printing non-BMP unicode character. + - Issue #12818: format address no longer needlessly \ escapes ()s in names when the name ends up being quoted. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 22:40:30 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 14 Mar 2012 22:40:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_more_Python_2_compat?= =?utf8?q?ibility_cruft_from_unittest=2Emock?= Message-ID: http://hg.python.org/cpython/rev/13a4fdc0176c changeset: 75646:13a4fdc0176c user: Michael Foord date: Wed Mar 14 14:40:22 2012 -0700 summary: Remove more Python 2 compatibility cruft from unittest.mock files: Lib/unittest/mock.py | 15 ++------ Lib/unittest/test/testmock/testcallable.py | 16 +-------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -143,13 +143,10 @@ # already an instance return getattr(obj, '__call__', None) is not None - klass = obj - # uses __bases__ instead of __mro__ so that we work with old style classes - if klass.__dict__.get('__call__') is not None: - return True - - for base in klass.__bases__: - if _instance_callable(base): + # *could* be broken by a class overriding __mro__ or __dict__ via + # a metaclass + for base in (obj,) + obj.__mro__: + if base.__dict__.get('__call__') is not None: return True return False @@ -2064,11 +2061,7 @@ if entry in getattr(spec, '__dict__', {}): # instance attribute - shouldn't skip return False - # can't use type because of old style classes spec = spec.__class__ - if not hasattr(spec, '__mro__'): - # old style class: can't have descriptors anyway - return is_type for klass in spec.__mro__: result = klass.__dict__.get(entry, DEFAULT) diff --git a/Lib/unittest/test/testmock/testcallable.py b/Lib/unittest/test/testmock/testcallable.py --- a/Lib/unittest/test/testmock/testcallable.py +++ b/Lib/unittest/test/testmock/testcallable.py @@ -107,19 +107,9 @@ class Multi(SomeClass, Sub): pass - class OldStyle: - def __call__(self): - pass - - class OldStyleSub(OldStyle): - pass - for arg in 'spec', 'spec_set': - for Klass in CallableX, Sub, Multi, OldStyle, OldStyleSub: - patcher = patch('%s.X' % __name__, **{arg: Klass}) - mock = patcher.start() - - try: + for Klass in CallableX, Sub, Multi: + with patch('%s.X' % __name__, **{arg: Klass}) as mock: instance = mock() mock.assert_called_once_with() @@ -136,8 +126,6 @@ result.assert_called_once_with(3, 2, 1) result.foo(3, 2, 1) result.foo.assert_called_once_with(3, 2, 1) - finally: - patcher.stop() def test_create_autopsec(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 22:42:54 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 14 Mar 2012 22:42:54 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314305?= =?utf8?q?=3A_fix_typo=2E?= Message-ID: http://hg.python.org/cpython/rev/0092ab03fdd5 changeset: 75647:0092ab03fdd5 branch: 3.2 parent: 75630:d0bf40ff20ef user: Georg Brandl date: Wed Mar 14 22:40:08 2012 +0100 summary: Closes #14305: fix typo. files: Doc/faq/programming.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -794,9 +794,9 @@ That's a tough one, in general. First, here are a list of things to remember before diving further: -* Performance characteristics vary accross Python implementations. This FAQ +* Performance characteristics vary across Python implementations. This FAQ focusses on :term:`CPython`. -* Behaviour can vary accross operating systems, especially when talking about +* Behaviour can vary across operating systems, especially when talking about I/O or multi-threading. * You should always find the hot spots in your program *before* attempting to optimize any code (see the :mod:`profile` module). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 22:42:55 2012 From: python-checkins at python.org (georg.brandl) Date: Wed, 14 Mar 2012 22:42:55 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/7e245e785b91 changeset: 75648:7e245e785b91 parent: 75646:13a4fdc0176c parent: 75647:0092ab03fdd5 user: Georg Brandl date: Wed Mar 14 22:42:49 2012 +0100 summary: merge with 3.2 files: Doc/faq/programming.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -794,9 +794,9 @@ That's a tough one, in general. First, here are a list of things to remember before diving further: -* Performance characteristics vary accross Python implementations. This FAQ +* Performance characteristics vary across Python implementations. This FAQ focusses on :term:`CPython`. -* Behaviour can vary accross operating systems, especially when talking about +* Behaviour can vary across operating systems, especially when talking about I/O or multi-threading. * You should always find the hot spots in your program *before* attempting to optimize any code (see the :mod:`profile` module). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 22:57:02 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 14 Mar 2012 22:57:02 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Removed_XXX_from_unittest?= =?utf8?q?=2Emock_docstring_and_switch_to_a_nicer?= Message-ID: http://hg.python.org/cpython/rev/d695be318949 changeset: 75649:d695be318949 user: Michael Foord date: Wed Mar 14 14:56:54 2012 -0700 summary: Removed XXX from unittest.mock docstring and switch to a nicer try...except...finally files: Lib/unittest/mock.py | 41 ++++++++++++++----------------- 1 files changed, 18 insertions(+), 23 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -619,9 +619,7 @@ def __dir__(self): - """Filter the output of `dir(mock)` to only useful members. - XXXX - """ + """Filter the output of `dir(mock)` to only useful members.""" extras = self._mock_methods or [] from_type = dir(type(self)) from_dict = list(self.__dict__) @@ -1057,31 +1055,28 @@ @wraps(func) def patched(*args, **keywargs): - # could use with statement here extra_args = [] entered_patchers = [] - # could use try..except...finally here try: - try: - for patching in patched.patchings: - arg = patching.__enter__() - entered_patchers.append(patching) - if patching.attribute_name is not None: - keywargs.update(arg) - elif patching.new is DEFAULT: - extra_args.append(arg) + for patching in patched.patchings: + arg = patching.__enter__() + entered_patchers.append(patching) + if patching.attribute_name is not None: + keywargs.update(arg) + elif patching.new is DEFAULT: + extra_args.append(arg) - args += tuple(extra_args) - return func(*args, **keywargs) - except: - if (patching not in entered_patchers and - _is_started(patching)): - # the patcher may have been started, but an exception - # raised whilst entering one of its additional_patchers - entered_patchers.append(patching) - # re-raise the exception - raise + args += tuple(extra_args) + return func(*args, **keywargs) + except: + if (patching not in entered_patchers and + _is_started(patching)): + # the patcher may have been started, but an exception + # raised whilst entering one of its additional_patchers + entered_patchers.append(patching) + # re-raise the exception + raise finally: for patching in reversed(entered_patchers): patching.__exit__() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:10:07 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:10:07 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E1=29=3A_Fixes_issue_=23?= =?utf8?q?14234=3A_CVE-2012-0876=3A_Randomize_hashes_of_xml_attributes?= Message-ID: http://hg.python.org/cpython/rev/7b5bc1719477 changeset: 75650:7b5bc1719477 branch: 3.1 parent: 75199:df3b2b5db900 user: Gregory P. Smith date: Wed Mar 14 14:26:55 2012 -0700 summary: Fixes issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project. files: Misc/NEWS | 5 + Modules/expat/expat.h | 9 + Modules/expat/pyexpatns.h | 1 + Modules/expat/xmlparse.c | 177 +++++++++++++++++-------- Modules/pyexpat.c | 2 + 5 files changed, 135 insertions(+), 59 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,11 @@ service attacks due to hash collisions within the dict and set types. Patch by David Malcolm, based on work by Victor Stinner. +- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash + table internal to the pyexpat module's copy of the expat library to avoid a + denial of service due to hash collisions. Patch by David Malcolm with some + modifications by the expat project. + Library ------- diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -883,6 +883,15 @@ XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing); +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt); + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/expat/pyexpatns.h b/Modules/expat/pyexpatns.h --- a/Modules/expat/pyexpatns.h +++ b/Modules/expat/pyexpatns.h @@ -97,6 +97,7 @@ #define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler #define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler #define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg +#define XML_SetHashSalt PyExpat_XML_SetHashSalt #define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler #define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler #define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -17,6 +17,8 @@ #include #include /* memset(), memcpy() */ #include +#include /* UINT_MAX */ +#include /* time() */ #include "expat.h" @@ -387,12 +389,13 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +dtdCopy(XML_Parser oldParser, + DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); static int -copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); - +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize); +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); static void FASTCALL hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); static void FASTCALL hashTableClear(HASH_TABLE *); @@ -425,6 +428,9 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); +static unsigned long generate_hash_secret_salt(void); +static XML_Bool startParsing(XML_Parser parser); + static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, @@ -542,6 +548,7 @@ XML_Bool m_useForeignDTD; enum XML_ParamEntityParsing m_paramEntityParsing; #endif + unsigned long m_hash_secret_salt; }; #define MALLOC(s) (parser->m_mem.malloc_fcn((s))) @@ -649,6 +656,7 @@ #define useForeignDTD (parser->m_useForeignDTD) #define paramEntityParsing (parser->m_paramEntityParsing) #endif /* XML_DTD */ +#define hash_secret_salt (parser->m_hash_secret_salt) XML_Parser XMLCALL XML_ParserCreate(const XML_Char *encodingName) @@ -671,22 +679,36 @@ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' }; -XML_Parser XMLCALL -XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) +static unsigned long +generate_hash_secret_salt(void) { - XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); - if (parser != NULL && ns) { + unsigned int seed = time(NULL) % UINT_MAX; + srand(seed); + return rand(); +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) +{ + /* hash functions must be initialized before setContext() is called */ + + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { /* implicit context only set for root parser, since child parsers (i.e. external entity parsers) will inherit it */ - if (!setContext(parser, implicitContext)) { - XML_ParserFree(parser); - return NULL; - } + return setContext(parser, implicitContext); } - return parser; + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + return parserCreate(encodingName, memsuite, nameSep, NULL); } static XML_Parser @@ -860,6 +882,7 @@ useForeignDTD = XML_FALSE; paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #endif + hash_secret_salt = 0; } /* moves list of bindings to freeBindingList */ @@ -907,7 +930,7 @@ poolClear(&temp2Pool); parserInit(parser, encodingName); dtdReset(_dtd, &parser->m_mem); - return setContext(parser, implicitContext); + return XML_TRUE; } enum XML_Status XMLCALL @@ -976,6 +999,12 @@ int oldInEntityValue = prologState.inEntityValue; #endif XML_Bool oldns_triplets = ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt = hash_secret_salt; #ifdef XML_DTD if (!context) @@ -1029,13 +1058,14 @@ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; defaultExpandInternalEntities = oldDefaultExpandInternalEntities; ns_triplets = oldns_triplets; + hash_secret_salt = oldhash_secret_salt; parentParser = oldParser; #ifdef XML_DTD paramEntityParsing = oldParamEntityParsing; prologState.inEntityValue = oldInEntityValue; if (context) { #endif /* XML_DTD */ - if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) || !setContext(parser, context)) { XML_ParserFree(parser); return NULL; @@ -1420,6 +1450,17 @@ #endif } +int XMLCALL +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; + hash_secret_salt = hash_salt; + return 1; +} + enum XML_Status XMLCALL XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { @@ -1430,6 +1471,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -1488,11 +1534,13 @@ break; case XML_INITIALIZED: case XML_PARSING: - result = XML_STATUS_OK; if (isFinal) { ps_parsing = XML_FINISHED; - return result; + return XML_STATUS_OK; } + /* fall through */ + default: + result = XML_STATUS_OK; } } @@ -1553,6 +1601,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -2231,7 +2284,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&dtd->pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -2618,12 +2671,12 @@ const XML_Char *localPart; /* lookup the element type name */ - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); if (!elementType) { const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); if (!name) return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!elementType) return XML_ERROR_NO_MEMORY; @@ -2792,9 +2845,9 @@ if (s[-1] == 2) { /* prefixed */ ATTRIBUTE_ID *id; const BINDING *b; - unsigned long uriHash = 0; + unsigned long uriHash = hash_secret_salt; ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); if (!id) return XML_ERROR_NO_MEMORY; b = id->prefix->binding; @@ -2818,7 +2871,7 @@ } while (*s++); { /* Check hash table for duplicate of expanded name (uriName). - Derived from code in lookup(HASH_TABLE *table, ...). + Derived from code in lookup(parser, HASH_TABLE *table, ...). */ unsigned char step = 0; unsigned long mask = nsAttsSize - 1; @@ -3756,7 +3809,8 @@ case XML_ROLE_DOCTYPE_PUBLIC_ID: #ifdef XML_DTD useForeignDTD = XML_FALSE; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -3811,7 +3865,8 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -3855,7 +3910,7 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -4069,7 +4124,8 @@ break; #else /* XML_DTD */ if (!declEntity) { - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -4144,7 +4200,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4176,7 +4232,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4358,7 +4414,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&dtd->pool); /* first, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -4882,7 +4938,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&temp2Pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal. @@ -4991,7 +5047,7 @@ result = XML_ERROR_NO_MEMORY; goto endEntityValue; } - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&tempPool); if (!entity) { /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ @@ -5281,7 +5337,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return 0; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!prefix) return 0; @@ -5310,7 +5366,7 @@ return NULL; /* skip quotation mark - its storage will be re-used (like in name[-1]) */ ++name; - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); if (!id) return NULL; if (id->name != name) @@ -5328,7 +5384,7 @@ if (name[5] == XML_T('\0')) id->prefix = &dtd->defaultPrefix; else - id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); id->xmlns = XML_TRUE; } else { @@ -5343,7 +5399,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return NULL; - id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!id->prefix) return NULL; @@ -5441,7 +5497,7 @@ ENTITY *e; if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); if (e) e->open = XML_TRUE; if (*s != XML_T('\0')) @@ -5456,7 +5512,7 @@ else { if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), sizeof(PREFIX)); if (!prefix) return XML_FALSE; @@ -5620,7 +5676,7 @@ The new DTD has already been initialized. */ static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) { HASH_TABLE_ITER iter; @@ -5635,7 +5691,7 @@ name = poolCopyString(&(newDtd->pool), oldP->name); if (!name) return 0; - if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) return 0; } @@ -5657,7 +5713,7 @@ if (!name) return 0; ++name; - newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); if (!newA) return 0; @@ -5667,7 +5723,7 @@ if (oldA->prefix == &oldDtd->defaultPrefix) newA->prefix = &newDtd->defaultPrefix; else - newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); } } @@ -5686,7 +5742,7 @@ name = poolCopyString(&(newDtd->pool), oldE->name); if (!name) return 0; - newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); if (!newE) return 0; @@ -5700,14 +5756,14 @@ } if (oldE->idAtt) newE->idAtt = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; if (oldE->prefix) - newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { newE->defaultAtts[i].id = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -5721,13 +5777,15 @@ } /* Copy the entity tables. */ - if (!copyEntityTable(&(newDtd->generalEntities), + if (!copyEntityTable(oldParser, + &(newDtd->generalEntities), &(newDtd->pool), &(oldDtd->generalEntities))) return 0; #ifdef XML_DTD - if (!copyEntityTable(&(newDtd->paramEntities), + if (!copyEntityTable(oldParser, + &(newDtd->paramEntities), &(newDtd->pool), &(oldDtd->paramEntities))) return 0; @@ -5750,7 +5808,8 @@ } /* End dtdCopy */ static int -copyEntityTable(HASH_TABLE *newTable, +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable) { @@ -5769,7 +5828,7 @@ name = poolCopyString(newPool, oldE->name); if (!name) return 0; - newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); if (!newE) return 0; if (oldE->systemId) { @@ -5827,16 +5886,16 @@ } static unsigned long FASTCALL -hash(KEY s) +hash(XML_Parser parser, KEY s) { - unsigned long h = 0; + unsigned long h = hash_secret_salt; while (*s) h = CHAR_HASH(h, *s++); return h; } static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize) +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { size_t i; if (table->size == 0) { @@ -5853,10 +5912,10 @@ return NULL; } memset(table->v, 0, tsize); - i = hash(name) & ((unsigned long)table->size - 1); + i = hash(parser, name) & ((unsigned long)table->size - 1); } else { - unsigned long h = hash(name); + unsigned long h = hash(parser, name); unsigned long mask = (unsigned long)table->size - 1; unsigned char step = 0; i = h & mask; @@ -5882,7 +5941,7 @@ memset(newV, 0, tsize); for (i = 0; i < table->size; i++) if (table->v[i]) { - unsigned long newHash = hash(table->v[i]->name); + unsigned long newHash = hash(parser, table->v[i]->name); size_t j = newHash & newMask; step = 0; while (newV[j]) { @@ -6257,7 +6316,7 @@ if (!name) return NULL; - ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!ret) return NULL; if (ret->name != name) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1245,6 +1245,8 @@ else { self->itself = XML_ParserCreate(encoding); } + XML_SetHashSalt(self->itself, + (unsigned long)_Py_HashSecret.prefix); self->intern = intern; Py_XINCREF(self->intern); #ifdef Py_TPFLAGS_HAVE_GC -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:10:08 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:10:08 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4xIC0+IDMuMik6?= =?utf8?q?_Fixes_Issue_=2314234=3A_CVE-2012-0876=3A_Randomize_hashes_of_xm?= =?utf8?q?l_attributes?= Message-ID: http://hg.python.org/cpython/rev/d6c197edd99b changeset: 75651:d6c197edd99b branch: 3.2 parent: 75630:d0bf40ff20ef parent: 75650:7b5bc1719477 user: Gregory P. Smith date: Wed Mar 14 14:41:00 2012 -0700 summary: Fixes Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project. files: Misc/NEWS | 15 ++- Modules/expat/expat.h | 9 + Modules/expat/pyexpatns.h | 1 + Modules/expat/xmlparse.c | 177 +++++++++++++++++-------- Modules/pyexpat.c | 2 + 5 files changed, 144 insertions(+), 60 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,10 +69,23 @@ scanning, resulting in segfaults. +What's New in Python 3.2.3 release candidate 2? +=============================================== + +*Release date: XX-Mar-2012* + +Library +------- + +- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash + table internal to the pyexpat module's copy of the expat library to avoid a + denial of service due to hash collisions. Patch by David Malcolm with some + modifications by the expat project. + What's New in Python 3.2.3 release candidate 1? =============================================== -*Release date: 24-Feb-2011* +*Release date: 24-Feb-2012* Core and Builtins ----------------- diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -883,6 +883,15 @@ XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing); +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt); + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/expat/pyexpatns.h b/Modules/expat/pyexpatns.h --- a/Modules/expat/pyexpatns.h +++ b/Modules/expat/pyexpatns.h @@ -97,6 +97,7 @@ #define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler #define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler #define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg +#define XML_SetHashSalt PyExpat_XML_SetHashSalt #define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler #define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler #define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -17,6 +17,8 @@ #include #include /* memset(), memcpy() */ #include +#include /* UINT_MAX */ +#include /* time() */ #include "expat.h" @@ -387,12 +389,13 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +dtdCopy(XML_Parser oldParser, + DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); static int -copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); - +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize); +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); static void FASTCALL hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); static void FASTCALL hashTableClear(HASH_TABLE *); @@ -425,6 +428,9 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); +static unsigned long generate_hash_secret_salt(void); +static XML_Bool startParsing(XML_Parser parser); + static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, @@ -542,6 +548,7 @@ XML_Bool m_useForeignDTD; enum XML_ParamEntityParsing m_paramEntityParsing; #endif + unsigned long m_hash_secret_salt; }; #define MALLOC(s) (parser->m_mem.malloc_fcn((s))) @@ -649,6 +656,7 @@ #define useForeignDTD (parser->m_useForeignDTD) #define paramEntityParsing (parser->m_paramEntityParsing) #endif /* XML_DTD */ +#define hash_secret_salt (parser->m_hash_secret_salt) XML_Parser XMLCALL XML_ParserCreate(const XML_Char *encodingName) @@ -671,22 +679,36 @@ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' }; -XML_Parser XMLCALL -XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) +static unsigned long +generate_hash_secret_salt(void) { - XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); - if (parser != NULL && ns) { + unsigned int seed = time(NULL) % UINT_MAX; + srand(seed); + return rand(); +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) +{ + /* hash functions must be initialized before setContext() is called */ + + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { /* implicit context only set for root parser, since child parsers (i.e. external entity parsers) will inherit it */ - if (!setContext(parser, implicitContext)) { - XML_ParserFree(parser); - return NULL; - } + return setContext(parser, implicitContext); } - return parser; + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + return parserCreate(encodingName, memsuite, nameSep, NULL); } static XML_Parser @@ -860,6 +882,7 @@ useForeignDTD = XML_FALSE; paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #endif + hash_secret_salt = 0; } /* moves list of bindings to freeBindingList */ @@ -907,7 +930,7 @@ poolClear(&temp2Pool); parserInit(parser, encodingName); dtdReset(_dtd, &parser->m_mem); - return setContext(parser, implicitContext); + return XML_TRUE; } enum XML_Status XMLCALL @@ -976,6 +999,12 @@ int oldInEntityValue = prologState.inEntityValue; #endif XML_Bool oldns_triplets = ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt = hash_secret_salt; #ifdef XML_DTD if (!context) @@ -1029,13 +1058,14 @@ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; defaultExpandInternalEntities = oldDefaultExpandInternalEntities; ns_triplets = oldns_triplets; + hash_secret_salt = oldhash_secret_salt; parentParser = oldParser; #ifdef XML_DTD paramEntityParsing = oldParamEntityParsing; prologState.inEntityValue = oldInEntityValue; if (context) { #endif /* XML_DTD */ - if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) || !setContext(parser, context)) { XML_ParserFree(parser); return NULL; @@ -1420,6 +1450,17 @@ #endif } +int XMLCALL +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; + hash_secret_salt = hash_salt; + return 1; +} + enum XML_Status XMLCALL XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { @@ -1430,6 +1471,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -1488,11 +1534,13 @@ break; case XML_INITIALIZED: case XML_PARSING: - result = XML_STATUS_OK; if (isFinal) { ps_parsing = XML_FINISHED; - return result; + return XML_STATUS_OK; } + /* fall through */ + default: + result = XML_STATUS_OK; } } @@ -1553,6 +1601,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -2231,7 +2284,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&dtd->pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -2618,12 +2671,12 @@ const XML_Char *localPart; /* lookup the element type name */ - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); if (!elementType) { const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); if (!name) return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!elementType) return XML_ERROR_NO_MEMORY; @@ -2792,9 +2845,9 @@ if (s[-1] == 2) { /* prefixed */ ATTRIBUTE_ID *id; const BINDING *b; - unsigned long uriHash = 0; + unsigned long uriHash = hash_secret_salt; ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); if (!id) return XML_ERROR_NO_MEMORY; b = id->prefix->binding; @@ -2818,7 +2871,7 @@ } while (*s++); { /* Check hash table for duplicate of expanded name (uriName). - Derived from code in lookup(HASH_TABLE *table, ...). + Derived from code in lookup(parser, HASH_TABLE *table, ...). */ unsigned char step = 0; unsigned long mask = nsAttsSize - 1; @@ -3756,7 +3809,8 @@ case XML_ROLE_DOCTYPE_PUBLIC_ID: #ifdef XML_DTD useForeignDTD = XML_FALSE; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -3811,7 +3865,8 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -3855,7 +3910,7 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -4069,7 +4124,8 @@ break; #else /* XML_DTD */ if (!declEntity) { - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -4144,7 +4200,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4176,7 +4232,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4358,7 +4414,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&dtd->pool); /* first, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -4882,7 +4938,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&temp2Pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal. @@ -4991,7 +5047,7 @@ result = XML_ERROR_NO_MEMORY; goto endEntityValue; } - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&tempPool); if (!entity) { /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ @@ -5281,7 +5337,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return 0; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!prefix) return 0; @@ -5310,7 +5366,7 @@ return NULL; /* skip quotation mark - its storage will be re-used (like in name[-1]) */ ++name; - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); if (!id) return NULL; if (id->name != name) @@ -5328,7 +5384,7 @@ if (name[5] == XML_T('\0')) id->prefix = &dtd->defaultPrefix; else - id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); id->xmlns = XML_TRUE; } else { @@ -5343,7 +5399,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return NULL; - id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!id->prefix) return NULL; @@ -5441,7 +5497,7 @@ ENTITY *e; if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); if (e) e->open = XML_TRUE; if (*s != XML_T('\0')) @@ -5456,7 +5512,7 @@ else { if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), sizeof(PREFIX)); if (!prefix) return XML_FALSE; @@ -5620,7 +5676,7 @@ The new DTD has already been initialized. */ static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) { HASH_TABLE_ITER iter; @@ -5635,7 +5691,7 @@ name = poolCopyString(&(newDtd->pool), oldP->name); if (!name) return 0; - if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) return 0; } @@ -5657,7 +5713,7 @@ if (!name) return 0; ++name; - newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); if (!newA) return 0; @@ -5667,7 +5723,7 @@ if (oldA->prefix == &oldDtd->defaultPrefix) newA->prefix = &newDtd->defaultPrefix; else - newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); } } @@ -5686,7 +5742,7 @@ name = poolCopyString(&(newDtd->pool), oldE->name); if (!name) return 0; - newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); if (!newE) return 0; @@ -5700,14 +5756,14 @@ } if (oldE->idAtt) newE->idAtt = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; if (oldE->prefix) - newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { newE->defaultAtts[i].id = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -5721,13 +5777,15 @@ } /* Copy the entity tables. */ - if (!copyEntityTable(&(newDtd->generalEntities), + if (!copyEntityTable(oldParser, + &(newDtd->generalEntities), &(newDtd->pool), &(oldDtd->generalEntities))) return 0; #ifdef XML_DTD - if (!copyEntityTable(&(newDtd->paramEntities), + if (!copyEntityTable(oldParser, + &(newDtd->paramEntities), &(newDtd->pool), &(oldDtd->paramEntities))) return 0; @@ -5750,7 +5808,8 @@ } /* End dtdCopy */ static int -copyEntityTable(HASH_TABLE *newTable, +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable) { @@ -5769,7 +5828,7 @@ name = poolCopyString(newPool, oldE->name); if (!name) return 0; - newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); if (!newE) return 0; if (oldE->systemId) { @@ -5827,16 +5886,16 @@ } static unsigned long FASTCALL -hash(KEY s) +hash(XML_Parser parser, KEY s) { - unsigned long h = 0; + unsigned long h = hash_secret_salt; while (*s) h = CHAR_HASH(h, *s++); return h; } static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize) +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { size_t i; if (table->size == 0) { @@ -5853,10 +5912,10 @@ return NULL; } memset(table->v, 0, tsize); - i = hash(name) & ((unsigned long)table->size - 1); + i = hash(parser, name) & ((unsigned long)table->size - 1); } else { - unsigned long h = hash(name); + unsigned long h = hash(parser, name); unsigned long mask = (unsigned long)table->size - 1; unsigned char step = 0; i = h & mask; @@ -5882,7 +5941,7 @@ memset(newV, 0, tsize); for (i = 0; i < table->size; i++) if (table->v[i]) { - unsigned long newHash = hash(table->v[i]->name); + unsigned long newHash = hash(parser, table->v[i]->name); size_t j = newHash & newMask; step = 0; while (newV[j]) { @@ -6257,7 +6316,7 @@ if (!name) return NULL; - ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!ret) return NULL; if (ret->name != name) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1150,6 +1150,8 @@ else { self->itself = XML_ParserCreate(encoding); } + XML_SetHashSalt(self->itself, + (unsigned long)_Py_HashSecret.prefix); self->intern = intern; Py_XINCREF(self->intern); PyObject_GC_Track(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:10:09 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:10:09 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E1=29=3A_move_the_Misc/N?= =?utf8?q?EWS_entry_to_the_right_section=2E?= Message-ID: http://hg.python.org/cpython/rev/0abd368609c9 changeset: 75652:0abd368609c9 branch: 3.1 parent: 75650:7b5bc1719477 user: Gregory P. Smith date: Wed Mar 14 14:58:22 2012 -0700 summary: move the Misc/NEWS entry to the right section. files: Misc/NEWS | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,14 +15,14 @@ service attacks due to hash collisions within the dict and set types. Patch by David Malcolm, based on work by Victor Stinner. +Library +------- + - Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project. -Library -------- - - Issue #14001: CVE-2012-0845: xmlrpc: Fix an endless loop in SimpleXMLRPCServer upon malformed POST request. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:10:10 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:10:10 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4xIC0+IDMuMik6?= =?utf8?q?_merge_=28no_change_needed_in_3=2E2=29?= Message-ID: http://hg.python.org/cpython/rev/e3c5416989e1 changeset: 75653:e3c5416989e1 branch: 3.2 parent: 75651:d6c197edd99b parent: 75652:0abd368609c9 user: Gregory P. Smith date: Wed Mar 14 14:58:50 2012 -0700 summary: merge (no change needed in 3.2) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:10:10 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:10:10 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Fixes_Issue_=2314234=3A_CVE-2012-0876=3A_Randomize_hashes_of?= =?utf8?q?_xml_attributes?= Message-ID: http://hg.python.org/cpython/rev/a8b164ab98bf changeset: 75654:a8b164ab98bf parent: 75645:8943649201c5 parent: 75651:d6c197edd99b user: Gregory P. Smith date: Wed Mar 14 15:00:39 2012 -0700 summary: Fixes Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project. files: Misc/NEWS | 5 + Modules/expat/expat.h | 9 + Modules/expat/pyexpatns.h | 1 + Modules/expat/xmlparse.c | 177 +++++++++++++++++-------- Modules/pyexpat.c | 2 + 5 files changed, 135 insertions(+), 59 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,11 @@ Library ------- +- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash + table internal to the pyexpat module's copy of the expat library to avoid a + denial of service due to hash collisions. Patch by David Malcolm with some + modifications by the expat project. + - Issue #14200: Idle shell crash on printing non-BMP unicode character. - Issue #12818: format address no longer needlessly \ escapes ()s in names when diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -883,6 +883,15 @@ XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing); +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt); + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/expat/pyexpatns.h b/Modules/expat/pyexpatns.h --- a/Modules/expat/pyexpatns.h +++ b/Modules/expat/pyexpatns.h @@ -97,6 +97,7 @@ #define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler #define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler #define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg +#define XML_SetHashSalt PyExpat_XML_SetHashSalt #define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler #define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler #define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -17,6 +17,8 @@ #include #include /* memset(), memcpy() */ #include +#include /* UINT_MAX */ +#include /* time() */ #include "expat.h" @@ -387,12 +389,13 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +dtdCopy(XML_Parser oldParser, + DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); static int -copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); - +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize); +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); static void FASTCALL hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); static void FASTCALL hashTableClear(HASH_TABLE *); @@ -425,6 +428,9 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); +static unsigned long generate_hash_secret_salt(void); +static XML_Bool startParsing(XML_Parser parser); + static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, @@ -542,6 +548,7 @@ XML_Bool m_useForeignDTD; enum XML_ParamEntityParsing m_paramEntityParsing; #endif + unsigned long m_hash_secret_salt; }; #define MALLOC(s) (parser->m_mem.malloc_fcn((s))) @@ -649,6 +656,7 @@ #define useForeignDTD (parser->m_useForeignDTD) #define paramEntityParsing (parser->m_paramEntityParsing) #endif /* XML_DTD */ +#define hash_secret_salt (parser->m_hash_secret_salt) XML_Parser XMLCALL XML_ParserCreate(const XML_Char *encodingName) @@ -671,22 +679,36 @@ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' }; -XML_Parser XMLCALL -XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) +static unsigned long +generate_hash_secret_salt(void) { - XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); - if (parser != NULL && ns) { + unsigned int seed = time(NULL) % UINT_MAX; + srand(seed); + return rand(); +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) +{ + /* hash functions must be initialized before setContext() is called */ + + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { /* implicit context only set for root parser, since child parsers (i.e. external entity parsers) will inherit it */ - if (!setContext(parser, implicitContext)) { - XML_ParserFree(parser); - return NULL; - } + return setContext(parser, implicitContext); } - return parser; + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + return parserCreate(encodingName, memsuite, nameSep, NULL); } static XML_Parser @@ -860,6 +882,7 @@ useForeignDTD = XML_FALSE; paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #endif + hash_secret_salt = 0; } /* moves list of bindings to freeBindingList */ @@ -907,7 +930,7 @@ poolClear(&temp2Pool); parserInit(parser, encodingName); dtdReset(_dtd, &parser->m_mem); - return setContext(parser, implicitContext); + return XML_TRUE; } enum XML_Status XMLCALL @@ -976,6 +999,12 @@ int oldInEntityValue = prologState.inEntityValue; #endif XML_Bool oldns_triplets = ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt = hash_secret_salt; #ifdef XML_DTD if (!context) @@ -1029,13 +1058,14 @@ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; defaultExpandInternalEntities = oldDefaultExpandInternalEntities; ns_triplets = oldns_triplets; + hash_secret_salt = oldhash_secret_salt; parentParser = oldParser; #ifdef XML_DTD paramEntityParsing = oldParamEntityParsing; prologState.inEntityValue = oldInEntityValue; if (context) { #endif /* XML_DTD */ - if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) || !setContext(parser, context)) { XML_ParserFree(parser); return NULL; @@ -1420,6 +1450,17 @@ #endif } +int XMLCALL +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; + hash_secret_salt = hash_salt; + return 1; +} + enum XML_Status XMLCALL XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { @@ -1430,6 +1471,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -1488,11 +1534,13 @@ break; case XML_INITIALIZED: case XML_PARSING: - result = XML_STATUS_OK; if (isFinal) { ps_parsing = XML_FINISHED; - return result; + return XML_STATUS_OK; } + /* fall through */ + default: + result = XML_STATUS_OK; } } @@ -1553,6 +1601,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -2231,7 +2284,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&dtd->pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -2618,12 +2671,12 @@ const XML_Char *localPart; /* lookup the element type name */ - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); if (!elementType) { const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); if (!name) return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!elementType) return XML_ERROR_NO_MEMORY; @@ -2792,9 +2845,9 @@ if (s[-1] == 2) { /* prefixed */ ATTRIBUTE_ID *id; const BINDING *b; - unsigned long uriHash = 0; + unsigned long uriHash = hash_secret_salt; ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); if (!id) return XML_ERROR_NO_MEMORY; b = id->prefix->binding; @@ -2818,7 +2871,7 @@ } while (*s++); { /* Check hash table for duplicate of expanded name (uriName). - Derived from code in lookup(HASH_TABLE *table, ...). + Derived from code in lookup(parser, HASH_TABLE *table, ...). */ unsigned char step = 0; unsigned long mask = nsAttsSize - 1; @@ -3756,7 +3809,8 @@ case XML_ROLE_DOCTYPE_PUBLIC_ID: #ifdef XML_DTD useForeignDTD = XML_FALSE; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -3811,7 +3865,8 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -3855,7 +3910,7 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -4069,7 +4124,8 @@ break; #else /* XML_DTD */ if (!declEntity) { - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -4144,7 +4200,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4176,7 +4232,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4358,7 +4414,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&dtd->pool); /* first, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -4882,7 +4938,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&temp2Pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal. @@ -4991,7 +5047,7 @@ result = XML_ERROR_NO_MEMORY; goto endEntityValue; } - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&tempPool); if (!entity) { /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ @@ -5281,7 +5337,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return 0; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!prefix) return 0; @@ -5310,7 +5366,7 @@ return NULL; /* skip quotation mark - its storage will be re-used (like in name[-1]) */ ++name; - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); if (!id) return NULL; if (id->name != name) @@ -5328,7 +5384,7 @@ if (name[5] == XML_T('\0')) id->prefix = &dtd->defaultPrefix; else - id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); id->xmlns = XML_TRUE; } else { @@ -5343,7 +5399,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return NULL; - id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!id->prefix) return NULL; @@ -5441,7 +5497,7 @@ ENTITY *e; if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); if (e) e->open = XML_TRUE; if (*s != XML_T('\0')) @@ -5456,7 +5512,7 @@ else { if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), sizeof(PREFIX)); if (!prefix) return XML_FALSE; @@ -5620,7 +5676,7 @@ The new DTD has already been initialized. */ static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) { HASH_TABLE_ITER iter; @@ -5635,7 +5691,7 @@ name = poolCopyString(&(newDtd->pool), oldP->name); if (!name) return 0; - if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) return 0; } @@ -5657,7 +5713,7 @@ if (!name) return 0; ++name; - newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); if (!newA) return 0; @@ -5667,7 +5723,7 @@ if (oldA->prefix == &oldDtd->defaultPrefix) newA->prefix = &newDtd->defaultPrefix; else - newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); } } @@ -5686,7 +5742,7 @@ name = poolCopyString(&(newDtd->pool), oldE->name); if (!name) return 0; - newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); if (!newE) return 0; @@ -5700,14 +5756,14 @@ } if (oldE->idAtt) newE->idAtt = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; if (oldE->prefix) - newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { newE->defaultAtts[i].id = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -5721,13 +5777,15 @@ } /* Copy the entity tables. */ - if (!copyEntityTable(&(newDtd->generalEntities), + if (!copyEntityTable(oldParser, + &(newDtd->generalEntities), &(newDtd->pool), &(oldDtd->generalEntities))) return 0; #ifdef XML_DTD - if (!copyEntityTable(&(newDtd->paramEntities), + if (!copyEntityTable(oldParser, + &(newDtd->paramEntities), &(newDtd->pool), &(oldDtd->paramEntities))) return 0; @@ -5750,7 +5808,8 @@ } /* End dtdCopy */ static int -copyEntityTable(HASH_TABLE *newTable, +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable) { @@ -5769,7 +5828,7 @@ name = poolCopyString(newPool, oldE->name); if (!name) return 0; - newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); if (!newE) return 0; if (oldE->systemId) { @@ -5827,16 +5886,16 @@ } static unsigned long FASTCALL -hash(KEY s) +hash(XML_Parser parser, KEY s) { - unsigned long h = 0; + unsigned long h = hash_secret_salt; while (*s) h = CHAR_HASH(h, *s++); return h; } static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize) +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { size_t i; if (table->size == 0) { @@ -5853,10 +5912,10 @@ return NULL; } memset(table->v, 0, tsize); - i = hash(name) & ((unsigned long)table->size - 1); + i = hash(parser, name) & ((unsigned long)table->size - 1); } else { - unsigned long h = hash(name); + unsigned long h = hash(parser, name); unsigned long mask = (unsigned long)table->size - 1; unsigned char step = 0; i = h & mask; @@ -5882,7 +5941,7 @@ memset(newV, 0, tsize); for (i = 0; i < table->size; i++) if (table->v[i]) { - unsigned long newHash = hash(table->v[i]->name); + unsigned long newHash = hash(parser, table->v[i]->name); size_t j = newHash & newMask; step = 0; while (newV[j]) { @@ -6257,7 +6316,7 @@ if (!name) return NULL; - ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!ret) return NULL; if (ret->name != name) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1156,6 +1156,8 @@ else { self->itself = XML_ParserCreate(encoding); } + XML_SetHashSalt(self->itself, + (unsigned long)_Py_HashSecret.prefix); self->intern = intern; Py_XINCREF(self->intern); PyObject_GC_Track(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:10:11 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:10:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_=28no_change=29?= Message-ID: http://hg.python.org/cpython/rev/eb9aa30ea15a changeset: 75655:eb9aa30ea15a parent: 75654:a8b164ab98bf parent: 75653:e3c5416989e1 user: Gregory P. Smith date: Wed Mar 14 15:01:57 2012 -0700 summary: merge (no change) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:10:12 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:10:12 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/6c70d8e8b7a9 changeset: 75656:6c70d8e8b7a9 branch: 3.2 parent: 75653:e3c5416989e1 parent: 75647:0092ab03fdd5 user: Gregory P. Smith date: Wed Mar 14 15:03:40 2012 -0700 summary: merge heads files: Doc/faq/programming.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -794,9 +794,9 @@ That's a tough one, in general. First, here are a list of things to remember before diving further: -* Performance characteristics vary accross Python implementations. This FAQ +* Performance characteristics vary across Python implementations. This FAQ focusses on :term:`CPython`. -* Behaviour can vary accross operating systems, especially when talking about +* Behaviour can vary across operating systems, especially when talking about I/O or multi-threading. * You should always find the hot spots in your program *before* attempting to optimize any code (see the :mod:`profile` module). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:10:12 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:10:12 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/48cf54dc22c7 changeset: 75657:48cf54dc22c7 parent: 75655:eb9aa30ea15a parent: 75649:d695be318949 user: Gregory P. Smith date: Wed Mar 14 15:04:18 2012 -0700 summary: merge heads files: Doc/faq/programming.rst | 4 +- Lib/unittest/mock.py | 56 +++------ Lib/unittest/test/testmock/testcallable.py | 16 +-- 3 files changed, 26 insertions(+), 50 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -794,9 +794,9 @@ That's a tough one, in general. First, here are a list of things to remember before diving further: -* Performance characteristics vary accross Python implementations. This FAQ +* Performance characteristics vary across Python implementations. This FAQ focusses on :term:`CPython`. -* Behaviour can vary accross operating systems, especially when talking about +* Behaviour can vary across operating systems, especially when talking about I/O or multi-threading. * You should always find the hot spots in your program *before* attempting to optimize any code (see the :mod:`profile` module). diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -143,13 +143,10 @@ # already an instance return getattr(obj, '__call__', None) is not None - klass = obj - # uses __bases__ instead of __mro__ so that we work with old style classes - if klass.__dict__.get('__call__') is not None: - return True - - for base in klass.__bases__: - if _instance_callable(base): + # *could* be broken by a class overriding __mro__ or __dict__ via + # a metaclass + for base in (obj,) + obj.__mro__: + if base.__dict__.get('__call__') is not None: return True return False @@ -622,9 +619,7 @@ def __dir__(self): - """Filter the output of `dir(mock)` to only useful members. - XXXX - """ + """Filter the output of `dir(mock)` to only useful members.""" extras = self._mock_methods or [] from_type = dir(type(self)) from_dict = list(self.__dict__) @@ -1060,31 +1055,28 @@ @wraps(func) def patched(*args, **keywargs): - # could use with statement here extra_args = [] entered_patchers = [] - # could use try..except...finally here try: - try: - for patching in patched.patchings: - arg = patching.__enter__() - entered_patchers.append(patching) - if patching.attribute_name is not None: - keywargs.update(arg) - elif patching.new is DEFAULT: - extra_args.append(arg) + for patching in patched.patchings: + arg = patching.__enter__() + entered_patchers.append(patching) + if patching.attribute_name is not None: + keywargs.update(arg) + elif patching.new is DEFAULT: + extra_args.append(arg) - args += tuple(extra_args) - return func(*args, **keywargs) - except: - if (patching not in entered_patchers and - _is_started(patching)): - # the patcher may have been started, but an exception - # raised whilst entering one of its additional_patchers - entered_patchers.append(patching) - # re-raise the exception - raise + args += tuple(extra_args) + return func(*args, **keywargs) + except: + if (patching not in entered_patchers and + _is_started(patching)): + # the patcher may have been started, but an exception + # raised whilst entering one of its additional_patchers + entered_patchers.append(patching) + # re-raise the exception + raise finally: for patching in reversed(entered_patchers): patching.__exit__() @@ -2064,11 +2056,7 @@ if entry in getattr(spec, '__dict__', {}): # instance attribute - shouldn't skip return False - # can't use type because of old style classes spec = spec.__class__ - if not hasattr(spec, '__mro__'): - # old style class: can't have descriptors anyway - return is_type for klass in spec.__mro__: result = klass.__dict__.get(entry, DEFAULT) diff --git a/Lib/unittest/test/testmock/testcallable.py b/Lib/unittest/test/testmock/testcallable.py --- a/Lib/unittest/test/testmock/testcallable.py +++ b/Lib/unittest/test/testmock/testcallable.py @@ -107,19 +107,9 @@ class Multi(SomeClass, Sub): pass - class OldStyle: - def __call__(self): - pass - - class OldStyleSub(OldStyle): - pass - for arg in 'spec', 'spec_set': - for Klass in CallableX, Sub, Multi, OldStyle, OldStyleSub: - patcher = patch('%s.X' % __name__, **{arg: Klass}) - mock = patcher.start() - - try: + for Klass in CallableX, Sub, Multi: + with patch('%s.X' % __name__, **{arg: Klass}) as mock: instance = mock() mock.assert_called_once_with() @@ -136,8 +126,6 @@ result.assert_called_once_with(3, 2, 1) result.foo(3, 2, 1) result.foo.assert_called_once_with(3, 2, 1) - finally: - patcher.stop() def test_create_autopsec(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:10:13 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:10:13 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge?= Message-ID: http://hg.python.org/cpython/rev/64197559ad9f changeset: 75658:64197559ad9f parent: 75657:48cf54dc22c7 parent: 75656:6c70d8e8b7a9 user: Gregory P. Smith date: Wed Mar 14 15:04:57 2012 -0700 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:18:32 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 14 Mar 2012 23:18:32 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_416=3A_Add_links_to_existi?= =?utf8?q?ng_implementations?= Message-ID: http://hg.python.org/peps/rev/eb2ed0fae94d changeset: 4137:eb2ed0fae94d user: Victor Stinner date: Wed Mar 14 23:18:49 2012 +0100 summary: PEP 416: Add links to existing implementations files: pep-0416.txt | 44 ++++++++++++++++++++++++++++++--------- 1 files changed, 34 insertions(+), 10 deletions(-) diff --git a/pep-0416.txt b/pep-0416.txt --- a/pep-0416.txt +++ b/pep-0416.txt @@ -125,6 +125,38 @@ not an issue, to avoid a copy of the dictionary. +Existing implementations +======================== + +Whitelist approach. + + * `Implementing an Immutable Dictionary (Python recipe 498072) + `_ by Aristotelis Mikropoulos. + Similar to frozendict except that it is not truly read-only: it is possible + to access to this private internal dict. It does not implement __hash__ and + has an implementation issue: it is possible to call again __init__() to + modify the mapping. + * PyWebmail contains an ImmutableDict type: `webmail.utils.ImmutableDict + `_. + It is hashable if keys and values are hashable. It is not truly read-only: + its internal dict is a public attribute. + +Blacklist approach: inherit from dict and override write methods to raise an +exception. It is not truly read-only: it is still possible to call dict methods +on such "frozen dictionary" to modify it. + + * brownie: `brownie.datastructures.ImmuatableDict + `_. + It is hashable if keys and values are hashable. werkzeug project has the + same code: `werkzeug.datastructures.ImmutableDict + `_. + * SQLAchemy project: `sqlachemy.util.immutabledict + `_. + It is not hashable and has an extra method: union(). + * `Frozen dictionaries (Python recipe 414283) `_ + by Oren Tirosh. It is hashable if keys and values are hashable. + + Links ===== @@ -133,16 +165,8 @@ * PEP 412: Key-Sharing Dictionary (`issue #13903 `_) * PEP 351: The freeze protocol - * `The case for immutable dictionaries; and the central misunderstanding of PEP 351 `_ - * `Frozen dictionaries (Python recipe 414283) `_ - by Oren Tirosh. Blacklist approach: inherit from dict and override write - methods to raise an exception. It is not truly read-only: it is still - possible to call dict methods on such "frozen dictionary" to modify it. - * `Implementing an Immutable Dictionary (Python recipe 498072) `_ - by Aristotelis Mikropoulos. Similar to frozendict except that it is not - truly read-only. It is possible to access to this private internal dict. - It does not implement __hash__ and has an implementation issue: it is - possible to call again __init__() to modify the mapping. + * `The case for immutable dictionaries; and the central misunderstanding of + PEP 351 `_ * `make dictproxy object via ctypes.pythonapi and type() (Python recipe 576540) `_ by Ikkei Shimomura. * Python security modules implementing read-only object proxies using a C -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Mar 14 23:27:24 2012 From: python-checkins at python.org (matthias.klose) Date: Wed, 14 Mar 2012 23:27:24 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E1=29=3A_-_rename_config?= =?utf8?q?ure=2Ein_to_configure=2Eac?= Message-ID: http://hg.python.org/cpython/rev/55ab7a272f0a changeset: 75659:55ab7a272f0a branch: 3.1 parent: 75199:df3b2b5db900 user: Matthias Klose date: Wed Mar 14 23:10:15 2012 +0100 summary: - rename configure.in to configure.ac - change references from configure.in to configure.ac files: Include/patchlevel.h | 2 +- Makefile.pre.in | 4 ++-- Misc/README.OpenBSD | 2 +- PC/pyconfig.h | 2 +- Python/thread.c | 2 +- configure | 5 ++--- configure.in | 0 pyconfig.h.in | 5 ++++- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -2,7 +2,7 @@ /* Python version identification scheme. When the major or minor version changes, the VERSION variable in - configure.in must also be changed. + configure.ac must also be changed. There is also (independent) API version information in modsupport.h. */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -151,7 +151,7 @@ SUBDIRSTOO= Include Lib Misc Demo # Files and directories to be distributed -CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in +CONFIGFILES= configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in DISTFILES= README ChangeLog $(CONFIGFILES) DISTDIRS= $(SUBDIRS) $(SUBDIRSTOO) Ext-dummy DIST= $(DISTFILES) $(DISTDIRS) @@ -1137,7 +1137,7 @@ $(SHELL) config.status --recheck $(SHELL) config.status -# Rebuild the configure script from configure.in; also rebuild pyconfig.h.in +# Rebuild the configure script from configure.ac; also rebuild pyconfig.h.in autoconf: (cd $(srcdir); autoconf) (cd $(srcdir); autoheader) diff --git a/Misc/README.OpenBSD b/Misc/README.OpenBSD --- a/Misc/README.OpenBSD +++ b/Misc/README.OpenBSD @@ -29,7 +29,7 @@ If your version is not in that list, e.g., 3.9, add the version number. In this case, you would just need to add a 9 after the 8. -If you modify configure.in, you will need to regenerate configure +If you modify configure.ac, you will need to regenerate configure with autoconf. If your version is already in the list, this is not a known problem. diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -344,7 +344,7 @@ # define SIZEOF_FPOS_T 8 # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 -/* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, +/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, sizeof(off_t) > sizeof(long), and sizeof(PY_LONG_LONG) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -24,7 +24,7 @@ #include #ifdef __sgi -#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.in */ +#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.ac */ #undef _POSIX_THREADS #endif #endif diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision. +# From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for python 3.1. # @@ -769,8 +769,7 @@ LDFLAGS LIBS CPPFLAGS -CPP -CPPFLAGS' +CPP' # Initialize some variables set by options. diff --git a/configure.in b/configure.ac rename from configure.in rename to configure.ac diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1,4 +1,4 @@ -/* pyconfig.h.in. Generated from configure.in by autoheader. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ #ifndef Py_PYCONFIG_H @@ -1102,6 +1102,9 @@ /* This must be defined on some systems to enable large file support. */ #undef _LARGEFILE_SOURCE +/* This must be defined on AIX systems to enable large file support. */ +#undef _LARGE_FILES + /* Define to 1 if on MINIX. */ #undef _MINIX -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:27:25 2012 From: python-checkins at python.org (matthias.klose) Date: Wed, 14 Mar 2012 23:27:25 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4xIC0+IDMuMik6?= =?utf8?q?_merge_3=2E1?= Message-ID: http://hg.python.org/cpython/rev/e51fc42d1f57 changeset: 75660:e51fc42d1f57 branch: 3.2 parent: 75630:d0bf40ff20ef parent: 75659:55ab7a272f0a user: Matthias Klose date: Wed Mar 14 23:14:35 2012 +0100 summary: merge 3.1 files: Include/patchlevel.h | 2 +- Makefile.pre.in | 4 ++-- PC/pyconfig.h | 2 +- configure | 2 +- configure.in | 0 pyconfig.h.in | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -2,7 +2,7 @@ /* Python version identification scheme. When the major or minor version changes, the VERSION variable in - configure.in must also be changed. + configure.ac must also be changed. There is also (independent) API version information in modsupport.h. */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -161,7 +161,7 @@ SUBDIRSTOO= Include Lib Misc # Files and directories to be distributed -CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in +CONFIGFILES= configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in DISTFILES= README ChangeLog $(CONFIGFILES) DISTDIRS= $(SUBDIRS) $(SUBDIRSTOO) Ext-dummy DIST= $(DISTFILES) $(DISTDIRS) @@ -1210,7 +1210,7 @@ $(SHELL) config.status --recheck $(SHELL) config.status -# Rebuild the configure script from configure.in; also rebuild pyconfig.h.in +# Rebuild the configure script from configure.ac; also rebuild pyconfig.h.in autoconf: (cd $(srcdir); autoconf -Wall) (cd $(srcdir); autoheader -Wall) diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -340,7 +340,7 @@ # define SIZEOF_FPOS_T 8 # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 -/* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, +/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, sizeof(off_t) > sizeof(long), and sizeof(PY_LONG_LONG) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision. +# From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for python 3.2. # diff --git a/configure.in b/configure.ac rename from configure.in rename to configure.ac diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1,4 +1,4 @@ -/* pyconfig.h.in. Generated from configure.in by autoheader. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ #ifndef Py_PYCONFIG_H -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:27:26 2012 From: python-checkins at python.org (matthias.klose) Date: Wed, 14 Mar 2012 23:27:26 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/f75fd74a0c13 changeset: 75661:f75fd74a0c13 parent: 75645:8943649201c5 parent: 75660:e51fc42d1f57 user: Matthias Klose date: Wed Mar 14 23:17:31 2012 +0100 summary: merge 3.2 files: Include/patchlevel.h | 2 +- Makefile.pre.in | 4 ++-- PC/pyconfig.h | 2 +- Tools/scripts/patchcheck.py | 4 ++-- configure | 4 ++-- configure.in | 0 pyconfig.h.in | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -2,7 +2,7 @@ /* Python version identification scheme. When the major or minor version changes, the VERSION variable in - configure.in must also be changed. + configure.ac must also be changed. There is also (independent) API version information in modsupport.h. */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -160,7 +160,7 @@ SUBDIRSTOO= Include Lib Misc # Files and directories to be distributed -CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in +CONFIGFILES= configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in DISTFILES= README ChangeLog $(CONFIGFILES) DISTDIRS= $(SUBDIRS) $(SUBDIRSTOO) Ext-dummy DIST= $(DISTFILES) $(DISTDIRS) @@ -1274,7 +1274,7 @@ $(SHELL) config.status --recheck $(SHELL) config.status -# Rebuild the configure script from configure.in; also rebuild pyconfig.h.in +# Rebuild the configure script from configure.ac; also rebuild pyconfig.h.in autoconf: (cd $(srcdir); autoconf -Wall) (cd $(srcdir); autoheader -Wall) diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -340,7 +340,7 @@ # define SIZEOF_FPOS_T 8 # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 -/* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, +/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, sizeof(off_t) > sizeof(long), and sizeof(PY_LONG_LONG) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py --- a/Tools/scripts/patchcheck.py +++ b/Tools/scripts/patchcheck.py @@ -135,7 +135,7 @@ @status("configure regenerated", modal=True, info=str) def regenerated_configure(file_paths): """Check if configure has been regenerated.""" - if 'configure.in' in file_paths: + if 'configure.ac' in file_paths: return "yes" if 'configure' in file_paths else "no" else: return "not needed" @@ -143,7 +143,7 @@ @status("pyconfig.h.in regenerated", modal=True, info=str) def regenerated_pyconfig_h_in(file_paths): """Check if pyconfig.h.in has been regenerated.""" - if 'configure.in' in file_paths: + if 'configure.ac' in file_paths: return "yes" if 'pyconfig.h.in' in file_paths else "no" else: return "not needed" diff --git a/configure b/configure --- a/configure +++ b/configure @@ -14599,8 +14599,8 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. -config_files="`echo $ac_config_files`" -config_headers="`echo $ac_config_headers`" +config_files="$ac_config_files" +config_headers="$ac_config_headers" _ACEOF diff --git a/configure.in b/configure.ac rename from configure.in rename to configure.ac diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1,4 +1,4 @@ -/* pyconfig.h.in. Generated from configure.in by autoheader. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ #ifndef Py_PYCONFIG_H -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:27:27 2012 From: python-checkins at python.org (matthias.klose) Date: Wed, 14 Mar 2012 23:27:27 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4xIC0+IDMuMSk6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/7198ccff7afd changeset: 75662:7198ccff7afd branch: 3.1 parent: 75652:0abd368609c9 parent: 75659:55ab7a272f0a user: Matthias Klose date: Wed Mar 14 23:24:11 2012 +0100 summary: merge heads files: Include/patchlevel.h | 2 +- Makefile.pre.in | 4 ++-- Misc/README.OpenBSD | 2 +- PC/pyconfig.h | 2 +- Python/thread.c | 2 +- configure | 5 ++--- configure.in | 0 pyconfig.h.in | 5 ++++- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -2,7 +2,7 @@ /* Python version identification scheme. When the major or minor version changes, the VERSION variable in - configure.in must also be changed. + configure.ac must also be changed. There is also (independent) API version information in modsupport.h. */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -151,7 +151,7 @@ SUBDIRSTOO= Include Lib Misc Demo # Files and directories to be distributed -CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in +CONFIGFILES= configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in DISTFILES= README ChangeLog $(CONFIGFILES) DISTDIRS= $(SUBDIRS) $(SUBDIRSTOO) Ext-dummy DIST= $(DISTFILES) $(DISTDIRS) @@ -1137,7 +1137,7 @@ $(SHELL) config.status --recheck $(SHELL) config.status -# Rebuild the configure script from configure.in; also rebuild pyconfig.h.in +# Rebuild the configure script from configure.ac; also rebuild pyconfig.h.in autoconf: (cd $(srcdir); autoconf) (cd $(srcdir); autoheader) diff --git a/Misc/README.OpenBSD b/Misc/README.OpenBSD --- a/Misc/README.OpenBSD +++ b/Misc/README.OpenBSD @@ -29,7 +29,7 @@ If your version is not in that list, e.g., 3.9, add the version number. In this case, you would just need to add a 9 after the 8. -If you modify configure.in, you will need to regenerate configure +If you modify configure.ac, you will need to regenerate configure with autoconf. If your version is already in the list, this is not a known problem. diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -344,7 +344,7 @@ # define SIZEOF_FPOS_T 8 # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 -/* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, +/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, sizeof(off_t) > sizeof(long), and sizeof(PY_LONG_LONG) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -24,7 +24,7 @@ #include #ifdef __sgi -#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.in */ +#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.ac */ #undef _POSIX_THREADS #endif #endif diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision. +# From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for python 3.1. # @@ -769,8 +769,7 @@ LDFLAGS LIBS CPPFLAGS -CPP -CPPFLAGS' +CPP' # Initialize some variables set by options. diff --git a/configure.in b/configure.ac rename from configure.in rename to configure.ac diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1,4 +1,4 @@ -/* pyconfig.h.in. Generated from configure.in by autoheader. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ #ifndef Py_PYCONFIG_H @@ -1102,6 +1102,9 @@ /* This must be defined on some systems to enable large file support. */ #undef _LARGEFILE_SOURCE +/* This must be defined on AIX systems to enable large file support. */ +#undef _LARGE_FILES + /* Define to 1 if on MINIX. */ #undef _MINIX -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:27:28 2012 From: python-checkins at python.org (matthias.klose) Date: Wed, 14 Mar 2012 23:27:28 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/3fd9f7f1d0ae changeset: 75663:3fd9f7f1d0ae branch: 3.2 parent: 75656:6c70d8e8b7a9 parent: 75660:e51fc42d1f57 user: Matthias Klose date: Wed Mar 14 23:24:32 2012 +0100 summary: merge heads files: Include/patchlevel.h | 2 +- Makefile.pre.in | 4 ++-- PC/pyconfig.h | 2 +- configure | 2 +- configure.in | 0 pyconfig.h.in | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -2,7 +2,7 @@ /* Python version identification scheme. When the major or minor version changes, the VERSION variable in - configure.in must also be changed. + configure.ac must also be changed. There is also (independent) API version information in modsupport.h. */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -161,7 +161,7 @@ SUBDIRSTOO= Include Lib Misc # Files and directories to be distributed -CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in +CONFIGFILES= configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in DISTFILES= README ChangeLog $(CONFIGFILES) DISTDIRS= $(SUBDIRS) $(SUBDIRSTOO) Ext-dummy DIST= $(DISTFILES) $(DISTDIRS) @@ -1210,7 +1210,7 @@ $(SHELL) config.status --recheck $(SHELL) config.status -# Rebuild the configure script from configure.in; also rebuild pyconfig.h.in +# Rebuild the configure script from configure.ac; also rebuild pyconfig.h.in autoconf: (cd $(srcdir); autoconf -Wall) (cd $(srcdir); autoheader -Wall) diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -340,7 +340,7 @@ # define SIZEOF_FPOS_T 8 # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 -/* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, +/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, sizeof(off_t) > sizeof(long), and sizeof(PY_LONG_LONG) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision. +# From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for python 3.2. # diff --git a/configure.in b/configure.ac rename from configure.in rename to configure.ac diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1,4 +1,4 @@ -/* pyconfig.h.in. Generated from configure.in by autoheader. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ #ifndef Py_PYCONFIG_H -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:27:28 2012 From: python-checkins at python.org (matthias.klose) Date: Wed, 14 Mar 2012 23:27:28 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4xIC0+IDMuMik6?= =?utf8?q?_merge_3=2E1?= Message-ID: http://hg.python.org/cpython/rev/421d308a48f7 changeset: 75664:421d308a48f7 branch: 3.2 parent: 75663:3fd9f7f1d0ae parent: 75662:7198ccff7afd user: Matthias Klose date: Wed Mar 14 23:26:07 2012 +0100 summary: merge 3.1 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:27:29 2012 From: python-checkins at python.org (matthias.klose) Date: Wed, 14 Mar 2012 23:27:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/b64218fbc1b7 changeset: 75665:b64218fbc1b7 parent: 75658:64197559ad9f parent: 75661:f75fd74a0c13 user: Matthias Klose date: Wed Mar 14 23:26:26 2012 +0100 summary: merge heads files: Include/patchlevel.h | 2 +- Makefile.pre.in | 4 ++-- PC/pyconfig.h | 2 +- Tools/scripts/patchcheck.py | 4 ++-- configure | 4 ++-- configure.in | 0 pyconfig.h.in | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -2,7 +2,7 @@ /* Python version identification scheme. When the major or minor version changes, the VERSION variable in - configure.in must also be changed. + configure.ac must also be changed. There is also (independent) API version information in modsupport.h. */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -160,7 +160,7 @@ SUBDIRSTOO= Include Lib Misc # Files and directories to be distributed -CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in +CONFIGFILES= configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in DISTFILES= README ChangeLog $(CONFIGFILES) DISTDIRS= $(SUBDIRS) $(SUBDIRSTOO) Ext-dummy DIST= $(DISTFILES) $(DISTDIRS) @@ -1274,7 +1274,7 @@ $(SHELL) config.status --recheck $(SHELL) config.status -# Rebuild the configure script from configure.in; also rebuild pyconfig.h.in +# Rebuild the configure script from configure.ac; also rebuild pyconfig.h.in autoconf: (cd $(srcdir); autoconf -Wall) (cd $(srcdir); autoheader -Wall) diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -340,7 +340,7 @@ # define SIZEOF_FPOS_T 8 # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 -/* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, +/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, sizeof(off_t) > sizeof(long), and sizeof(PY_LONG_LONG) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py --- a/Tools/scripts/patchcheck.py +++ b/Tools/scripts/patchcheck.py @@ -135,7 +135,7 @@ @status("configure regenerated", modal=True, info=str) def regenerated_configure(file_paths): """Check if configure has been regenerated.""" - if 'configure.in' in file_paths: + if 'configure.ac' in file_paths: return "yes" if 'configure' in file_paths else "no" else: return "not needed" @@ -143,7 +143,7 @@ @status("pyconfig.h.in regenerated", modal=True, info=str) def regenerated_pyconfig_h_in(file_paths): """Check if pyconfig.h.in has been regenerated.""" - if 'configure.in' in file_paths: + if 'configure.ac' in file_paths: return "yes" if 'pyconfig.h.in' in file_paths else "no" else: return "not needed" diff --git a/configure b/configure --- a/configure +++ b/configure @@ -14599,8 +14599,8 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. -config_files="`echo $ac_config_files`" -config_headers="`echo $ac_config_headers`" +config_files="$ac_config_files" +config_headers="$ac_config_headers" _ACEOF diff --git a/configure.in b/configure.ac rename from configure.in rename to configure.ac diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1,4 +1,4 @@ -/* pyconfig.h.in. Generated from configure.in by autoheader. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ #ifndef Py_PYCONFIG_H -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:27:30 2012 From: python-checkins at python.org (matthias.klose) Date: Wed, 14 Mar 2012 23:27:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/587bca79599f changeset: 75666:587bca79599f parent: 75665:b64218fbc1b7 parent: 75664:421d308a48f7 user: Matthias Klose date: Wed Mar 14 23:27:12 2012 +0100 summary: merge 3.2 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:28:27 2012 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 14 Mar 2012 23:28:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fixes_Issue_=23?= =?utf8?q?14234=3A_CVE-2012-0876=3A_Randomize_hashes_of_xml_attributes?= Message-ID: http://hg.python.org/cpython/rev/b54f5849013c changeset: 75667:b54f5849013c branch: 2.7 parent: 75627:3e62379008c2 user: Gregory P. Smith date: Wed Mar 14 15:28:10 2012 -0700 summary: Fixes Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project. files: Misc/NEWS | 14 ++ Modules/expat/expat.h | 9 + Modules/expat/pyexpatns.h | 1 + Modules/expat/xmlparse.c | 177 +++++++++++++++++-------- Modules/pyexpat.c | 2 + 5 files changed, 144 insertions(+), 59 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -42,6 +42,20 @@ on Windows. +What's New in Python 2.7.3 release candidate 2? +=============================================== + +*Release date: 2012-03-XX* + +Library +------- + +- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash + table internal to the pyexpat module's copy of the expat library to avoid a + denial of service due to hash collisions. Patch by David Malcolm with some + modifications by the expat project. + + What's New in Python 2.7.3 release candidate 1? =============================================== diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -883,6 +883,15 @@ XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing); +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt); + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/expat/pyexpatns.h b/Modules/expat/pyexpatns.h --- a/Modules/expat/pyexpatns.h +++ b/Modules/expat/pyexpatns.h @@ -97,6 +97,7 @@ #define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler #define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler #define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg +#define XML_SetHashSalt PyExpat_XML_SetHashSalt #define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler #define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler #define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -17,6 +17,8 @@ #include #include /* memset(), memcpy() */ #include +#include /* UINT_MAX */ +#include /* time() */ #include "expat.h" @@ -387,12 +389,13 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +dtdCopy(XML_Parser oldParser, + DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); static int -copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); - +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize); +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); static void FASTCALL hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); static void FASTCALL hashTableClear(HASH_TABLE *); @@ -425,6 +428,9 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); +static unsigned long generate_hash_secret_salt(void); +static XML_Bool startParsing(XML_Parser parser); + static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, @@ -542,6 +548,7 @@ XML_Bool m_useForeignDTD; enum XML_ParamEntityParsing m_paramEntityParsing; #endif + unsigned long m_hash_secret_salt; }; #define MALLOC(s) (parser->m_mem.malloc_fcn((s))) @@ -649,6 +656,7 @@ #define useForeignDTD (parser->m_useForeignDTD) #define paramEntityParsing (parser->m_paramEntityParsing) #endif /* XML_DTD */ +#define hash_secret_salt (parser->m_hash_secret_salt) XML_Parser XMLCALL XML_ParserCreate(const XML_Char *encodingName) @@ -671,22 +679,36 @@ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' }; -XML_Parser XMLCALL -XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) +static unsigned long +generate_hash_secret_salt(void) { - XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); - if (parser != NULL && ns) { + unsigned int seed = time(NULL) % UINT_MAX; + srand(seed); + return rand(); +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) +{ + /* hash functions must be initialized before setContext() is called */ + + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { /* implicit context only set for root parser, since child parsers (i.e. external entity parsers) will inherit it */ - if (!setContext(parser, implicitContext)) { - XML_ParserFree(parser); - return NULL; - } + return setContext(parser, implicitContext); } - return parser; + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + return parserCreate(encodingName, memsuite, nameSep, NULL); } static XML_Parser @@ -860,6 +882,7 @@ useForeignDTD = XML_FALSE; paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #endif + hash_secret_salt = 0; } /* moves list of bindings to freeBindingList */ @@ -907,7 +930,7 @@ poolClear(&temp2Pool); parserInit(parser, encodingName); dtdReset(_dtd, &parser->m_mem); - return setContext(parser, implicitContext); + return XML_TRUE; } enum XML_Status XMLCALL @@ -976,6 +999,12 @@ int oldInEntityValue = prologState.inEntityValue; #endif XML_Bool oldns_triplets = ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt = hash_secret_salt; #ifdef XML_DTD if (!context) @@ -1029,13 +1058,14 @@ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; defaultExpandInternalEntities = oldDefaultExpandInternalEntities; ns_triplets = oldns_triplets; + hash_secret_salt = oldhash_secret_salt; parentParser = oldParser; #ifdef XML_DTD paramEntityParsing = oldParamEntityParsing; prologState.inEntityValue = oldInEntityValue; if (context) { #endif /* XML_DTD */ - if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) || !setContext(parser, context)) { XML_ParserFree(parser); return NULL; @@ -1420,6 +1450,17 @@ #endif } +int XMLCALL +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; + hash_secret_salt = hash_salt; + return 1; +} + enum XML_Status XMLCALL XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { @@ -1430,6 +1471,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -1488,11 +1534,13 @@ break; case XML_INITIALIZED: case XML_PARSING: - result = XML_STATUS_OK; if (isFinal) { ps_parsing = XML_FINISHED; - return result; + return XML_STATUS_OK; } + /* fall through */ + default: + result = XML_STATUS_OK; } } @@ -1553,6 +1601,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -2231,7 +2284,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&dtd->pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -2618,12 +2671,12 @@ const XML_Char *localPart; /* lookup the element type name */ - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); if (!elementType) { const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); if (!name) return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!elementType) return XML_ERROR_NO_MEMORY; @@ -2792,9 +2845,9 @@ if (s[-1] == 2) { /* prefixed */ ATTRIBUTE_ID *id; const BINDING *b; - unsigned long uriHash = 0; + unsigned long uriHash = hash_secret_salt; ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); if (!id) return XML_ERROR_NO_MEMORY; b = id->prefix->binding; @@ -2818,7 +2871,7 @@ } while (*s++); { /* Check hash table for duplicate of expanded name (uriName). - Derived from code in lookup(HASH_TABLE *table, ...). + Derived from code in lookup(parser, HASH_TABLE *table, ...). */ unsigned char step = 0; unsigned long mask = nsAttsSize - 1; @@ -3756,7 +3809,8 @@ case XML_ROLE_DOCTYPE_PUBLIC_ID: #ifdef XML_DTD useForeignDTD = XML_FALSE; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -3811,7 +3865,8 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -3855,7 +3910,7 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -4069,7 +4124,8 @@ break; #else /* XML_DTD */ if (!declEntity) { - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -4144,7 +4200,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4176,7 +4232,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4358,7 +4414,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&dtd->pool); /* first, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -4882,7 +4938,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&temp2Pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal. @@ -4991,7 +5047,7 @@ result = XML_ERROR_NO_MEMORY; goto endEntityValue; } - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&tempPool); if (!entity) { /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ @@ -5281,7 +5337,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return 0; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!prefix) return 0; @@ -5310,7 +5366,7 @@ return NULL; /* skip quotation mark - its storage will be re-used (like in name[-1]) */ ++name; - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); if (!id) return NULL; if (id->name != name) @@ -5328,7 +5384,7 @@ if (name[5] == XML_T('\0')) id->prefix = &dtd->defaultPrefix; else - id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); id->xmlns = XML_TRUE; } else { @@ -5343,7 +5399,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return NULL; - id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!id->prefix) return NULL; @@ -5441,7 +5497,7 @@ ENTITY *e; if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); if (e) e->open = XML_TRUE; if (*s != XML_T('\0')) @@ -5456,7 +5512,7 @@ else { if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), sizeof(PREFIX)); if (!prefix) return XML_FALSE; @@ -5620,7 +5676,7 @@ The new DTD has already been initialized. */ static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) { HASH_TABLE_ITER iter; @@ -5635,7 +5691,7 @@ name = poolCopyString(&(newDtd->pool), oldP->name); if (!name) return 0; - if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) return 0; } @@ -5657,7 +5713,7 @@ if (!name) return 0; ++name; - newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); if (!newA) return 0; @@ -5667,7 +5723,7 @@ if (oldA->prefix == &oldDtd->defaultPrefix) newA->prefix = &newDtd->defaultPrefix; else - newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); } } @@ -5686,7 +5742,7 @@ name = poolCopyString(&(newDtd->pool), oldE->name); if (!name) return 0; - newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); if (!newE) return 0; @@ -5700,14 +5756,14 @@ } if (oldE->idAtt) newE->idAtt = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; if (oldE->prefix) - newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { newE->defaultAtts[i].id = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -5721,13 +5777,15 @@ } /* Copy the entity tables. */ - if (!copyEntityTable(&(newDtd->generalEntities), + if (!copyEntityTable(oldParser, + &(newDtd->generalEntities), &(newDtd->pool), &(oldDtd->generalEntities))) return 0; #ifdef XML_DTD - if (!copyEntityTable(&(newDtd->paramEntities), + if (!copyEntityTable(oldParser, + &(newDtd->paramEntities), &(newDtd->pool), &(oldDtd->paramEntities))) return 0; @@ -5750,7 +5808,8 @@ } /* End dtdCopy */ static int -copyEntityTable(HASH_TABLE *newTable, +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable) { @@ -5769,7 +5828,7 @@ name = poolCopyString(newPool, oldE->name); if (!name) return 0; - newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); if (!newE) return 0; if (oldE->systemId) { @@ -5827,16 +5886,16 @@ } static unsigned long FASTCALL -hash(KEY s) +hash(XML_Parser parser, KEY s) { - unsigned long h = 0; + unsigned long h = hash_secret_salt; while (*s) h = CHAR_HASH(h, *s++); return h; } static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize) +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { size_t i; if (table->size == 0) { @@ -5853,10 +5912,10 @@ return NULL; } memset(table->v, 0, tsize); - i = hash(name) & ((unsigned long)table->size - 1); + i = hash(parser, name) & ((unsigned long)table->size - 1); } else { - unsigned long h = hash(name); + unsigned long h = hash(parser, name); unsigned long mask = (unsigned long)table->size - 1; unsigned char step = 0; i = h & mask; @@ -5882,7 +5941,7 @@ memset(newV, 0, tsize); for (i = 0; i < table->size; i++) if (table->v[i]) { - unsigned long newHash = hash(table->v[i]->name); + unsigned long newHash = hash(parser, table->v[i]->name); size_t j = newHash & newMask; step = 0; while (newV[j]) { @@ -6257,7 +6316,7 @@ if (!name) return NULL; - ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!ret) return NULL; if (ret->name != name) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1302,6 +1302,8 @@ else { self->itself = XML_ParserCreate(encoding); } + XML_SetHashSalt(self->itself, + (unsigned long)_Py_HashSecret.prefix); self->intern = intern; Py_XINCREF(self->intern); #ifdef Py_TPFLAGS_HAVE_GC -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:39:42 2012 From: python-checkins at python.org (matthias.klose) Date: Wed, 14 Mar 2012 23:39:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_-_rename_config?= =?utf8?q?ure=2Ein_to_configure=2Eac?= Message-ID: http://hg.python.org/cpython/rev/f5bf91af01ca changeset: 75668:f5bf91af01ca branch: 2.7 user: Matthias Klose date: Wed Mar 14 23:39:33 2012 +0100 summary: - rename configure.in to configure.ac - change references from configure.in to configure.ac files: Include/patchlevel.h | 2 +- Makefile.pre.in | 4 +- Misc/README.OpenBSD | 2 +- PC/pyconfig.h | 2 +- Python/thread.c | 2 +- README | 9 +- configure | 595 ++++++++++++++++-------------- configure.in | 0 pyconfig.h.in | 2 +- 9 files changed, 321 insertions(+), 297 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -6,7 +6,7 @@ defined(PY_MAJOR_VERSION). When the major or minor version changes, the VERSION variable in - configure.in must also be changed. + configure.ac must also be changed. There is also (independent) API version information in modsupport.h. */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -152,7 +152,7 @@ SUBDIRSTOO= Include Lib Misc Demo # Files and directories to be distributed -CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in +CONFIGFILES= configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in DISTFILES= README ChangeLog $(CONFIGFILES) DISTDIRS= $(SUBDIRS) $(SUBDIRSTOO) Ext-dummy DIST= $(DISTFILES) $(DISTDIRS) @@ -1165,7 +1165,7 @@ $(SHELL) config.status --recheck $(SHELL) config.status -# Rebuild the configure script from configure.in; also rebuild pyconfig.h.in +# Rebuild the configure script from configure.ac; also rebuild pyconfig.h.in autoconf: (cd $(srcdir); autoconf) (cd $(srcdir); autoheader) diff --git a/Misc/README.OpenBSD b/Misc/README.OpenBSD --- a/Misc/README.OpenBSD +++ b/Misc/README.OpenBSD @@ -29,7 +29,7 @@ If your version is not in that list, e.g., 3.9, add the version number. In this case, you would just need to add a 9 after the 8. -If you modify configure.in, you will need to regenerate configure +If you modify configure.ac, you will need to regenerate configure with autoconf. If your version is already in the list, this is not a known problem. diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -342,7 +342,7 @@ # define SIZEOF_FPOS_T 8 # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 -/* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, +/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, sizeof(off_t) > sizeof(long), and sizeof(PY_LONG_LONG) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -24,7 +24,7 @@ #include #ifdef __sgi -#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.in */ +#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.ac */ #undef _POSIX_THREADS #endif #endif diff --git a/README b/README --- a/README +++ b/README @@ -241,7 +241,7 @@ - NeXT - Irix 4 and --with-sgi-dl - Linux 1 -- Systems defining __d6_pthread_create (configure.in) +- Systems defining __d6_pthread_create (configure.ac) - Systems defining PY_PTHREAD_D4, PY_PTHREAD_D6, or PY_PTHREAD_D7 in thread_pthread.h - Systems using --with-dl-dld @@ -680,10 +680,10 @@ threads to work properly. Below is a table of those options, collected by Bill Janssen. We would love to automate this process more, but the information below is not enough to write a patch for the -configure.in file, so manual intervention is required. If you patch -the configure.in file and are confident that the patch works, please +configure.ac file, so manual intervention is required. If you patch +the configure.ac file and are confident that the patch works, please send in the patch. (Don't bother patching the configure script itself --- it is regenerated each time the configure.in file changes.) +-- it is regenerated each time the configure.ac file changes.) Compiler switches for threads ............................. @@ -1201,7 +1201,7 @@ Tools/ Some useful programs written in Python pyconfig.h.in Source from which pyconfig.h is created (GNU autoheader output) configure Configuration shell script (GNU autoconf output) -configure.in Configuration specification (input for GNU autoconf) +configure.ac Configuration specification (input for GNU autoconf) install-sh Shell script used to install files setup.py Python script used to build extension modules diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,7 +1,7 @@ #! /bin/sh -# From configure.in Revision. +# From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.67 for python 2.7. +# Generated by GNU Autoconf 2.68 for python 2.7. # # Report bugs to . # @@ -92,6 +92,7 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -217,11 +218,18 @@ # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -1174,7 +1182,7 @@ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac @@ -1511,7 +1519,7 @@ if $ac_init_version; then cat <<\_ACEOF python configure 2.7 -generated by GNU Autoconf 2.67 +generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation @@ -1557,7 +1565,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile @@ -1594,7 +1602,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp @@ -1607,10 +1615,10 @@ ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval "test \"\${$3+set}\"" = set; then : + if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -1677,7 +1685,7 @@ esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -1686,7 +1694,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel @@ -1727,7 +1735,7 @@ ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run @@ -1741,7 +1749,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -1759,7 +1767,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile @@ -1804,7 +1812,7 @@ # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link @@ -1818,7 +1826,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1859,7 +1867,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type @@ -1872,7 +1880,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1912,7 +1920,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t @@ -1925,7 +1933,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 $as_echo_n "checking for int$2_t... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1986,7 +1994,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t @@ -2163,7 +2171,7 @@ rm -f conftest.val fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_compute_int @@ -2176,7 +2184,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2231,7 +2239,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func @@ -2244,7 +2252,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } -if eval "test \"\${$4+set}\"" = set; then : +if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2288,7 +2296,7 @@ eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member @@ -2303,7 +2311,7 @@ as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2334,7 +2342,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl cat >config.log <<_ACEOF @@ -2342,7 +2350,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by python $as_me 2.7, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2600,7 +2608,7 @@ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi done @@ -3241,7 +3249,7 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3281,7 +3289,7 @@ set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3334,7 +3342,7 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3374,7 +3382,7 @@ set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3433,7 +3441,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3477,7 +3485,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3532,7 +3540,7 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -3647,7 +3655,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -3690,7 +3698,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -3749,7 +3757,7 @@ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi fi fi @@ -3760,7 +3768,7 @@ ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then : +if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3801,7 +3809,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi @@ -3811,7 +3819,7 @@ ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then : +if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3848,7 +3856,7 @@ ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then : +if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag @@ -3926,7 +3934,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then : +if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no @@ -4065,7 +4073,7 @@ set dummy g++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CXX+set}" = set; then : +if ${ac_cv_path_CXX+:} false; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4106,7 +4114,7 @@ set dummy c++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CXX+set}" = set; then : +if ${ac_cv_path_CXX+:} false; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4157,7 +4165,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CXX+set}" = set; then : +if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then @@ -4228,7 +4236,7 @@ CPP= fi if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then : + if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded @@ -4344,7 +4352,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c @@ -4356,7 +4364,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then : +if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -4419,7 +4427,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then : +if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -4486,7 +4494,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4615,7 +4623,7 @@ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = x""yes; then : +if test "x$ac_cv_header_minix_config_h" = xyes; then : MINIX=yes else MINIX= @@ -4637,7 +4645,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : +if ${ac_cv_safe_to_define___extensions__+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4981,7 +4989,7 @@ set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then : +if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then @@ -5021,7 +5029,7 @@ set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then @@ -5075,7 +5083,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AR+set}" = set; then : +if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then @@ -5125,7 +5133,7 @@ set dummy svnversion; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_SVNVERSION+set}" = set; then : +if ${ac_cv_prog_SVNVERSION+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$SVNVERSION"; then @@ -5173,7 +5181,7 @@ set dummy hg; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_HAS_HG+set}" = set; then : +if ${ac_cv_prog_HAS_HG+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$HAS_HG"; then @@ -5272,7 +5280,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if test "${ac_cv_path_install+set}" = set; then : +if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5460,7 +5468,7 @@ $as_echo_n "checking whether $CC accepts -fno-strict-aliasing... " >&6; } ac_save_cc="$CC" CC="$CC -fno-strict-aliasing" - if test "${ac_cv_no_strict_aliasing_ok+set}" = set; then : + if ${ac_cv_no_strict_aliasing_ok+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5650,7 +5658,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -OPT:Olimit=0" >&5 $as_echo_n "checking whether $CC accepts -OPT:Olimit=0... " >&6; } -if test "${ac_cv_opt_olimit_ok+set}" = set; then : +if ${ac_cv_opt_olimit_ok+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5692,7 +5700,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Olimit 1500" >&5 $as_echo_n "checking whether $CC accepts -Olimit 1500... " >&6; } - if test "${ac_cv_olimit_ok+set}" = set; then : + if ${ac_cv_olimit_ok+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5770,7 +5778,7 @@ # options before we can check whether -Kpthread improves anything. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads are available without options" >&5 $as_echo_n "checking whether pthreads are available without options... " >&6; } -if test "${ac_cv_pthread_is_default+set}" = set; then : +if ${ac_cv_pthread_is_default+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -5823,7 +5831,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kpthread" >&5 $as_echo_n "checking whether $CC accepts -Kpthread... " >&6; } -if test "${ac_cv_kpthread+set}" = set; then : +if ${ac_cv_kpthread+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5872,7 +5880,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kthread" >&5 $as_echo_n "checking whether $CC accepts -Kthread... " >&6; } -if test "${ac_cv_kthread+set}" = set; then : +if ${ac_cv_kthread+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5921,7 +5929,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -pthread" >&5 $as_echo_n "checking whether $CC accepts -pthread... " >&6; } -if test "${ac_cv_thread+set}" = set; then : +if ${ac_cv_thread+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -6006,7 +6014,7 @@ # checks for header files { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6145,7 +6153,7 @@ as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } -if eval "test \"\${$as_ac_Header+set}\"" = set; then : +if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6185,7 +6193,7 @@ if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6219,11 +6227,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no @@ -6242,7 +6250,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6276,11 +6284,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no @@ -6300,7 +6308,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 $as_echo_n "checking whether sys/types.h defines makedev... " >&6; } -if test "${ac_cv_header_sys_types_h_makedev+set}" = set; then : +if ${ac_cv_header_sys_types_h_makedev+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6328,7 +6336,7 @@ if test $ac_cv_header_sys_types_h_makedev = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = x""yes; then : +if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : $as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h @@ -6338,7 +6346,7 @@ if test $ac_cv_header_sys_mkdev_h = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = x""yes; then : +if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then : $as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h @@ -6358,7 +6366,7 @@ #endif " -if test "x$ac_cv_header_term_h" = x""yes; then : +if test "x$ac_cv_header_term_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_TERM_H 1 _ACEOF @@ -6380,7 +6388,7 @@ #endif " -if test "x$ac_cv_header_linux_netlink_h" = x""yes; then : +if test "x$ac_cv_header_linux_netlink_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_NETLINK_H 1 _ACEOF @@ -6543,7 +6551,7 @@ # Type availability checks ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" -if test "x$ac_cv_type_mode_t" = x""yes; then : +if test "x$ac_cv_type_mode_t" = xyes; then : else @@ -6554,7 +6562,7 @@ fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" -if test "x$ac_cv_type_off_t" = x""yes; then : +if test "x$ac_cv_type_off_t" = xyes; then : else @@ -6565,7 +6573,7 @@ fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = x""yes; then : +if test "x$ac_cv_type_pid_t" = xyes; then : else @@ -6581,7 +6589,7 @@ _ACEOF ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = x""yes; then : +if test "x$ac_cv_type_size_t" = xyes; then : else @@ -6593,7 +6601,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if test "${ac_cv_type_uid_t+set}" = set; then : +if ${ac_cv_type_uid_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6672,7 +6680,7 @@ esac ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" -if test "x$ac_cv_type_ssize_t" = x""yes; then : +if test "x$ac_cv_type_ssize_t" = xyes; then : $as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h @@ -6687,7 +6695,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 $as_echo_n "checking size of int... " >&6; } -if test "${ac_cv_sizeof_int+set}" = set; then : +if ${ac_cv_sizeof_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : @@ -6697,7 +6705,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int=0 fi @@ -6720,7 +6728,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } -if test "${ac_cv_sizeof_long+set}" = set; then : +if ${ac_cv_sizeof_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : @@ -6730,7 +6738,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long=0 fi @@ -6753,7 +6761,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 $as_echo_n "checking size of void *... " >&6; } -if test "${ac_cv_sizeof_void_p+set}" = set; then : +if ${ac_cv_sizeof_void_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : @@ -6763,7 +6771,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_void_p=0 fi @@ -6786,7 +6794,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 $as_echo_n "checking size of short... " >&6; } -if test "${ac_cv_sizeof_short+set}" = set; then : +if ${ac_cv_sizeof_short+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : @@ -6796,7 +6804,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (short) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_short=0 fi @@ -6819,7 +6827,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 $as_echo_n "checking size of float... " >&6; } -if test "${ac_cv_sizeof_float+set}" = set; then : +if ${ac_cv_sizeof_float+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default"; then : @@ -6829,7 +6837,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (float) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_float=0 fi @@ -6852,7 +6860,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 $as_echo_n "checking size of double... " >&6; } -if test "${ac_cv_sizeof_double+set}" = set; then : +if ${ac_cv_sizeof_double+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then : @@ -6862,7 +6870,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (double) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_double=0 fi @@ -6885,7 +6893,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 $as_echo_n "checking size of fpos_t... " >&6; } -if test "${ac_cv_sizeof_fpos_t+set}" = set; then : +if ${ac_cv_sizeof_fpos_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default"; then : @@ -6895,7 +6903,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (fpos_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_fpos_t=0 fi @@ -6918,7 +6926,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 $as_echo_n "checking size of size_t... " >&6; } -if test "${ac_cv_sizeof_size_t+set}" = set; then : +if ${ac_cv_sizeof_size_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : @@ -6928,7 +6936,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (size_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_size_t=0 fi @@ -6951,7 +6959,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 $as_echo_n "checking size of pid_t... " >&6; } -if test "${ac_cv_sizeof_pid_t+set}" = set; then : +if ${ac_cv_sizeof_pid_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default"; then : @@ -6961,7 +6969,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (pid_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_pid_t=0 fi @@ -7011,7 +7019,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 $as_echo_n "checking size of long long... " >&6; } -if test "${ac_cv_sizeof_long_long+set}" = set; then : +if ${ac_cv_sizeof_long_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : @@ -7021,7 +7029,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long long) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_long=0 fi @@ -7072,7 +7080,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 $as_echo_n "checking size of long double... " >&6; } -if test "${ac_cv_sizeof_long_double+set}" = set; then : +if ${ac_cv_sizeof_long_double+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then : @@ -7082,7 +7090,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long double) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_double=0 fi @@ -7133,7 +7141,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of _Bool" >&5 $as_echo_n "checking size of _Bool... " >&6; } -if test "${ac_cv_sizeof__Bool+set}" = set; then : +if ${ac_cv_sizeof__Bool+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default"; then : @@ -7143,7 +7151,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (_Bool) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof__Bool=0 fi @@ -7169,7 +7177,7 @@ #include #endif " -if test "x$ac_cv_type_uintptr_t" = x""yes; then : +if test "x$ac_cv_type_uintptr_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINTPTR_T 1 @@ -7181,7 +7189,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 $as_echo_n "checking size of uintptr_t... " >&6; } -if test "${ac_cv_sizeof_uintptr_t+set}" = set; then : +if ${ac_cv_sizeof_uintptr_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default"; then : @@ -7191,7 +7199,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (uintptr_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uintptr_t=0 fi @@ -7217,7 +7225,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 $as_echo_n "checking size of off_t... " >&6; } -if test "${ac_cv_sizeof_off_t+set}" = set; then : +if ${ac_cv_sizeof_off_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " @@ -7232,7 +7240,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (off_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_off_t=0 fi @@ -7276,7 +7284,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 $as_echo_n "checking size of time_t... " >&6; } -if test "${ac_cv_sizeof_time_t+set}" = set; then : +if ${ac_cv_sizeof_time_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " @@ -7294,7 +7302,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (time_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_time_t=0 fi @@ -7350,7 +7358,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 $as_echo_n "checking size of pthread_t... " >&6; } -if test "${ac_cv_sizeof_pthread_t+set}" = set; then : +if ${ac_cv_sizeof_pthread_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " @@ -7365,7 +7373,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (pthread_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_pthread_t=0 fi @@ -7877,7 +7885,7 @@ # checks for libraries { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then : +if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7911,7 +7919,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF @@ -7922,7 +7930,7 @@ # Dynamic linking for SunOS/Solaris and SYSV { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } -if test "${ac_cv_lib_dld_shl_load+set}" = set; then : +if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7956,7 +7964,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDLD 1 _ACEOF @@ -7970,7 +7978,7 @@ if test "$with_threads" = "yes" -o -z "$with_threads"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5 $as_echo_n "checking for library containing sem_init... " >&6; } -if test "${ac_cv_search_sem_init+set}" = set; then : +if ${ac_cv_search_sem_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -8004,11 +8012,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_sem_init+set}" = set; then : + if ${ac_cv_search_sem_init+:} false; then : break fi done -if test "${ac_cv_search_sem_init+set}" = set; then : +if ${ac_cv_search_sem_init+:} false; then : else ac_cv_search_sem_init=no @@ -8031,7 +8039,7 @@ # check if we need libintl for locale functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for textdomain in -lintl" >&5 $as_echo_n "checking for textdomain in -lintl... " >&6; } -if test "${ac_cv_lib_intl_textdomain+set}" = set; then : +if ${ac_cv_lib_intl_textdomain+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8065,7 +8073,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_textdomain" >&5 $as_echo "$ac_cv_lib_intl_textdomain" >&6; } -if test "x$ac_cv_lib_intl_textdomain" = x""yes; then : +if test "x$ac_cv_lib_intl_textdomain" = xyes; then : $as_echo "#define WITH_LIBINTL 1" >>confdefs.h @@ -8112,7 +8120,7 @@ # BeOS' sockets are stashed in libnet. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for t_open in -lnsl" >&5 $as_echo_n "checking for t_open in -lnsl... " >&6; } -if test "${ac_cv_lib_nsl_t_open+set}" = set; then : +if ${ac_cv_lib_nsl_t_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8146,13 +8154,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 $as_echo "$ac_cv_lib_nsl_t_open" >&6; } -if test "x$ac_cv_lib_nsl_t_open" = x""yes; then : +if test "x$ac_cv_lib_nsl_t_open" = xyes; then : LIBS="-lnsl $LIBS" fi # SVR4 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 $as_echo_n "checking for socket in -lsocket... " >&6; } -if test "${ac_cv_lib_socket_socket+set}" = set; then : +if ${ac_cv_lib_socket_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8186,7 +8194,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 $as_echo "$ac_cv_lib_socket_socket" >&6; } -if test "x$ac_cv_lib_socket_socket" = x""yes; then : +if test "x$ac_cv_lib_socket_socket" = xyes; then : LIBS="-lsocket $LIBS" fi # SVR4 sockets @@ -8195,7 +8203,7 @@ BeOS*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnet" >&5 $as_echo_n "checking for socket in -lnet... " >&6; } -if test "${ac_cv_lib_net_socket+set}" = set; then : +if ${ac_cv_lib_net_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8229,7 +8237,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_net_socket" >&5 $as_echo "$ac_cv_lib_net_socket" >&6; } -if test "x$ac_cv_lib_net_socket" = x""yes; then : +if test "x$ac_cv_lib_net_socket" = xyes; then : LIBS="-lnet $LIBS" fi # BeOS @@ -8257,7 +8265,7 @@ set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_PKG_CONFIG+set}" = set; then : +if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in @@ -8300,7 +8308,7 @@ set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then : +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in @@ -8568,7 +8576,7 @@ $as_echo "#define _REENTRANT 1" >>confdefs.h ac_fn_c_check_header_mongrel "$LINENO" "cthreads.h" "ac_cv_header_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_cthreads_h" = x""yes; then : +if test "x$ac_cv_header_cthreads_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8581,7 +8589,7 @@ else ac_fn_c_check_header_mongrel "$LINENO" "mach/cthreads.h" "ac_cv_header_mach_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_mach_cthreads_h" = x""yes; then : +if test "x$ac_cv_header_mach_cthreads_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8643,7 +8651,7 @@ LIBS=$_libs ac_fn_c_check_func "$LINENO" "pthread_detach" "ac_cv_func_pthread_detach" -if test "x$ac_cv_func_pthread_detach" = x""yes; then : +if test "x$ac_cv_func_pthread_detach" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8651,7 +8659,7 @@ else ac_fn_c_check_header_mongrel "$LINENO" "atheos/threads.h" "ac_cv_header_atheos_threads_h" "$ac_includes_default" -if test "x$ac_cv_header_atheos_threads_h" = x""yes; then : +if test "x$ac_cv_header_atheos_threads_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h @@ -8661,7 +8669,7 @@ else ac_fn_c_check_header_mongrel "$LINENO" "kernel/OS.h" "ac_cv_header_kernel_OS_h" "$ac_includes_default" -if test "x$ac_cv_header_kernel_OS_h" = x""yes; then : +if test "x$ac_cv_header_kernel_OS_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h @@ -8672,7 +8680,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 $as_echo_n "checking for pthread_create in -lpthreads... " >&6; } -if test "${ac_cv_lib_pthreads_pthread_create+set}" = set; then : +if ${ac_cv_lib_pthreads_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8706,7 +8714,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 $as_echo "$ac_cv_lib_pthreads_pthread_create" >&6; } -if test "x$ac_cv_lib_pthreads_pthread_create" = x""yes; then : +if test "x$ac_cv_lib_pthreads_pthread_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8716,7 +8724,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 $as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if test "${ac_cv_lib_c_r_pthread_create+set}" = set; then : +if ${ac_cv_lib_c_r_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8750,7 +8758,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 $as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = x""yes; then : +if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8760,7 +8768,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_create_system in -lpthread" >&5 $as_echo_n "checking for __pthread_create_system in -lpthread... " >&6; } -if test "${ac_cv_lib_pthread___pthread_create_system+set}" = set; then : +if ${ac_cv_lib_pthread___pthread_create_system+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8794,7 +8802,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_create_system" >&5 $as_echo "$ac_cv_lib_pthread___pthread_create_system" >&6; } -if test "x$ac_cv_lib_pthread___pthread_create_system" = x""yes; then : +if test "x$ac_cv_lib_pthread___pthread_create_system" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8804,7 +8812,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lcma" >&5 $as_echo_n "checking for pthread_create in -lcma... " >&6; } -if test "${ac_cv_lib_cma_pthread_create+set}" = set; then : +if ${ac_cv_lib_cma_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8838,7 +8846,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cma_pthread_create" >&5 $as_echo "$ac_cv_lib_cma_pthread_create" >&6; } -if test "x$ac_cv_lib_cma_pthread_create" = x""yes; then : +if test "x$ac_cv_lib_cma_pthread_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8878,7 +8886,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usconfig in -lmpc" >&5 $as_echo_n "checking for usconfig in -lmpc... " >&6; } -if test "${ac_cv_lib_mpc_usconfig+set}" = set; then : +if ${ac_cv_lib_mpc_usconfig+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8912,7 +8920,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mpc_usconfig" >&5 $as_echo "$ac_cv_lib_mpc_usconfig" >&6; } -if test "x$ac_cv_lib_mpc_usconfig" = x""yes; then : +if test "x$ac_cv_lib_mpc_usconfig" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lmpc" @@ -8924,7 +8932,7 @@ if test "$posix_threads" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for thr_create in -lthread" >&5 $as_echo_n "checking for thr_create in -lthread... " >&6; } -if test "${ac_cv_lib_thread_thr_create+set}" = set; then : +if ${ac_cv_lib_thread_thr_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8958,7 +8966,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_thread_thr_create" >&5 $as_echo "$ac_cv_lib_thread_thr_create" >&6; } -if test "x$ac_cv_lib_thread_thr_create" = x""yes; then : +if test "x$ac_cv_lib_thread_thr_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lthread" @@ -9003,7 +9011,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PTHREAD_SCOPE_SYSTEM is supported" >&5 $as_echo_n "checking if PTHREAD_SCOPE_SYSTEM is supported... " >&6; } - if test "${ac_cv_pthread_system_supported+set}" = set; then : + if ${ac_cv_pthread_system_supported+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -9046,7 +9054,7 @@ for ac_func in pthread_sigmask do : ac_fn_c_check_func "$LINENO" "pthread_sigmask" "ac_cv_func_pthread_sigmask" -if test "x$ac_cv_func_pthread_sigmask" = x""yes; then : +if test "x$ac_cv_func_pthread_sigmask" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_SIGMASK 1 _ACEOF @@ -9436,7 +9444,7 @@ $as_echo "$with_valgrind" >&6; } if test "$with_valgrind" != no; then ac_fn_c_check_header_mongrel "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_valgrind_h" = x""yes; then : +if test "x$ac_cv_header_valgrind_valgrind_h" = xyes; then : $as_echo "#define WITH_VALGRIND 1" >>confdefs.h @@ -9480,7 +9488,7 @@ for ac_func in dlopen do : ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = x""yes; then : +if test "x$ac_cv_func_dlopen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLOPEN 1 _ACEOF @@ -9810,7 +9818,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock declaration" >&5 $as_echo_n "checking for flock declaration... " >&6; } -if test "${ac_cv_flock_decl+set}" = set; then : +if ${ac_cv_flock_decl+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -9840,7 +9848,7 @@ for ac_func in flock do : ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" -if test "x$ac_cv_func_flock" = x""yes; then : +if test "x$ac_cv_func_flock" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FLOCK 1 _ACEOF @@ -9848,7 +9856,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 $as_echo_n "checking for flock in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_flock+set}" = set; then : +if ${ac_cv_lib_bsd_flock+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9882,7 +9890,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_flock" >&5 $as_echo "$ac_cv_lib_bsd_flock" >&6; } -if test "x$ac_cv_lib_bsd_flock" = x""yes; then : +if test "x$ac_cv_lib_bsd_flock" = xyes; then : $as_echo "#define HAVE_FLOCK 1" >>confdefs.h @@ -9959,7 +9967,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_TRUE+set}" = set; then : +if ${ac_cv_prog_TRUE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$TRUE"; then @@ -9999,7 +10007,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lc" >&5 $as_echo_n "checking for inet_aton in -lc... " >&6; } -if test "${ac_cv_lib_c_inet_aton+set}" = set; then : +if ${ac_cv_lib_c_inet_aton+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10033,12 +10041,12 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_aton" >&5 $as_echo "$ac_cv_lib_c_inet_aton" >&6; } -if test "x$ac_cv_lib_c_inet_aton" = x""yes; then : +if test "x$ac_cv_lib_c_inet_aton" = xyes; then : $ac_cv_prog_TRUE else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 $as_echo_n "checking for inet_aton in -lresolv... " >&6; } -if test "${ac_cv_lib_resolv_inet_aton+set}" = set; then : +if ${ac_cv_lib_resolv_inet_aton+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10072,7 +10080,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5 $as_echo "$ac_cv_lib_resolv_inet_aton" >&6; } -if test "x$ac_cv_lib_resolv_inet_aton" = x""yes; then : +if test "x$ac_cv_lib_resolv_inet_aton" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF @@ -10089,7 +10097,7 @@ # exit Python { $as_echo "$as_me:${as_lineno-$LINENO}: checking for chflags" >&5 $as_echo_n "checking for chflags... " >&6; } -if test "${ac_cv_have_chflags+set}" = set; then : +if ${ac_cv_have_chflags+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10123,7 +10131,7 @@ $as_echo "$ac_cv_have_chflags" >&6; } if test "$ac_cv_have_chflags" = cross ; then ac_fn_c_check_func "$LINENO" "chflags" "ac_cv_func_chflags" -if test "x$ac_cv_func_chflags" = x""yes; then : +if test "x$ac_cv_func_chflags" = xyes; then : ac_cv_have_chflags="yes" else ac_cv_have_chflags="no" @@ -10138,7 +10146,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lchflags" >&5 $as_echo_n "checking for lchflags... " >&6; } -if test "${ac_cv_have_lchflags+set}" = set; then : +if ${ac_cv_have_lchflags+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10172,7 +10180,7 @@ $as_echo "$ac_cv_have_lchflags" >&6; } if test "$ac_cv_have_lchflags" = cross ; then ac_fn_c_check_func "$LINENO" "lchflags" "ac_cv_func_lchflags" -if test "x$ac_cv_func_lchflags" = x""yes; then : +if test "x$ac_cv_func_lchflags" = xyes; then : ac_cv_have_lchflags="yes" else ac_cv_have_lchflags="no" @@ -10196,7 +10204,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 $as_echo_n "checking for inflateCopy in -lz... " >&6; } -if test "${ac_cv_lib_z_inflateCopy+set}" = set; then : +if ${ac_cv_lib_z_inflateCopy+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10230,7 +10238,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 $as_echo "$ac_cv_lib_z_inflateCopy" >&6; } -if test "x$ac_cv_lib_z_inflateCopy" = x""yes; then : +if test "x$ac_cv_lib_z_inflateCopy" = xyes; then : $as_echo "#define HAVE_ZLIB_COPY 1" >>confdefs.h @@ -10373,7 +10381,7 @@ for ac_func in openpty do : ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty" -if test "x$ac_cv_func_openpty" = x""yes; then : +if test "x$ac_cv_func_openpty" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENPTY 1 _ACEOF @@ -10381,7 +10389,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 $as_echo_n "checking for openpty in -lutil... " >&6; } -if test "${ac_cv_lib_util_openpty+set}" = set; then : +if ${ac_cv_lib_util_openpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10415,13 +10423,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 $as_echo "$ac_cv_lib_util_openpty" >&6; } -if test "x$ac_cv_lib_util_openpty" = x""yes; then : +if test "x$ac_cv_lib_util_openpty" = xyes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 $as_echo_n "checking for openpty in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_openpty+set}" = set; then : +if ${ac_cv_lib_bsd_openpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10455,7 +10463,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_openpty" >&5 $as_echo "$ac_cv_lib_bsd_openpty" >&6; } -if test "x$ac_cv_lib_bsd_openpty" = x""yes; then : +if test "x$ac_cv_lib_bsd_openpty" = xyes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10470,7 +10478,7 @@ for ac_func in forkpty do : ac_fn_c_check_func "$LINENO" "forkpty" "ac_cv_func_forkpty" -if test "x$ac_cv_func_forkpty" = x""yes; then : +if test "x$ac_cv_func_forkpty" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FORKPTY 1 _ACEOF @@ -10478,7 +10486,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 $as_echo_n "checking for forkpty in -lutil... " >&6; } -if test "${ac_cv_lib_util_forkpty+set}" = set; then : +if ${ac_cv_lib_util_forkpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10512,13 +10520,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_forkpty" >&5 $as_echo "$ac_cv_lib_util_forkpty" >&6; } -if test "x$ac_cv_lib_util_forkpty" = x""yes; then : +if test "x$ac_cv_lib_util_forkpty" = xyes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 $as_echo_n "checking for forkpty in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_forkpty+set}" = set; then : +if ${ac_cv_lib_bsd_forkpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10552,7 +10560,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_forkpty" >&5 $as_echo "$ac_cv_lib_bsd_forkpty" >&6; } -if test "x$ac_cv_lib_bsd_forkpty" = x""yes; then : +if test "x$ac_cv_lib_bsd_forkpty" = xyes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10569,7 +10577,7 @@ for ac_func in memmove do : ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" -if test "x$ac_cv_func_memmove" = x""yes; then : +if test "x$ac_cv_func_memmove" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MEMMOVE 1 _ACEOF @@ -10593,7 +10601,7 @@ ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" -if test "x$ac_cv_func_dup2" = x""yes; then : +if test "x$ac_cv_func_dup2" = xyes; then : $as_echo "#define HAVE_DUP2 1" >>confdefs.h else @@ -10606,7 +10614,7 @@ fi ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" -if test "x$ac_cv_func_getcwd" = x""yes; then : +if test "x$ac_cv_func_getcwd" = xyes; then : $as_echo "#define HAVE_GETCWD 1" >>confdefs.h else @@ -10619,7 +10627,7 @@ fi ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup" -if test "x$ac_cv_func_strdup" = x""yes; then : +if test "x$ac_cv_func_strdup" = xyes; then : $as_echo "#define HAVE_STRDUP 1" >>confdefs.h else @@ -10635,7 +10643,7 @@ for ac_func in getpgrp do : ac_fn_c_check_func "$LINENO" "getpgrp" "ac_cv_func_getpgrp" -if test "x$ac_cv_func_getpgrp" = x""yes; then : +if test "x$ac_cv_func_getpgrp" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETPGRP 1 _ACEOF @@ -10663,7 +10671,7 @@ for ac_func in setpgrp do : ac_fn_c_check_func "$LINENO" "setpgrp" "ac_cv_func_setpgrp" -if test "x$ac_cv_func_setpgrp" = x""yes; then : +if test "x$ac_cv_func_setpgrp" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETPGRP 1 _ACEOF @@ -10691,7 +10699,7 @@ for ac_func in gettimeofday do : ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" -if test "x$ac_cv_func_gettimeofday" = x""yes; then : +if test "x$ac_cv_func_gettimeofday" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETTIMEOFDAY 1 _ACEOF @@ -10793,7 +10801,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking getaddrinfo bug" >&5 $as_echo_n "checking getaddrinfo bug... " >&6; } - if test "${ac_cv_buggy_getaddrinfo+set}" = set; then : + if ${ac_cv_buggy_getaddrinfo+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10922,7 +10930,7 @@ for ac_func in getnameinfo do : ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo" -if test "x$ac_cv_func_getnameinfo" = x""yes; then : +if test "x$ac_cv_func_getnameinfo" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETNAMEINFO 1 _ACEOF @@ -10934,7 +10942,7 @@ # checks for structures { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if test "${ac_cv_header_time+set}" = set; then : +if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10969,7 +10977,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if test "${ac_cv_struct_tm+set}" = set; then : +if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11006,7 +11014,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -11022,7 +11030,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = x""yes; then : +if test "x$ac_cv_have_decl_tzname" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11034,7 +11042,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if test "${ac_cv_var_tzname+set}" = set; then : +if ${ac_cv_var_tzname+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11070,7 +11078,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_RDEV 1 @@ -11080,7 +11088,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blksize" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 @@ -11090,7 +11098,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_flags" "ac_cv_member_struct_stat_st_flags" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_flags" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_flags" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_FLAGS 1 @@ -11100,7 +11108,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_gen" "ac_cv_member_struct_stat_st_gen" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_gen" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_gen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_GEN 1 @@ -11110,7 +11118,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtime" "ac_cv_member_struct_stat_st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtime" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_birthtime" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 @@ -11120,7 +11128,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blocks" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLOCKS 1 @@ -11142,7 +11150,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 $as_echo_n "checking for time.h that defines altzone... " >&6; } -if test "${ac_cv_header_time_altzone+set}" = set; then : +if ${ac_cv_header_time_altzone+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11206,7 +11214,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for addrinfo" >&5 $as_echo_n "checking for addrinfo... " >&6; } -if test "${ac_cv_struct_addrinfo+set}" = set; then : +if ${ac_cv_struct_addrinfo+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11238,7 +11246,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sockaddr_storage" >&5 $as_echo_n "checking for sockaddr_storage... " >&6; } -if test "${ac_cv_struct_sockaddr_storage+set}" = set; then : +if ${ac_cv_struct_sockaddr_storage+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11274,7 +11282,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether char is unsigned" >&5 $as_echo_n "checking whether char is unsigned... " >&6; } -if test "${ac_cv_c_char_unsigned+set}" = set; then : +if ${ac_cv_c_char_unsigned+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11306,7 +11314,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if test "${ac_cv_c_const+set}" = set; then : +if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11594,7 +11602,7 @@ ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" -if test "x$ac_cv_func_gethostbyname_r" = x""yes; then : +if test "x$ac_cv_func_gethostbyname_r" = xyes; then : $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h @@ -11725,7 +11733,7 @@ for ac_func in gethostbyname do : ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = x""yes; then : +if test "x$ac_cv_func_gethostbyname" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTBYNAME 1 _ACEOF @@ -11747,12 +11755,12 @@ # Linux requires this for correct f.p. operations ac_fn_c_check_func "$LINENO" "__fpu_control" "ac_cv_func___fpu_control" -if test "x$ac_cv_func___fpu_control" = x""yes; then : +if test "x$ac_cv_func___fpu_control" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 $as_echo_n "checking for __fpu_control in -lieee... " >&6; } -if test "${ac_cv_lib_ieee___fpu_control+set}" = set; then : +if ${ac_cv_lib_ieee___fpu_control+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -11786,7 +11794,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee___fpu_control" >&5 $as_echo "$ac_cv_lib_ieee___fpu_control" >&6; } -if test "x$ac_cv_lib_ieee___fpu_control" = x""yes; then : +if test "x$ac_cv_lib_ieee___fpu_control" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBIEEE 1 _ACEOF @@ -11881,7 +11889,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are little-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are little-endian IEEE 754 binary64... " >&6; } -if test "${ac_cv_little_endian_double+set}" = set; then : +if ${ac_cv_little_endian_double+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11923,7 +11931,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are big-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are big-endian IEEE 754 binary64... " >&6; } -if test "${ac_cv_big_endian_double+set}" = set; then : +if ${ac_cv_big_endian_double+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11969,7 +11977,7 @@ # conversions work. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are ARM mixed-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are ARM mixed-endian IEEE 754 binary64... " >&6; } -if test "${ac_cv_mixed_endian_double+set}" = set; then : +if ${ac_cv_mixed_endian_double+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12117,7 +12125,7 @@ # -0. on some architectures. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tanh preserves the sign of zero" >&5 $as_echo_n "checking whether tanh preserves the sign of zero... " >&6; } -if test "${ac_cv_tanh_preserves_zero_sign+set}" = set; then : +if ${ac_cv_tanh_preserves_zero_sign+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12185,7 +12193,7 @@ ac_fn_c_check_decl "$LINENO" "isinf" "ac_cv_have_decl_isinf" "#include " -if test "x$ac_cv_have_decl_isinf" = x""yes; then : +if test "x$ac_cv_have_decl_isinf" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -12196,7 +12204,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isnan" "ac_cv_have_decl_isnan" "#include " -if test "x$ac_cv_have_decl_isnan" = x""yes; then : +if test "x$ac_cv_have_decl_isnan" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -12207,7 +12215,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isfinite" "ac_cv_have_decl_isfinite" "#include " -if test "x$ac_cv_have_decl_isfinite" = x""yes; then : +if test "x$ac_cv_have_decl_isfinite" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -12227,7 +12235,7 @@ # sem_open results in a 'Signal 12' error. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX semaphores are enabled" >&5 $as_echo_n "checking whether POSIX semaphores are enabled... " >&6; } -if test "${ac_cv_posix_semaphores_enabled+set}" = set; then : +if ${ac_cv_posix_semaphores_enabled+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12278,7 +12286,7 @@ # Multiprocessing check for broken sem_getvalue { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken sem_getvalue" >&5 $as_echo_n "checking for broken sem_getvalue... " >&6; } -if test "${ac_cv_broken_sem_getvalue+set}" = set; then : +if ${ac_cv_broken_sem_getvalue+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12343,7 +12351,7 @@ 15|30) ;; *) - as_fn_error $? "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; + as_fn_error $? "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_big_digits" >&5 $as_echo "$enable_big_digits" >&6; } @@ -12361,7 +12369,7 @@ # check for wchar.h ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" -if test "x$ac_cv_header_wchar_h" = x""yes; then : +if test "x$ac_cv_header_wchar_h" = xyes; then : $as_echo "#define HAVE_WCHAR_H 1" >>confdefs.h @@ -12384,7 +12392,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 $as_echo_n "checking size of wchar_t... " >&6; } -if test "${ac_cv_sizeof_wchar_t+set}" = set; then : +if ${ac_cv_sizeof_wchar_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include @@ -12395,7 +12403,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (wchar_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_wchar_t=0 fi @@ -12450,7 +12458,7 @@ # check whether wchar_t is signed or not { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wchar_t is signed" >&5 $as_echo_n "checking whether wchar_t is signed... " >&6; } - if test "${ac_cv_wchar_t_signed+set}" = set; then : + if ${ac_cv_wchar_t_signed+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12514,7 +12522,7 @@ $as_echo "#define Py_UNICODE_SIZE 4" >>confdefs.h ;; -*) as_fn_error $? "invalid value for --enable-unicode. Use either ucs2 or ucs4 (lowercase)." "$LINENO" 5 ;; +*) as_fn_error $? "invalid value for --enable-unicode. Use either ucs2 or ucs4 (lowercase)." "$LINENO" 5 ;; esac @@ -12561,7 +12569,7 @@ # check for endianness { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if test "${ac_cv_c_bigendian+set}" = set; then : +if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown @@ -12780,7 +12788,7 @@ ;; #( *) as_fn_error $? "unknown endianness - presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac @@ -12788,7 +12796,7 @@ # or fills with zeros (like the Cray J90, according to Tim Peters). { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether right shift extends the sign bit" >&5 $as_echo_n "checking whether right shift extends the sign bit... " >&6; } -if test "${ac_cv_rshift_extends_sign+set}" = set; then : +if ${ac_cv_rshift_extends_sign+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12827,7 +12835,7 @@ # check for getc_unlocked and related locking functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getc_unlocked() and friends" >&5 $as_echo_n "checking for getc_unlocked() and friends... " >&6; } -if test "${ac_cv_have_getc_unlocked+set}" = set; then : +if ${ac_cv_have_getc_unlocked+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12925,7 +12933,7 @@ # check for readline 2.1 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_callback_handler_install in -lreadline" >&5 $as_echo_n "checking for rl_callback_handler_install in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_callback_handler_install+set}" = set; then : +if ${ac_cv_lib_readline_rl_callback_handler_install+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12959,7 +12967,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_callback_handler_install" >&5 $as_echo "$ac_cv_lib_readline_rl_callback_handler_install" >&6; } -if test "x$ac_cv_lib_readline_rl_callback_handler_install" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_callback_handler_install" = xyes; then : $as_echo "#define HAVE_RL_CALLBACK 1" >>confdefs.h @@ -13011,7 +13019,7 @@ # check for readline 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_pre_input_hook in -lreadline" >&5 $as_echo_n "checking for rl_pre_input_hook in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_pre_input_hook+set}" = set; then : +if ${ac_cv_lib_readline_rl_pre_input_hook+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -13045,7 +13053,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_pre_input_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_pre_input_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_pre_input_hook" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_pre_input_hook" = xyes; then : $as_echo "#define HAVE_RL_PRE_INPUT_HOOK 1" >>confdefs.h @@ -13055,7 +13063,7 @@ # also in 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_display_matches_hook in -lreadline" >&5 $as_echo_n "checking for rl_completion_display_matches_hook in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_completion_display_matches_hook+set}" = set; then : +if ${ac_cv_lib_readline_rl_completion_display_matches_hook+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -13089,7 +13097,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_display_matches_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_display_matches_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = xyes; then : $as_echo "#define HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK 1" >>confdefs.h @@ -13099,7 +13107,7 @@ # check for readline 4.2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_matches in -lreadline" >&5 $as_echo_n "checking for rl_completion_matches in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_completion_matches+set}" = set; then : +if ${ac_cv_lib_readline_rl_completion_matches+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -13133,7 +13141,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_matches" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_matches" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_matches" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_completion_matches" = xyes; then : $as_echo "#define HAVE_RL_COMPLETION_MATCHES 1" >>confdefs.h @@ -13174,7 +13182,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken nice()" >&5 $as_echo_n "checking for broken nice()... " >&6; } -if test "${ac_cv_broken_nice+set}" = set; then : +if ${ac_cv_broken_nice+:} false; then : $as_echo_n "(cached) " >&6 else @@ -13215,7 +13223,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken poll()" >&5 $as_echo_n "checking for broken poll()... " >&6; } -if test "${ac_cv_broken_poll+set}" = set; then : +if ${ac_cv_broken_poll+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13270,7 +13278,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -13286,7 +13294,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = x""yes; then : +if test "x$ac_cv_have_decl_tzname" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -13298,7 +13306,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if test "${ac_cv_var_tzname+set}" = set; then : +if ${ac_cv_var_tzname+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13337,7 +13345,7 @@ # check tzset(3) exists and works like we expect it to { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working tzset()" >&5 $as_echo_n "checking for working tzset()... " >&6; } -if test "${ac_cv_working_tzset+set}" = set; then : +if ${ac_cv_working_tzset+:} false; then : $as_echo_n "(cached) " >&6 else @@ -13434,7 +13442,7 @@ # Look for subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec in struct stat" >&5 $as_echo_n "checking for tv_nsec in struct stat... " >&6; } -if test "${ac_cv_stat_tv_nsec+set}" = set; then : +if ${ac_cv_stat_tv_nsec+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13471,7 +13479,7 @@ # Look for BSD style subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec2 in struct stat" >&5 $as_echo_n "checking for tv_nsec2 in struct stat... " >&6; } -if test "${ac_cv_stat_tv_nsec2+set}" = set; then : +if ${ac_cv_stat_tv_nsec2+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13508,7 +13516,7 @@ # On HP/UX 11.0, mvwdelch is a block with a return statement { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mvwdelch is an expression" >&5 $as_echo_n "checking whether mvwdelch is an expression... " >&6; } -if test "${ac_cv_mvwdelch_is_expression+set}" = set; then : +if ${ac_cv_mvwdelch_is_expression+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13545,7 +13553,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether WINDOW has _flags" >&5 $as_echo_n "checking whether WINDOW has _flags... " >&6; } -if test "${ac_cv_window_has_flags+set}" = set; then : +if ${ac_cv_window_has_flags+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13693,7 +13701,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %lld and %llu printf() format support" >&5 $as_echo_n "checking for %lld and %llu printf() format support... " >&6; } - if test "${ac_cv_have_long_long_format+set}" = set; then : + if ${ac_cv_have_long_long_format+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13764,7 +13772,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %zd printf() format support" >&5 $as_echo_n "checking for %zd printf() format support... " >&6; } -if test "${ac_cv_have_size_t_format+set}" = set; then : +if ${ac_cv_have_size_t_format+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13837,7 +13845,7 @@ #endif " -if test "x$ac_cv_type_socklen_t" = x""yes; then : +if test "x$ac_cv_type_socklen_t" = xyes; then : else @@ -13942,10 +13950,21 @@ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && + if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} @@ -13978,7 +13997,7 @@ -: ${CONFIG_STATUS=./config.status} +: "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" @@ -14079,6 +14098,7 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -14386,7 +14406,7 @@ # values after options handling. ac_log=" This file was extended by python $as_me 2.7, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -14448,7 +14468,7 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ python config.status 2.7 -configured by $0, generated by GNU Autoconf 2.67, +configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. @@ -14580,7 +14600,7 @@ "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; "Modules/ld_so_aix") CONFIG_FILES="$CONFIG_FILES Modules/ld_so_aix" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done @@ -14602,9 +14622,10 @@ # after its creation but before its name has been assigned to `$tmp'. $debug || { - tmp= + tmp= ac_tmp= trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } @@ -14612,12 +14633,13 @@ { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" + test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -14639,7 +14661,7 @@ ac_cs_awk_cr=$ac_cr fi -echo 'BEGIN {' >"$tmp/subs1.awk" && +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF @@ -14667,7 +14689,7 @@ rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h @@ -14715,7 +14737,7 @@ rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$tmp/subs1.awk" <<_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" @@ -14747,7 +14769,7 @@ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF @@ -14781,7 +14803,7 @@ # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then -cat >"$tmp/defines.awk" <<\_ACAWK || +cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF @@ -14793,8 +14815,8 @@ # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do - ac_t=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_t"; then + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 @@ -14895,7 +14917,7 @@ esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -14914,7 +14936,7 @@ for ac_f do case $ac_f in - -) ac_f="$tmp/stdin";; + -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. @@ -14923,7 +14945,7 @@ [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" @@ -14949,8 +14971,8 @@ esac case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -15080,21 +15102,22 @@ s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} - rm -f "$tmp/stdin" + rm -f "$ac_tmp/stdin" case $ac_file in - -) cat "$tmp/out" && rm -f "$tmp/out";; - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; @@ -15105,20 +15128,20 @@ if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" - } >"$tmp/config.h" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" - mv "$tmp/config.h" "$ac_file" \ + mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; diff --git a/configure.in b/configure.ac rename from configure.in rename to configure.ac diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1,4 +1,4 @@ -/* pyconfig.h.in. Generated from configure.in by autoheader. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ #ifndef Py_PYCONFIG_H -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:41:26 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 14 Mar 2012 23:41:26 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_remove_get=5Fprefix_and_set?= =?utf8?q?=5Fprefix_=28=2313248=29?= Message-ID: http://hg.python.org/cpython/rev/b30171bbc571 changeset: 75669:b30171bbc571 parent: 75666:587bca79599f user: Benjamin Peterson date: Wed Mar 14 17:41:15 2012 -0500 summary: remove get_prefix and set_prefix (#13248) files: Lib/lib2to3/pytree.py | 20 -------------------- Lib/lib2to3/tests/test_pytree.py | 17 ----------------- Misc/NEWS | 2 ++ 3 files changed, 2 insertions(+), 37 deletions(-) diff --git a/Lib/lib2to3/pytree.py b/Lib/lib2to3/pytree.py --- a/Lib/lib2to3/pytree.py +++ b/Lib/lib2to3/pytree.py @@ -109,26 +109,6 @@ """ raise NotImplementedError - def set_prefix(self, prefix): - """ - Set the prefix for the node (see Leaf class). - - DEPRECATED; use the prefix property directly. - """ - warnings.warn("set_prefix() is deprecated; use the prefix property", - DeprecationWarning, stacklevel=2) - self.prefix = prefix - - def get_prefix(self): - """ - Return the prefix for the node (see Leaf class). - - DEPRECATED; use the prefix property directly. - """ - warnings.warn("get_prefix() is deprecated; use the prefix property", - DeprecationWarning, stacklevel=2) - return self.prefix - def replace(self, new): """Replace this node with a new one in the parent.""" assert self.parent is not None, str(self) diff --git a/Lib/lib2to3/tests/test_pytree.py b/Lib/lib2to3/tests/test_pytree.py --- a/Lib/lib2to3/tests/test_pytree.py +++ b/Lib/lib2to3/tests/test_pytree.py @@ -31,23 +31,6 @@ """Unit tests for nodes (Base, Leaf, Node).""" - if sys.version_info >= (2,6): - # warnings.catch_warnings is new in 2.6. - def test_deprecated_prefix_methods(self): - l = pytree.Leaf(100, "foo") - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always", DeprecationWarning) - self.assertEqual(l.get_prefix(), "") - l.set_prefix("hi") - self.assertEqual(l.prefix, "hi") - self.assertEqual(len(w), 2) - for warning in w: - self.assertTrue(warning.category is DeprecationWarning) - self.assertEqual(str(w[0].message), "get_prefix() is deprecated; " \ - "use the prefix property") - self.assertEqual(str(w[1].message), "set_prefix() is deprecated; " \ - "use the prefix property") - def test_instantiate_base(self): if __debug__: # Test that instantiating Base() raises an AssertionError diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #13248: Remove lib2to3.pytree.Base.get_prefix/set_prefix. + - Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 14 23:42:01 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 14 Mar 2012 23:42:01 +0100 Subject: [Python-checkins] =?utf8?q?devguide=3A_Add_unittest=2Emock_inform?= =?utf8?q?ation?= Message-ID: http://hg.python.org/devguide/rev/82cef2985e2f changeset: 496:82cef2985e2f user: Michael Foord date: Wed Mar 14 15:41:54 2012 -0700 summary: Add unittest.mock information files: experts.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -231,7 +231,8 @@ turtle gregorlingl types unicodedata loewis, lemburg, ezio.melotti -unittest michael.foord, ezio.melotti +unittest michael.foord*, ezio.melotti +unittest.mock michael.foord* urllib orsenthil uu uuid -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Mar 15 00:21:50 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 00:21:50 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_compiler_warnings?= Message-ID: http://hg.python.org/cpython/rev/b4ca2f17dde4 changeset: 75670:b4ca2f17dde4 user: Benjamin Peterson date: Wed Mar 14 18:21:35 2012 -0500 summary: fix compiler warnings files: Modules/_cursesmodule.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -649,7 +649,7 @@ int rtn; int x, y; int strtype; - PyObject *strobj, *bytesobj; + PyObject *strobj, *bytesobj = NULL; #ifdef HAVE_NCURSESW wchar_t *wstr = NULL; #endif @@ -725,7 +725,7 @@ { int rtn, x, y, n; int strtype; - PyObject *strobj, *bytesobj; + PyObject *strobj, *bytesobj = NULL; #ifdef HAVE_NCURSESW wchar_t *wstr = NULL; #endif @@ -1413,7 +1413,7 @@ int rtn; int x, y; int strtype; - PyObject *strobj, *bytesobj; + PyObject *strobj, *bytesobj = NULL; #ifdef HAVE_NCURSESW wchar_t *wstr = NULL; #endif @@ -1491,7 +1491,7 @@ { int rtn, x, y, n; int strtype; - PyObject *strobj, *bytesobj; + PyObject *strobj, *bytesobj = NULL; #ifdef HAVE_NCURSESW wchar_t *wstr = NULL; #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 00:41:28 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 15 Mar 2012 00:41:28 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_416=3A_Rephrase_use_cases?= =?utf8?q?=3B_add_more_existing_implementations?= Message-ID: http://hg.python.org/peps/rev/f25d13bfea17 changeset: 4138:f25d13bfea17 user: Victor Stinner date: Thu Mar 15 00:41:46 2012 +0100 summary: PEP 416: Rephrase use cases; add more existing implementations files: pep-0416.txt | 58 +++++++++++++++++++++++++++++++++------ 1 files changed, 48 insertions(+), 10 deletions(-) diff --git a/pep-0416.txt b/pep-0416.txt --- a/pep-0416.txt +++ b/pep-0416.txt @@ -25,15 +25,17 @@ Use cases: - * frozendict lookup can be done at compile time instead of runtime because the - mapping is read-only. frozendict can be used instead of a preprocessor to - remove conditional code at compilation, like code specific to a debug build. - * hashable frozendict can be used as a key of a mapping or as a member of set. - frozendict can be used to implement a cache. + * Immutable global variable like a default configuration. + * Default value of a function parameter. Avoid the issue of mutable default arguments. + * Implement a cache: frozendict can be used to store function keywords. + frozendict can be used as a key of a mapping or as a member of set. * frozendict avoids the need of a lock when the frozendict is shared by multiple threads or processes, especially hashable frozendict. It would also help to prohibe coroutines (generators + greenlets) to modify the global state. + * frozendict lookup can be done at compile time instead of runtime because the + mapping is read-only. frozendict can be used instead of a preprocessor to + remove conditional code at compilation, like code specific to a debug build. * frozendict helps to implement read-only object proxies for security modules. For example, it would be possible to use frozendict type for __builtins__ mapping or type.__dict__. This is possible because frozendict is compatible @@ -41,8 +43,6 @@ * frozendict avoids the need of a read-only proxy in some cases. frozendict is faster than a proxy because getting an item in a frozendict is a fast lookup whereas a proxy requires a function call. - * use a frozendict as the default value of function argument: avoid the - problem of mutable default argument. Constraints @@ -137,9 +137,18 @@ has an implementation issue: it is possible to call again __init__() to modify the mapping. * PyWebmail contains an ImmutableDict type: `webmail.utils.ImmutableDict - `_. + `_. It is hashable if keys and values are hashable. It is not truly read-only: its internal dict is a public attribute. + * remember project: `remember.dicts.FrozenDict + `_. + It is used to implement a cache: FrozenDict is used to store function callbacks. + FrozenDict may be hashable. It has an extra supply_dict() class method to + create a FrozenDict from a dict without copying the dict: store the dict as + the internal dict. Implementation issue: __init__() can be called to modify + the mapping and the hash may differ depending on item creation order. The + mapping is not truly read-only: the internal dict is accessible in Python. + Blacklist approach: inherit from dict and override write methods to raise an exception. It is not truly read-only: it is still possible to call dict methods @@ -150,11 +159,40 @@ It is hashable if keys and values are hashable. werkzeug project has the same code: `werkzeug.datastructures.ImmutableDict `_. + ImmutableDict is used for global constant (configuration options). The Flask + project uses ImmutableDict of werkzeug for its default configuration. * SQLAchemy project: `sqlachemy.util.immutabledict `_. - It is not hashable and has an extra method: union(). + It is not hashable and has an extra method: union(). immutabledict is used + for the default value of parameter of some functions expecting a mapping. + Example: mapper_args=immutabledict() in SqlSoup.map(). * `Frozen dictionaries (Python recipe 414283) `_ - by Oren Tirosh. It is hashable if keys and values are hashable. + by Oren Tirosh. It is hashable if keys and values are hashable. Included in + the following projects: + + * lingospot: `frozendict/frozendict.py + `_ + * factor-graphics: frozendict type in `python/fglib/util_ext_frozendict.py + `_ + + * The gsakkis-utils project written by George Sakkis includes a frozendict + type: `datastructs.frozendict + `_ + * characters: `scripts/python/frozendict.py + `_. + It is hashable. __init__() sets __init__ to None. + * Old NLTK (1.x): `nltk.util.frozendict + `_. Keys and + values must be hashable. __init__() can be called twice to modify the + mapping. frozendict is used to "freeze" an object. + +Hashable dict: inherit from dict and just add an __hash__ method. + + * `pypy.rpython.lltypesystem.lltype.frozendict + `_. + It is hashable but don't deny modification of the mapping. + * factor-graphics: hashabledict type in `python/fglib/util_ext_frozendict.py + `_ Links -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 15 00:58:49 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 15 Mar 2012 00:58:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2310278=3A_Drop_time?= =?utf8?q?=2Emonotonic=28=29_function=2C_rename_time=2Ewallclock=28=29_to?= Message-ID: http://hg.python.org/cpython/rev/c11946846474 changeset: 75671:c11946846474 user: Victor Stinner date: Thu Mar 15 00:58:32 2012 +0100 summary: Issue #10278: Drop time.monotonic() function, rename time.wallclock() to time.steady() * On Mac OS X, time.steady() now uses mach_absolute_time(), a monotonic clock * Optimistic change: bet that CLOCK_MONOTONIC and CLOCK_REALTIME are available when clock_gettime() is available * Rewrite time.steady() documentation files: Doc/library/time.rst | 26 ++----- Doc/whatsnew/3.3.rst | 3 +- Lib/test/test_time.py | 25 +------- Modules/timemodule.c | 96 +++++++----------------------- 4 files changed, 34 insertions(+), 116 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -226,11 +226,15 @@ The earliest date for which it can generate a time is platform-dependent. -.. function:: monotonic() +.. function:: steady() - Monotonic non-decreasing clock. The clock is not related to the system clock - and cannot go backward. The reference point of the returned - value is undefined so only the difference of consecutive calls is valid. + .. index:: + single: benchmarking + + Return the current time as a floating point number expressed in seconds. + This clock advances at a steady rate relative to real time and it may not be + adjusted. The reference point of the returned value is undefined so only the + difference of consecutive calls is valid. .. versionadded:: 3.3 @@ -547,20 +551,6 @@ ('EET', 'EEST') -.. function:: wallclock() - - .. index:: - single: Wallclock - single: benchmarking - - Return the current time in fractions of a second to the system's best ability. - Use this when the most accurate representation of wall-clock is required, i.e. - when "processor time" is inappropriate. The reference point of the returned - value is undefined so only the difference of consecutive calls is valid. - - .. versionadded:: 3.3 - - .. seealso:: Module :mod:`datetime` diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -943,8 +943,7 @@ * :func:`~time.clock_getres` and :func:`~time.clock_gettime` functions and ``CLOCK_xxx`` constants. -* :func:`~time.monotonic`: monotonic clock. -* :func:`~time.wallclock`. +* :func:`~time.steady`. (Contributed by Victor Stinner in :issue:`10278`) diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -331,29 +331,10 @@ pass self.assertEqual(time.strftime('%Z', tt), tzname) - @unittest.skipUnless(hasattr(time, 'monotonic'), - 'need time.monotonic()') - def test_monotonic(self): - t1 = time.monotonic() - t2 = time.monotonic() - self.assertGreaterEqual(t2, t1) - - t1 = time.monotonic() + def test_steady(self): + t1 = time.steady() time.sleep(0.1) - t2 = time.monotonic() - dt = t2 - t1 - self.assertGreater(t2, t1) - self.assertAlmostEqual(dt, 0.1, delta=0.2) - - def test_wallclock(self): - t1 = time.wallclock() - t2 = time.wallclock() - # may fail if the system clock was changed - self.assertGreaterEqual(t2, t1) - - t1 = time.wallclock() - time.sleep(0.1) - t2 = time.wallclock() + t2 = time.steady() dt = t2 - t1 # may fail if the system clock was changed self.assertGreater(t2, t1) diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -769,22 +769,29 @@ #endif /* HAVE_WORKING_TZSET */ static PyObject * -time_wallclock(PyObject *self, PyObject *unused) +time_steady(PyObject *self, PyObject *unused) { #if defined(MS_WINDOWS) && !defined(__BORLANDC__) return win32_clock(1); -#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) +#elif defined(__APPLE__) + uint64_t time = mach_absolute_time(); + double secs; + + static mach_timebase_info_data_t timebase; + if (timebase.denom == 0) + mach_timebase_info(&timebase); + + secs = (double)time * timebase.numer / timebase.denom * 1e-9; + + return PyFloat_FromDouble(secs); +#elif defined(HAVE_CLOCK_GETTIME) static int clk_index = 0; clockid_t clk_ids[] = { #ifdef CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC_RAW, #endif - CLOCK_MONOTONIC -#ifdef CLOCK_REALTIME - /* On Linux, CLOCK_REALTIME uses the same clock than gettimeofday(), - but clock_gettime() has a nanosecond resolution. */ - , CLOCK_REALTIME -#endif + CLOCK_MONOTONIC, + CLOCK_REALTIME }; int ret; struct timespec tp; @@ -805,70 +812,14 @@ #endif } -PyDoc_STRVAR(wallclock_doc, -"wallclock() -> float\n\ +PyDoc_STRVAR(steady_doc, +"steady() -> float\n\ \n\ -Return the current time in fractions of a second to the system's best\n\ -ability. Use this when the most accurate representation of wall-clock is\n\ -required, i.e. when \"processor time\" is inappropriate. The reference point\n\ -of the returned value is undefined so only the difference of consecutive\n\ -calls is valid."); +Return the current time as a floating point number expressed in seconds.\n\ +This clock advances at a steady rate relative to real time and it may not\n\ +be adjusted. The reference point of the returned value is undefined so only\n\ +the difference of consecutive calls is valid."); -#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) \ - || (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)) \ - || (defined(__APPLE__)) -# define HAVE_PYTIME_MONOTONIC -#endif - -#ifdef HAVE_PYTIME_MONOTONIC -static PyObject * -time_monotonic(PyObject *self, PyObject *unused) -{ -#if defined(MS_WINDOWS) && !defined(__BORLANDC__) - return win32_clock(0); -#elif defined(__APPLE__) - uint64_t time = mach_absolute_time(); - double secs; - - static mach_timebase_info_data_t timebase; - if (timebase.denom == 0) - mach_timebase_info(&timebase); - - secs = (double)time * timebase.numer / timebase.denom * 1e-9; - - return PyFloat_FromDouble(secs); -#else - static int clk_index = 0; - clockid_t clk_ids[] = { -#ifdef CLOCK_MONOTONIC_RAW - CLOCK_MONOTONIC_RAW, -#endif - CLOCK_MONOTONIC - }; - int ret; - struct timespec tp; - - while (0 <= clk_index) { - clockid_t clk_id = clk_ids[clk_index]; - ret = clock_gettime(clk_id, &tp); - if (ret == 0) - return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); - - clk_index++; - if (Py_ARRAY_LENGTH(clk_ids) <= clk_index) - clk_index = -1; - } - PyErr_SetFromErrno(PyExc_OSError); - return NULL; -#endif -} - -PyDoc_STRVAR(monotonic_doc, -"monotonic() -> float\n\ -\n\ -Monotonic clock. The reference point of the returned value is undefined so\n\ -only the difference of consecutive calls is valid."); -#endif static void PyInit_timezone(PyObject *m) { @@ -998,9 +949,7 @@ #ifdef HAVE_MKTIME {"mktime", time_mktime, METH_O, mktime_doc}, #endif -#ifdef HAVE_PYTIME_MONOTONIC - {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc}, -#endif + {"steady", time_steady, METH_NOARGS, steady_doc}, #ifdef HAVE_STRFTIME {"strftime", time_strftime, METH_VARARGS, strftime_doc}, #endif @@ -1008,7 +957,6 @@ #ifdef HAVE_WORKING_TZSET {"tzset", time_tzset, METH_NOARGS, tzset_doc}, #endif - {"wallclock", time_wallclock, METH_NOARGS, wallclock_doc}, {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 01:17:25 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 15 Mar 2012 01:17:25 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2310278=3A_Add_an_op?= =?utf8?q?tional_strict_argument_to_time=2Esteady=28=29=2C_False_by_defaul?= =?utf8?q?t?= Message-ID: http://hg.python.org/cpython/rev/27441e0d6a75 changeset: 75672:27441e0d6a75 user: Victor Stinner date: Thu Mar 15 01:17:09 2012 +0100 summary: Issue #10278: Add an optional strict argument to time.steady(), False by default files: Doc/library/time.rst | 7 +++- Lib/test/test_time.py | 10 +++++ Modules/timemodule.c | 58 +++++++++++++++++++++--------- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -226,7 +226,7 @@ The earliest date for which it can generate a time is platform-dependent. -.. function:: steady() +.. function:: steady(strict=False) .. index:: single: benchmarking @@ -236,6 +236,11 @@ adjusted. The reference point of the returned value is undefined so only the difference of consecutive calls is valid. + If available, a monotonic clock is used. By default, if *strict* is False, + the function falls back to another clock if the monotonic clock failed or is + not available. If *strict* is True, raise an :exc:`OSError` on error or + :exc:`NotImplementedError` if no monotonic clock is available. + .. versionadded:: 3.3 diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -340,6 +340,16 @@ self.assertGreater(t2, t1) self.assertAlmostEqual(dt, 0.1, delta=0.2) + def test_steady_strict(self): + try: + t1 = time.steady(strict=True) + except OSError as err: + self.skipTest("the monotonic clock failed: %s" % err) + except NotImplementedError: + self.skipTest("no monotonic clock available") + t2 = time.steady(strict=True) + self.assertGreaterEqual(t2, t1) + def test_localtime_failure(self): # Issue #13847: check for localtime() failure invalid_time_t = None diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -45,18 +45,12 @@ /* Forward declarations */ static int floatsleep(double); -static double floattime(void); +static PyObject* floattime(void); static PyObject * time_time(PyObject *self, PyObject *unused) { - double secs; - secs = floattime(); - if (secs == 0.0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - return PyFloat_FromDouble(secs); + return floattime(); } PyDoc_STRVAR(time_doc, @@ -768,11 +762,11 @@ should not be relied on."); #endif /* HAVE_WORKING_TZSET */ -static PyObject * -time_steady(PyObject *self, PyObject *unused) +static PyObject* +steady_clock(int strict) { #if defined(MS_WINDOWS) && !defined(__BORLANDC__) - return win32_clock(1); + return win32_clock(!strict); #elif defined(__APPLE__) uint64_t time = mach_absolute_time(); double secs; @@ -806,14 +800,37 @@ if (Py_ARRAY_LENGTH(clk_ids) <= clk_index) clk_index = -1; } - return time_time(self, NULL); + if (strict) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return floattime(); #else - return time_time(self, NULL); + if (strict) { + PyErr_SetString(PyExc_NotImplementedError, + "no steady clock available on your platform"); + return NULL; + } + return floattime(); #endif } +static PyObject * +time_steady(PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = {"strict", NULL}; + int strict = 0; + + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "|i:steady", kwlist, + &strict)) + return NULL; + + return steady_clock(strict); +} + PyDoc_STRVAR(steady_doc, -"steady() -> float\n\ +"steady(strict=False) -> float\n\ \n\ Return the current time as a floating point number expressed in seconds.\n\ This clock advances at a steady rate relative to real time and it may not\n\ @@ -949,7 +966,8 @@ #ifdef HAVE_MKTIME {"mktime", time_mktime, METH_O, mktime_doc}, #endif - {"steady", time_steady, METH_NOARGS, steady_doc}, + {"steady", (PyCFunction)time_steady, METH_VARARGS|METH_KEYWORDS, + steady_doc}, #ifdef HAVE_STRFTIME {"strftime", time_strftime, METH_VARARGS, strftime_doc}, #endif @@ -1041,12 +1059,18 @@ return m; } -static double +static PyObject* floattime(void) { _PyTime_timeval t; + double secs; _PyTime_gettimeofday(&t); - return (double)t.tv_sec + t.tv_usec*0.000001; + secs = (double)t.tv_sec + t.tv_usec*0.000001; + if (secs == 0.0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return PyFloat_FromDouble(secs); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 01:19:17 2012 From: python-checkins at python.org (barry.warsaw) Date: Thu, 15 Mar 2012 01:19:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E6=29=3A_-_Issue_=231423?= =?utf8?q?4=3A_CVE-2012-0876=3A_Randomize_hashes_of_xml_attributes_in_the_?= =?utf8?q?hash?= Message-ID: http://hg.python.org/cpython/rev/9c8d066013ea changeset: 75673:9c8d066013ea branch: 2.6 parent: 75208:47e10d72358b user: Barry Warsaw date: Wed Mar 14 17:10:41 2012 -0700 summary: - Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project. files: Misc/NEWS | 23 ++- Modules/expat/expat.h | 9 + Modules/expat/pyexpatns.h | 1 + Modules/expat/xmlparse.c | 177 +++++++++++++++++-------- Modules/pyexpat.c | 2 + 5 files changed, 149 insertions(+), 63 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,20 @@ Python News +++++++++++ +What's New in Python 2.6.8 rc 2? +================================ + +*Release date: 2012-XX-XX* + +Library +------- + +- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash + table internal to the pyexpat module's copy of the expat library to avoid a + denial of service due to hash collisions. Patch by David Malcolm with some + modifications by the expat project. + + What's New in Python 2.6.8 rc 1? ================================ @@ -10,10 +24,11 @@ Core and Builtins ----------------- -- Issue #13703: oCERT-2011-003: add -R command-line option and PYTHONHASHSEED - environment variable, to provide an opt-in way to protect against denial of - service attacks due to hash collisions within the dict and set types. Patch - by David Malcolm, based on work by Victor Stinner. +- Issue #13703: oCERT-2011-003 CVE-2012-1150: add -R command-line + option and PYTHONHASHSEED environment variable, to provide an opt-in + way to protect against denial of service attacks due to hash + collisions within the dict and set types. Patch by David Malcolm, + based on work by Victor Stinner. Library ------- diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -883,6 +883,15 @@ XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing); +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt); + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/expat/pyexpatns.h b/Modules/expat/pyexpatns.h --- a/Modules/expat/pyexpatns.h +++ b/Modules/expat/pyexpatns.h @@ -97,6 +97,7 @@ #define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler #define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler #define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg +#define XML_SetHashSalt PyExpat_XML_SetHashSalt #define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler #define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler #define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -17,6 +17,8 @@ #include #include /* memset(), memcpy() */ #include +#include /* UINT_MAX */ +#include /* time() */ #include "expat.h" @@ -387,12 +389,13 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +dtdCopy(XML_Parser oldParser, + DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); static int -copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); - +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize); +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); static void FASTCALL hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); static void FASTCALL hashTableClear(HASH_TABLE *); @@ -425,6 +428,9 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); +static unsigned long generate_hash_secret_salt(void); +static XML_Bool startParsing(XML_Parser parser); + static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, @@ -542,6 +548,7 @@ XML_Bool m_useForeignDTD; enum XML_ParamEntityParsing m_paramEntityParsing; #endif + unsigned long m_hash_secret_salt; }; #define MALLOC(s) (parser->m_mem.malloc_fcn((s))) @@ -649,6 +656,7 @@ #define useForeignDTD (parser->m_useForeignDTD) #define paramEntityParsing (parser->m_paramEntityParsing) #endif /* XML_DTD */ +#define hash_secret_salt (parser->m_hash_secret_salt) XML_Parser XMLCALL XML_ParserCreate(const XML_Char *encodingName) @@ -671,22 +679,36 @@ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' }; -XML_Parser XMLCALL -XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) +static unsigned long +generate_hash_secret_salt(void) { - XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); - if (parser != NULL && ns) { + unsigned int seed = time(NULL) % UINT_MAX; + srand(seed); + return rand(); +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) +{ + /* hash functions must be initialized before setContext() is called */ + + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { /* implicit context only set for root parser, since child parsers (i.e. external entity parsers) will inherit it */ - if (!setContext(parser, implicitContext)) { - XML_ParserFree(parser); - return NULL; - } + return setContext(parser, implicitContext); } - return parser; + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + return parserCreate(encodingName, memsuite, nameSep, NULL); } static XML_Parser @@ -860,6 +882,7 @@ useForeignDTD = XML_FALSE; paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #endif + hash_secret_salt = 0; } /* moves list of bindings to freeBindingList */ @@ -907,7 +930,7 @@ poolClear(&temp2Pool); parserInit(parser, encodingName); dtdReset(_dtd, &parser->m_mem); - return setContext(parser, implicitContext); + return XML_TRUE; } enum XML_Status XMLCALL @@ -976,6 +999,12 @@ int oldInEntityValue = prologState.inEntityValue; #endif XML_Bool oldns_triplets = ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt = hash_secret_salt; #ifdef XML_DTD if (!context) @@ -1029,13 +1058,14 @@ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; defaultExpandInternalEntities = oldDefaultExpandInternalEntities; ns_triplets = oldns_triplets; + hash_secret_salt = oldhash_secret_salt; parentParser = oldParser; #ifdef XML_DTD paramEntityParsing = oldParamEntityParsing; prologState.inEntityValue = oldInEntityValue; if (context) { #endif /* XML_DTD */ - if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) || !setContext(parser, context)) { XML_ParserFree(parser); return NULL; @@ -1420,6 +1450,17 @@ #endif } +int XMLCALL +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; + hash_secret_salt = hash_salt; + return 1; +} + enum XML_Status XMLCALL XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { @@ -1430,6 +1471,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -1488,11 +1534,13 @@ break; case XML_INITIALIZED: case XML_PARSING: - result = XML_STATUS_OK; if (isFinal) { ps_parsing = XML_FINISHED; - return result; + return XML_STATUS_OK; } + /* fall through */ + default: + result = XML_STATUS_OK; } } @@ -1553,6 +1601,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -2231,7 +2284,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&dtd->pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -2618,12 +2671,12 @@ const XML_Char *localPart; /* lookup the element type name */ - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); if (!elementType) { const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); if (!name) return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!elementType) return XML_ERROR_NO_MEMORY; @@ -2792,9 +2845,9 @@ if (s[-1] == 2) { /* prefixed */ ATTRIBUTE_ID *id; const BINDING *b; - unsigned long uriHash = 0; + unsigned long uriHash = hash_secret_salt; ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); if (!id) return XML_ERROR_NO_MEMORY; b = id->prefix->binding; @@ -2818,7 +2871,7 @@ } while (*s++); { /* Check hash table for duplicate of expanded name (uriName). - Derived from code in lookup(HASH_TABLE *table, ...). + Derived from code in lookup(parser, HASH_TABLE *table, ...). */ unsigned char step = 0; unsigned long mask = nsAttsSize - 1; @@ -3756,7 +3809,8 @@ case XML_ROLE_DOCTYPE_PUBLIC_ID: #ifdef XML_DTD useForeignDTD = XML_FALSE; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -3811,7 +3865,8 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -3855,7 +3910,7 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -4069,7 +4124,8 @@ break; #else /* XML_DTD */ if (!declEntity) { - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -4144,7 +4200,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4176,7 +4232,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4358,7 +4414,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&dtd->pool); /* first, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -4882,7 +4938,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&temp2Pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal. @@ -4991,7 +5047,7 @@ result = XML_ERROR_NO_MEMORY; goto endEntityValue; } - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&tempPool); if (!entity) { /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ @@ -5281,7 +5337,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return 0; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!prefix) return 0; @@ -5310,7 +5366,7 @@ return NULL; /* skip quotation mark - its storage will be re-used (like in name[-1]) */ ++name; - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); if (!id) return NULL; if (id->name != name) @@ -5328,7 +5384,7 @@ if (name[5] == XML_T('\0')) id->prefix = &dtd->defaultPrefix; else - id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); id->xmlns = XML_TRUE; } else { @@ -5343,7 +5399,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return NULL; - id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!id->prefix) return NULL; @@ -5441,7 +5497,7 @@ ENTITY *e; if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); if (e) e->open = XML_TRUE; if (*s != XML_T('\0')) @@ -5456,7 +5512,7 @@ else { if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), sizeof(PREFIX)); if (!prefix) return XML_FALSE; @@ -5620,7 +5676,7 @@ The new DTD has already been initialized. */ static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) { HASH_TABLE_ITER iter; @@ -5635,7 +5691,7 @@ name = poolCopyString(&(newDtd->pool), oldP->name); if (!name) return 0; - if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) return 0; } @@ -5657,7 +5713,7 @@ if (!name) return 0; ++name; - newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); if (!newA) return 0; @@ -5667,7 +5723,7 @@ if (oldA->prefix == &oldDtd->defaultPrefix) newA->prefix = &newDtd->defaultPrefix; else - newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); } } @@ -5686,7 +5742,7 @@ name = poolCopyString(&(newDtd->pool), oldE->name); if (!name) return 0; - newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); if (!newE) return 0; @@ -5700,14 +5756,14 @@ } if (oldE->idAtt) newE->idAtt = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; if (oldE->prefix) - newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { newE->defaultAtts[i].id = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -5721,13 +5777,15 @@ } /* Copy the entity tables. */ - if (!copyEntityTable(&(newDtd->generalEntities), + if (!copyEntityTable(oldParser, + &(newDtd->generalEntities), &(newDtd->pool), &(oldDtd->generalEntities))) return 0; #ifdef XML_DTD - if (!copyEntityTable(&(newDtd->paramEntities), + if (!copyEntityTable(oldParser, + &(newDtd->paramEntities), &(newDtd->pool), &(oldDtd->paramEntities))) return 0; @@ -5750,7 +5808,8 @@ } /* End dtdCopy */ static int -copyEntityTable(HASH_TABLE *newTable, +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable) { @@ -5769,7 +5828,7 @@ name = poolCopyString(newPool, oldE->name); if (!name) return 0; - newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); if (!newE) return 0; if (oldE->systemId) { @@ -5827,16 +5886,16 @@ } static unsigned long FASTCALL -hash(KEY s) +hash(XML_Parser parser, KEY s) { - unsigned long h = 0; + unsigned long h = hash_secret_salt; while (*s) h = CHAR_HASH(h, *s++); return h; } static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize) +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { size_t i; if (table->size == 0) { @@ -5853,10 +5912,10 @@ return NULL; } memset(table->v, 0, tsize); - i = hash(name) & ((unsigned long)table->size - 1); + i = hash(parser, name) & ((unsigned long)table->size - 1); } else { - unsigned long h = hash(name); + unsigned long h = hash(parser, name); unsigned long mask = (unsigned long)table->size - 1; unsigned char step = 0; i = h & mask; @@ -5882,7 +5941,7 @@ memset(newV, 0, tsize); for (i = 0; i < table->size; i++) if (table->v[i]) { - unsigned long newHash = hash(table->v[i]->name); + unsigned long newHash = hash(parser, table->v[i]->name); size_t j = newHash & newMask; step = 0; while (newV[j]) { @@ -6257,7 +6316,7 @@ if (!name) return NULL; - ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!ret) return NULL; if (ret->name != name) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1355,6 +1355,8 @@ else { self->itself = XML_ParserCreate(encoding); } + XML_SetHashSalt(self->itself, + (unsigned long)_Py_HashSecret.prefix); self->intern = intern; Py_XINCREF(self->intern); #ifdef Py_TPFLAGS_HAVE_GC -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 01:19:18 2012 From: python-checkins at python.org (barry.warsaw) Date: Thu, 15 Mar 2012 01:19:18 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi42IC0+IDIuNyk6?= =?utf8?q?_merge_2=2E6?= Message-ID: http://hg.python.org/cpython/rev/5cdb26684ebd changeset: 75674:5cdb26684ebd branch: 2.7 parent: 75668:f5bf91af01ca parent: 75673:9c8d066013ea user: Barry Warsaw date: Wed Mar 14 17:18:46 2012 -0700 summary: merge 2.6 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 01:22:04 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 15 Mar 2012 01:22:04 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314222=3A_Use_the_n?= =?utf8?q?ew_time=2Esteady=28=29_function_instead_of_time=2Etime=28=29_for?= Message-ID: http://hg.python.org/cpython/rev/d97ae725814c changeset: 75675:d97ae725814c parent: 75672:27441e0d6a75 user: Victor Stinner date: Thu Mar 15 01:22:16 2012 +0100 summary: Issue #14222: Use the new time.steady() function instead of time.time() for timeout in queue and threading modules to not be affected of system time update. files: Lib/queue.py | 2 +- Lib/threading.py | 2 +- Misc/NEWS | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/queue.py b/Lib/queue.py --- a/Lib/queue.py +++ b/Lib/queue.py @@ -6,7 +6,7 @@ import dummy_threading as threading from collections import deque from heapq import heappush, heappop -from time import time +from time import steady as time __all__ = ['Empty', 'Full', 'Queue', 'PriorityQueue', 'LifoQueue'] diff --git a/Lib/threading.py b/Lib/threading.py --- a/Lib/threading.py +++ b/Lib/threading.py @@ -3,7 +3,7 @@ import sys as _sys import _thread -from time import time as _time, sleep as _sleep +from time import steady as _time, sleep as _sleep from traceback import format_exc as _format_exc from _weakrefset import WeakSet diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,10 @@ Library ------- +- Issue #14222: Use the new time.steady() function instead of time.time() for + timeout in queue and threading modules to not be affected of system time + update. + - Issue #13248: Remove lib2to3.pytree.Base.get_prefix/set_prefix. - Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:11:54 2012 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 15 Mar 2012 02:11:54 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_the_wrong_u?= =?utf8?q?rllib_exampls_which_use_str_for_POST_data=2E_Closes_Issue11261?= Message-ID: http://hg.python.org/cpython/rev/fddbe9a59d26 changeset: 75676:fddbe9a59d26 branch: 3.2 parent: 75664:421d308a48f7 user: Senthil Kumaran date: Wed Mar 14 18:08:13 2012 -0700 summary: Fix the wrong urllib exampls which use str for POST data. Closes Issue11261 files: Doc/howto/urllib2.rst | 4 ++- Doc/library/urllib.request.rst | 23 ++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -108,6 +108,7 @@ 'language' : 'Python' } data = urllib.parse.urlencode(values) + data = data.encode('utf-8') # data should be bytes req = urllib.request.Request(url, data) response = urllib.request.urlopen(req) the_page = response.read() @@ -172,7 +173,8 @@ 'language' : 'Python' } headers = { 'User-Agent' : user_agent } - data = urllib.parse.urlencode(values) + data = urllib.parse.urlencode(values) + data = data.encode('utf-8') req = urllib.request.Request(url, data, headers) response = urllib.request.urlopen(req) the_page = response.read() diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -138,14 +138,13 @@ *url* should be a string containing a valid URL. - *data* may be a string specifying additional data to send to the - server, or ``None`` if no such data is needed. Currently HTTP - requests are the only ones that use *data*; the HTTP request will - be a POST instead of a GET when the *data* parameter is provided. - *data* should be a buffer in the standard - :mimetype:`application/x-www-form-urlencoded` format. The - :func:`urllib.parse.urlencode` function takes a mapping or sequence - of 2-tuples and returns a string in this format. + *data* may be a bytes object specifying additional data to send to the + server, or ``None`` if no such data is needed. Currently HTTP requests are + the only ones that use *data*; the HTTP request will be a POST instead of a + GET when the *data* parameter is provided. *data* should be a buffer in the + standard :mimetype:`application/x-www-form-urlencoded` format. The + :func:`urllib.parse.urlencode` function takes a mapping or sequence of + 2-tuples and returns a string in this format. *headers* should be a dictionary, and will be treated as if :meth:`add_header` was called with each key and value as arguments. @@ -1122,10 +1121,10 @@ size in response to a retrieval request. If the *url* uses the :file:`http:` scheme identifier, the optional *data* - argument may be given to specify a ``POST`` request (normally the request type - is ``GET``). The *data* argument must in standard - :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode` - function below. + argument may be given to specify a ``POST`` request (normally the request + type is ``GET``). The *data* argument must be a bytes object in standard + :mimetype:`application/x-www-form-urlencoded` format; see the + :func:`urlencode` function below. :func:`urlretrieve` will raise :exc:`ContentTooShortError` when it detects that the amount of data available was less than the expected amount (which is the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:11:55 2012 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 15 Mar 2012 02:11:55 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_cpython=3AFix_the_wrong_urllib_exampls_which_use_str_for_POS?= =?utf8?q?T_data=2E_Closes?= Message-ID: http://hg.python.org/cpython/rev/0345dc184e9a changeset: 75677:0345dc184e9a parent: 75675:d97ae725814c parent: 75676:fddbe9a59d26 user: Senthil Kumaran date: Wed Mar 14 18:11:46 2012 -0700 summary: cpython:Fix the wrong urllib exampls which use str for POST data. Closes Issue11261 files: Doc/howto/urllib2.rst | 4 +++- Doc/library/urllib.request.rst | 17 ++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -115,6 +115,7 @@ 'language' : 'Python' } data = urllib.parse.urlencode(values) + data = data.encode('utf-8') # data should be bytes req = urllib.request.Request(url, data) response = urllib.request.urlopen(req) the_page = response.read() @@ -179,7 +180,8 @@ 'language' : 'Python' } headers = { 'User-Agent' : user_agent } - data = urllib.parse.urlencode(values) + data = urllib.parse.urlencode(values) + data = data.encode('utf-8') req = urllib.request.Request(url, data, headers) response = urllib.request.urlopen(req) the_page = response.read() diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -138,14 +138,13 @@ *url* should be a string containing a valid URL. - *data* may be a string specifying additional data to send to the - server, or ``None`` if no such data is needed. Currently HTTP - requests are the only ones that use *data*, in order to choose between - ``'GET'`` and ``'POST'`` when *method* is not specified. - *data* should be a buffer in the standard - :mimetype:`application/x-www-form-urlencoded` format. The - :func:`urllib.parse.urlencode` function takes a mapping or sequence - of 2-tuples and returns a string in this format. + *data* may be a bytes object specifying additional data to send to the + server, or ``None`` if no such data is needed. Currently HTTP requests are + the only ones that use *data*; the HTTP request will be a POST instead of a + GET when the *data* parameter is provided. *data* should be a buffer in the + standard :mimetype:`application/x-www-form-urlencoded` format. The + :func:`urllib.parse.urlencode` function takes a mapping or sequence of + 2-tuples and returns a string in this format. *headers* should be a dictionary, and will be treated as if :meth:`add_header` was called with each key and value as arguments. @@ -1183,7 +1182,7 @@ If the *url* uses the :file:`http:` scheme identifier, the optional *data* argument may be given to specify a ``POST`` request (normally the request - type is ``GET``). The *data* argument must in standard + type is ``GET``). The *data* argument must be a bytes object in standard :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode` function below. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:15:31 2012 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 15 Mar 2012 02:15:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fixes_Issue_142?= =?utf8?q?34=3A_fix_for_the_previous_commit=2C_keep_compilation_when?= Message-ID: http://hg.python.org/cpython/rev/b2d4a6a9463e changeset: 75678:b2d4a6a9463e branch: 3.2 parent: 75664:421d308a48f7 user: Gregory P. Smith date: Wed Mar 14 18:10:37 2012 -0700 summary: Fixes Issue 14234: fix for the previous commit, keep compilation when using --with-system-expat working when the system expat does not have salted hash support. files: Modules/expat/expat.h | 2 ++ Modules/pyexpat.c | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -892,6 +892,8 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); +#define XML_HAS_SET_HASH_SALT /* Python Only: Defined for pyexpat.c. */ + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1150,8 +1150,13 @@ else { self->itself = XML_ParserCreate(encoding); } +#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) + /* This feature was added upstream in libexpat 2.1.0. Our expat copy + * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT + * to indicate that we can still use it. */ XML_SetHashSalt(self->itself, (unsigned long)_Py_HashSecret.prefix); +#endif self->intern = intern; Py_XINCREF(self->intern); PyObject_GC_Track(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:15:31 2012 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 15 Mar 2012 02:15:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Fixes_Issue_14234=3A_fix_for_the_previous_commit=2C_keep_com?= =?utf8?q?pilation_when?= Message-ID: http://hg.python.org/cpython/rev/db27b7353400 changeset: 75679:db27b7353400 parent: 75675:d97ae725814c parent: 75678:b2d4a6a9463e user: Gregory P. Smith date: Wed Mar 14 18:11:46 2012 -0700 summary: Fixes Issue 14234: fix for the previous commit, keep compilation when using --with-system-expat working when the system expat does not have salted hash support. files: Modules/expat/expat.h | 2 ++ Modules/pyexpat.c | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -892,6 +892,8 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); +#define XML_HAS_SET_HASH_SALT /* Python Only: Defined for pyexpat.c. */ + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1156,8 +1156,13 @@ else { self->itself = XML_ParserCreate(encoding); } +#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) + /* This feature was added upstream in libexpat 2.1.0. Our expat copy + * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT + * to indicate that we can still use it. */ XML_SetHashSalt(self->itself, (unsigned long)_Py_HashSecret.prefix); +#endif self->intern = intern; Py_XINCREF(self->intern); PyObject_GC_Track(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:15:32 2012 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 15 Mar 2012 02:15:32 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fixes_Issue_142?= =?utf8?q?34=3A_fix_for_the_previous_commit=2C_keep_compilation_when?= Message-ID: http://hg.python.org/cpython/rev/cb72aa8a8008 changeset: 75680:cb72aa8a8008 branch: 2.7 parent: 75667:b54f5849013c user: Gregory P. Smith date: Wed Mar 14 18:12:23 2012 -0700 summary: Fixes Issue 14234: fix for the previous commit, keep compilation when using --with-system-expat working when the system expat does not have salted hash support. files: Modules/expat/expat.h | 2 ++ Modules/pyexpat.c | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -892,6 +892,8 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); +#define XML_HAS_SET_HASH_SALT /* Python Only: Defined for pyexpat.c. */ + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1302,8 +1302,13 @@ else { self->itself = XML_ParserCreate(encoding); } +#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) + /* This feature was added upstream in libexpat 2.1.0. Our expat copy + * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT + * to indicate that we can still use it. */ XML_SetHashSalt(self->itself, (unsigned long)_Py_HashSecret.prefix); +#endif self->intern = intern; Py_XINCREF(self->intern); #ifdef Py_TPFLAGS_HAVE_GC -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:15:33 2012 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 15 Mar 2012 02:15:33 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_merge_heads=2E?= Message-ID: http://hg.python.org/cpython/rev/2f03819c8203 changeset: 75681:2f03819c8203 branch: 2.7 parent: 75680:cb72aa8a8008 parent: 75674:5cdb26684ebd user: Gregory P. Smith date: Wed Mar 14 18:13:25 2012 -0700 summary: merge heads. files: Include/patchlevel.h | 2 +- Makefile.pre.in | 4 +- Misc/README.OpenBSD | 2 +- PC/pyconfig.h | 2 +- Python/thread.c | 2 +- README | 9 +- configure | 595 ++++++++++++++++-------------- configure.in | 0 pyconfig.h.in | 2 +- 9 files changed, 321 insertions(+), 297 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -6,7 +6,7 @@ defined(PY_MAJOR_VERSION). When the major or minor version changes, the VERSION variable in - configure.in must also be changed. + configure.ac must also be changed. There is also (independent) API version information in modsupport.h. */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -152,7 +152,7 @@ SUBDIRSTOO= Include Lib Misc Demo # Files and directories to be distributed -CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in +CONFIGFILES= configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in DISTFILES= README ChangeLog $(CONFIGFILES) DISTDIRS= $(SUBDIRS) $(SUBDIRSTOO) Ext-dummy DIST= $(DISTFILES) $(DISTDIRS) @@ -1165,7 +1165,7 @@ $(SHELL) config.status --recheck $(SHELL) config.status -# Rebuild the configure script from configure.in; also rebuild pyconfig.h.in +# Rebuild the configure script from configure.ac; also rebuild pyconfig.h.in autoconf: (cd $(srcdir); autoconf) (cd $(srcdir); autoheader) diff --git a/Misc/README.OpenBSD b/Misc/README.OpenBSD --- a/Misc/README.OpenBSD +++ b/Misc/README.OpenBSD @@ -29,7 +29,7 @@ If your version is not in that list, e.g., 3.9, add the version number. In this case, you would just need to add a 9 after the 8. -If you modify configure.in, you will need to regenerate configure +If you modify configure.ac, you will need to regenerate configure with autoconf. If your version is already in the list, this is not a known problem. diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -342,7 +342,7 @@ # define SIZEOF_FPOS_T 8 # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 -/* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, +/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, sizeof(off_t) > sizeof(long), and sizeof(PY_LONG_LONG) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -24,7 +24,7 @@ #include #ifdef __sgi -#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.in */ +#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.ac */ #undef _POSIX_THREADS #endif #endif diff --git a/README b/README --- a/README +++ b/README @@ -241,7 +241,7 @@ - NeXT - Irix 4 and --with-sgi-dl - Linux 1 -- Systems defining __d6_pthread_create (configure.in) +- Systems defining __d6_pthread_create (configure.ac) - Systems defining PY_PTHREAD_D4, PY_PTHREAD_D6, or PY_PTHREAD_D7 in thread_pthread.h - Systems using --with-dl-dld @@ -680,10 +680,10 @@ threads to work properly. Below is a table of those options, collected by Bill Janssen. We would love to automate this process more, but the information below is not enough to write a patch for the -configure.in file, so manual intervention is required. If you patch -the configure.in file and are confident that the patch works, please +configure.ac file, so manual intervention is required. If you patch +the configure.ac file and are confident that the patch works, please send in the patch. (Don't bother patching the configure script itself --- it is regenerated each time the configure.in file changes.) +-- it is regenerated each time the configure.ac file changes.) Compiler switches for threads ............................. @@ -1201,7 +1201,7 @@ Tools/ Some useful programs written in Python pyconfig.h.in Source from which pyconfig.h is created (GNU autoheader output) configure Configuration shell script (GNU autoconf output) -configure.in Configuration specification (input for GNU autoconf) +configure.ac Configuration specification (input for GNU autoconf) install-sh Shell script used to install files setup.py Python script used to build extension modules diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,7 +1,7 @@ #! /bin/sh -# From configure.in Revision. +# From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.67 for python 2.7. +# Generated by GNU Autoconf 2.68 for python 2.7. # # Report bugs to . # @@ -92,6 +92,7 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -217,11 +218,18 @@ # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -1174,7 +1182,7 @@ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac @@ -1511,7 +1519,7 @@ if $ac_init_version; then cat <<\_ACEOF python configure 2.7 -generated by GNU Autoconf 2.67 +generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation @@ -1557,7 +1565,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile @@ -1594,7 +1602,7 @@ ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp @@ -1607,10 +1615,10 @@ ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval "test \"\${$3+set}\"" = set; then : + if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -1677,7 +1685,7 @@ esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -1686,7 +1694,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel @@ -1727,7 +1735,7 @@ ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run @@ -1741,7 +1749,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -1759,7 +1767,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile @@ -1804,7 +1812,7 @@ # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link @@ -1818,7 +1826,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1859,7 +1867,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type @@ -1872,7 +1880,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1912,7 +1920,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t @@ -1925,7 +1933,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 $as_echo_n "checking for int$2_t... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1986,7 +1994,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t @@ -2163,7 +2171,7 @@ rm -f conftest.val fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_compute_int @@ -2176,7 +2184,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2231,7 +2239,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func @@ -2244,7 +2252,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } -if eval "test \"\${$4+set}\"" = set; then : +if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2288,7 +2296,7 @@ eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member @@ -2303,7 +2311,7 @@ as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 $as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2334,7 +2342,7 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl cat >config.log <<_ACEOF @@ -2342,7 +2350,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by python $as_me 2.7, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2600,7 +2608,7 @@ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi done @@ -3241,7 +3249,7 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3281,7 +3289,7 @@ set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3334,7 +3342,7 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3374,7 +3382,7 @@ set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3433,7 +3441,7 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3477,7 +3485,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3532,7 +3540,7 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -3647,7 +3655,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -3690,7 +3698,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -3749,7 +3757,7 @@ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi fi fi @@ -3760,7 +3768,7 @@ ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then : +if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3801,7 +3809,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi @@ -3811,7 +3819,7 @@ ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then : +if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3848,7 +3856,7 @@ ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then : +if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag @@ -3926,7 +3934,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then : +if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no @@ -4065,7 +4073,7 @@ set dummy g++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CXX+set}" = set; then : +if ${ac_cv_path_CXX+:} false; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4106,7 +4114,7 @@ set dummy c++; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_CXX+set}" = set; then : +if ${ac_cv_path_CXX+:} false; then : $as_echo_n "(cached) " >&6 else case $CXX in @@ -4157,7 +4165,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CXX+set}" = set; then : +if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then @@ -4228,7 +4236,7 @@ CPP= fi if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then : + if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded @@ -4344,7 +4352,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c @@ -4356,7 +4364,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then : +if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -4419,7 +4427,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then : +if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -4486,7 +4494,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4615,7 +4623,7 @@ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = x""yes; then : +if test "x$ac_cv_header_minix_config_h" = xyes; then : MINIX=yes else MINIX= @@ -4637,7 +4645,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : +if ${ac_cv_safe_to_define___extensions__+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4981,7 +4989,7 @@ set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then : +if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then @@ -5021,7 +5029,7 @@ set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then @@ -5075,7 +5083,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AR+set}" = set; then : +if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then @@ -5125,7 +5133,7 @@ set dummy svnversion; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_SVNVERSION+set}" = set; then : +if ${ac_cv_prog_SVNVERSION+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$SVNVERSION"; then @@ -5173,7 +5181,7 @@ set dummy hg; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_HAS_HG+set}" = set; then : +if ${ac_cv_prog_HAS_HG+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$HAS_HG"; then @@ -5272,7 +5280,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if test "${ac_cv_path_install+set}" = set; then : +if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5460,7 +5468,7 @@ $as_echo_n "checking whether $CC accepts -fno-strict-aliasing... " >&6; } ac_save_cc="$CC" CC="$CC -fno-strict-aliasing" - if test "${ac_cv_no_strict_aliasing_ok+set}" = set; then : + if ${ac_cv_no_strict_aliasing_ok+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5650,7 +5658,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -OPT:Olimit=0" >&5 $as_echo_n "checking whether $CC accepts -OPT:Olimit=0... " >&6; } -if test "${ac_cv_opt_olimit_ok+set}" = set; then : +if ${ac_cv_opt_olimit_ok+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5692,7 +5700,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Olimit 1500" >&5 $as_echo_n "checking whether $CC accepts -Olimit 1500... " >&6; } - if test "${ac_cv_olimit_ok+set}" = set; then : + if ${ac_cv_olimit_ok+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5770,7 +5778,7 @@ # options before we can check whether -Kpthread improves anything. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads are available without options" >&5 $as_echo_n "checking whether pthreads are available without options... " >&6; } -if test "${ac_cv_pthread_is_default+set}" = set; then : +if ${ac_cv_pthread_is_default+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -5823,7 +5831,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kpthread" >&5 $as_echo_n "checking whether $CC accepts -Kpthread... " >&6; } -if test "${ac_cv_kpthread+set}" = set; then : +if ${ac_cv_kpthread+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5872,7 +5880,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Kthread" >&5 $as_echo_n "checking whether $CC accepts -Kthread... " >&6; } -if test "${ac_cv_kthread+set}" = set; then : +if ${ac_cv_kthread+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -5921,7 +5929,7 @@ # function available. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -pthread" >&5 $as_echo_n "checking whether $CC accepts -pthread... " >&6; } -if test "${ac_cv_thread+set}" = set; then : +if ${ac_cv_thread+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cc="$CC" @@ -6006,7 +6014,7 @@ # checks for header files { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6145,7 +6153,7 @@ as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } -if eval "test \"\${$as_ac_Header+set}\"" = set; then : +if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6185,7 +6193,7 @@ if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6219,11 +6227,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no @@ -6242,7 +6250,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -6276,11 +6284,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no @@ -6300,7 +6308,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 $as_echo_n "checking whether sys/types.h defines makedev... " >&6; } -if test "${ac_cv_header_sys_types_h_makedev+set}" = set; then : +if ${ac_cv_header_sys_types_h_makedev+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6328,7 +6336,7 @@ if test $ac_cv_header_sys_types_h_makedev = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = x""yes; then : +if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : $as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h @@ -6338,7 +6346,7 @@ if test $ac_cv_header_sys_mkdev_h = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = x""yes; then : +if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then : $as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h @@ -6358,7 +6366,7 @@ #endif " -if test "x$ac_cv_header_term_h" = x""yes; then : +if test "x$ac_cv_header_term_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_TERM_H 1 _ACEOF @@ -6380,7 +6388,7 @@ #endif " -if test "x$ac_cv_header_linux_netlink_h" = x""yes; then : +if test "x$ac_cv_header_linux_netlink_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LINUX_NETLINK_H 1 _ACEOF @@ -6543,7 +6551,7 @@ # Type availability checks ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" -if test "x$ac_cv_type_mode_t" = x""yes; then : +if test "x$ac_cv_type_mode_t" = xyes; then : else @@ -6554,7 +6562,7 @@ fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" -if test "x$ac_cv_type_off_t" = x""yes; then : +if test "x$ac_cv_type_off_t" = xyes; then : else @@ -6565,7 +6573,7 @@ fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = x""yes; then : +if test "x$ac_cv_type_pid_t" = xyes; then : else @@ -6581,7 +6589,7 @@ _ACEOF ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = x""yes; then : +if test "x$ac_cv_type_size_t" = xyes; then : else @@ -6593,7 +6601,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if test "${ac_cv_type_uid_t+set}" = set; then : +if ${ac_cv_type_uid_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6672,7 +6680,7 @@ esac ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" -if test "x$ac_cv_type_ssize_t" = x""yes; then : +if test "x$ac_cv_type_ssize_t" = xyes; then : $as_echo "#define HAVE_SSIZE_T 1" >>confdefs.h @@ -6687,7 +6695,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 $as_echo_n "checking size of int... " >&6; } -if test "${ac_cv_sizeof_int+set}" = set; then : +if ${ac_cv_sizeof_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : @@ -6697,7 +6705,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int=0 fi @@ -6720,7 +6728,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } -if test "${ac_cv_sizeof_long+set}" = set; then : +if ${ac_cv_sizeof_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : @@ -6730,7 +6738,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long=0 fi @@ -6753,7 +6761,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 $as_echo_n "checking size of void *... " >&6; } -if test "${ac_cv_sizeof_void_p+set}" = set; then : +if ${ac_cv_sizeof_void_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : @@ -6763,7 +6771,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_void_p=0 fi @@ -6786,7 +6794,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 $as_echo_n "checking size of short... " >&6; } -if test "${ac_cv_sizeof_short+set}" = set; then : +if ${ac_cv_sizeof_short+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : @@ -6796,7 +6804,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (short) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_short=0 fi @@ -6819,7 +6827,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of float" >&5 $as_echo_n "checking size of float... " >&6; } -if test "${ac_cv_sizeof_float+set}" = set; then : +if ${ac_cv_sizeof_float+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (float))" "ac_cv_sizeof_float" "$ac_includes_default"; then : @@ -6829,7 +6837,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (float) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_float=0 fi @@ -6852,7 +6860,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5 $as_echo_n "checking size of double... " >&6; } -if test "${ac_cv_sizeof_double+set}" = set; then : +if ${ac_cv_sizeof_double+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then : @@ -6862,7 +6870,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (double) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_double=0 fi @@ -6885,7 +6893,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of fpos_t" >&5 $as_echo_n "checking size of fpos_t... " >&6; } -if test "${ac_cv_sizeof_fpos_t+set}" = set; then : +if ${ac_cv_sizeof_fpos_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (fpos_t))" "ac_cv_sizeof_fpos_t" "$ac_includes_default"; then : @@ -6895,7 +6903,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (fpos_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_fpos_t=0 fi @@ -6918,7 +6926,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5 $as_echo_n "checking size of size_t... " >&6; } -if test "${ac_cv_sizeof_size_t+set}" = set; then : +if ${ac_cv_sizeof_size_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then : @@ -6928,7 +6936,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (size_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_size_t=0 fi @@ -6951,7 +6959,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 $as_echo_n "checking size of pid_t... " >&6; } -if test "${ac_cv_sizeof_pid_t+set}" = set; then : +if ${ac_cv_sizeof_pid_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pid_t))" "ac_cv_sizeof_pid_t" "$ac_includes_default"; then : @@ -6961,7 +6969,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (pid_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_pid_t=0 fi @@ -7011,7 +7019,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 $as_echo_n "checking size of long long... " >&6; } -if test "${ac_cv_sizeof_long_long+set}" = set; then : +if ${ac_cv_sizeof_long_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : @@ -7021,7 +7029,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long long) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_long=0 fi @@ -7072,7 +7080,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 $as_echo_n "checking size of long double... " >&6; } -if test "${ac_cv_sizeof_long_double+set}" = set; then : +if ${ac_cv_sizeof_long_double+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then : @@ -7082,7 +7090,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long double) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_double=0 fi @@ -7133,7 +7141,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of _Bool" >&5 $as_echo_n "checking size of _Bool... " >&6; } -if test "${ac_cv_sizeof__Bool+set}" = set; then : +if ${ac_cv_sizeof__Bool+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (_Bool))" "ac_cv_sizeof__Bool" "$ac_includes_default"; then : @@ -7143,7 +7151,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (_Bool) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof__Bool=0 fi @@ -7169,7 +7177,7 @@ #include #endif " -if test "x$ac_cv_type_uintptr_t" = x""yes; then : +if test "x$ac_cv_type_uintptr_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINTPTR_T 1 @@ -7181,7 +7189,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uintptr_t" >&5 $as_echo_n "checking size of uintptr_t... " >&6; } -if test "${ac_cv_sizeof_uintptr_t+set}" = set; then : +if ${ac_cv_sizeof_uintptr_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uintptr_t))" "ac_cv_sizeof_uintptr_t" "$ac_includes_default"; then : @@ -7191,7 +7199,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (uintptr_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uintptr_t=0 fi @@ -7217,7 +7225,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 $as_echo_n "checking size of off_t... " >&6; } -if test "${ac_cv_sizeof_off_t+set}" = set; then : +if ${ac_cv_sizeof_off_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" " @@ -7232,7 +7240,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (off_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_off_t=0 fi @@ -7276,7 +7284,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 $as_echo_n "checking size of time_t... " >&6; } -if test "${ac_cv_sizeof_time_t+set}" = set; then : +if ${ac_cv_sizeof_time_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" " @@ -7294,7 +7302,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (time_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_time_t=0 fi @@ -7350,7 +7358,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 $as_echo_n "checking size of pthread_t... " >&6; } -if test "${ac_cv_sizeof_pthread_t+set}" = set; then : +if ${ac_cv_sizeof_pthread_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" " @@ -7365,7 +7373,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (pthread_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_pthread_t=0 fi @@ -7877,7 +7885,7 @@ # checks for libraries { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then : +if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7911,7 +7919,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF @@ -7922,7 +7930,7 @@ # Dynamic linking for SunOS/Solaris and SYSV { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } -if test "${ac_cv_lib_dld_shl_load+set}" = set; then : +if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -7956,7 +7964,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDLD 1 _ACEOF @@ -7970,7 +7978,7 @@ if test "$with_threads" = "yes" -o -z "$with_threads"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5 $as_echo_n "checking for library containing sem_init... " >&6; } -if test "${ac_cv_search_sem_init+set}" = set; then : +if ${ac_cv_search_sem_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -8004,11 +8012,11 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_sem_init+set}" = set; then : + if ${ac_cv_search_sem_init+:} false; then : break fi done -if test "${ac_cv_search_sem_init+set}" = set; then : +if ${ac_cv_search_sem_init+:} false; then : else ac_cv_search_sem_init=no @@ -8031,7 +8039,7 @@ # check if we need libintl for locale functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for textdomain in -lintl" >&5 $as_echo_n "checking for textdomain in -lintl... " >&6; } -if test "${ac_cv_lib_intl_textdomain+set}" = set; then : +if ${ac_cv_lib_intl_textdomain+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8065,7 +8073,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_textdomain" >&5 $as_echo "$ac_cv_lib_intl_textdomain" >&6; } -if test "x$ac_cv_lib_intl_textdomain" = x""yes; then : +if test "x$ac_cv_lib_intl_textdomain" = xyes; then : $as_echo "#define WITH_LIBINTL 1" >>confdefs.h @@ -8112,7 +8120,7 @@ # BeOS' sockets are stashed in libnet. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for t_open in -lnsl" >&5 $as_echo_n "checking for t_open in -lnsl... " >&6; } -if test "${ac_cv_lib_nsl_t_open+set}" = set; then : +if ${ac_cv_lib_nsl_t_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8146,13 +8154,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_t_open" >&5 $as_echo "$ac_cv_lib_nsl_t_open" >&6; } -if test "x$ac_cv_lib_nsl_t_open" = x""yes; then : +if test "x$ac_cv_lib_nsl_t_open" = xyes; then : LIBS="-lnsl $LIBS" fi # SVR4 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 $as_echo_n "checking for socket in -lsocket... " >&6; } -if test "${ac_cv_lib_socket_socket+set}" = set; then : +if ${ac_cv_lib_socket_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8186,7 +8194,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 $as_echo "$ac_cv_lib_socket_socket" >&6; } -if test "x$ac_cv_lib_socket_socket" = x""yes; then : +if test "x$ac_cv_lib_socket_socket" = xyes; then : LIBS="-lsocket $LIBS" fi # SVR4 sockets @@ -8195,7 +8203,7 @@ BeOS*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnet" >&5 $as_echo_n "checking for socket in -lnet... " >&6; } -if test "${ac_cv_lib_net_socket+set}" = set; then : +if ${ac_cv_lib_net_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8229,7 +8237,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_net_socket" >&5 $as_echo "$ac_cv_lib_net_socket" >&6; } -if test "x$ac_cv_lib_net_socket" = x""yes; then : +if test "x$ac_cv_lib_net_socket" = xyes; then : LIBS="-lnet $LIBS" fi # BeOS @@ -8257,7 +8265,7 @@ set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_PKG_CONFIG+set}" = set; then : +if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in @@ -8300,7 +8308,7 @@ set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then : +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in @@ -8568,7 +8576,7 @@ $as_echo "#define _REENTRANT 1" >>confdefs.h ac_fn_c_check_header_mongrel "$LINENO" "cthreads.h" "ac_cv_header_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_cthreads_h" = x""yes; then : +if test "x$ac_cv_header_cthreads_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8581,7 +8589,7 @@ else ac_fn_c_check_header_mongrel "$LINENO" "mach/cthreads.h" "ac_cv_header_mach_cthreads_h" "$ac_includes_default" -if test "x$ac_cv_header_mach_cthreads_h" = x""yes; then : +if test "x$ac_cv_header_mach_cthreads_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h $as_echo "#define C_THREADS 1" >>confdefs.h @@ -8643,7 +8651,7 @@ LIBS=$_libs ac_fn_c_check_func "$LINENO" "pthread_detach" "ac_cv_func_pthread_detach" -if test "x$ac_cv_func_pthread_detach" = x""yes; then : +if test "x$ac_cv_func_pthread_detach" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8651,7 +8659,7 @@ else ac_fn_c_check_header_mongrel "$LINENO" "atheos/threads.h" "ac_cv_header_atheos_threads_h" "$ac_includes_default" -if test "x$ac_cv_header_atheos_threads_h" = x""yes; then : +if test "x$ac_cv_header_atheos_threads_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h @@ -8661,7 +8669,7 @@ else ac_fn_c_check_header_mongrel "$LINENO" "kernel/OS.h" "ac_cv_header_kernel_OS_h" "$ac_includes_default" -if test "x$ac_cv_header_kernel_OS_h" = x""yes; then : +if test "x$ac_cv_header_kernel_OS_h" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h @@ -8672,7 +8680,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthreads" >&5 $as_echo_n "checking for pthread_create in -lpthreads... " >&6; } -if test "${ac_cv_lib_pthreads_pthread_create+set}" = set; then : +if ${ac_cv_lib_pthreads_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8706,7 +8714,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_create" >&5 $as_echo "$ac_cv_lib_pthreads_pthread_create" >&6; } -if test "x$ac_cv_lib_pthreads_pthread_create" = x""yes; then : +if test "x$ac_cv_lib_pthreads_pthread_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8716,7 +8724,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 $as_echo_n "checking for pthread_create in -lc_r... " >&6; } -if test "${ac_cv_lib_c_r_pthread_create+set}" = set; then : +if ${ac_cv_lib_c_r_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8750,7 +8758,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 $as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } -if test "x$ac_cv_lib_c_r_pthread_create" = x""yes; then : +if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8760,7 +8768,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_create_system in -lpthread" >&5 $as_echo_n "checking for __pthread_create_system in -lpthread... " >&6; } -if test "${ac_cv_lib_pthread___pthread_create_system+set}" = set; then : +if ${ac_cv_lib_pthread___pthread_create_system+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8794,7 +8802,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_create_system" >&5 $as_echo "$ac_cv_lib_pthread___pthread_create_system" >&6; } -if test "x$ac_cv_lib_pthread___pthread_create_system" = x""yes; then : +if test "x$ac_cv_lib_pthread___pthread_create_system" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8804,7 +8812,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lcma" >&5 $as_echo_n "checking for pthread_create in -lcma... " >&6; } -if test "${ac_cv_lib_cma_pthread_create+set}" = set; then : +if ${ac_cv_lib_cma_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8838,7 +8846,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cma_pthread_create" >&5 $as_echo "$ac_cv_lib_cma_pthread_create" >&6; } -if test "x$ac_cv_lib_cma_pthread_create" = x""yes; then : +if test "x$ac_cv_lib_cma_pthread_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h posix_threads=yes @@ -8878,7 +8886,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usconfig in -lmpc" >&5 $as_echo_n "checking for usconfig in -lmpc... " >&6; } -if test "${ac_cv_lib_mpc_usconfig+set}" = set; then : +if ${ac_cv_lib_mpc_usconfig+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8912,7 +8920,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mpc_usconfig" >&5 $as_echo "$ac_cv_lib_mpc_usconfig" >&6; } -if test "x$ac_cv_lib_mpc_usconfig" = x""yes; then : +if test "x$ac_cv_lib_mpc_usconfig" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lmpc" @@ -8924,7 +8932,7 @@ if test "$posix_threads" != "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for thr_create in -lthread" >&5 $as_echo_n "checking for thr_create in -lthread... " >&6; } -if test "${ac_cv_lib_thread_thr_create+set}" = set; then : +if ${ac_cv_lib_thread_thr_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8958,7 +8966,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_thread_thr_create" >&5 $as_echo "$ac_cv_lib_thread_thr_create" >&6; } -if test "x$ac_cv_lib_thread_thr_create" = x""yes; then : +if test "x$ac_cv_lib_thread_thr_create" = xyes; then : $as_echo "#define WITH_THREAD 1" >>confdefs.h LIBS="$LIBS -lthread" @@ -9003,7 +9011,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PTHREAD_SCOPE_SYSTEM is supported" >&5 $as_echo_n "checking if PTHREAD_SCOPE_SYSTEM is supported... " >&6; } - if test "${ac_cv_pthread_system_supported+set}" = set; then : + if ${ac_cv_pthread_system_supported+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -9046,7 +9054,7 @@ for ac_func in pthread_sigmask do : ac_fn_c_check_func "$LINENO" "pthread_sigmask" "ac_cv_func_pthread_sigmask" -if test "x$ac_cv_func_pthread_sigmask" = x""yes; then : +if test "x$ac_cv_func_pthread_sigmask" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_SIGMASK 1 _ACEOF @@ -9436,7 +9444,7 @@ $as_echo "$with_valgrind" >&6; } if test "$with_valgrind" != no; then ac_fn_c_check_header_mongrel "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_valgrind_h" = x""yes; then : +if test "x$ac_cv_header_valgrind_valgrind_h" = xyes; then : $as_echo "#define WITH_VALGRIND 1" >>confdefs.h @@ -9480,7 +9488,7 @@ for ac_func in dlopen do : ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = x""yes; then : +if test "x$ac_cv_func_dlopen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLOPEN 1 _ACEOF @@ -9810,7 +9818,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock declaration" >&5 $as_echo_n "checking for flock declaration... " >&6; } -if test "${ac_cv_flock_decl+set}" = set; then : +if ${ac_cv_flock_decl+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -9840,7 +9848,7 @@ for ac_func in flock do : ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" -if test "x$ac_cv_func_flock" = x""yes; then : +if test "x$ac_cv_func_flock" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FLOCK 1 _ACEOF @@ -9848,7 +9856,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock in -lbsd" >&5 $as_echo_n "checking for flock in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_flock+set}" = set; then : +if ${ac_cv_lib_bsd_flock+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9882,7 +9890,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_flock" >&5 $as_echo "$ac_cv_lib_bsd_flock" >&6; } -if test "x$ac_cv_lib_bsd_flock" = x""yes; then : +if test "x$ac_cv_lib_bsd_flock" = xyes; then : $as_echo "#define HAVE_FLOCK 1" >>confdefs.h @@ -9959,7 +9967,7 @@ set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_TRUE+set}" = set; then : +if ${ac_cv_prog_TRUE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$TRUE"; then @@ -9999,7 +10007,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lc" >&5 $as_echo_n "checking for inet_aton in -lc... " >&6; } -if test "${ac_cv_lib_c_inet_aton+set}" = set; then : +if ${ac_cv_lib_c_inet_aton+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10033,12 +10041,12 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_inet_aton" >&5 $as_echo "$ac_cv_lib_c_inet_aton" >&6; } -if test "x$ac_cv_lib_c_inet_aton" = x""yes; then : +if test "x$ac_cv_lib_c_inet_aton" = xyes; then : $ac_cv_prog_TRUE else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lresolv" >&5 $as_echo_n "checking for inet_aton in -lresolv... " >&6; } -if test "${ac_cv_lib_resolv_inet_aton+set}" = set; then : +if ${ac_cv_lib_resolv_inet_aton+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10072,7 +10080,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_aton" >&5 $as_echo "$ac_cv_lib_resolv_inet_aton" >&6; } -if test "x$ac_cv_lib_resolv_inet_aton" = x""yes; then : +if test "x$ac_cv_lib_resolv_inet_aton" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF @@ -10089,7 +10097,7 @@ # exit Python { $as_echo "$as_me:${as_lineno-$LINENO}: checking for chflags" >&5 $as_echo_n "checking for chflags... " >&6; } -if test "${ac_cv_have_chflags+set}" = set; then : +if ${ac_cv_have_chflags+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10123,7 +10131,7 @@ $as_echo "$ac_cv_have_chflags" >&6; } if test "$ac_cv_have_chflags" = cross ; then ac_fn_c_check_func "$LINENO" "chflags" "ac_cv_func_chflags" -if test "x$ac_cv_func_chflags" = x""yes; then : +if test "x$ac_cv_func_chflags" = xyes; then : ac_cv_have_chflags="yes" else ac_cv_have_chflags="no" @@ -10138,7 +10146,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lchflags" >&5 $as_echo_n "checking for lchflags... " >&6; } -if test "${ac_cv_have_lchflags+set}" = set; then : +if ${ac_cv_have_lchflags+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10172,7 +10180,7 @@ $as_echo "$ac_cv_have_lchflags" >&6; } if test "$ac_cv_have_lchflags" = cross ; then ac_fn_c_check_func "$LINENO" "lchflags" "ac_cv_func_lchflags" -if test "x$ac_cv_func_lchflags" = x""yes; then : +if test "x$ac_cv_func_lchflags" = xyes; then : ac_cv_have_lchflags="yes" else ac_cv_have_lchflags="no" @@ -10196,7 +10204,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateCopy in -lz" >&5 $as_echo_n "checking for inflateCopy in -lz... " >&6; } -if test "${ac_cv_lib_z_inflateCopy+set}" = set; then : +if ${ac_cv_lib_z_inflateCopy+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10230,7 +10238,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateCopy" >&5 $as_echo "$ac_cv_lib_z_inflateCopy" >&6; } -if test "x$ac_cv_lib_z_inflateCopy" = x""yes; then : +if test "x$ac_cv_lib_z_inflateCopy" = xyes; then : $as_echo "#define HAVE_ZLIB_COPY 1" >>confdefs.h @@ -10373,7 +10381,7 @@ for ac_func in openpty do : ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty" -if test "x$ac_cv_func_openpty" = x""yes; then : +if test "x$ac_cv_func_openpty" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENPTY 1 _ACEOF @@ -10381,7 +10389,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 $as_echo_n "checking for openpty in -lutil... " >&6; } -if test "${ac_cv_lib_util_openpty+set}" = set; then : +if ${ac_cv_lib_util_openpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10415,13 +10423,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 $as_echo "$ac_cv_lib_util_openpty" >&6; } -if test "x$ac_cv_lib_util_openpty" = x""yes; then : +if test "x$ac_cv_lib_util_openpty" = xyes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lbsd" >&5 $as_echo_n "checking for openpty in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_openpty+set}" = set; then : +if ${ac_cv_lib_bsd_openpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10455,7 +10463,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_openpty" >&5 $as_echo "$ac_cv_lib_bsd_openpty" >&6; } -if test "x$ac_cv_lib_bsd_openpty" = x""yes; then : +if test "x$ac_cv_lib_bsd_openpty" = xyes; then : $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10470,7 +10478,7 @@ for ac_func in forkpty do : ac_fn_c_check_func "$LINENO" "forkpty" "ac_cv_func_forkpty" -if test "x$ac_cv_func_forkpty" = x""yes; then : +if test "x$ac_cv_func_forkpty" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FORKPTY 1 _ACEOF @@ -10478,7 +10486,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lutil" >&5 $as_echo_n "checking for forkpty in -lutil... " >&6; } -if test "${ac_cv_lib_util_forkpty+set}" = set; then : +if ${ac_cv_lib_util_forkpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10512,13 +10520,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_forkpty" >&5 $as_echo "$ac_cv_lib_util_forkpty" >&6; } -if test "x$ac_cv_lib_util_forkpty" = x""yes; then : +if test "x$ac_cv_lib_util_forkpty" = xyes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lutil" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for forkpty in -lbsd" >&5 $as_echo_n "checking for forkpty in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_forkpty+set}" = set; then : +if ${ac_cv_lib_bsd_forkpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -10552,7 +10560,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_forkpty" >&5 $as_echo "$ac_cv_lib_bsd_forkpty" >&6; } -if test "x$ac_cv_lib_bsd_forkpty" = x""yes; then : +if test "x$ac_cv_lib_bsd_forkpty" = xyes; then : $as_echo "#define HAVE_FORKPTY 1" >>confdefs.h LIBS="$LIBS -lbsd" fi @@ -10569,7 +10577,7 @@ for ac_func in memmove do : ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" -if test "x$ac_cv_func_memmove" = x""yes; then : +if test "x$ac_cv_func_memmove" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MEMMOVE 1 _ACEOF @@ -10593,7 +10601,7 @@ ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" -if test "x$ac_cv_func_dup2" = x""yes; then : +if test "x$ac_cv_func_dup2" = xyes; then : $as_echo "#define HAVE_DUP2 1" >>confdefs.h else @@ -10606,7 +10614,7 @@ fi ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" -if test "x$ac_cv_func_getcwd" = x""yes; then : +if test "x$ac_cv_func_getcwd" = xyes; then : $as_echo "#define HAVE_GETCWD 1" >>confdefs.h else @@ -10619,7 +10627,7 @@ fi ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup" -if test "x$ac_cv_func_strdup" = x""yes; then : +if test "x$ac_cv_func_strdup" = xyes; then : $as_echo "#define HAVE_STRDUP 1" >>confdefs.h else @@ -10635,7 +10643,7 @@ for ac_func in getpgrp do : ac_fn_c_check_func "$LINENO" "getpgrp" "ac_cv_func_getpgrp" -if test "x$ac_cv_func_getpgrp" = x""yes; then : +if test "x$ac_cv_func_getpgrp" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETPGRP 1 _ACEOF @@ -10663,7 +10671,7 @@ for ac_func in setpgrp do : ac_fn_c_check_func "$LINENO" "setpgrp" "ac_cv_func_setpgrp" -if test "x$ac_cv_func_setpgrp" = x""yes; then : +if test "x$ac_cv_func_setpgrp" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETPGRP 1 _ACEOF @@ -10691,7 +10699,7 @@ for ac_func in gettimeofday do : ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" -if test "x$ac_cv_func_gettimeofday" = x""yes; then : +if test "x$ac_cv_func_gettimeofday" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETTIMEOFDAY 1 _ACEOF @@ -10793,7 +10801,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking getaddrinfo bug" >&5 $as_echo_n "checking getaddrinfo bug... " >&6; } - if test "${ac_cv_buggy_getaddrinfo+set}" = set; then : + if ${ac_cv_buggy_getaddrinfo+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -10922,7 +10930,7 @@ for ac_func in getnameinfo do : ac_fn_c_check_func "$LINENO" "getnameinfo" "ac_cv_func_getnameinfo" -if test "x$ac_cv_func_getnameinfo" = x""yes; then : +if test "x$ac_cv_func_getnameinfo" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETNAMEINFO 1 _ACEOF @@ -10934,7 +10942,7 @@ # checks for structures { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if test "${ac_cv_header_time+set}" = set; then : +if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10969,7 +10977,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if test "${ac_cv_struct_tm+set}" = set; then : +if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11006,7 +11014,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -11022,7 +11030,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = x""yes; then : +if test "x$ac_cv_have_decl_tzname" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -11034,7 +11042,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if test "${ac_cv_var_tzname+set}" = set; then : +if ${ac_cv_var_tzname+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11070,7 +11078,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_RDEV 1 @@ -11080,7 +11088,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blksize" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLKSIZE 1 @@ -11090,7 +11098,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_flags" "ac_cv_member_struct_stat_st_flags" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_flags" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_flags" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_FLAGS 1 @@ -11100,7 +11108,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_gen" "ac_cv_member_struct_stat_st_gen" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_gen" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_gen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_GEN 1 @@ -11110,7 +11118,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtime" "ac_cv_member_struct_stat_st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtime" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_birthtime" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 @@ -11120,7 +11128,7 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_blocks" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BLOCKS 1 @@ -11142,7 +11150,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for time.h that defines altzone" >&5 $as_echo_n "checking for time.h that defines altzone... " >&6; } -if test "${ac_cv_header_time_altzone+set}" = set; then : +if ${ac_cv_header_time_altzone+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11206,7 +11214,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for addrinfo" >&5 $as_echo_n "checking for addrinfo... " >&6; } -if test "${ac_cv_struct_addrinfo+set}" = set; then : +if ${ac_cv_struct_addrinfo+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11238,7 +11246,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sockaddr_storage" >&5 $as_echo_n "checking for sockaddr_storage... " >&6; } -if test "${ac_cv_struct_sockaddr_storage+set}" = set; then : +if ${ac_cv_struct_sockaddr_storage+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11274,7 +11282,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether char is unsigned" >&5 $as_echo_n "checking whether char is unsigned... " >&6; } -if test "${ac_cv_c_char_unsigned+set}" = set; then : +if ${ac_cv_c_char_unsigned+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11306,7 +11314,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if test "${ac_cv_c_const+set}" = set; then : +if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11594,7 +11602,7 @@ ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" -if test "x$ac_cv_func_gethostbyname_r" = x""yes; then : +if test "x$ac_cv_func_gethostbyname_r" = xyes; then : $as_echo "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h @@ -11725,7 +11733,7 @@ for ac_func in gethostbyname do : ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = x""yes; then : +if test "x$ac_cv_func_gethostbyname" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETHOSTBYNAME 1 _ACEOF @@ -11747,12 +11755,12 @@ # Linux requires this for correct f.p. operations ac_fn_c_check_func "$LINENO" "__fpu_control" "ac_cv_func___fpu_control" -if test "x$ac_cv_func___fpu_control" = x""yes; then : +if test "x$ac_cv_func___fpu_control" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __fpu_control in -lieee" >&5 $as_echo_n "checking for __fpu_control in -lieee... " >&6; } -if test "${ac_cv_lib_ieee___fpu_control+set}" = set; then : +if ${ac_cv_lib_ieee___fpu_control+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -11786,7 +11794,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee___fpu_control" >&5 $as_echo "$ac_cv_lib_ieee___fpu_control" >&6; } -if test "x$ac_cv_lib_ieee___fpu_control" = x""yes; then : +if test "x$ac_cv_lib_ieee___fpu_control" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBIEEE 1 _ACEOF @@ -11881,7 +11889,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are little-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are little-endian IEEE 754 binary64... " >&6; } -if test "${ac_cv_little_endian_double+set}" = set; then : +if ${ac_cv_little_endian_double+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11923,7 +11931,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are big-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are big-endian IEEE 754 binary64... " >&6; } -if test "${ac_cv_big_endian_double+set}" = set; then : +if ${ac_cv_big_endian_double+:} false; then : $as_echo_n "(cached) " >&6 else @@ -11969,7 +11977,7 @@ # conversions work. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C doubles are ARM mixed-endian IEEE 754 binary64" >&5 $as_echo_n "checking whether C doubles are ARM mixed-endian IEEE 754 binary64... " >&6; } -if test "${ac_cv_mixed_endian_double+set}" = set; then : +if ${ac_cv_mixed_endian_double+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12117,7 +12125,7 @@ # -0. on some architectures. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tanh preserves the sign of zero" >&5 $as_echo_n "checking whether tanh preserves the sign of zero... " >&6; } -if test "${ac_cv_tanh_preserves_zero_sign+set}" = set; then : +if ${ac_cv_tanh_preserves_zero_sign+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12185,7 +12193,7 @@ ac_fn_c_check_decl "$LINENO" "isinf" "ac_cv_have_decl_isinf" "#include " -if test "x$ac_cv_have_decl_isinf" = x""yes; then : +if test "x$ac_cv_have_decl_isinf" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -12196,7 +12204,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isnan" "ac_cv_have_decl_isnan" "#include " -if test "x$ac_cv_have_decl_isnan" = x""yes; then : +if test "x$ac_cv_have_decl_isnan" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -12207,7 +12215,7 @@ _ACEOF ac_fn_c_check_decl "$LINENO" "isfinite" "ac_cv_have_decl_isfinite" "#include " -if test "x$ac_cv_have_decl_isfinite" = x""yes; then : +if test "x$ac_cv_have_decl_isfinite" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -12227,7 +12235,7 @@ # sem_open results in a 'Signal 12' error. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX semaphores are enabled" >&5 $as_echo_n "checking whether POSIX semaphores are enabled... " >&6; } -if test "${ac_cv_posix_semaphores_enabled+set}" = set; then : +if ${ac_cv_posix_semaphores_enabled+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12278,7 +12286,7 @@ # Multiprocessing check for broken sem_getvalue { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken sem_getvalue" >&5 $as_echo_n "checking for broken sem_getvalue... " >&6; } -if test "${ac_cv_broken_sem_getvalue+set}" = set; then : +if ${ac_cv_broken_sem_getvalue+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12343,7 +12351,7 @@ 15|30) ;; *) - as_fn_error $? "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; + as_fn_error $? "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_big_digits" >&5 $as_echo "$enable_big_digits" >&6; } @@ -12361,7 +12369,7 @@ # check for wchar.h ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" -if test "x$ac_cv_header_wchar_h" = x""yes; then : +if test "x$ac_cv_header_wchar_h" = xyes; then : $as_echo "#define HAVE_WCHAR_H 1" >>confdefs.h @@ -12384,7 +12392,7 @@ # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5 $as_echo_n "checking size of wchar_t... " >&6; } -if test "${ac_cv_sizeof_wchar_t+set}" = set; then : +if ${ac_cv_sizeof_wchar_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t" "#include @@ -12395,7 +12403,7 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (wchar_t) -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_wchar_t=0 fi @@ -12450,7 +12458,7 @@ # check whether wchar_t is signed or not { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether wchar_t is signed" >&5 $as_echo_n "checking whether wchar_t is signed... " >&6; } - if test "${ac_cv_wchar_t_signed+set}" = set; then : + if ${ac_cv_wchar_t_signed+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12514,7 +12522,7 @@ $as_echo "#define Py_UNICODE_SIZE 4" >>confdefs.h ;; -*) as_fn_error $? "invalid value for --enable-unicode. Use either ucs2 or ucs4 (lowercase)." "$LINENO" 5 ;; +*) as_fn_error $? "invalid value for --enable-unicode. Use either ucs2 or ucs4 (lowercase)." "$LINENO" 5 ;; esac @@ -12561,7 +12569,7 @@ # check for endianness { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if test "${ac_cv_c_bigendian+set}" = set; then : +if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown @@ -12780,7 +12788,7 @@ ;; #( *) as_fn_error $? "unknown endianness - presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac @@ -12788,7 +12796,7 @@ # or fills with zeros (like the Cray J90, according to Tim Peters). { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether right shift extends the sign bit" >&5 $as_echo_n "checking whether right shift extends the sign bit... " >&6; } -if test "${ac_cv_rshift_extends_sign+set}" = set; then : +if ${ac_cv_rshift_extends_sign+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12827,7 +12835,7 @@ # check for getc_unlocked and related locking functions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getc_unlocked() and friends" >&5 $as_echo_n "checking for getc_unlocked() and friends... " >&6; } -if test "${ac_cv_have_getc_unlocked+set}" = set; then : +if ${ac_cv_have_getc_unlocked+:} false; then : $as_echo_n "(cached) " >&6 else @@ -12925,7 +12933,7 @@ # check for readline 2.1 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_callback_handler_install in -lreadline" >&5 $as_echo_n "checking for rl_callback_handler_install in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_callback_handler_install+set}" = set; then : +if ${ac_cv_lib_readline_rl_callback_handler_install+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12959,7 +12967,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_callback_handler_install" >&5 $as_echo "$ac_cv_lib_readline_rl_callback_handler_install" >&6; } -if test "x$ac_cv_lib_readline_rl_callback_handler_install" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_callback_handler_install" = xyes; then : $as_echo "#define HAVE_RL_CALLBACK 1" >>confdefs.h @@ -13011,7 +13019,7 @@ # check for readline 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_pre_input_hook in -lreadline" >&5 $as_echo_n "checking for rl_pre_input_hook in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_pre_input_hook+set}" = set; then : +if ${ac_cv_lib_readline_rl_pre_input_hook+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -13045,7 +13053,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_pre_input_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_pre_input_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_pre_input_hook" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_pre_input_hook" = xyes; then : $as_echo "#define HAVE_RL_PRE_INPUT_HOOK 1" >>confdefs.h @@ -13055,7 +13063,7 @@ # also in 4.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_display_matches_hook in -lreadline" >&5 $as_echo_n "checking for rl_completion_display_matches_hook in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_completion_display_matches_hook+set}" = set; then : +if ${ac_cv_lib_readline_rl_completion_display_matches_hook+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -13089,7 +13097,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_display_matches_hook" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_display_matches_hook" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_completion_display_matches_hook" = xyes; then : $as_echo "#define HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK 1" >>confdefs.h @@ -13099,7 +13107,7 @@ # check for readline 4.2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_completion_matches in -lreadline" >&5 $as_echo_n "checking for rl_completion_matches in -lreadline... " >&6; } -if test "${ac_cv_lib_readline_rl_completion_matches+set}" = set; then : +if ${ac_cv_lib_readline_rl_completion_matches+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -13133,7 +13141,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_completion_matches" >&5 $as_echo "$ac_cv_lib_readline_rl_completion_matches" >&6; } -if test "x$ac_cv_lib_readline_rl_completion_matches" = x""yes; then : +if test "x$ac_cv_lib_readline_rl_completion_matches" = xyes; then : $as_echo "#define HAVE_RL_COMPLETION_MATCHES 1" >>confdefs.h @@ -13174,7 +13182,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken nice()" >&5 $as_echo_n "checking for broken nice()... " >&6; } -if test "${ac_cv_broken_nice+set}" = set; then : +if ${ac_cv_broken_nice+:} false; then : $as_echo_n "(cached) " >&6 else @@ -13215,7 +13223,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken poll()" >&5 $as_echo_n "checking for broken poll()... " >&6; } -if test "${ac_cv_broken_poll+set}" = set; then : +if ${ac_cv_broken_poll+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13270,7 +13278,7 @@ #include <$ac_cv_struct_tm> " -if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then : +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 @@ -13286,7 +13294,7 @@ else ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include " -if test "x$ac_cv_have_decl_tzname" = x""yes; then : +if test "x$ac_cv_have_decl_tzname" = xyes; then : ac_have_decl=1 else ac_have_decl=0 @@ -13298,7 +13306,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } -if test "${ac_cv_var_tzname+set}" = set; then : +if ${ac_cv_var_tzname+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13337,7 +13345,7 @@ # check tzset(3) exists and works like we expect it to { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working tzset()" >&5 $as_echo_n "checking for working tzset()... " >&6; } -if test "${ac_cv_working_tzset+set}" = set; then : +if ${ac_cv_working_tzset+:} false; then : $as_echo_n "(cached) " >&6 else @@ -13434,7 +13442,7 @@ # Look for subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec in struct stat" >&5 $as_echo_n "checking for tv_nsec in struct stat... " >&6; } -if test "${ac_cv_stat_tv_nsec+set}" = set; then : +if ${ac_cv_stat_tv_nsec+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13471,7 +13479,7 @@ # Look for BSD style subsecond timestamps in struct stat { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tv_nsec2 in struct stat" >&5 $as_echo_n "checking for tv_nsec2 in struct stat... " >&6; } -if test "${ac_cv_stat_tv_nsec2+set}" = set; then : +if ${ac_cv_stat_tv_nsec2+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13508,7 +13516,7 @@ # On HP/UX 11.0, mvwdelch is a block with a return statement { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mvwdelch is an expression" >&5 $as_echo_n "checking whether mvwdelch is an expression... " >&6; } -if test "${ac_cv_mvwdelch_is_expression+set}" = set; then : +if ${ac_cv_mvwdelch_is_expression+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13545,7 +13553,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether WINDOW has _flags" >&5 $as_echo_n "checking whether WINDOW has _flags... " >&6; } -if test "${ac_cv_window_has_flags+set}" = set; then : +if ${ac_cv_window_has_flags+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13693,7 +13701,7 @@ then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %lld and %llu printf() format support" >&5 $as_echo_n "checking for %lld and %llu printf() format support... " >&6; } - if test "${ac_cv_have_long_long_format+set}" = set; then : + if ${ac_cv_have_long_long_format+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13764,7 +13772,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for %zd printf() format support" >&5 $as_echo_n "checking for %zd printf() format support... " >&6; } -if test "${ac_cv_have_size_t_format+set}" = set; then : +if ${ac_cv_have_size_t_format+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -13837,7 +13845,7 @@ #endif " -if test "x$ac_cv_type_socklen_t" = x""yes; then : +if test "x$ac_cv_type_socklen_t" = xyes; then : else @@ -13942,10 +13950,21 @@ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && + if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} @@ -13978,7 +13997,7 @@ -: ${CONFIG_STATUS=./config.status} +: "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" @@ -14079,6 +14098,7 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -14386,7 +14406,7 @@ # values after options handling. ac_log=" This file was extended by python $as_me 2.7, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -14448,7 +14468,7 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ python config.status 2.7 -configured by $0, generated by GNU Autoconf 2.67, +configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. @@ -14580,7 +14600,7 @@ "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; "Modules/ld_so_aix") CONFIG_FILES="$CONFIG_FILES Modules/ld_so_aix" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done @@ -14602,9 +14622,10 @@ # after its creation but before its name has been assigned to `$tmp'. $debug || { - tmp= + tmp= ac_tmp= trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } @@ -14612,12 +14633,13 @@ { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" + test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -14639,7 +14661,7 @@ ac_cs_awk_cr=$ac_cr fi -echo 'BEGIN {' >"$tmp/subs1.awk" && +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF @@ -14667,7 +14689,7 @@ rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h @@ -14715,7 +14737,7 @@ rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$tmp/subs1.awk" <<_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" @@ -14747,7 +14769,7 @@ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF @@ -14781,7 +14803,7 @@ # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then -cat >"$tmp/defines.awk" <<\_ACAWK || +cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF @@ -14793,8 +14815,8 @@ # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do - ac_t=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_t"; then + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 @@ -14895,7 +14917,7 @@ esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -14914,7 +14936,7 @@ for ac_f do case $ac_f in - -) ac_f="$tmp/stdin";; + -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. @@ -14923,7 +14945,7 @@ [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" @@ -14949,8 +14971,8 @@ esac case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -15080,21 +15102,22 @@ s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} - rm -f "$tmp/stdin" + rm -f "$ac_tmp/stdin" case $ac_file in - -) cat "$tmp/out" && rm -f "$tmp/out";; - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; @@ -15105,20 +15128,20 @@ if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" - } >"$tmp/config.h" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" - mv "$tmp/config.h" "$ac_file" \ + mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; diff --git a/configure.in b/configure.ac rename from configure.in rename to configure.ac diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1,4 +1,4 @@ -/* pyconfig.h.in. Generated from configure.in by autoheader. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ #ifndef Py_PYCONFIG_H -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:15:34 2012 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 15 Mar 2012 02:15:34 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/fd0aceb20382 changeset: 75682:fd0aceb20382 branch: 3.2 parent: 75678:b2d4a6a9463e parent: 75676:fddbe9a59d26 user: Gregory P. Smith date: Wed Mar 14 18:14:26 2012 -0700 summary: merge heads files: Doc/howto/urllib2.rst | 4 ++- Doc/library/urllib.request.rst | 23 ++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -108,6 +108,7 @@ 'language' : 'Python' } data = urllib.parse.urlencode(values) + data = data.encode('utf-8') # data should be bytes req = urllib.request.Request(url, data) response = urllib.request.urlopen(req) the_page = response.read() @@ -172,7 +173,8 @@ 'language' : 'Python' } headers = { 'User-Agent' : user_agent } - data = urllib.parse.urlencode(values) + data = urllib.parse.urlencode(values) + data = data.encode('utf-8') req = urllib.request.Request(url, data, headers) response = urllib.request.urlopen(req) the_page = response.read() diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -138,14 +138,13 @@ *url* should be a string containing a valid URL. - *data* may be a string specifying additional data to send to the - server, or ``None`` if no such data is needed. Currently HTTP - requests are the only ones that use *data*; the HTTP request will - be a POST instead of a GET when the *data* parameter is provided. - *data* should be a buffer in the standard - :mimetype:`application/x-www-form-urlencoded` format. The - :func:`urllib.parse.urlencode` function takes a mapping or sequence - of 2-tuples and returns a string in this format. + *data* may be a bytes object specifying additional data to send to the + server, or ``None`` if no such data is needed. Currently HTTP requests are + the only ones that use *data*; the HTTP request will be a POST instead of a + GET when the *data* parameter is provided. *data* should be a buffer in the + standard :mimetype:`application/x-www-form-urlencoded` format. The + :func:`urllib.parse.urlencode` function takes a mapping or sequence of + 2-tuples and returns a string in this format. *headers* should be a dictionary, and will be treated as if :meth:`add_header` was called with each key and value as arguments. @@ -1122,10 +1121,10 @@ size in response to a retrieval request. If the *url* uses the :file:`http:` scheme identifier, the optional *data* - argument may be given to specify a ``POST`` request (normally the request type - is ``GET``). The *data* argument must in standard - :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode` - function below. + argument may be given to specify a ``POST`` request (normally the request + type is ``GET``). The *data* argument must be a bytes object in standard + :mimetype:`application/x-www-form-urlencoded` format; see the + :func:`urlencode` function below. :func:`urlretrieve` will raise :exc:`ContentTooShortError` when it detects that the amount of data available was less than the expected amount (which is the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:15:34 2012 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 15 Mar 2012 02:15:34 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/dcf39147deeb changeset: 75683:dcf39147deeb parent: 75679:db27b7353400 parent: 75677:0345dc184e9a user: Gregory P. Smith date: Wed Mar 14 18:14:48 2012 -0700 summary: merge heads files: Doc/howto/urllib2.rst | 4 +++- Doc/library/urllib.request.rst | 17 ++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -115,6 +115,7 @@ 'language' : 'Python' } data = urllib.parse.urlencode(values) + data = data.encode('utf-8') # data should be bytes req = urllib.request.Request(url, data) response = urllib.request.urlopen(req) the_page = response.read() @@ -179,7 +180,8 @@ 'language' : 'Python' } headers = { 'User-Agent' : user_agent } - data = urllib.parse.urlencode(values) + data = urllib.parse.urlencode(values) + data = data.encode('utf-8') req = urllib.request.Request(url, data, headers) response = urllib.request.urlopen(req) the_page = response.read() diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -138,14 +138,13 @@ *url* should be a string containing a valid URL. - *data* may be a string specifying additional data to send to the - server, or ``None`` if no such data is needed. Currently HTTP - requests are the only ones that use *data*, in order to choose between - ``'GET'`` and ``'POST'`` when *method* is not specified. - *data* should be a buffer in the standard - :mimetype:`application/x-www-form-urlencoded` format. The - :func:`urllib.parse.urlencode` function takes a mapping or sequence - of 2-tuples and returns a string in this format. + *data* may be a bytes object specifying additional data to send to the + server, or ``None`` if no such data is needed. Currently HTTP requests are + the only ones that use *data*; the HTTP request will be a POST instead of a + GET when the *data* parameter is provided. *data* should be a buffer in the + standard :mimetype:`application/x-www-form-urlencoded` format. The + :func:`urllib.parse.urlencode` function takes a mapping or sequence of + 2-tuples and returns a string in this format. *headers* should be a dictionary, and will be treated as if :meth:`add_header` was called with each key and value as arguments. @@ -1183,7 +1182,7 @@ If the *url* uses the :file:`http:` scheme identifier, the optional *data* argument may be given to specify a ``POST`` request (normally the request - type is ``GET``). The *data* argument must in standard + type is ``GET``). The *data* argument must be a bytes object in standard :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode` function below. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:17:28 2012 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 15 Mar 2012 02:17:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2313248=3A__Removed_?= =?utf8?q?docs_for_two_deprecated_unittest_features=2E__To_be?= Message-ID: http://hg.python.org/cpython/rev/0ddb78341290 changeset: 75684:0ddb78341290 parent: 75675:d97ae725814c user: Raymond Hettinger date: Wed Mar 14 18:16:18 2012 -0700 summary: Issue #13248: Removed docs for two deprecated unittest features. To be conservative, the code is left in for one more release. files: Doc/library/unittest.rst | 30 ---------------------------- 1 files changed, 0 insertions(+), 30 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1175,21 +1175,6 @@ :meth:`.assertNotRegex`. - .. method:: assertDictContainsSubset(subset, dictionary, msg=None) - - Tests whether the key/value pairs in *dictionary* are a superset of - those in *subset*. If not, an error message listing the missing keys - and mismatched values is generated. - - Note, the arguments are in the opposite order of what the method name - dictates. Instead, consider using the set-methods on :ref:`dictionary - views `, for example: ``d.keys() <= e.keys()`` or - ``d.items() <= d.items()``. - - .. versionadded:: 3.1 - .. deprecated:: 3.2 - - .. method:: assertCountEqual(first, second, msg=None) Test that sequence *first* contains the same elements as *second*, @@ -1204,21 +1189,6 @@ .. versionadded:: 3.2 - .. method:: assertSameElements(first, second, msg=None) - - Test that sequence *first* contains the same elements as *second*, - regardless of their order. When they don't, an error message listing - the differences between the sequences will be generated. - - Duplicate elements are ignored when comparing *first* and *second*. - It is the equivalent of ``assertEqual(set(first), set(second))`` - but it works with sequences of unhashable objects as well. Because - duplicates are ignored, this method has been deprecated in favour of - :meth:`assertCountEqual`. - - .. versionadded:: 3.1 - .. deprecated:: 3.2 - .. _type-specific-methods: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 02:17:29 2012 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 15 Mar 2012 02:17:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge?= Message-ID: http://hg.python.org/cpython/rev/b86b414673c3 changeset: 75685:b86b414673c3 parent: 75684:0ddb78341290 parent: 75683:dcf39147deeb user: Raymond Hettinger date: Wed Mar 14 18:17:20 2012 -0700 summary: merge files: Doc/howto/urllib2.rst | 4 +++- Doc/library/urllib.request.rst | 17 ++++++++--------- Modules/expat/expat.h | 2 ++ Modules/pyexpat.c | 5 +++++ 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -115,6 +115,7 @@ 'language' : 'Python' } data = urllib.parse.urlencode(values) + data = data.encode('utf-8') # data should be bytes req = urllib.request.Request(url, data) response = urllib.request.urlopen(req) the_page = response.read() @@ -179,7 +180,8 @@ 'language' : 'Python' } headers = { 'User-Agent' : user_agent } - data = urllib.parse.urlencode(values) + data = urllib.parse.urlencode(values) + data = data.encode('utf-8') req = urllib.request.Request(url, data, headers) response = urllib.request.urlopen(req) the_page = response.read() diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -138,14 +138,13 @@ *url* should be a string containing a valid URL. - *data* may be a string specifying additional data to send to the - server, or ``None`` if no such data is needed. Currently HTTP - requests are the only ones that use *data*, in order to choose between - ``'GET'`` and ``'POST'`` when *method* is not specified. - *data* should be a buffer in the standard - :mimetype:`application/x-www-form-urlencoded` format. The - :func:`urllib.parse.urlencode` function takes a mapping or sequence - of 2-tuples and returns a string in this format. + *data* may be a bytes object specifying additional data to send to the + server, or ``None`` if no such data is needed. Currently HTTP requests are + the only ones that use *data*; the HTTP request will be a POST instead of a + GET when the *data* parameter is provided. *data* should be a buffer in the + standard :mimetype:`application/x-www-form-urlencoded` format. The + :func:`urllib.parse.urlencode` function takes a mapping or sequence of + 2-tuples and returns a string in this format. *headers* should be a dictionary, and will be treated as if :meth:`add_header` was called with each key and value as arguments. @@ -1183,7 +1182,7 @@ If the *url* uses the :file:`http:` scheme identifier, the optional *data* argument may be given to specify a ``POST`` request (normally the request - type is ``GET``). The *data* argument must in standard + type is ``GET``). The *data* argument must be a bytes object in standard :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode` function below. diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -892,6 +892,8 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); +#define XML_HAS_SET_HASH_SALT /* Python Only: Defined for pyexpat.c. */ + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1156,8 +1156,13 @@ else { self->itself = XML_ParserCreate(encoding); } +#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) + /* This feature was added upstream in libexpat 2.1.0. Our expat copy + * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT + * to indicate that we can still use it. */ XML_SetHashSalt(self->itself, (unsigned long)_Py_HashSecret.prefix); +#endif self->intern = intern; Py_XINCREF(self->intern); PyObject_GC_Track(self); -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Mar 15 03:36:10 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 15 Mar 2012 03:36:10 +0100 Subject: [Python-checkins] Daily reference leaks (b86b414673c3): sum=2640 Message-ID: results for b86b414673c3 on branch "default" -------------------------------------------- test_builtin leaked [880, 880, 880] references, sum=2640 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogz4O1rs', '-x'] From solipsis at pitrou.net Thu Mar 15 03:36:11 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 15 Mar 2012 03:36:11 +0100 Subject: [Python-checkins] Daily reference leaks (53715804dc71): sum=9199464 Message-ID: results for 53715804dc71 on branch "default" -------------------------------------------- test_builtin leaked [880, 880, 880] references, sum=2640 test_ast leaked [3043281, 3043281, 3043281] references, sum=9129843 test_compile leaked [22295, 22295, 22295] references, sum=66885 test_pickle leaked [24, 24, 24] references, sum=72 test_pickletools leaked [8, 8, 8] references, sum=24 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogtIGtbX', '-x'] From python-checkins at python.org Thu Mar 15 03:50:40 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 03:50:40 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_free_AST=27s_dict?= Message-ID: http://hg.python.org/cpython/rev/9e7f6ddc0d76 changeset: 75686:9e7f6ddc0d76 user: Benjamin Peterson date: Wed Mar 14 21:50:29 2012 -0500 summary: free AST's dict files: Parser/asdl_c.py | 8 +++++++- Python/Python-ast.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -608,6 +608,12 @@ PyObject *dict; } AST_object; +static void +ast_dealloc(AST_object *self) +{ + Py_CLEAR(self->dict); +} + static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { @@ -696,7 +702,7 @@ "_ast.AST", sizeof(AST_object), 0, - 0, /* tp_dealloc */ + (destructor)ast_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -460,6 +460,12 @@ PyObject *dict; } AST_object; +static void +ast_dealloc(AST_object *self) +{ + Py_CLEAR(self->dict); +} + static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { @@ -548,7 +554,7 @@ "_ast.AST", sizeof(AST_object), 0, - 0, /* tp_dealloc */ + (destructor)ast_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 04:28:36 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 04:28:36 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_try_to_fix_compilation_on_g?= =?utf8?q?libc=27s_with_cpu_sets_=28=2314296=29?= Message-ID: http://hg.python.org/cpython/rev/760347b11ef8 changeset: 75687:760347b11ef8 user: Benjamin Peterson date: Wed Mar 14 22:28:25 2012 -0500 summary: try to fix compilation on glibc's with cpu sets (#14296) files: Modules/posixmodule.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -107,6 +107,10 @@ #include #endif +#if defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY) +#undef HAVE_SCHED_SETAFFINITY +#endif + #if defined(HAVE_SYS_XATTR_H) && defined(__GLIBC__) #define USE_XATTRS #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 04:57:10 2012 From: python-checkins at python.org (ross.lagerwall) Date: Thu, 15 Mar 2012 04:57:10 +0100 Subject: [Python-checkins] =?utf8?q?devguide=3A_Update_configure=2Ein_to_c?= =?utf8?q?onfigure=2Eac=2E?= Message-ID: http://hg.python.org/devguide/rev/01d8edef1109 changeset: 497:01d8edef1109 user: Ross Lagerwall date: Thu Mar 15 05:56:55 2012 +0200 summary: Update configure.in to configure.ac. files: patch.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/patch.rst b/patch.rst --- a/patch.rst +++ b/patch.rst @@ -144,12 +144,12 @@ functionality (such as using a new system call), it is necessary to update the ``configure`` script to test for availability of the functionality. -Python's ``configure`` script is generated from ``configure.in`` using Autoconf. -Instead of editing ``configure``, edit ``configure.in`` and then run +Python's ``configure`` script is generated from ``configure.ac`` using Autoconf. +Instead of editing ``configure``, edit ``configure.ac`` and then run ``autoreconf`` to regenerate ``configure`` and a number of other files (such as ``pyconfig.h``. -When submitting a patch with changes made to ``configure.in``, it is preferred +When submitting a patch with changes made to ``configure.ac``, it is preferred to leave out the generated files as differences between Autoconf versions frequently results in many spurious changes cluttering the patch. Instead, remind any potential reviewers on the tracker to run ``autoreconf``. @@ -159,14 +159,14 @@ ``autoreconf`` runs ``autoconf`` and a number of other tools repeatedly as is appropriate. -Python's ``configure.in`` script typically requires a specific version of +Python's ``configure.ac`` script typically requires a specific version of Autoconf. At the moment, this reads: ``version_required(2.65)`` If the system copy of Autoconf does not match this version, you will need to install your own copy of Autoconf: 1. Go to http://ftp.gnu.org/gnu/autoconf/ and download the version of Autoconf - matching the one in ``configure.in``:: + matching the one in ``configure.ac``:: wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.65.tar.bz2 -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Mar 15 05:41:36 2012 From: python-checkins at python.org (andrew.svetlov) Date: Thu, 15 Mar 2012 05:41:36 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Closes_issue_=2314163_-_tki?= =?utf8?q?nter=3A_problems_with_hello_doc_example?= Message-ID: http://hg.python.org/cpython/rev/d8ba959a547b changeset: 75688:d8ba959a547b user: Andrew Svetlov date: Wed Mar 14 21:41:23 2012 -0700 summary: Closes issue #14163 - tkinter: problems with hello doc example files: Doc/library/tkinter.rst | 43 ++++++++++++---------------- 1 files changed, 19 insertions(+), 24 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -179,35 +179,30 @@ :: - from tkinter import * + import tkinter as tk - class Application(Frame): - def say_hi(self): - print("hi there, everyone!") + class Application(tk.Frame): + def __init__(self, master=None): + tk.Frame.__init__(self, master) + self.pack() + self.createWidgets() - def createWidgets(self): - self.QUIT = Button(self) - self.QUIT["text"] = "QUIT" - self.QUIT["fg"] = "red" - self.QUIT["command"] = self.quit + def createWidgets(self): + self.hi_there = tk.Button(self) + self.hi_there["text"] = "Hello World\n(click me)" + self.hi_there["command"] = self.say_hi + self.hi_there.pack(side="top") - self.QUIT.pack({"side": "left"}) + self.QUIT = tk.Button(self, text = "QUIT", fg = "red", + command = root.destroy) + self.QUIT.pack(side = "bottom") - self.hi_there = Button(self) - self.hi_there["text"] = "Hello", - self.hi_there["command"] = self.say_hi + def say_hi(self): + print("hi there, everyone!") - self.hi_there.pack({"side": "left"}) - - def __init__(self, master=None): - Frame.__init__(self, master) - self.pack() - self.createWidgets() - - root = Tk() - app = Application(master=root) - app.mainloop() - root.destroy() + root = tk.Tk() + app = Application(master=root) + app.mainloop() A (Very) Quick Look at Tcl/Tk -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 08:10:57 2012 From: python-checkins at python.org (r.david.murray) Date: Thu, 15 Mar 2012 08:10:57 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzEyNzU4OiByZW1v?= =?utf8?q?ving_confusing_mention_of_UTC_from_time=2Etime_description?= Message-ID: http://hg.python.org/cpython/rev/1559a82a3529 changeset: 75689:1559a82a3529 branch: 2.7 parent: 75681:2f03819c8203 user: R David Murray date: Thu Mar 15 03:05:01 2012 -0400 summary: #12758: removing confusing mention of UTC from time.time description Patch by Dylan Sarber. files: Doc/library/time.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -435,8 +435,8 @@ .. function:: time() - Return the time as a floating point number expressed in seconds since the epoch, - in UTC. Note that even though the time is always returned as a floating point + Return the time in seconds since the epoch as a floating point number. + Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 08:10:58 2012 From: python-checkins at python.org (r.david.murray) Date: Thu, 15 Mar 2012 08:10:58 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzEyNzU4OiByZW1v?= =?utf8?q?ving_confusing_mention_of_UTC_from_time=2Etime_description?= Message-ID: http://hg.python.org/cpython/rev/5615d6b91b53 changeset: 75690:5615d6b91b53 branch: 3.2 parent: 75682:fd0aceb20382 user: R David Murray date: Thu Mar 15 03:06:15 2012 -0400 summary: #12758: removing confusing mention of UTC from time.time description Patch by Dylan Sarber. files: Doc/library/time.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -430,8 +430,8 @@ .. function:: time() - Return the time as a floating point number expressed in seconds since the epoch, - in UTC. Note that even though the time is always returned as a floating point + Return the time in seconds since the epoch as a floating point number. + Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 08:10:58 2012 From: python-checkins at python.org (r.david.murray) Date: Thu, 15 Mar 2012 08:10:58 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2312758=3A_removing_confusing_mention_of_UTC_from_tim?= =?utf8?q?e=2Etime_description?= Message-ID: http://hg.python.org/cpython/rev/f18767bb66ba changeset: 75691:f18767bb66ba parent: 75688:d8ba959a547b parent: 75690:5615d6b91b53 user: R David Murray date: Thu Mar 15 03:09:53 2012 -0400 summary: Merge #12758: removing confusing mention of UTC from time.time description Patch by Dylan Sarber. (Not sure why hg told me it merged pyexpat.c too, it showed no changes) files: Doc/library/time.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -452,8 +452,8 @@ .. function:: time() - Return the time as a floating point number expressed in seconds since the epoch, - in UTC. Note that even though the time is always returned as a floating point + Return the time in seconds since the epoch as a floating point number. + Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 08:20:07 2012 From: python-checkins at python.org (georg.brandl) Date: Thu, 15 Mar 2012 08:20:07 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Convert_PEP_7_and_PEP_8_to_rst?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/peps/rev/c1fd4a5af1c5 changeset: 4139:c1fd4a5af1c5 user: Georg Brandl date: Thu Mar 15 08:18:38 2012 +0100 summary: Convert PEP 7 and PEP 8 to rst. files: pep-0007.txt | 275 ++++---- pep-0008.txt | 1178 +++++++++++++++++++------------------ 2 files changed, 753 insertions(+), 700 deletions(-) diff --git a/pep-0007.txt b/pep-0007.txt --- a/pep-0007.txt +++ b/pep-0007.txt @@ -2,210 +2,221 @@ Title: Style Guide for C Code Version: $Revision$ Last-Modified: $Date$ -Author: guido at python.org (Guido van Rossum) +Author: Guido van Rossum Status: Active Type: Process +Content-Type: text/x-rst Created: 05-Jul-2001 Post-History: + Introduction +============ - This document gives coding conventions for the C code comprising - the C implementation of Python. Please see the companion - informational PEP describing style guidelines for Python code[1]. +This document gives coding conventions for the C code comprising the C +implementation of Python. Please see the companion informational PEP +describing style guidelines for Python code [1]_. - Note, rules are there to be broken. Two good reasons to break a - particular rule: +Note, rules are there to be broken. Two good reasons to break a +particular rule: - (1) When applying the rule would make the code less readable, even - for someone who is used to reading code that follows the rules. +1. When applying the rule would make the code less readable, even for + someone who is used to reading code that follows the rules. - (2) To be consistent with surrounding code that also breaks it - (maybe for historic reasons) -- although this is also an - opportunity to clean up someone else's mess (in true XP style). +2. To be consistent with surrounding code that also breaks it (maybe + for historic reasons) -- although this is also an opportunity to + clean up someone else's mess (in true XP style). C dialect +========= - - Use ANSI/ISO standard C (the 1989 version of the standard). - This means (amongst many other things) that all declarations - must be at the top of a block (not necessarily at the top of - function). +* Use ANSI/ISO standard C (the 1989 version of the standard). This + means (amongst many other things) that all declarations must be at + the top of a block (not necessarily at the top of function). - - Don't use GCC extensions (e.g. don't write multi-line strings - without trailing backslashes). +* Don't use GCC extensions (e.g. don't write multi-line strings + without trailing backslashes). - - All function declarations and definitions must use full - prototypes (i.e. specify the types of all arguments). +* All function declarations and definitions must use full prototypes + (i.e. specify the types of all arguments). - - Never use C++ style // one-line comments. +* Never use C++ style // one-line comments. - - No compiler warnings with major compilers (gcc, VC++, a few - others). +* No compiler warnings with major compilers (gcc, VC++, a few others). Code lay-out +============ - - Use 4-space indents and no tabs at all. +* Use 4-space indents and no tabs at all. - - No line should be longer than 79 characters. If this and the - previous rule together don't give you enough room to code, your - code is too complicated -- consider using subroutines. +* No line should be longer than 79 characters. If this and the + previous rule together don't give you enough room to code, your code + is too complicated -- consider using subroutines. - - No line should end in whitespace. If you think you need - significant trailing whitespace, think again -- somebody's - editor might delete it as a matter of routine. +* No line should end in whitespace. If you think you need significant + trailing whitespace, think again -- somebody's editor might delete + it as a matter of routine. - - Function definition style: function name in column 1, outermost - curly braces in column 1, blank line after local variable - declarations. +* Function definition style: function name in column 1, outermost + curly braces in column 1, blank line after local variable + declarations. :: - static int - extra_ivars(PyTypeObject *type, PyTypeObject *base) - { - int t_size = PyType_BASICSIZE(type); - int b_size = PyType_BASICSIZE(base); + static int + extra_ivars(PyTypeObject *type, PyTypeObject *base) + { + int t_size = PyType_BASICSIZE(type); + int b_size = PyType_BASICSIZE(base); - assert(t_size >= b_size); /* type smaller than base! */ - ... - return 1; - } + assert(t_size >= b_size); /* type smaller than base! */ + ... + return 1; + } - - Code structure: one space between keywords like 'if', 'for' and - the following left paren; no spaces inside the paren; braces may be - omitted where C permits but when present, they should be formatted as - shown: +* Code structure: one space between keywords like ``if``, ``for`` and + the following left paren; no spaces inside the paren; braces may be + omitted where C permits but when present, they should be formatted + as shown:: - if (mro != NULL) { - ... - } - else { - ... - } + if (mro != NULL) { + ... + } + else { + ... + } - - The return statement should *not* get redundant parentheses: +* The return statement should *not* get redundant parentheses:: - return Py_None; /* correct */ - return(Py_None); /* incorrect */ + return Py_None; /* correct */ + return(Py_None); /* incorrect */ - - Function and macro call style: foo(a, b, c) -- no space before - the open paren, no spaces inside the parens, no spaces before - commas, one space after each comma. +* Function and macro call style: ``foo(a, b, c)`` -- no space before + the open paren, no spaces inside the parens, no spaces before + commas, one space after each comma. - - Always put spaces around assignment, Boolean and comparison - operators. In expressions using a lot of operators, add spaces - around the outermost (lowest-priority) operators. +* Always put spaces around assignment, Boolean and comparison + operators. In expressions using a lot of operators, add spaces + around the outermost (lowest-priority) operators. - - Breaking long lines: if you can, break after commas in the - outermost argument list. Always indent continuation lines - appropriately, e.g.: +* Breaking long lines: if you can, break after commas in the outermost + argument list. Always indent continuation lines appropriately, + e.g.:: - PyErr_Format(PyExc_TypeError, - "cannot create '%.100s' instances", - type->tp_name); + PyErr_Format(PyExc_TypeError, + "cannot create '%.100s' instances", + type->tp_name); - - When you break a long expression at a binary operator, the - operator goes at the end of the previous line, e.g.: +* When you break a long expression at a binary operator, the + operator goes at the end of the previous line, e.g.:: - if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 && - type->tp_dictoffset == b_size && - (size_t)t_size == b_size + sizeof(PyObject *)) - return 0; /* "Forgive" adding a __dict__ only */ + if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 && + type->tp_dictoffset == b_size && + (size_t)t_size == b_size + sizeof(PyObject *)) + return 0; /* "Forgive" adding a __dict__ only */ - - Put blank lines around functions, structure definitions, and - major sections inside functions. +* Put blank lines around functions, structure definitions, and major + sections inside functions. - - Comments go before the code they describe. +* Comments go before the code they describe. - - All functions and global variables should be declared static - unless they are to be part of a published interface +* All functions and global variables should be declared static unless + they are to be part of a published interface - - For external functions and variables, we always have a - declaration in an appropriate header file in the "Include" - directory, which uses the PyAPI_FUNC() macro, like this: +* For external functions and variables, we always have a declaration + in an appropriate header file in the "Include" directory, which uses + the ``PyAPI_FUNC()`` macro, like this:: - PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); + PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); Naming conventions +================== - - Use a Py prefix for public functions; never for static - functions. The Py_ prefix is reserved for global service - routines like Py_FatalError; specific groups of routines - (e.g. specific object type APIs) use a longer prefix, - e.g. PyString_ for string functions. +* Use a ``Py`` prefix for public functions; never for static + functions. The ``Py_`` prefix is reserved for global service + routines like ``Py_FatalError``; specific groups of routines + (e.g. specific object type APIs) use a longer prefix, + e.g. ``PyString_`` for string functions. - - Public functions and variables use MixedCase with underscores, - like this: PyObject_GetAttr, Py_BuildValue, PyExc_TypeError. +* Public functions and variables use MixedCase with underscores, like + this: ``PyObject_GetAttr``, ``Py_BuildValue``, ``PyExc_TypeError``. - - Occasionally an "internal" function has to be visible to the - loader; we use the _Py prefix for this, e.g.: _PyObject_Dump. +* Occasionally an "internal" function has to be visible to the loader; + we use the ``_Py`` prefix for this, e.g.: ``_PyObject_Dump``. - - Macros should have a MixedCase prefix and then use upper case, - for example: PyString_AS_STRING, Py_PRINT_RAW. +* Macros should have a MixedCase prefix and then use upper case, for + example: ``PyString_AS_STRING``, ``Py_PRINT_RAW``. Documentation Strings +===================== - - Use the PyDoc_STR() or PyDoc_STRVAR() macro for docstrings to - support building Python without docstrings (./configure - --without-doc-strings). +* Use the ``PyDoc_STR()`` or ``PyDoc_STRVAR()`` macro for docstrings + to support building Python without docstrings (``./configure + --without-doc-strings``). - For C code that needs to support versions of Python older than - 2.3, you can include this after including Python.h: + For C code that needs to support versions of Python older than 2.3, + you can include this after including ``Python.h``:: - #ifndef PyDoc_STR - #define PyDoc_VAR(name) static char name[] - #define PyDoc_STR(str) (str) - #define PyDoc_STRVAR(name, str) PyDoc_VAR(name) = PyDoc_STR(str) - #endif + #ifndef PyDoc_STR + #define PyDoc_VAR(name) static char name[] + #define PyDoc_STR(str) (str) + #define PyDoc_STRVAR(name, str) PyDoc_VAR(name) = PyDoc_STR(str) + #endif - - The first line of each fuction docstring should be a "signature - line" that gives a brief synopsis of the arguments and return - value. For example: +* The first line of each fuction docstring should be a "signature + line" that gives a brief synopsis of the arguments and return value. + For example:: - PyDoc_STRVAR(myfunction__doc__, - "myfunction(name, value) -> bool\n\n\ - Determine whether name and value make a valid pair."); + PyDoc_STRVAR(myfunction__doc__, + "myfunction(name, value) -> bool\n\n\ + Determine whether name and value make a valid pair."); - Always include a blank line between the signature line and the - text of the description. + Always include a blank line between the signature line and the text + of the description. - If the return value for the function is always None (because - there is no meaningful return value), do not include the - indication of the return type. + If the return value for the function is always None (because there + is no meaningful return value), do not include the indication of the + return type. - - When writing multi-line docstrings, be sure to always use - backslash continuations, as in the example above, or string - literal concatenation: +* When writing multi-line docstrings, be sure to always use backslash + continuations, as in the example above, or string literal + concatenation:: - PyDoc_STRVAR(myfunction__doc__, - "myfunction(name, value) -> bool\n\n" - "Determine whether name and value make a valid pair."); + PyDoc_STRVAR(myfunction__doc__, + "myfunction(name, value) -> bool\n\n" + "Determine whether name and value make a valid pair."); - Though some C compilers accept string literals without either: + Though some C compilers accept string literals without either:: - /* BAD -- don't do this! */ - PyDoc_STRVAR(myfunction__doc__, - "myfunction(name, value) -> bool\n\n - Determine whether name and value make a valid pair."); + /* BAD -- don't do this! */ + PyDoc_STRVAR(myfunction__doc__, + "myfunction(name, value) -> bool\n\n + Determine whether name and value make a valid pair."); - not all do; the MSVC compiler is known to complain about this. + not all do; the MSVC compiler is known to complain about this. References +========== - [1] PEP 8, Style Guide for Python Code, van Rossum, Warsaw - http://www.python.org/dev/peps/pep-0008/ +.. [1] PEP 8, "Style Guide for Python Code", van Rossum, Warsaw + (http://www.python.org/dev/peps/pep-0008) Copyright +========= - This document has been placed in the public domain. +This document has been placed in the public domain. -Local Variables: -mode: indented-text -indent-tabs-mode: nil -End: +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -2,130 +2,145 @@ Title: Style Guide for Python Code Version: $Revision$ Last-Modified: $Date$ -Author: guido at python.org (Guido van Rossum), - barry at python.org (Barry Warsaw) +Author: Guido van Rossum , + Barry Warsaw Status: Active Type: Process +Content-Type: text/x-rst Created: 05-Jul-2001 Post-History: 05-Jul-2001 Introduction +============ - This document gives coding conventions for the Python code comprising the - standard library in the main Python distribution. Please see the - companion informational PEP describing style guidelines for the C code in - the C implementation of Python[1]. +This document gives coding conventions for the Python code comprising +the standard library in the main Python distribution. Please see the +companion informational PEP describing style guidelines for the C code +in the C implementation of Python [1]_. - This document was adapted from Guido's original Python Style Guide - essay[2], with some additions from Barry's style guide[5]. Where there's - conflict, Guido's style rules for the purposes of this PEP. This PEP may - still be incomplete (in fact, it may never be finished ). +This document was adapted from Guido's original Python Style Guide +essay [2]_, with some additions from Barry's style guide [3]_. Where +there's conflict, Guido's style rules for the purposes of this PEP. +This PEP may still be incomplete (in fact, it may never be finished +). A Foolish Consistency is the Hobgoblin of Little Minds +====================================================== - One of Guido's key insights is that code is read much more often than it - is written. The guidelines provided here are intended to improve the - readability of code and make it consistent across the wide spectrum of - Python code. As PEP 20 [6] says, "Readability counts". +One of Guido's key insights is that code is read much more often than +it is written. The guidelines provided here are intended to improve +the readability of code and make it consistent across the wide +spectrum of Python code. As PEP 20 says, "Readability counts". - A style guide is about consistency. Consistency with this style guide is - important. Consistency within a project is more important. Consistency - within one module or function is most important. +A style guide is about consistency. Consistency with this style guide +is important. Consistency within a project is more important. +Consistency within one module or function is most important. - But most importantly: know when to be inconsistent -- sometimes the style - guide just doesn't apply. When in doubt, use your best judgment. Look - at other examples and decide what looks best. And don't hesitate to ask! +But most importantly: know when to be inconsistent -- sometimes the +style guide just doesn't apply. When in doubt, use your best +judgment. Look at other examples and decide what looks best. And +don't hesitate to ask! - Two good reasons to break a particular rule: +Two good reasons to break a particular rule: - (1) When applying the rule would make the code less readable, even for - someone who is used to reading code that follows the rules. +1. When applying the rule would make the code less readable, even for + someone who is used to reading code that follows the rules. - (2) To be consistent with surrounding code that also breaks it (maybe for - historic reasons) -- although this is also an opportunity to clean up - someone else's mess (in true XP style). +2. To be consistent with surrounding code that also breaks it (maybe + for historic reasons) -- although this is also an opportunity to + clean up someone else's mess (in true XP style). Code lay-out +============ - Indentation +Indentation +----------- - Use 4 spaces per indentation level. +Use 4 spaces per indentation level. - For really old code that you don't want to mess up, you can continue to - use 8-space tabs. +For really old code that you don't want to mess up, you can continue +to use 8-space tabs. - Continuation lines should align wrapped elements either vertically using - Python's implicit line joining inside parentheses, brackets and braces, or - using a hanging indent. When using a hanging indent the following - considerations should be applied; there should be no arguments on the - first line and further indentation should be used to clearly distinguish - itself as a continuation line. +Continuation lines should align wrapped elements either vertically +using Python's implicit line joining inside parentheses, brackets and +braces, or using a hanging indent. When using a hanging indent the +following considerations should be applied; there should be no +arguments on the first line and further indentation should be used to +clearly distinguish itself as a continuation line. - Yes: # Aligned with opening delimiter - foo = long_function_name(var_one, var_two, - var_three, var_four) +Yes:: - # More indentation included to distinguish this from the rest. - def long_function_name( - var_one, var_two, var_three, - var_four): - print(var_one) + # Aligned with opening delimiter + foo = long_function_name(var_one, var_two, + var_three, var_four) - No: # Arguments on first line forbidden when not using vertical alignment - foo = long_function_name(var_one, var_two, - var_three, var_four) + # More indentation included to distinguish this from the rest. + def long_function_name( + var_one, var_two, var_three, + var_four): + print(var_one) - # Further indentation required as indentation is not distinguishable - def long_function_name( - var_one, var_two, var_three, - var_four): - print(var_one) +No:: - Optional: - # Extra indentation is not necessary. - foo = long_function_name( - var_one, var_two, - var_three, var_four) + # Arguments on first line forbidden when not using vertical alignment + foo = long_function_name(var_one, var_two, + var_three, var_four) - Tabs or Spaces? + # Further indentation required as indentation is not distinguishable + def long_function_name( + var_one, var_two, var_three, + var_four): + print(var_one) - Never mix tabs and spaces. +Optional:: - The most popular way of indenting Python is with spaces only. The - second-most popular way is with tabs only. Code indented with a mixture - of tabs and spaces should be converted to using spaces exclusively. When - invoking the Python command line interpreter with the -t option, it issues - warnings about code that illegally mixes tabs and spaces. When using -tt - these warnings become errors. These options are highly recommended! + # Extra indentation is not necessary. + foo = long_function_name( + var_one, var_two, + var_three, var_four) - For new projects, spaces-only are strongly recommended over tabs. Most - editors have features that make this easy to do. +Tabs or Spaces? +--------------- - Maximum Line Length +Never mix tabs and spaces. - Limit all lines to a maximum of 79 characters. +The most popular way of indenting Python is with spaces only. The +second-most popular way is with tabs only. Code indented with a +mixture of tabs and spaces should be converted to using spaces +exclusively. When invoking the Python command line interpreter with +the ``-t`` option, it issues warnings about code that illegally mixes +tabs and spaces. When using ``-tt`` these warnings become errors. +These options are highly recommended! - There are still many devices around that are limited to 80 character - lines; plus, limiting windows to 80 characters makes it possible to have - several windows side-by-side. The default wrapping on such devices - disrupts the visual structure of the code, making it more difficult to - understand. Therefore, please limit all lines to a maximum of 79 - characters. For flowing long blocks of text (docstrings or comments), - limiting the length to 72 characters is recommended. +For new projects, spaces-only are strongly recommended over tabs. +Most editors have features that make this easy to do. - The preferred way of wrapping long lines is by using Python's implied line - continuation inside parentheses, brackets and braces. Long lines can be - broken over multiple lines by wrapping expressions in parentheses. These - should be used in preference to using a backslash for line continuation. - Make sure to indent the continued line appropriately. The preferred place - to break around a binary operator is *after* the operator, not before it. - Some examples: +Maximum Line Length +------------------- + +Limit all lines to a maximum of 79 characters. + +There are still many devices around that are limited to 80 character +lines; plus, limiting windows to 80 characters makes it possible to +have several windows side-by-side. The default wrapping on such +devices disrupts the visual structure of the code, making it more +difficult to understand. Therefore, please limit all lines to a +maximum of 79 characters. For flowing long blocks of text (docstrings +or comments), limiting the length to 72 characters is recommended. + +The preferred way of wrapping long lines is by using Python's implied +line continuation inside parentheses, brackets and braces. Long lines +can be broken over multiple lines by wrapping expressions in +parentheses. These should be used in preference to using a backslash +for line continuation. Make sure to indent the continued line +appropriately. The preferred place to break around a binary operator +is *after* the operator, not before it. Some examples:: class Rectangle(Blob): - + def __init__(self, width, height, color='black', emphasis=None, highlight=0): if (width == 0 and height == 0 and @@ -139,282 +154,294 @@ Blob.__init__(self, width, height, color, emphasis, highlight) - Blank Lines +Blank Lines +----------- - Separate top-level function and class definitions with two blank lines. +Separate top-level function and class definitions with two blank +lines. - Method definitions inside a class are separated by a single blank line. +Method definitions inside a class are separated by a single blank +line. - Extra blank lines may be used (sparingly) to separate groups of related - functions. Blank lines may be omitted between a bunch of related - one-liners (e.g. a set of dummy implementations). +Extra blank lines may be used (sparingly) to separate groups of +related functions. Blank lines may be omitted between a bunch of +related one-liners (e.g. a set of dummy implementations). - Use blank lines in functions, sparingly, to indicate logical sections. +Use blank lines in functions, sparingly, to indicate logical sections. - Python accepts the control-L (i.e. ^L) form feed character as whitespace; - Many tools treat these characters as page separators, so you may use them - to separate pages of related sections of your file. Note, some editors - and web-based code viewers may not recognize control-L as a form feed - and will show another glyph in its place. +Python accepts the control-L (i.e. ^L) form feed character as +whitespace; Many tools treat these characters as page separators, so +you may use them to separate pages of related sections of your file. +Note, some editors and web-based code viewers may not recognize +control-L as a form feed and will show another glyph in its place. - Encodings (PEP 263) +Encodings (PEP 263) +------------------- - Code in the core Python distribution should always use the ASCII or - Latin-1 encoding (a.k.a. ISO-8859-1). For Python 3.0 and beyond, - UTF-8 is preferred over Latin-1, see PEP 3120. +Code in the core Python distribution should always use the ASCII or +Latin-1 encoding (a.k.a. ISO-8859-1). For Python 3.0 and beyond, +UTF-8 is preferred over Latin-1, see PEP 3120. - Files using ASCII should not have a coding cookie. Latin-1 (or - UTF-8) should only be used when a comment or docstring needs to - mention an author name that requires Latin-1; otherwise, using - \x, \u or \U escapes is the preferred way to include non-ASCII - data in string literals. +Files using ASCII should not have a coding cookie. Latin-1 (or UTF-8) +should only be used when a comment or docstring needs to mention an +author name that requires Latin-1; otherwise, using ``\x``, ``\u`` or +``\U`` escapes is the preferred way to include non-ASCII data in +string literals. - For Python 3.0 and beyond, the following policy is prescribed for - the standard library (see PEP 3131): All identifiers in the Python - standard library MUST use ASCII-only identifiers, and SHOULD use - English words wherever feasible (in many cases, abbreviations and - technical terms are used which aren't English). In addition, - string literals and comments must also be in ASCII. The only - exceptions are (a) test cases testing the non-ASCII features, and - (b) names of authors. Authors whose names are not based on the - latin alphabet MUST provide a latin transliteration of their - names. +For Python 3.0 and beyond, the following policy is prescribed for the +standard library (see PEP 3131): All identifiers in the Python +standard library MUST use ASCII-only identifiers, and SHOULD use +English words wherever feasible (in many cases, abbreviations and +technical terms are used which aren't English). In addition, string +literals and comments must also be in ASCII. The only exceptions are +(a) test cases testing the non-ASCII features, and +(b) names of authors. Authors whose names are not based on the +latin alphabet MUST provide a latin transliteration of their +names. - Open source projects with a global audience are encouraged to - adopt a similar policy. +Open source projects with a global audience are encouraged to adopt a +similar policy. Imports +------- - - Imports should usually be on separate lines, e.g.: +- Imports should usually be on separate lines, e.g.:: - Yes: import os - import sys + Yes: import os + import sys - No: import sys, os + No: import sys, os - it's okay to say this though: + It's okay to say this though:: - from subprocess import Popen, PIPE + from subprocess import Popen, PIPE - - Imports are always put at the top of the file, just after any module - comments and docstrings, and before module globals and constants. +- Imports are always put at the top of the file, just after any module + comments and docstrings, and before module globals and constants. - Imports should be grouped in the following order: + Imports should be grouped in the following order: - 1. standard library imports - 2. related third party imports - 3. local application/library specific imports + 1. standard library imports + 2. related third party imports + 3. local application/library specific imports - You should put a blank line between each group of imports. + You should put a blank line between each group of imports. - Put any relevant __all__ specification after the imports. + Put any relevant ``__all__`` specification after the imports. - - Relative imports for intra-package imports are highly discouraged. - Always use the absolute package path for all imports. - Even now that PEP 328 [7] is fully implemented in Python 2.5, - its style of explicit relative imports is actively discouraged; - absolute imports are more portable and usually more readable. +- Relative imports for intra-package imports are highly discouraged. + Always use the absolute package path for all imports. Even now that + PEP 328 is fully implemented in Python 2.5, its style of explicit + relative imports is actively discouraged; absolute imports are more + portable and usually more readable. - - When importing a class from a class-containing module, it's usually okay - to spell this +- When importing a class from a class-containing module, it's usually + okay to spell this:: - from myclass import MyClass - from foo.bar.yourclass import YourClass + from myclass import MyClass + from foo.bar.yourclass import YourClass - If this spelling causes local name clashes, then spell them + If this spelling causes local name clashes, then spell them :: - import myclass - import foo.bar.yourclass + import myclass + import foo.bar.yourclass - and use "myclass.MyClass" and "foo.bar.yourclass.YourClass" + and use "myclass.MyClass" and "foo.bar.yourclass.YourClass". Whitespace in Expressions and Statements +======================================== - Pet Peeves +Pet Peeves +---------- - Avoid extraneous whitespace in the following situations: +Avoid extraneous whitespace in the following situations: - - Immediately inside parentheses, brackets or braces. +- Immediately inside parentheses, brackets or braces. :: Yes: spam(ham[1], {eggs: 2}) No: spam( ham[ 1 ], { eggs: 2 } ) - - Immediately before a comma, semicolon, or colon: +- Immediately before a comma, semicolon, or colon:: Yes: if x == 4: print x, y; x, y = y, x No: if x == 4 : print x , y ; x , y = y , x - - Immediately before the open parenthesis that starts the argument - list of a function call: +- Immediately before the open parenthesis that starts the argument + list of a function call:: Yes: spam(1) No: spam (1) - - Immediately before the open parenthesis that starts an indexing or - slicing: +- Immediately before the open parenthesis that starts an indexing or + slicing:: Yes: dict['key'] = list[index] No: dict ['key'] = list [index] - - More than one space around an assignment (or other) operator to - align it with another. +- More than one space around an assignment (or other) operator to + align it with another. - Yes: + Yes:: - x = 1 - y = 2 - long_variable = 3 + x = 1 + y = 2 + long_variable = 3 - No: + No:: - x = 1 - y = 2 - long_variable = 3 + x = 1 + y = 2 + long_variable = 3 - Other Recommendations +Other Recommendations +--------------------- - - Always surround these binary operators with a single space on - either side: assignment (=), augmented assignment (+=, -= etc.), - comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not), - Booleans (and, or, not). +- Always surround these binary operators with a single space on either + side: assignment (``=``), augmented assignment (``+=``, ``-=`` + etc.), comparisons (``==``, ``<``, ``>``, ``!=``, ``<>``, ``<=``, + ``>=``, ``in``, ``not in``, ``is``, ``is not``), Booleans (``and``, + ``or``, ``not``). - - Use spaces around arithmetic operators: +- Use spaces around arithmetic operators: - Yes: + Yes:: - i = i + 1 - submitted += 1 - x = x * 2 - 1 - hypot2 = x * x + y * y - c = (a + b) * (a - b) + i = i + 1 + submitted += 1 + x = x * 2 - 1 + hypot2 = x * x + y * y + c = (a + b) * (a - b) - No: + No:: - i=i+1 - submitted +=1 - x = x*2 - 1 - hypot2 = x*x + y*y - c = (a+b) * (a-b) + i=i+1 + submitted +=1 + x = x*2 - 1 + hypot2 = x*x + y*y + c = (a+b) * (a-b) - - Don't use spaces around the '=' sign when used to indicate a - keyword argument or a default parameter value. +- Don't use spaces around the ``=`` sign when used to indicate a + keyword argument or a default parameter value. - Yes: + Yes:: - def complex(real, imag=0.0): - return magic(r=real, i=imag) + def complex(real, imag=0.0): + return magic(r=real, i=imag) - No: + No:: - def complex(real, imag = 0.0): - return magic(r = real, i = imag) + def complex(real, imag = 0.0): + return magic(r = real, i = imag) - - Compound statements (multiple statements on the same line) are - generally discouraged. +- Compound statements (multiple statements on the same line) are + generally discouraged. - Yes: + Yes:: - if foo == 'blah': - do_blah_thing() - do_one() - do_two() - do_three() + if foo == 'blah': + do_blah_thing() + do_one() + do_two() + do_three() - Rather not: + Rather not:: - if foo == 'blah': do_blah_thing() - do_one(); do_two(); do_three() + if foo == 'blah': do_blah_thing() + do_one(); do_two(); do_three() - - While sometimes it's okay to put an if/for/while with a small - body on the same line, never do this for multi-clause - statements. Also avoid folding such long lines! +- While sometimes it's okay to put an if/for/while with a small body + on the same line, never do this for multi-clause statements. Also + avoid folding such long lines! - Rather not: + Rather not:: - if foo == 'blah': do_blah_thing() - for x in lst: total += x - while t < 10: t = delay() + if foo == 'blah': do_blah_thing() + for x in lst: total += x + while t < 10: t = delay() - Definitely not: + Definitely not:: - if foo == 'blah': do_blah_thing() - else: do_non_blah_thing() + if foo == 'blah': do_blah_thing() + else: do_non_blah_thing() - try: something() - finally: cleanup() + try: something() + finally: cleanup() - do_one(); do_two(); do_three(long, argument, - list, like, this) + do_one(); do_two(); do_three(long, argument, + list, like, this) - if foo == 'blah': one(); two(); three() + if foo == 'blah': one(); two(); three() Comments +======== - Comments that contradict the code are worse than no comments. Always make - a priority of keeping the comments up-to-date when the code changes! +Comments that contradict the code are worse than no comments. Always +make a priority of keeping the comments up-to-date when the code +changes! - Comments should be complete sentences. If a comment is a phrase or - sentence, its first word should be capitalized, unless it is an identifier - that begins with a lower case letter (never alter the case of - identifiers!). +Comments should be complete sentences. If a comment is a phrase or +sentence, its first word should be capitalized, unless it is an +identifier that begins with a lower case letter (never alter the case +of identifiers!). - If a comment is short, the period at the end can be omitted. Block - comments generally consist of one or more paragraphs built out of complete - sentences, and each sentence should end in a period. +If a comment is short, the period at the end can be omitted. Block +comments generally consist of one or more paragraphs built out of +complete sentences, and each sentence should end in a period. - You should use two spaces after a sentence-ending period. +You should use two spaces after a sentence-ending period. - When writing English, Strunk and White apply. +When writing English, Strunk and White apply. - Python coders from non-English speaking countries: please write - your comments in English, unless you are 120% sure that the code - will never be read by people who don't speak your language. +Python coders from non-English speaking countries: please write your +comments in English, unless you are 120% sure that the code will never +be read by people who don't speak your language. +Block Comments +-------------- - Block Comments +Block comments generally apply to some (or all) code that follows +them, and are indented to the same level as that code. Each line of a +block comment starts with a ``#`` and a single space (unless it is +indented text inside the comment). - Block comments generally apply to some (or all) code that follows them, - and are indented to the same level as that code. Each line of a block - comment starts with a # and a single space (unless it is indented text - inside the comment). +Paragraphs inside a block comment are separated by a line containing a +single ``#``. - Paragraphs inside a block comment are separated by a line containing a - single #. +Inline Comments +--------------- - Inline Comments +Use inline comments sparingly. - Use inline comments sparingly. +An inline comment is a comment on the same line as a statement. +Inline comments should be separated by at least two spaces from the +statement. They should start with a # and a single space. - An inline comment is a comment on the same line as a statement. Inline - comments should be separated by at least two spaces from the statement. - They should start with a # and a single space. +Inline comments are unnecessary and in fact distracting if they state +the obvious. Don't do this:: - Inline comments are unnecessary and in fact distracting if they state - the obvious. Don't do this: + x = x + 1 # Increment x - x = x + 1 # Increment x +But sometimes, this is useful:: - But sometimes, this is useful: - - x = x + 1 # Compensate for border - + x = x + 1 # Compensate for border Documentation Strings +--------------------- - Conventions for writing good documentation strings (a.k.a. "docstrings") - are immortalized in PEP 257 [3]. +Conventions for writing good documentation strings +(a.k.a. "docstrings") are immortalized in PEP 257. - - Write docstrings for all public modules, functions, classes, and - methods. Docstrings are not necessary for non-public methods, but you - should have a comment that describes what the method does. This comment - should appear after the "def" line. +- Write docstrings for all public modules, functions, classes, and + methods. Docstrings are not necessary for non-public methods, but + you should have a comment that describes what the method does. This + comment should appear after the ``def`` line. - - PEP 257 describes good docstring conventions. Note that most - importantly, the """ that ends a multiline docstring should be on a line - by itself, and preferably preceded by a blank line, e.g.: +- PEP 257 describes good docstring conventions. Note that most + importantly, the ``"""`` that ends a multiline docstring should be + on a line by itself, and preferably preceded by a blank line, e.g.:: """Return a foobang @@ -422,405 +449,422 @@ """ - - For one liner docstrings, it's okay to keep the closing """ on the same - line. +- For one liner docstrings, it's okay to keep the closing ``"""`` on + the same line. Version Bookkeeping +=================== - If you have to have Subversion, CVS, or RCS crud in your source file, do - it as follows. +If you have to have Subversion, CVS, or RCS crud in your source file, +do it as follows. :: - __version__ = "$Revision$" - # $Source$ + __version__ = "$Revision$" + # $Source$ - These lines should be included after the module's docstring, before any - other code, separated by a blank line above and below. +These lines should be included after the module's docstring, before +any other code, separated by a blank line above and below. Naming Conventions +================== - The naming conventions of Python's library are a bit of a mess, so we'll - never get this completely consistent -- nevertheless, here are the - currently recommended naming standards. New modules and packages - (including third party frameworks) should be written to these standards, - but where an existing library has a different style, internal consistency - is preferred. +The naming conventions of Python's library are a bit of a mess, so +we'll never get this completely consistent -- nevertheless, here are +the currently recommended naming standards. New modules and packages +(including third party frameworks) should be written to these +standards, but where an existing library has a different style, +internal consistency is preferred. - Descriptive: Naming Styles +Descriptive: Naming Styles +-------------------------- - There are a lot of different naming styles. It helps to be able to - recognize what naming style is being used, independently from what they - are used for. +There are a lot of different naming styles. It helps to be able to +recognize what naming style is being used, independently from what +they are used for. - The following naming styles are commonly distinguished: +The following naming styles are commonly distinguished: - - b (single lowercase letter) +- ``b`` (single lowercase letter) +- ``B`` (single uppercase letter) +- ``lowercase`` +- ``lower_case_with_underscores`` +- ``UPPERCASE`` +- ``UPPER_CASE_WITH_UNDERSCORES`` +- ``CapitalizedWords`` (or CapWords, or CamelCase -- so named because + of the bumpy look of its letters [4]_). This is also sometimes known + as StudlyCaps. - - B (single uppercase letter) + Note: When using abbreviations in CapWords, capitalize all the + letters of the abbreviation. Thus HTTPServerError is better than + HttpServerError. +- ``mixedCase`` (differs from CapitalizedWords by initial lowercase + character!) +- ``Capitalized_Words_With_Underscores`` (ugly!) - - lowercase +There's also the style of using a short unique prefix to group related +names together. This is not used much in Python, but it is mentioned +for completeness. For example, the ``os.stat()`` function returns a +tuple whose items traditionally have names like ``st_mode``, +``st_size`, ``st_mtime`` and so on. (This is done to emphasize the +correspondence with the fields of the POSIX system call struct, which +helps programmers familiar with that.) - - lower_case_with_underscores +The X11 library uses a leading X for all its public functions. In +Python, this style is generally deemed unnecessary because attribute +and method names are prefixed with an object, and function names are +prefixed with a module name. - - UPPERCASE +In addition, the following special forms using leading or trailing +underscores are recognized (these can generally be combined with any +case convention): - - UPPER_CASE_WITH_UNDERSCORES +- ``_single_leading_underscore``: weak "internal use" indicator. + E.g. ``from M import *`` does not import objects whose name starts + with an underscore. - - CapitalizedWords (or CapWords, or CamelCase -- so named because - of the bumpy look of its letters[4]). This is also sometimes known as - StudlyCaps. - - Note: When using abbreviations in CapWords, capitalize all the letters - of the abbreviation. Thus HTTPServerError is better than - HttpServerError. - - - mixedCase (differs from CapitalizedWords by initial lowercase - character!) - - - Capitalized_Words_With_Underscores (ugly!) - - There's also the style of using a short unique prefix to group related - names together. This is not used much in Python, but it is mentioned for - completeness. For example, the os.stat() function returns a tuple whose - items traditionally have names like st_mode, st_size, st_mtime and so on. - (This is done to emphasize the correspondence with the fields of the - POSIX system call struct, which helps programmers familiar with that.) - - The X11 library uses a leading X for all its public functions. In Python, - this style is generally deemed unnecessary because attribute and method - names are prefixed with an object, and function names are prefixed with a - module name. - - In addition, the following special forms using leading or trailing - underscores are recognized (these can generally be combined with any case - convention): - - - _single_leading_underscore: weak "internal use" indicator. E.g. "from M - import *" does not import objects whose name starts with an underscore. - - - single_trailing_underscore_: used by convention to avoid conflicts with - Python keyword, e.g. +- ``single_trailing_underscore_``: used by convention to avoid + conflicts with Python keyword, e.g. :: Tkinter.Toplevel(master, class_='ClassName') - - __double_leading_underscore: when naming a class attribute, invokes name - mangling (inside class FooBar, __boo becomes _FooBar__boo; see below). +- ``__double_leading_underscore``: when naming a class attribute, + invokes name mangling (inside class FooBar, ``__boo`` becomes + ``_FooBar__boo``; see below). - - __double_leading_and_trailing_underscore__: "magic" objects or - attributes that live in user-controlled namespaces. E.g. __init__, - __import__ or __file__. Never invent such names; only use them - as documented. +- ``__double_leading_and_trailing_underscore__``: "magic" objects or + attributes that live in user-controlled namespaces. + E.g. ``__init__``, ``__import__`` or ``__file__``. Never invent + such names; only use them as documented. - Prescriptive: Naming Conventions +Prescriptive: Naming Conventions +-------------------------------- - Names to Avoid +Names to Avoid +~~~~~~~~~~~~~~ - Never use the characters `l' (lowercase letter el), `O' (uppercase - letter oh), or `I' (uppercase letter eye) as single character variable - names. +Never use the characters `l' (lowercase letter el), `O' (uppercase +letter oh), or `I' (uppercase letter eye) as single character variable +names. - In some fonts, these characters are indistinguishable from the numerals - one and zero. When tempted to use `l', use `L' instead. +In some fonts, these characters are indistinguishable from the +numerals one and zero. When tempted to use `l', use `L' instead. - Package and Module Names +Package and Module Names +~~~~~~~~~~~~~~~~~~~~~~~~ - Modules should have short, all-lowercase names. Underscores can be used - in the module name if it improves readability. Python packages should - also have short, all-lowercase names, although the use of underscores is - discouraged. +Modules should have short, all-lowercase names. Underscores can be +used in the module name if it improves readability. Python packages +should also have short, all-lowercase names, although the use of +underscores is discouraged. - Since module names are mapped to file names, and some file systems are - case insensitive and truncate long names, it is important that module - names be chosen to be fairly short -- this won't be a problem on Unix, - but it may be a problem when the code is transported to older Mac or - Windows versions, or DOS. +Since module names are mapped to file names, and some file systems are +case insensitive and truncate long names, it is important that module +names be chosen to be fairly short -- this won't be a problem on Unix, +but it may be a problem when the code is transported to older Mac or +Windows versions, or DOS. - When an extension module written in C or C++ has an accompanying Python - module that provides a higher level (e.g. more object oriented) - interface, the C/C++ module has a leading underscore (e.g. _socket). +When an extension module written in C or C++ has an accompanying +Python module that provides a higher level (e.g. more object oriented) +interface, the C/C++ module has a leading underscore +(e.g. ``_socket``). - Class Names +Class Names +~~~~~~~~~~~ - Almost without exception, class names use the CapWords convention. - Classes for internal use have a leading underscore in addition. +Almost without exception, class names use the CapWords convention. +Classes for internal use have a leading underscore in addition. - Exception Names +Exception Names +~~~~~~~~~~~~~~~ - Because exceptions should be classes, the class naming convention - applies here. However, you should use the suffix "Error" on your - exception names (if the exception actually is an error). +Because exceptions should be classes, the class naming convention +applies here. However, you should use the suffix "Error" on your +exception names (if the exception actually is an error). - Global Variable Names +Global Variable Names +~~~~~~~~~~~~~~~~~~~~~ - (Let's hope that these variables are meant for use inside one module - only.) The conventions are about the same as those for functions. +(Let's hope that these variables are meant for use inside one module +only.) The conventions are about the same as those for functions. - Modules that are designed for use via "from M import *" should use the - __all__ mechanism to prevent exporting globals, or use the older - convention of prefixing such globals with an underscore (which you might - want to do to indicate these globals are "module non-public"). +Modules that are designed for use via "from M import *" should use the +``__all__`` mechanism to prevent exporting globals, or use the older +convention of prefixing such globals with an underscore (which you +might want to do to indicate these globals are "module non-public"). - Function Names +Function Names +~~~~~~~~~~~~~~ - Function names should be lowercase, with words separated by underscores - as necessary to improve readability. +Function names should be lowercase, with words separated by +underscores as necessary to improve readability. - mixedCase is allowed only in contexts where that's already the - prevailing style (e.g. threading.py), to retain backwards compatibility. +mixedCase is allowed only in contexts where that's already the +prevailing style (e.g. threading.py), to retain backwards +compatibility. - Function and method arguments +Function and method arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Always use 'self' for the first argument to instance methods. +Always use ``self`` for the first argument to instance methods. - Always use 'cls' for the first argument to class methods. +Always use ``cls`` for the first argument to class methods. - If a function argument's name clashes with a reserved keyword, it is - generally better to append a single trailing underscore rather than use - an abbreviation or spelling corruption. Thus "print_" is better than - "prnt". (Perhaps better is to avoid such clashes by using a synonym.) +If a function argument's name clashes with a reserved keyword, it is +generally better to append a single trailing underscore rather than +use an abbreviation or spelling corruption. Thus ``class_`` is better +than ``clss``. (Perhaps better is to avoid such clashes by using a +synonym.) - Method Names and Instance Variables +Method Names and Instance Variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Use the function naming rules: lowercase with words separated by - underscores as necessary to improve readability. +Use the function naming rules: lowercase with words separated by +underscores as necessary to improve readability. - Use one leading underscore only for non-public methods and instance - variables. +Use one leading underscore only for non-public methods and instance +variables. - To avoid name clashes with subclasses, use two leading underscores to - invoke Python's name mangling rules. +To avoid name clashes with subclasses, use two leading underscores to +invoke Python's name mangling rules. - Python mangles these names with the class name: if class Foo has an - attribute named __a, it cannot be accessed by Foo.__a. (An insistent - user could still gain access by calling Foo._Foo__a.) Generally, double - leading underscores should be used only to avoid name conflicts with - attributes in classes designed to be subclassed. +Python mangles these names with the class name: if class Foo has an +attribute named ``__a``, it cannot be accessed by ``Foo.__a``. (An +insistent user could still gain access by calling ``Foo._Foo__a``.) +Generally, double leading underscores should be used only to avoid +name conflicts with attributes in classes designed to be subclassed. - Note: there is some controversy about the use of __names (see below). +Note: there is some controversy about the use of __names (see below). - Constants +Constants +~~~~~~~~~ - Constants are usually defined on a module level and written in all - capital letters with underscores separating words. Examples include - MAX_OVERFLOW and TOTAL. +Constants are usually defined on a module level and written in all +capital letters with underscores separating words. Examples include +``MAX_OVERFLOW`` and ``TOTAL``. - Designing for inheritance +Designing for inheritance +~~~~~~~~~~~~~~~~~~~~~~~~~ - Always decide whether a class's methods and instance variables - (collectively: "attributes") should be public or non-public. If in - doubt, choose non-public; it's easier to make it public later than to - make a public attribute non-public. +Always decide whether a class's methods and instance variables +(collectively: "attributes") should be public or non-public. If in +doubt, choose non-public; it's easier to make it public later than to +make a public attribute non-public. - Public attributes are those that you expect unrelated clients of your - class to use, with your commitment to avoid backward incompatible - changes. Non-public attributes are those that are not intended to be - used by third parties; you make no guarantees that non-public attributes - won't change or even be removed. +Public attributes are those that you expect unrelated clients of your +class to use, with your commitment to avoid backward incompatible +changes. Non-public attributes are those that are not intended to be +used by third parties; you make no guarantees that non-public +attributes won't change or even be removed. - We don't use the term "private" here, since no attribute is really - private in Python (without a generally unnecessary amount of work). +We don't use the term "private" here, since no attribute is really +private in Python (without a generally unnecessary amount of work). - Another category of attributes are those that are part of the "subclass - API" (often called "protected" in other languages). Some classes are - designed to be inherited from, either to extend or modify aspects of the - class's behavior. When designing such a class, take care to make - explicit decisions about which attributes are public, which are part of - the subclass API, and which are truly only to be used by your base - class. +Another category of attributes are those that are part of the +"subclass API" (often called "protected" in other languages). Some +classes are designed to be inherited from, either to extend or modify +aspects of the class's behavior. When designing such a class, take +care to make explicit decisions about which attributes are public, +which are part of the subclass API, and which are truly only to be +used by your base class. - With this in mind, here are the Pythonic guidelines: +With this in mind, here are the Pythonic guidelines: - - Public attributes should have no leading underscores. +- Public attributes should have no leading underscores. - - If your public attribute name collides with a reserved keyword, append - a single trailing underscore to your attribute name. This is - preferable to an abbreviation or corrupted spelling. (However, - notwithstanding this rule, 'cls' is the preferred spelling for any - variable or argument which is known to be a class, especially the - first argument to a class method.) +- If your public attribute name collides with a reserved keyword, + append a single trailing underscore to your attribute name. This is + preferable to an abbreviation or corrupted spelling. (However, + notwithstanding this rule, 'cls' is the preferred spelling for any + variable or argument which is known to be a class, especially the + first argument to a class method.) - Note 1: See the argument name recommendation above for class methods. + Note 1: See the argument name recommendation above for class methods. - - For simple public data attributes, it is best to expose just the - attribute name, without complicated accessor/mutator methods. Keep in - mind that Python provides an easy path to future enhancement, should - you find that a simple data attribute needs to grow functional - behavior. In that case, use properties to hide functional - implementation behind simple data attribute access syntax. +- For simple public data attributes, it is best to expose just the + attribute name, without complicated accessor/mutator methods. Keep + in mind that Python provides an easy path to future enhancement, + should you find that a simple data attribute needs to grow + functional behavior. In that case, use properties to hide + functional implementation behind simple data attribute access + syntax. - Note 1: Properties only work on new-style classes. + Note 1: Properties only work on new-style classes. - Note 2: Try to keep the functional behavior side-effect free, although - side-effects such as caching are generally fine. + Note 2: Try to keep the functional behavior side-effect free, + although side-effects such as caching are generally fine. - Note 3: Avoid using properties for computationally expensive - operations; the attribute notation makes the caller believe - that access is (relatively) cheap. + Note 3: Avoid using properties for computationally expensive + operations; the attribute notation makes the caller believe that + access is (relatively) cheap. - - If your class is intended to be subclassed, and you have attributes - that you do not want subclasses to use, consider naming them with - double leading underscores and no trailing underscores. This invokes - Python's name mangling algorithm, where the name of the class is - mangled into the attribute name. This helps avoid attribute name - collisions should subclasses inadvertently contain attributes with the - same name. +- If your class is intended to be subclassed, and you have attributes + that you do not want subclasses to use, consider naming them with + double leading underscores and no trailing underscores. This + invokes Python's name mangling algorithm, where the name of the + class is mangled into the attribute name. This helps avoid + attribute name collisions should subclasses inadvertently contain + attributes with the same name. - Note 1: Note that only the simple class name is used in the mangled - name, so if a subclass chooses both the same class name and attribute - name, you can still get name collisions. + Note 1: Note that only the simple class name is used in the mangled + name, so if a subclass chooses both the same class name and attribute + name, you can still get name collisions. - Note 2: Name mangling can make certain uses, such as debugging and - __getattr__(), less convenient. However the name mangling algorithm - is well documented and easy to perform manually. + Note 2: Name mangling can make certain uses, such as debugging and + ``__getattr__()``, less convenient. However the name mangling + algorithm is well documented and easy to perform manually. - Note 3: Not everyone likes name mangling. Try to balance the - need to avoid accidental name clashes with potential use by - advanced callers. + Note 3: Not everyone likes name mangling. Try to balance the + need to avoid accidental name clashes with potential use by + advanced callers. Programming Recommendations +=========================== - - Code should be written in a way that does not disadvantage other - implementations of Python (PyPy, Jython, IronPython, Pyrex, Psyco, - and such). +- Code should be written in a way that does not disadvantage other + implementations of Python (PyPy, Jython, IronPython, Cython, Psyco, + and such). - For example, do not rely on CPython's efficient implementation of - in-place string concatenation for statements in the form a+=b or a=a+b. - Those statements run more slowly in Jython. In performance sensitive - parts of the library, the ''.join() form should be used instead. This - will ensure that concatenation occurs in linear time across various - implementations. + For example, do not rely on CPython's efficient implementation of + in-place string concatenation for statements in the form ``a += b`` + or ``a = a + b``. Those statements run more slowly in Jython. In + performance sensitive parts of the library, the ``''.join()`` form + should be used instead. This will ensure that concatenation occurs + in linear time across various implementations. - - Comparisons to singletons like None should always be done with - 'is' or 'is not', never the equality operators. +- Comparisons to singletons like None should always be done with + ``is`` or ``is not``, never the equality operators. - Also, beware of writing "if x" when you really mean "if x is not None" - -- e.g. when testing whether a variable or argument that defaults to - None was set to some other value. The other value might have a type - (such as a container) that could be false in a boolean context! + Also, beware of writing ``if x`` when you really mean ``if x is not + None`` -- e.g. when testing whether a variable or argument that + defaults to None was set to some other value. The other value might + have a type (such as a container) that could be false in a boolean + context! - - When implementing ordering operations with rich comparisons, it is best to - implement all six operations (__eq__, __ne__, __lt__, __le__, __gt__, - __ge__) rather than relying on other code to only exercise a particular - comparison. +- When implementing ordering operations with rich comparisons, it is + best to implement all six operations (``__eq__``, ``__ne__``, + ``__lt__``, ``__le__``, ``__gt__``, ``__ge__``) rather than relying + on other code to only exercise a particular comparison. - To minimize the effort involved, the functools.total_ordering() decorator - provides a tool to generate missing comparison methods. + To minimize the effort involved, the ``functools.total_ordering()`` + decorator provides a tool to generate missing comparison methods. - PEP 207 indicates that reflexivity rules *are* assumed by Python. Thus, - the interpreter may swap y>x with x=x with x<=y, and may swap the - arguments of x==y and x!=y. The sort() and min() operations are - guaranteed to use the < operator and the max() function uses the > - operator. However, it is best to implement all six operations so that - confusion doesn't arise in other contexts. + PEP 207 indicates that reflexivity rules *are* assumed by Python. + Thus, the interpreter may swap ``y > x`` with ``x < y``, ``y >= x`` + with ``x <= y``, and may swap the arguments of ``x == y`` and ``x != + y``. The ``sort()`` and ``min()`` operations are guaranteed to use + the ``<`` operator and the ``max()`` function uses the ``>`` + operator. However, it is best to implement all six operations so + that confusion doesn't arise in other contexts. - - Use class-based exceptions. +- Use class-based exceptions. - String exceptions in new code are forbidden, because this language - feature is being removed in Python 2.6. + String exceptions in new code are forbidden, because this language + feature is being removed in Python 2.6. - Modules or packages should define their own domain-specific base - exception class, which should be subclassed from the built-in Exception - class. Always include a class docstring. E.g.: + Modules or packages should define their own domain-specific base + exception class, which should be subclassed from the built-in + Exception class. Always include a class docstring. E.g.:: - class MessageError(Exception): - """Base class for errors in the email package.""" + class MessageError(Exception): + """Base class for errors in the email package.""" - Class naming conventions apply here, although you should add the suffix - "Error" to your exception classes, if the exception is an error. - Non-error exceptions need no special suffix. + Class naming conventions apply here, although you should add the + suffix "Error" to your exception classes, if the exception is an + error. Non-error exceptions need no special suffix. - - When raising an exception, use "raise ValueError('message')" instead of - the older form "raise ValueError, 'message'". +- When raising an exception, use ``raise ValueError('message')`` + instead of the older form ``raise ValueError, 'message'``. - The paren-using form is preferred because when the exception arguments - are long or include string formatting, you don't need to use line - continuation characters thanks to the containing parentheses. The older - form will be removed in Python 3000. + The paren-using form is preferred because when the exception + arguments are long or include string formatting, you don't need to + use line continuation characters thanks to the containing + parentheses. The older form will be removed in Python 3. - - When catching exceptions, mention specific exceptions - whenever possible instead of using a bare 'except:' clause. +- When catching exceptions, mention specific exceptions whenever + possible instead of using a bare ``except:`` clause. - For example, use: + For example, use:: - try: - import platform_specific_module - except ImportError: - platform_specific_module = None + try: + import platform_specific_module + except ImportError: + platform_specific_module = None - A bare 'except:' clause will catch SystemExit and KeyboardInterrupt - exceptions, making it harder to interrupt a program with Control-C, - and can disguise other problems. If you want to catch all - exceptions that signal program errors, use 'except Exception:'. + A bare ``except:`` clause will catch SystemExit and + KeyboardInterrupt exceptions, making it harder to interrupt a + program with Control-C, and can disguise other problems. If you + want to catch all exceptions that signal program errors, use + ``except Exception:`` (bare except is equivalent to ``except + BaseException:``). - A good rule of thumb is to limit use of bare 'except' clauses to two - cases: + A good rule of thumb is to limit use of bare 'except' clauses to two + cases: - 1) If the exception handler will be printing out or logging - the traceback; at least the user will be aware that an - error has occurred. + 1. If the exception handler will be printing out or logging the + traceback; at least the user will be aware that an error has + occurred. - 2) If the code needs to do some cleanup work, but then lets - the exception propagate upwards with 'raise'. - 'try...finally' is a better way to handle this case. + 2. If the code needs to do some cleanup work, but then lets the + exception propagate upwards with ``raise``. ``try...finally`` + can be a better way to handle this case. - - Additionally, for all try/except clauses, limit the 'try' clause - to the absolute minimum amount of code necessary. Again, this - avoids masking bugs. +- Additionally, for all try/except clauses, limit the ``try`` clause + to the absolute minimum amount of code necessary. Again, this + avoids masking bugs. - Yes: + Yes:: - try: - value = collection[key] - except KeyError: - return key_not_found(key) - else: - return handle_value(value) + try: + value = collection[key] + except KeyError: + return key_not_found(key) + else: + return handle_value(value) - No: + No:: - try: - # Too broad! - return handle_value(collection[key]) - except KeyError: - # Will also catch KeyError raised by handle_value() - return key_not_found(key) + try: + # Too broad! + return handle_value(collection[key]) + except KeyError: + # Will also catch KeyError raised by handle_value() + return key_not_found(key) - - Use string methods instead of the string module. +- Use string methods instead of the string module. - String methods are always much faster and share the same API with - unicode strings. Override this rule if backward compatibility with - Pythons older than 2.0 is required. + String methods are always much faster and share the same API with + unicode strings. Override this rule if backward compatibility with + Pythons older than 2.0 is required. - - Use ''.startswith() and ''.endswith() instead of string slicing to check - for prefixes or suffixes. +- Use ``''.startswith()`` and ``''.endswith()`` instead of string + slicing to check for prefixes or suffixes. - startswith() and endswith() are cleaner and less error prone. For - example: + startswith() and endswith() are cleaner and less error prone. For + example:: - Yes: if foo.startswith('bar'): + Yes: if foo.startswith('bar'): + No: if foo[:3] == 'bar': - No: if foo[:3] == 'bar': + The exception is if your code must work with Python 1.5.2 (but let's + hope not!). - The exception is if your code must work with Python 1.5.2 (but let's - hope not!). +- Object type comparisons should always use isinstance() instead of + comparing types directly. :: - - Object type comparisons should always use isinstance() instead - of comparing types directly. + Yes: if isinstance(obj, int): - Yes: if isinstance(obj, int): + No: if type(obj) is type(1): - No: if type(obj) is type(1): + When checking if an object is a string, keep in mind that it might + be a unicode string too! In Python 2.3, str and unicode have a + common base class, basestring, so you can do:: - When checking if an object is a string, keep in mind that it might be a - unicode string too! In Python 2.3, str and unicode have a common base - class, basestring, so you can do: + if isinstance(obj, basestring): - if isinstance(obj, basestring): - - - For sequences, (strings, lists, tuples), use the fact that empty - sequences are false. +- For sequences, (strings, lists, tuples), use the fact that empty + sequences are false. :: Yes: if not seq: if seq: @@ -828,44 +872,42 @@ No: if len(seq) if not len(seq) - - Don't write string literals that rely on significant trailing - whitespace. Such trailing whitespace is visually indistinguishable and - some editors (or more recently, reindent.py) will trim them. +- Don't write string literals that rely on significant trailing + whitespace. Such trailing whitespace is visually indistinguishable + and some editors (or more recently, reindent.py) will trim them. - - Don't compare boolean values to True or False using == +- Don't compare boolean values to True or False using ``==``. :: - Yes: if greeting: - - No: if greeting == True: - - Worse: if greeting is True: + Yes: if greeting: + No: if greeting == True: + Worse: if greeting is True: References +========== - [1] PEP 7, Style Guide for C Code, van Rossum +.. [1] PEP 7, Style Guide for C Code, van Rossum - [2] http://www.python.org/doc/essays/styleguide.html +.. [2] http://www.python.org/doc/essays/styleguide.html - [3] PEP 257, Docstring Conventions, Goodger, van Rossum +.. [3] Barry's GNU Mailman style guide + http://barry.warsaw.us/software/STYLEGUIDE.txt - [4] http://www.wikipedia.com/wiki/CamelCase - - [5] Barry's GNU Mailman style guide - http://barry.warsaw.us/software/STYLEGUIDE.txt - - [6] PEP 20, The Zen of Python - - [7] PEP 328, Imports: Multi-Line and Absolute/Relative +.. [4] http://www.wikipedia.com/wiki/CamelCase Copyright +========= - This document has been placed in the public domain. +This document has been placed in the public domain. -Local Variables: -mode: indented-text -indent-tabs-mode: nil -End: +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 15 08:23:25 2012 From: python-checkins at python.org (georg.brandl) Date: Thu, 15 Mar 2012 08:23:25 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Fix_markup=2E?= Message-ID: http://hg.python.org/peps/rev/cd6a32d7a3a3 changeset: 4140:cd6a32d7a3a3 user: Georg Brandl date: Thu Mar 15 08:23:23 2012 +0100 summary: Fix markup. files: pep-0008.txt | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -543,12 +543,12 @@ Names to Avoid ~~~~~~~~~~~~~~ -Never use the characters `l' (lowercase letter el), `O' (uppercase -letter oh), or `I' (uppercase letter eye) as single character variable +Never use the characters 'l' (lowercase letter el), 'O' (uppercase +letter oh), or 'I' (uppercase letter eye) as single character variable names. In some fonts, these characters are indistinguishable from the -numerals one and zero. When tempted to use `l', use `L' instead. +numerals one and zero. When tempted to use 'l', use 'L' instead. Package and Module Names ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -588,10 +588,11 @@ (Let's hope that these variables are meant for use inside one module only.) The conventions are about the same as those for functions. -Modules that are designed for use via "from M import *" should use the -``__all__`` mechanism to prevent exporting globals, or use the older -convention of prefixing such globals with an underscore (which you -might want to do to indicate these globals are "module non-public"). +Modules that are designed for use via ``from M import *`` should use +the ``__all__`` mechanism to prevent exporting globals, or use the +older convention of prefixing such globals with an underscore (which +you might want to do to indicate these globals are "module +non-public"). Function Names ~~~~~~~~~~~~~~ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 15 08:24:14 2012 From: python-checkins at python.org (georg.brandl) Date: Thu, 15 Mar 2012 08:24:14 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Fix_more_markup=2E?= Message-ID: http://hg.python.org/peps/rev/dc5a21b8bc47 changeset: 4141:dc5a21b8bc47 user: Georg Brandl date: Thu Mar 15 08:24:13 2012 +0100 summary: Fix more markup. files: pep-0008.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -506,7 +506,7 @@ names together. This is not used much in Python, but it is mentioned for completeness. For example, the ``os.stat()`` function returns a tuple whose items traditionally have names like ``st_mode``, -``st_size`, ``st_mtime`` and so on. (This is done to emphasize the +``st_size``, ``st_mtime`` and so on. (This is done to emphasize the correspondence with the fields of the POSIX system call struct, which helps programmers familiar with that.) -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 15 13:02:15 2012 From: python-checkins at python.org (vinay.sajip) Date: Thu, 15 Mar 2012 13:02:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fixes_=2314314=3A_Improved_?= =?utf8?q?SMTP_timeout_handling=2E?= Message-ID: http://hg.python.org/cpython/rev/4b3f81720809 changeset: 75692:4b3f81720809 user: Vinay Sajip date: Thu Mar 15 12:02:08 2012 +0000 summary: Fixes #14314: Improved SMTP timeout handling. files: Lib/logging/handlers.py | 7 +++++-- Lib/test/test_logging.py | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -867,7 +867,7 @@ A handler class which sends an SMTP email for each logging event. """ def __init__(self, mailhost, fromaddr, toaddrs, subject, - credentials=None, secure=None): + credentials=None, secure=None, timeout=1.0): """ Initialize the handler. @@ -881,6 +881,8 @@ will be either an empty tuple, or a single-value tuple with the name of a keyfile, or a 2-value tuple with the names of the keyfile and certificate file. (This tuple is passed to the `starttls` method). + A timeout in seconds can be specified for the SMTP connection (the + default is one second). """ logging.Handler.__init__(self) if isinstance(mailhost, tuple): @@ -897,6 +899,7 @@ self.toaddrs = toaddrs self.subject = subject self.secure = secure + self.timeout = timeout def getSubject(self, record): """ @@ -919,7 +922,7 @@ port = self.mailport if not port: port = smtplib.SMTP_PORT - smtp = smtplib.SMTP(self.mailhost, port) + smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout) msg = self.format(record) msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % ( self.fromaddr, diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -936,8 +936,9 @@ r = logging.makeLogRecord({'msg': 'Hello'}) self.handled = threading.Event() h.handle(r) - self.handled.wait() + self.handled.wait(5.0) # 14314: don't wait forever server.stop() + self.assertTrue(self.handled.is_set()) self.assertEqual(len(self.messages), 1) peer, mailfrom, rcpttos, data = self.messages[0] self.assertEqual(mailfrom, 'me') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 13:05:46 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Thu, 15 Mar 2012 13:05:46 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=28sched=29_when_run=28=29_?= =?utf8?q?is_invoked_with_blocking=3DFalse_return_the_deadline_of_the?= Message-ID: http://hg.python.org/cpython/rev/59f0e6de54b3 changeset: 75693:59f0e6de54b3 user: Giampaolo Rodola' date: Thu Mar 15 13:05:41 2012 +0100 summary: (sched) when run() is invoked with blocking=False return the deadline of the next scheduled call in the scheduler; this use case was suggested in http://bugs.python.org/issue1641#msg149453 files: Doc/library/sched.rst | 3 ++- Lib/sched.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/library/sched.rst b/Doc/library/sched.rst --- a/Doc/library/sched.rst +++ b/Doc/library/sched.rst @@ -109,7 +109,8 @@ on until there are no more scheduled events. If *blocking* is False executes the scheduled events due to expire soonest - (if any) and then return. + (if any) and then return the deadline of the next scheduled call in the + scheduler (if any). Either *action* or *delayfunc* can raise an exception. In either case, the scheduler will maintain a consistent state and propagate the exception. If an diff --git a/Lib/sched.py b/Lib/sched.py --- a/Lib/sched.py +++ b/Lib/sched.py @@ -97,7 +97,8 @@ def run(self, blocking=True): """Execute events until the queue is empty. If blocking is False executes the scheduled events due to - expire soonest (if any) and then return. + expire soonest (if any) and then return the deadline of the + next scheduled call in the scheduler. When there is a positive delay until the first event, the delay function is called and the event is left in the queue; @@ -129,7 +130,7 @@ now = timefunc() if now < time: if not blocking: - return + return time - now delayfunc(time - now) else: event = pop(q) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 18:08:48 2012 From: python-checkins at python.org (matthias.klose) Date: Thu, 15 Mar 2012 18:08:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2314321=3A_Do_not_?= =?utf8?q?run_pgen_during_the_build_if_files_are_up_to_date=2E?= Message-ID: http://hg.python.org/cpython/rev/52597f888e7a changeset: 75694:52597f888e7a user: Matthias Klose date: Thu Mar 15 18:08:34 2012 +0100 summary: - Issue #14321: Do not run pgen during the build if files are up to date. files: Makefile.pre.in | 38 +++++++++++++++++++++++---- Misc/NEWS | 5 +++ configure | 50 +++++++++++++++++++++++++++++++++++++ configure.ac | 1 + 4 files changed, 88 insertions(+), 6 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -58,6 +58,8 @@ # Also, making them read-only seems to be a good idea... INSTALL_SHARED= ${INSTALL} -m 555 +MKDIR_P= @MKDIR_P@ + MAKESETUP= $(srcdir)/Modules/makesetup # Compiler options @@ -233,6 +235,18 @@ # Parser PGEN= Parser/pgen$(EXE) +PSRCS= \ + Parser/acceler.c \ + Parser/grammar1.c \ + Parser/listnode.c \ + Parser/node.c \ + Parser/parser.c \ + Parser/bitset.c \ + Parser/metagrammar.c \ + Parser/firstsets.c \ + Parser/grammar.c \ + Parser/pgen.c + POBJS= \ Parser/acceler.o \ Parser/grammar1.o \ @@ -247,6 +261,16 @@ PARSER_OBJS= $(POBJS) Parser/myreadline.o Parser/parsetok.o Parser/tokenizer.o +PGSRCS= \ + Objects/obmalloc.c \ + Python/dynamic_annotations.c \ + Python/mysnprintf.c \ + Python/pyctype.c \ + Parser/tokenizer_pgen.c \ + Parser/printgrammar.c \ + Parser/parsetok_pgen.c \ + Parser/pgenmain.c + PGOBJS= \ Objects/obmalloc.o \ Python/dynamic_annotations.o \ @@ -262,7 +286,8 @@ $(srcdir)/Include/parsetok.h \ $(srcdir)/Parser/tokenizer.h -PGENOBJS= $(PGENMAIN) $(POBJS) $(PGOBJS) +PGENSRCS= $(PSRCS) $(PGSRCS) +PGENOBJS= $(POBJS) $(PGOBJS) ########################################################################## # AST @@ -591,12 +616,13 @@ $(IO_OBJS): $(IO_H) -# Use a stamp file to prevent make -j invoking pgen twice -$(GRAMMAR_H) $(GRAMMAR_C): Parser/pgen.stamp -Parser/pgen.stamp: $(PGEN) $(GRAMMAR_INPUT) - -@$(INSTALL) -d Include +$(GRAMMAR_H): $(GRAMMAR_INPUT) $(PGENSRCS) + @$(MKDIR_P) Include + $(MAKE) $(PGEN) $(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C) - -touch Parser/pgen.stamp +$(GRAMMAR_C): $(GRAMMAR_H) $(GRAMMAR_INPUT) $(PGENSRCS) + $(MAKE) $(GRAMMAR_H) + touch $(GRAMMAR_C) $(PGEN): $(PGENOBJS) $(CC) $(OPT) $(PY_LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -106,6 +106,11 @@ - Issue #14210: pdb now has tab-completion not only for command names, but also for their arguments, wherever possible. +Build +----- + +- Issue #14321: Do not run pgen during the build if files are up to date. + Extension Modules ----------------- diff --git a/configure b/configure --- a/configure +++ b/configure @@ -640,6 +640,7 @@ OPT ABIFLAGS LN +MKDIR_P INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM @@ -5382,6 +5383,48 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + # Not every filesystem supports hard links @@ -14647,6 +14690,7 @@ ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' test -n "\$AWK" || AWK=awk _ACEOF @@ -15214,6 +15258,11 @@ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 @@ -15268,6 +15317,7 @@ s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -848,6 +848,7 @@ fi esac AC_PROG_INSTALL +AC_PROG_MKDIR_P # Not every filesystem supports hard links AC_SUBST(LN) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:01:16 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:01:16 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzE0MTE0OiBkb24n?= =?utf8?q?t_include_copybutton=2Ejs_in_the_htmlhelp_output=2E?= Message-ID: http://hg.python.org/cpython/rev/11a11e5cac0f changeset: 75695:11a11e5cac0f branch: 2.7 parent: 75217:2cb325d661eb user: Ezio Melotti date: Sat Feb 25 19:24:24 2012 +0200 summary: #14114: don't include copybutton.js in the htmlhelp output. files: Doc/tools/sphinxext/layout.html | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tools/sphinxext/layout.html b/Doc/tools/sphinxext/layout.html --- a/Doc/tools/sphinxext/layout.html +++ b/Doc/tools/sphinxext/layout.html @@ -6,7 +6,7 @@ {% endblock %} {% block extrahead %} - + {% if not embedded %}{% endif %} {{ super() }} {% endblock %} {% block footer %} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:01:18 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:01:18 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_link_to_glo?= =?utf8?q?bal_module_index=2E?= Message-ID: http://hg.python.org/cpython/rev/c0db7cf0535a changeset: 75696:c0db7cf0535a branch: 2.7 parent: 75217:2cb325d661eb user: Georg Brandl date: Sat Mar 03 21:25:42 2012 +0100 summary: Fix link to global module index. files: Doc/tools/sphinxext/indexcontent.html | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tools/sphinxext/indexcontent.html b/Doc/tools/sphinxext/indexcontent.html --- a/Doc/tools/sphinxext/indexcontent.html +++ b/Doc/tools/sphinxext/indexcontent.html @@ -32,7 +32,7 @@

Indices and tables:

- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:01:19 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:01:19 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzE0MTE0OiBkb24n?= =?utf8?q?t_include_copybutton=2Ejs_in_the_htmlhelp_output=2E?= Message-ID: http://hg.python.org/cpython/rev/36ec90b6b5e5 changeset: 75697:36ec90b6b5e5 branch: 2.7 user: Ezio Melotti date: Sat Feb 25 19:24:24 2012 +0200 summary: #14114: don't include copybutton.js in the htmlhelp output. files: Doc/tools/sphinxext/layout.html | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tools/sphinxext/layout.html b/Doc/tools/sphinxext/layout.html --- a/Doc/tools/sphinxext/layout.html +++ b/Doc/tools/sphinxext/layout.html @@ -6,7 +6,7 @@ {% endblock %} {% block extrahead %} - + {% if not embedded %}{% endif %} {{ super() }} {% endblock %} {% block footer %} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:01:20 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:01:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fixes_Issue_=23?= =?utf8?q?14234=3A_CVE-2012-0876=3A_Randomize_hashes_of_xml_attributes?= Message-ID: http://hg.python.org/cpython/rev/04ff6e206b98 changeset: 75698:04ff6e206b98 branch: 2.7 user: Gregory P. Smith date: Wed Mar 14 15:28:10 2012 -0700 summary: Fixes Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project. files: Misc/NEWS | 15 ++ Modules/expat/expat.h | 9 + Modules/expat/pyexpatns.h | 1 + Modules/expat/xmlparse.c | 177 +++++++++++++++++-------- Modules/pyexpat.c | 2 + 5 files changed, 145 insertions(+), 59 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1,6 +1,21 @@ Python News +++++++++++ + +What's New in Python 2.7.3 release candidate 2? +=============================================== + +*Release date: 2012-03-XX* + +Library +------- + +- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash + table internal to the pyexpat module's copy of the expat library to avoid a + denial of service due to hash collisions. Patch by David Malcolm with some + modifications by the expat project. + + What's New in Python 2.7.3 release candidate 1? =============================================== diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -883,6 +883,15 @@ XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing); +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt); + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/expat/pyexpatns.h b/Modules/expat/pyexpatns.h --- a/Modules/expat/pyexpatns.h +++ b/Modules/expat/pyexpatns.h @@ -97,6 +97,7 @@ #define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler #define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler #define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg +#define XML_SetHashSalt PyExpat_XML_SetHashSalt #define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler #define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler #define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -17,6 +17,8 @@ #include #include /* memset(), memcpy() */ #include +#include /* UINT_MAX */ +#include /* time() */ #include "expat.h" @@ -387,12 +389,13 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +dtdCopy(XML_Parser oldParser, + DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); static int -copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); - +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize); +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); static void FASTCALL hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); static void FASTCALL hashTableClear(HASH_TABLE *); @@ -425,6 +428,9 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); +static unsigned long generate_hash_secret_salt(void); +static XML_Bool startParsing(XML_Parser parser); + static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, @@ -542,6 +548,7 @@ XML_Bool m_useForeignDTD; enum XML_ParamEntityParsing m_paramEntityParsing; #endif + unsigned long m_hash_secret_salt; }; #define MALLOC(s) (parser->m_mem.malloc_fcn((s))) @@ -649,6 +656,7 @@ #define useForeignDTD (parser->m_useForeignDTD) #define paramEntityParsing (parser->m_paramEntityParsing) #endif /* XML_DTD */ +#define hash_secret_salt (parser->m_hash_secret_salt) XML_Parser XMLCALL XML_ParserCreate(const XML_Char *encodingName) @@ -671,22 +679,36 @@ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' }; -XML_Parser XMLCALL -XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) +static unsigned long +generate_hash_secret_salt(void) { - XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); - if (parser != NULL && ns) { + unsigned int seed = time(NULL) % UINT_MAX; + srand(seed); + return rand(); +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) +{ + /* hash functions must be initialized before setContext() is called */ + + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { /* implicit context only set for root parser, since child parsers (i.e. external entity parsers) will inherit it */ - if (!setContext(parser, implicitContext)) { - XML_ParserFree(parser); - return NULL; - } + return setContext(parser, implicitContext); } - return parser; + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + return parserCreate(encodingName, memsuite, nameSep, NULL); } static XML_Parser @@ -860,6 +882,7 @@ useForeignDTD = XML_FALSE; paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #endif + hash_secret_salt = 0; } /* moves list of bindings to freeBindingList */ @@ -907,7 +930,7 @@ poolClear(&temp2Pool); parserInit(parser, encodingName); dtdReset(_dtd, &parser->m_mem); - return setContext(parser, implicitContext); + return XML_TRUE; } enum XML_Status XMLCALL @@ -976,6 +999,12 @@ int oldInEntityValue = prologState.inEntityValue; #endif XML_Bool oldns_triplets = ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt = hash_secret_salt; #ifdef XML_DTD if (!context) @@ -1029,13 +1058,14 @@ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; defaultExpandInternalEntities = oldDefaultExpandInternalEntities; ns_triplets = oldns_triplets; + hash_secret_salt = oldhash_secret_salt; parentParser = oldParser; #ifdef XML_DTD paramEntityParsing = oldParamEntityParsing; prologState.inEntityValue = oldInEntityValue; if (context) { #endif /* XML_DTD */ - if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) || !setContext(parser, context)) { XML_ParserFree(parser); return NULL; @@ -1420,6 +1450,17 @@ #endif } +int XMLCALL +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; + hash_secret_salt = hash_salt; + return 1; +} + enum XML_Status XMLCALL XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { @@ -1430,6 +1471,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -1488,11 +1534,13 @@ break; case XML_INITIALIZED: case XML_PARSING: - result = XML_STATUS_OK; if (isFinal) { ps_parsing = XML_FINISHED; - return result; + return XML_STATUS_OK; } + /* fall through */ + default: + result = XML_STATUS_OK; } } @@ -1553,6 +1601,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -2231,7 +2284,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&dtd->pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -2618,12 +2671,12 @@ const XML_Char *localPart; /* lookup the element type name */ - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); if (!elementType) { const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); if (!name) return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!elementType) return XML_ERROR_NO_MEMORY; @@ -2792,9 +2845,9 @@ if (s[-1] == 2) { /* prefixed */ ATTRIBUTE_ID *id; const BINDING *b; - unsigned long uriHash = 0; + unsigned long uriHash = hash_secret_salt; ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); if (!id) return XML_ERROR_NO_MEMORY; b = id->prefix->binding; @@ -2818,7 +2871,7 @@ } while (*s++); { /* Check hash table for duplicate of expanded name (uriName). - Derived from code in lookup(HASH_TABLE *table, ...). + Derived from code in lookup(parser, HASH_TABLE *table, ...). */ unsigned char step = 0; unsigned long mask = nsAttsSize - 1; @@ -3756,7 +3809,8 @@ case XML_ROLE_DOCTYPE_PUBLIC_ID: #ifdef XML_DTD useForeignDTD = XML_FALSE; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -3811,7 +3865,8 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -3855,7 +3910,7 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -4069,7 +4124,8 @@ break; #else /* XML_DTD */ if (!declEntity) { - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -4144,7 +4200,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4176,7 +4232,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4358,7 +4414,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&dtd->pool); /* first, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -4882,7 +4938,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&temp2Pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal. @@ -4991,7 +5047,7 @@ result = XML_ERROR_NO_MEMORY; goto endEntityValue; } - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&tempPool); if (!entity) { /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ @@ -5281,7 +5337,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return 0; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!prefix) return 0; @@ -5310,7 +5366,7 @@ return NULL; /* skip quotation mark - its storage will be re-used (like in name[-1]) */ ++name; - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); if (!id) return NULL; if (id->name != name) @@ -5328,7 +5384,7 @@ if (name[5] == XML_T('\0')) id->prefix = &dtd->defaultPrefix; else - id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); id->xmlns = XML_TRUE; } else { @@ -5343,7 +5399,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return NULL; - id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!id->prefix) return NULL; @@ -5441,7 +5497,7 @@ ENTITY *e; if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); if (e) e->open = XML_TRUE; if (*s != XML_T('\0')) @@ -5456,7 +5512,7 @@ else { if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), sizeof(PREFIX)); if (!prefix) return XML_FALSE; @@ -5620,7 +5676,7 @@ The new DTD has already been initialized. */ static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) { HASH_TABLE_ITER iter; @@ -5635,7 +5691,7 @@ name = poolCopyString(&(newDtd->pool), oldP->name); if (!name) return 0; - if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) return 0; } @@ -5657,7 +5713,7 @@ if (!name) return 0; ++name; - newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); if (!newA) return 0; @@ -5667,7 +5723,7 @@ if (oldA->prefix == &oldDtd->defaultPrefix) newA->prefix = &newDtd->defaultPrefix; else - newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); } } @@ -5686,7 +5742,7 @@ name = poolCopyString(&(newDtd->pool), oldE->name); if (!name) return 0; - newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); if (!newE) return 0; @@ -5700,14 +5756,14 @@ } if (oldE->idAtt) newE->idAtt = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; if (oldE->prefix) - newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { newE->defaultAtts[i].id = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -5721,13 +5777,15 @@ } /* Copy the entity tables. */ - if (!copyEntityTable(&(newDtd->generalEntities), + if (!copyEntityTable(oldParser, + &(newDtd->generalEntities), &(newDtd->pool), &(oldDtd->generalEntities))) return 0; #ifdef XML_DTD - if (!copyEntityTable(&(newDtd->paramEntities), + if (!copyEntityTable(oldParser, + &(newDtd->paramEntities), &(newDtd->pool), &(oldDtd->paramEntities))) return 0; @@ -5750,7 +5808,8 @@ } /* End dtdCopy */ static int -copyEntityTable(HASH_TABLE *newTable, +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable) { @@ -5769,7 +5828,7 @@ name = poolCopyString(newPool, oldE->name); if (!name) return 0; - newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); if (!newE) return 0; if (oldE->systemId) { @@ -5827,16 +5886,16 @@ } static unsigned long FASTCALL -hash(KEY s) +hash(XML_Parser parser, KEY s) { - unsigned long h = 0; + unsigned long h = hash_secret_salt; while (*s) h = CHAR_HASH(h, *s++); return h; } static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize) +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { size_t i; if (table->size == 0) { @@ -5853,10 +5912,10 @@ return NULL; } memset(table->v, 0, tsize); - i = hash(name) & ((unsigned long)table->size - 1); + i = hash(parser, name) & ((unsigned long)table->size - 1); } else { - unsigned long h = hash(name); + unsigned long h = hash(parser, name); unsigned long mask = (unsigned long)table->size - 1; unsigned char step = 0; i = h & mask; @@ -5882,7 +5941,7 @@ memset(newV, 0, tsize); for (i = 0; i < table->size; i++) if (table->v[i]) { - unsigned long newHash = hash(table->v[i]->name); + unsigned long newHash = hash(parser, table->v[i]->name); size_t j = newHash & newMask; step = 0; while (newV[j]) { @@ -6257,7 +6316,7 @@ if (!name) return NULL; - ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!ret) return NULL; if (ret->name != name) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1302,6 +1302,8 @@ else { self->itself = XML_ParserCreate(encoding); } + XML_SetHashSalt(self->itself, + (unsigned long)_Py_HashSecret.prefix); self->intern = intern; Py_XINCREF(self->intern); #ifdef Py_TPFLAGS_HAVE_GC -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:01:20 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:01:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fixes_Issue_142?= =?utf8?q?34=3A_fix_for_the_previous_commit=2C_keep_compilation_when?= Message-ID: http://hg.python.org/cpython/rev/ada6bfbeceb8 changeset: 75699:ada6bfbeceb8 branch: 2.7 user: Gregory P. Smith date: Wed Mar 14 18:12:23 2012 -0700 summary: Fixes Issue 14234: fix for the previous commit, keep compilation when using --with-system-expat working when the system expat does not have salted hash support. files: Modules/expat/expat.h | 2 ++ Modules/pyexpat.c | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -892,6 +892,8 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); +#define XML_HAS_SET_HASH_SALT /* Python Only: Defined for pyexpat.c. */ + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1302,8 +1302,13 @@ else { self->itself = XML_ParserCreate(encoding); } +#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) + /* This feature was added upstream in libexpat 2.1.0. Our expat copy + * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT + * to indicate that we can still use it. */ XML_SetHashSalt(self->itself, (unsigned long)_Py_HashSecret.prefix); +#endif self->intern = intern; Py_XINCREF(self->intern); #ifdef Py_TPFLAGS_HAVE_GC -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:01:21 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:01:21 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/c05839b1ae68 changeset: 75700:c05839b1ae68 branch: 2.7 parent: 75699:ada6bfbeceb8 parent: 75695:11a11e5cac0f user: Benjamin Peterson date: Wed Mar 14 21:07:00 2012 -0500 summary: merge heads files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:01:22 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:01:22 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogYnVtcCB0byAyLjcu?= =?utf8?q?3rc2?= Message-ID: http://hg.python.org/cpython/rev/d46c1973d3c4 changeset: 75701:d46c1973d3c4 branch: 2.7 tag: v2.7.3rc2 user: Benjamin Peterson date: Thu Mar 15 12:25:54 2012 -0500 summary: bump to 2.7.3rc2 files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 2 +- Misc/RPM/python-2.7.spec | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -24,10 +24,10 @@ #define PY_MINOR_VERSION 7 #define PY_MICRO_VERSION 3 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "2.7.3rc1" +#define PY_VERSION "2.7.3rc2" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -15,5 +15,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "2.7.3rc1" +__version__ = "2.7.3rc2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "2.7.3rc1" +IDLE_VERSION = "2.7.3rc2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,7 +5,7 @@ What's New in Python 2.7.3 release candidate 2? =============================================== -*Release date: 2012-03-XX* +*Release date: 2012-03-17* Library ------- diff --git a/Misc/RPM/python-2.7.spec b/Misc/RPM/python-2.7.spec --- a/Misc/RPM/python-2.7.spec +++ b/Misc/RPM/python-2.7.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 2.7.3rc1 +%define version 2.7.3rc2 %define libvers 2.7 #--end constants-- %define release 1pydotorg -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:01:23 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:01:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Added_tag_v2=2E?= =?utf8?q?7=2E3rc2_for_changeset_d46c1973d3c4?= Message-ID: http://hg.python.org/cpython/rev/32d54230e010 changeset: 75702:32d54230e010 branch: 2.7 user: Benjamin Peterson date: Thu Mar 15 12:59:07 2012 -0500 summary: Added tag v2.7.3rc2 for changeset d46c1973d3c4 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -151,3 +151,4 @@ f48756685406e8d0fa9d23d841fceb07e36a5656 v2.7.2rc1 8527427914a29d895bcb30be76a465143993a793 v2.7.2 b2c6aff96e1251a4f03cf866e7e75fb8232869f2 v2.7.3rc1 +d46c1973d3c407ecaa6a8ee16d3fad3ef506b51f v2.7.3rc2 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:01:26 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:01:26 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_merge_from_2=2E7_release_branch?= Message-ID: http://hg.python.org/cpython/rev/c4e0dfbc9f48 changeset: 75703:c4e0dfbc9f48 branch: 2.7 parent: 75689:1559a82a3529 parent: 75702:32d54230e010 user: Benjamin Peterson date: Thu Mar 15 13:01:04 2012 -0500 summary: merge from 2.7 release branch files: .hgtags | 1 + Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 2 +- Misc/RPM/python-2.7.spec | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -151,3 +151,4 @@ f48756685406e8d0fa9d23d841fceb07e36a5656 v2.7.2rc1 8527427914a29d895bcb30be76a465143993a793 v2.7.2 b2c6aff96e1251a4f03cf866e7e75fb8232869f2 v2.7.3rc1 +d46c1973d3c407ecaa6a8ee16d3fad3ef506b51f v2.7.3rc2 diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -24,10 +24,10 @@ #define PY_MINOR_VERSION 7 #define PY_MICRO_VERSION 3 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "2.7.3rc1" +#define PY_VERSION "2.7.3rc2" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -15,5 +15,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "2.7.3rc1" +__version__ = "2.7.3rc2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "2.7.3rc1" +IDLE_VERSION = "2.7.3rc2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -45,7 +45,7 @@ What's New in Python 2.7.3 release candidate 2? =============================================== -*Release date: 2012-03-XX* +*Release date: 2012-03-17* Library ------- diff --git a/Misc/RPM/python-2.7.spec b/Misc/RPM/python-2.7.spec --- a/Misc/RPM/python-2.7.spec +++ b/Misc/RPM/python-2.7.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 2.7.3rc1 +%define version 2.7.3rc2 %define libvers 2.7 #--end constants-- %define release 1pydotorg -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:51:58 2012 From: python-checkins at python.org (matthias.klose) Date: Thu, 15 Mar 2012 19:51:58 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2314324=3A_Fix_con?= =?utf8?q?figure_tests_for_cross_builds=2E?= Message-ID: http://hg.python.org/cpython/rev/fbbf9c187662 changeset: 75704:fbbf9c187662 parent: 75694:52597f888e7a user: Matthias Klose date: Thu Mar 15 19:31:06 2012 +0100 summary: - Issue #14324: Fix configure tests for cross builds. when using gcc, use a compilation test for the cross build check for long long format. files: Misc/NEWS | 2 ++ configure | 31 ++++++++++++++++++++++++++++++- configure.ac | 18 +++++++++++++++++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -111,6 +111,8 @@ - Issue #14321: Do not run pgen during the build if files are up to date. +- Issue #14324: Fix configure tests for cross builds. + Extension Modules ----------------- diff --git a/configure b/configure --- a/configure +++ b/configure @@ -13805,7 +13805,36 @@ $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : - ac_cv_have_long_long_format=no + ac_cv_have_long_long_format="cross -- assuming no" + if test x$GCC = xyes; then + save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Werror -Wformat" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + char *buffer; + sprintf(buffer, "%lld", (long long)123); + sprintf(buffer, "%lld", (long long)-123); + sprintf(buffer, "%llu", (unsigned long long)123); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_have_long_long_format=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$save_CFLAGS + fi else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -4128,7 +4128,23 @@ ]]])], [ac_cv_have_long_long_format=yes], [ac_cv_have_long_long_format=no], - [ac_cv_have_long_long_format=no]) + [ac_cv_have_long_long_format="cross -- assuming no" + if test x$GCC = xyes; then + save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Werror -Wformat" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + ]], [[ + char *buffer; + sprintf(buffer, "%lld", (long long)123); + sprintf(buffer, "%lld", (long long)-123); + sprintf(buffer, "%llu", (unsigned long long)123); + ]])], + ac_cv_have_long_long_format=yes + ) + CFLAGS=$save_CFLAGS + fi]) ) AC_MSG_RESULT($ac_cv_have_long_long_format) fi -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:51:59 2012 From: python-checkins at python.org (matthias.klose) Date: Thu, 15 Mar 2012 19:51:59 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2314324=3A_Fix_con?= =?utf8?q?figure_tests_for_cross_builds=2E?= Message-ID: http://hg.python.org/cpython/rev/29ee48f843ec changeset: 75705:29ee48f843ec user: Matthias Klose date: Thu Mar 15 19:51:34 2012 +0100 summary: - Issue #14324: Fix configure tests for cross builds. when configured --with(out)-computed-gotos for a cross, use this value instead of defaulting to no. files: configure | 71 ++++++++++++++++++++------------------- configure.ac | 51 +++++++++++++++------------- 2 files changed, 64 insertions(+), 58 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -14022,13 +14022,47 @@ fi +# Check for --with-computed-gotos +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-computed-gotos" >&5 +$as_echo_n "checking for --with-computed-gotos... " >&6; } + +# Check whether --with-computed-gotos was given. +if test "${with_computed_gotos+set}" = set; then : + withval=$with_computed_gotos; +if test "$withval" = yes +then + +$as_echo "#define USE_COMPUTED_GOTOS 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +if test "$withval" = no +then + +$as_echo "#define USE_COMPUTED_GOTOS 0" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 +$as_echo "no value specified" >&6; } +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports computed gotos" >&5 $as_echo_n "checking whether $CC supports computed gotos... " >&6; } if ${ac_cv_computed_gotos+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : - ac_cv_computed_gotos=no + if test "${with_computed_gotos+set}" = set; then + ac_cv_computed_gotos="$with_computed_gotos -- configured --with(out)-computed-gotos" + else + ac_cv_computed_gotos=no + fi else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -14058,42 +14092,11 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_computed_gotos" >&5 $as_echo "$ac_cv_computed_gotos" >&6; } -if test "$ac_cv_computed_gotos" = yes -then +case "$ac_cv_computed_gotos" in yes*) $as_echo "#define HAVE_COMPUTED_GOTOS 1" >>confdefs.h -fi - -# Check for --with-computed-gotos -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-computed-gotos" >&5 -$as_echo_n "checking for --with-computed-gotos... " >&6; } - -# Check whether --with-computed-gotos was given. -if test "${with_computed_gotos+set}" = set; then : - withval=$with_computed_gotos; -if test "$withval" = yes -then - -$as_echo "#define USE_COMPUTED_GOTOS 1" >>confdefs.h - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -if test "$withval" = no -then - -$as_echo "#define USE_COMPUTED_GOTOS 0" >>confdefs.h - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 -$as_echo "no value specified" >&6; } -fi - +esac case $ac_sys_system in AIX*) diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -4239,30 +4239,6 @@ wide chars that would be converted.]) fi -AC_MSG_CHECKING(whether $CC supports computed gotos) -AC_CACHE_VAL(ac_cv_computed_gotos, -AC_RUN_IFELSE([AC_LANG_SOURCE([[[ -int main(int argc, char **argv) -{ - static void *targets[1] = { &&LABEL1 }; - goto LABEL2; -LABEL1: - return 0; -LABEL2: - goto *targets[0]; - return 1; -} -]]])], -[ac_cv_computed_gotos=yes], -[ac_cv_computed_gotos=no], -[ac_cv_computed_gotos=no])) -AC_MSG_RESULT($ac_cv_computed_gotos) -if test "$ac_cv_computed_gotos" = yes -then - AC_DEFINE(HAVE_COMPUTED_GOTOS, 1, - [Define if the C compiler supports computed gotos.]) -fi - # Check for --with-computed-gotos AC_MSG_CHECKING(for --with-computed-gotos) AC_ARG_WITH(computed-gotos, @@ -4284,6 +4260,33 @@ ], [AC_MSG_RESULT(no value specified)]) +AC_MSG_CHECKING(whether $CC supports computed gotos) +AC_CACHE_VAL(ac_cv_computed_gotos, +AC_RUN_IFELSE([AC_LANG_SOURCE([[[ +int main(int argc, char **argv) +{ + static void *targets[1] = { &&LABEL1 }; + goto LABEL2; +LABEL1: + return 0; +LABEL2: + goto *targets[0]; + return 1; +} +]]])], +[ac_cv_computed_gotos=yes], +[ac_cv_computed_gotos=no], +[if test "${with_computed_gotos+set}" = set; then + ac_cv_computed_gotos="$with_computed_gotos -- configured --with(out)-computed-gotos" + else + ac_cv_computed_gotos=no + fi])) +AC_MSG_RESULT($ac_cv_computed_gotos) +case "$ac_cv_computed_gotos" in yes*) + AC_DEFINE(HAVE_COMPUTED_GOTOS, 1, + [Define if the C compiler supports computed gotos.]) +esac + case $ac_sys_system in AIX*) AC_DEFINE(HAVE_BROKEN_PIPE_BUF, 1, [Define if the system reports an invalid PIPE_BUF value.]) ;; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:59:00 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:59:00 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4xKTogYnVtcCB0byAzLjEu?= =?utf8?q?5rc2?= Message-ID: http://hg.python.org/cpython/rev/9346bc8d0a51 changeset: 75706:9346bc8d0a51 branch: 3.1 parent: 75199:df3b2b5db900 user: Benjamin Peterson date: Thu Mar 15 13:57:27 2012 -0500 summary: bump to 3.1.5rc2 files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 5 +++++ Misc/RPM/python-3.1.spec | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 1 #define PY_MICRO_VERSION 5 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.1.5rc1" +#define PY_VERSION "3.1.5rc2" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -15,5 +15,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.1.5rc1" +__version__ = "3.1.5rc2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.1.5rc1" +IDLE_VERSION = "3.1.5rc2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,11 @@ Library ------- +- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash + table internal to the pyexpat module's copy of the expat library to avoid a + denial of service due to hash collisions. Patch by David Malcolm with some + modifications by the expat project. + - Issue #14001: CVE-2012-0845: xmlrpc: Fix an endless loop in SimpleXMLRPCServer upon malformed POST request. diff --git a/Misc/RPM/python-3.1.spec b/Misc/RPM/python-3.1.spec --- a/Misc/RPM/python-3.1.spec +++ b/Misc/RPM/python-3.1.spec @@ -34,7 +34,7 @@ %define name python #--start constants-- -%define version 3.1.5rc1 +%define version 3.1.5rc2 %define libvers 3.1 #--end constants-- %define release 1pydotorg -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:59:01 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:59:01 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4xIC0+IDMuMSk6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/75db2bc69fc9 changeset: 75707:75db2bc69fc9 branch: 3.1 tag: v3.1.5rc2 parent: 75706:9346bc8d0a51 parent: 75662:7198ccff7afd user: Benjamin Peterson date: Thu Mar 15 13:57:38 2012 -0500 summary: merge heads files: Include/patchlevel.h | 2 +- Makefile.pre.in | 4 +- Misc/README.OpenBSD | 2 +- Modules/expat/expat.h | 9 + Modules/expat/pyexpatns.h | 1 + Modules/expat/xmlparse.c | 177 +++++++++++++++++-------- Modules/pyexpat.c | 2 + PC/pyconfig.h | 2 +- Python/thread.c | 2 +- configure | 5 +- configure.in | 0 pyconfig.h.in | 5 +- 12 files changed, 142 insertions(+), 69 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -2,7 +2,7 @@ /* Python version identification scheme. When the major or minor version changes, the VERSION variable in - configure.in must also be changed. + configure.ac must also be changed. There is also (independent) API version information in modsupport.h. */ diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -151,7 +151,7 @@ SUBDIRSTOO= Include Lib Misc Demo # Files and directories to be distributed -CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in +CONFIGFILES= configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in DISTFILES= README ChangeLog $(CONFIGFILES) DISTDIRS= $(SUBDIRS) $(SUBDIRSTOO) Ext-dummy DIST= $(DISTFILES) $(DISTDIRS) @@ -1137,7 +1137,7 @@ $(SHELL) config.status --recheck $(SHELL) config.status -# Rebuild the configure script from configure.in; also rebuild pyconfig.h.in +# Rebuild the configure script from configure.ac; also rebuild pyconfig.h.in autoconf: (cd $(srcdir); autoconf) (cd $(srcdir); autoheader) diff --git a/Misc/README.OpenBSD b/Misc/README.OpenBSD --- a/Misc/README.OpenBSD +++ b/Misc/README.OpenBSD @@ -29,7 +29,7 @@ If your version is not in that list, e.g., 3.9, add the version number. In this case, you would just need to add a 9 after the 8. -If you modify configure.in, you will need to regenerate configure +If you modify configure.ac, you will need to regenerate configure with autoconf. If your version is already in the list, this is not a known problem. diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -883,6 +883,15 @@ XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing); +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt); + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/expat/pyexpatns.h b/Modules/expat/pyexpatns.h --- a/Modules/expat/pyexpatns.h +++ b/Modules/expat/pyexpatns.h @@ -97,6 +97,7 @@ #define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler #define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler #define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg +#define XML_SetHashSalt PyExpat_XML_SetHashSalt #define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler #define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler #define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -17,6 +17,8 @@ #include #include /* memset(), memcpy() */ #include +#include /* UINT_MAX */ +#include /* time() */ #include "expat.h" @@ -387,12 +389,13 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +dtdCopy(XML_Parser oldParser, + DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); static int -copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); - +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize); +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); static void FASTCALL hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); static void FASTCALL hashTableClear(HASH_TABLE *); @@ -425,6 +428,9 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); +static unsigned long generate_hash_secret_salt(void); +static XML_Bool startParsing(XML_Parser parser); + static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, @@ -542,6 +548,7 @@ XML_Bool m_useForeignDTD; enum XML_ParamEntityParsing m_paramEntityParsing; #endif + unsigned long m_hash_secret_salt; }; #define MALLOC(s) (parser->m_mem.malloc_fcn((s))) @@ -649,6 +656,7 @@ #define useForeignDTD (parser->m_useForeignDTD) #define paramEntityParsing (parser->m_paramEntityParsing) #endif /* XML_DTD */ +#define hash_secret_salt (parser->m_hash_secret_salt) XML_Parser XMLCALL XML_ParserCreate(const XML_Char *encodingName) @@ -671,22 +679,36 @@ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' }; -XML_Parser XMLCALL -XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) +static unsigned long +generate_hash_secret_salt(void) { - XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); - if (parser != NULL && ns) { + unsigned int seed = time(NULL) % UINT_MAX; + srand(seed); + return rand(); +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) +{ + /* hash functions must be initialized before setContext() is called */ + + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { /* implicit context only set for root parser, since child parsers (i.e. external entity parsers) will inherit it */ - if (!setContext(parser, implicitContext)) { - XML_ParserFree(parser); - return NULL; - } + return setContext(parser, implicitContext); } - return parser; + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + return parserCreate(encodingName, memsuite, nameSep, NULL); } static XML_Parser @@ -860,6 +882,7 @@ useForeignDTD = XML_FALSE; paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #endif + hash_secret_salt = 0; } /* moves list of bindings to freeBindingList */ @@ -907,7 +930,7 @@ poolClear(&temp2Pool); parserInit(parser, encodingName); dtdReset(_dtd, &parser->m_mem); - return setContext(parser, implicitContext); + return XML_TRUE; } enum XML_Status XMLCALL @@ -976,6 +999,12 @@ int oldInEntityValue = prologState.inEntityValue; #endif XML_Bool oldns_triplets = ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt = hash_secret_salt; #ifdef XML_DTD if (!context) @@ -1029,13 +1058,14 @@ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; defaultExpandInternalEntities = oldDefaultExpandInternalEntities; ns_triplets = oldns_triplets; + hash_secret_salt = oldhash_secret_salt; parentParser = oldParser; #ifdef XML_DTD paramEntityParsing = oldParamEntityParsing; prologState.inEntityValue = oldInEntityValue; if (context) { #endif /* XML_DTD */ - if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) || !setContext(parser, context)) { XML_ParserFree(parser); return NULL; @@ -1420,6 +1450,17 @@ #endif } +int XMLCALL +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; + hash_secret_salt = hash_salt; + return 1; +} + enum XML_Status XMLCALL XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { @@ -1430,6 +1471,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -1488,11 +1534,13 @@ break; case XML_INITIALIZED: case XML_PARSING: - result = XML_STATUS_OK; if (isFinal) { ps_parsing = XML_FINISHED; - return result; + return XML_STATUS_OK; } + /* fall through */ + default: + result = XML_STATUS_OK; } } @@ -1553,6 +1601,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -2231,7 +2284,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&dtd->pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -2618,12 +2671,12 @@ const XML_Char *localPart; /* lookup the element type name */ - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); if (!elementType) { const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); if (!name) return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!elementType) return XML_ERROR_NO_MEMORY; @@ -2792,9 +2845,9 @@ if (s[-1] == 2) { /* prefixed */ ATTRIBUTE_ID *id; const BINDING *b; - unsigned long uriHash = 0; + unsigned long uriHash = hash_secret_salt; ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); if (!id) return XML_ERROR_NO_MEMORY; b = id->prefix->binding; @@ -2818,7 +2871,7 @@ } while (*s++); { /* Check hash table for duplicate of expanded name (uriName). - Derived from code in lookup(HASH_TABLE *table, ...). + Derived from code in lookup(parser, HASH_TABLE *table, ...). */ unsigned char step = 0; unsigned long mask = nsAttsSize - 1; @@ -3756,7 +3809,8 @@ case XML_ROLE_DOCTYPE_PUBLIC_ID: #ifdef XML_DTD useForeignDTD = XML_FALSE; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -3811,7 +3865,8 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -3855,7 +3910,7 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -4069,7 +4124,8 @@ break; #else /* XML_DTD */ if (!declEntity) { - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -4144,7 +4200,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4176,7 +4232,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4358,7 +4414,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&dtd->pool); /* first, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -4882,7 +4938,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&temp2Pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal. @@ -4991,7 +5047,7 @@ result = XML_ERROR_NO_MEMORY; goto endEntityValue; } - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&tempPool); if (!entity) { /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ @@ -5281,7 +5337,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return 0; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!prefix) return 0; @@ -5310,7 +5366,7 @@ return NULL; /* skip quotation mark - its storage will be re-used (like in name[-1]) */ ++name; - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); if (!id) return NULL; if (id->name != name) @@ -5328,7 +5384,7 @@ if (name[5] == XML_T('\0')) id->prefix = &dtd->defaultPrefix; else - id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); id->xmlns = XML_TRUE; } else { @@ -5343,7 +5399,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return NULL; - id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!id->prefix) return NULL; @@ -5441,7 +5497,7 @@ ENTITY *e; if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); if (e) e->open = XML_TRUE; if (*s != XML_T('\0')) @@ -5456,7 +5512,7 @@ else { if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), sizeof(PREFIX)); if (!prefix) return XML_FALSE; @@ -5620,7 +5676,7 @@ The new DTD has already been initialized. */ static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) { HASH_TABLE_ITER iter; @@ -5635,7 +5691,7 @@ name = poolCopyString(&(newDtd->pool), oldP->name); if (!name) return 0; - if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) return 0; } @@ -5657,7 +5713,7 @@ if (!name) return 0; ++name; - newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); if (!newA) return 0; @@ -5667,7 +5723,7 @@ if (oldA->prefix == &oldDtd->defaultPrefix) newA->prefix = &newDtd->defaultPrefix; else - newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); } } @@ -5686,7 +5742,7 @@ name = poolCopyString(&(newDtd->pool), oldE->name); if (!name) return 0; - newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); if (!newE) return 0; @@ -5700,14 +5756,14 @@ } if (oldE->idAtt) newE->idAtt = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; if (oldE->prefix) - newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { newE->defaultAtts[i].id = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -5721,13 +5777,15 @@ } /* Copy the entity tables. */ - if (!copyEntityTable(&(newDtd->generalEntities), + if (!copyEntityTable(oldParser, + &(newDtd->generalEntities), &(newDtd->pool), &(oldDtd->generalEntities))) return 0; #ifdef XML_DTD - if (!copyEntityTable(&(newDtd->paramEntities), + if (!copyEntityTable(oldParser, + &(newDtd->paramEntities), &(newDtd->pool), &(oldDtd->paramEntities))) return 0; @@ -5750,7 +5808,8 @@ } /* End dtdCopy */ static int -copyEntityTable(HASH_TABLE *newTable, +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable) { @@ -5769,7 +5828,7 @@ name = poolCopyString(newPool, oldE->name); if (!name) return 0; - newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); if (!newE) return 0; if (oldE->systemId) { @@ -5827,16 +5886,16 @@ } static unsigned long FASTCALL -hash(KEY s) +hash(XML_Parser parser, KEY s) { - unsigned long h = 0; + unsigned long h = hash_secret_salt; while (*s) h = CHAR_HASH(h, *s++); return h; } static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize) +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { size_t i; if (table->size == 0) { @@ -5853,10 +5912,10 @@ return NULL; } memset(table->v, 0, tsize); - i = hash(name) & ((unsigned long)table->size - 1); + i = hash(parser, name) & ((unsigned long)table->size - 1); } else { - unsigned long h = hash(name); + unsigned long h = hash(parser, name); unsigned long mask = (unsigned long)table->size - 1; unsigned char step = 0; i = h & mask; @@ -5882,7 +5941,7 @@ memset(newV, 0, tsize); for (i = 0; i < table->size; i++) if (table->v[i]) { - unsigned long newHash = hash(table->v[i]->name); + unsigned long newHash = hash(parser, table->v[i]->name); size_t j = newHash & newMask; step = 0; while (newV[j]) { @@ -6257,7 +6316,7 @@ if (!name) return NULL; - ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!ret) return NULL; if (ret->name != name) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1245,6 +1245,8 @@ else { self->itself = XML_ParserCreate(encoding); } + XML_SetHashSalt(self->itself, + (unsigned long)_Py_HashSecret.prefix); self->intern = intern; Py_XINCREF(self->intern); #ifdef Py_TPFLAGS_HAVE_GC diff --git a/PC/pyconfig.h b/PC/pyconfig.h --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -344,7 +344,7 @@ # define SIZEOF_FPOS_T 8 # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 -/* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, +/* configure.ac defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, sizeof(off_t) > sizeof(long), and sizeof(PY_LONG_LONG) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -24,7 +24,7 @@ #include #ifdef __sgi -#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.in */ +#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.ac */ #undef _POSIX_THREADS #endif #endif diff --git a/configure b/configure --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision. +# From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for python 3.1. # @@ -769,8 +769,7 @@ LDFLAGS LIBS CPPFLAGS -CPP -CPPFLAGS' +CPP' # Initialize some variables set by options. diff --git a/configure.in b/configure.ac rename from configure.in rename to configure.ac diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1,4 +1,4 @@ -/* pyconfig.h.in. Generated from configure.in by autoheader. */ +/* pyconfig.h.in. Generated from configure.ac by autoheader. */ #ifndef Py_PYCONFIG_H @@ -1102,6 +1102,9 @@ /* This must be defined on some systems to enable large file support. */ #undef _LARGEFILE_SOURCE +/* This must be defined on AIX systems to enable large file support. */ +#undef _LARGE_FILES + /* Define to 1 if on MINIX. */ #undef _MINIX -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 19:59:02 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 19:59:02 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E1=29=3A_Added_tag_v3=2E?= =?utf8?q?1=2E5rc2_for_changeset_75db2bc69fc9?= Message-ID: http://hg.python.org/cpython/rev/44eba26951f6 changeset: 75708:44eba26951f6 branch: 3.1 user: Benjamin Peterson date: Thu Mar 15 13:58:31 2012 -0500 summary: Added tag v3.1.5rc2 for changeset 75db2bc69fc9 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -78,3 +78,4 @@ 32fcb9e94985cb19ce37ba9543f091c0dbe9d7dd v3.1.4rc1 c918ec9f3a76d6afedfbb5d455004de880443a3d v3.1.4 ee26aca3219cf4bb0b93352e83edcc9cb28c7802 v3.1.5rc1 +75db2bc69fc9a3e4801e94e3e19801cb096208d8 v3.1.5rc2 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 20:42:31 2012 From: python-checkins at python.org (matthias.klose) Date: Thu, 15 Mar 2012 20:42:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2314324=3A_Fix_con?= =?utf8?q?figure_tests_for_cross_builds=2E?= Message-ID: http://hg.python.org/cpython/rev/58cd710d9dff changeset: 75709:58cd710d9dff parent: 75705:29ee48f843ec user: Matthias Klose date: Thu Mar 15 20:42:23 2012 +0100 summary: - Issue #14324: Fix configure tests for cross builds. when configured with --(en|dis)able-ipv6 for cross builds, don't fail the configury due to the missing buggy-getaddrinfo check. files: configure | 5 +++++ configure.ac | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -10854,7 +10854,12 @@ $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : + +if test "${enable_ipv6+set}" = set; then + ac_cv_buggy_getaddrinfo="no -- configured with --(en|dis)able-ipv6" +else ac_cv_buggy_getaddrinfo=yes +fi else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -3009,7 +3009,12 @@ ]]])], [ac_cv_buggy_getaddrinfo=no], [ac_cv_buggy_getaddrinfo=yes], -[ac_cv_buggy_getaddrinfo=yes])) +[ +if test "${enable_ipv6+set}" = set; then + ac_cv_buggy_getaddrinfo="no -- configured with --(en|dis)able-ipv6" +else + ac_cv_buggy_getaddrinfo=yes +fi])) fi AC_MSG_RESULT($ac_cv_buggy_getaddrinfo) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 21:28:47 2012 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 15 Mar 2012 21:28:47 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_the_urllib_?= =?utf8?q?closing_issue_which_hangs_on_particular_ftp_urls/ftp_servers=2E?= Message-ID: http://hg.python.org/cpython/rev/6ce4868861ba changeset: 75710:6ce4868861ba branch: 2.7 parent: 75703:c4e0dfbc9f48 user: Senthil Kumaran date: Thu Mar 15 13:24:40 2012 -0700 summary: Fix the urllib closing issue which hangs on particular ftp urls/ftp servers. closes issue11199 files: Lib/urllib.py | 2 +- Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/urllib.py b/Lib/urllib.py --- a/Lib/urllib.py +++ b/Lib/urllib.py @@ -980,11 +980,11 @@ self.hookargs = hookargs def close(self): - addbase.close(self) if self.closehook: self.closehook(*self.hookargs) self.closehook = None self.hookargs = None + addbase.close(self) class addinfo(addbase): """class to add an info() method to an open file.""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,8 @@ Library ------- +- Issue #11199: Fix the with urllib which hangs on particular ftp urls. + - Issue #5219: Prevent event handler cascade in IDLE. - Issue #14252: Fix subprocess.Popen.terminate() to not raise an error under -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 21:28:48 2012 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 15 Mar 2012 21:28:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_closes_Issue_?= =?utf8?q?=2311199=3A_Fix_the_with_urllib_which_hangs_on_particular_ftp_ur?= =?utf8?b?bHMu?= Message-ID: http://hg.python.org/cpython/rev/891184abbf6e changeset: 75711:891184abbf6e branch: 3.2 parent: 75690:5615d6b91b53 user: Senthil Kumaran date: Thu Mar 15 13:26:12 2012 -0700 summary: closes Issue #11199: Fix the with urllib which hangs on particular ftp urls. files: Lib/urllib/response.py | 2 +- Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/urllib/response.py b/Lib/urllib/response.py --- a/Lib/urllib/response.py +++ b/Lib/urllib/response.py @@ -61,11 +61,11 @@ self.hookargs = hookargs def close(self): - addbase.close(self) if self.closehook: self.closehook(*self.hookargs) self.closehook = None self.hookargs = None + addbase.close(self) class addinfo(addbase): """class to add an info() method to an open file.""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,8 @@ Library ------- +- Issue #11199: Fix the with urllib which hangs on particular ftp urls. + - Issue #14062: Header objects now correctly respect the 'linesep' setting when processed by BytesParser (which smtplib.SMTP.send_message uses). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 21:28:48 2012 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 15 Mar 2012 21:28:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_port_from_3=2E2_-_Fix_the_urllib_closing_issue_which_hangs_o?= =?utf8?q?n_particular_ftp?= Message-ID: http://hg.python.org/cpython/rev/9e7374779e19 changeset: 75712:9e7374779e19 parent: 75709:58cd710d9dff parent: 75711:891184abbf6e user: Senthil Kumaran date: Thu Mar 15 13:28:27 2012 -0700 summary: port from 3.2 - Fix the urllib closing issue which hangs on particular ftp urls/ftp servers. closes issue11199 files: Lib/urllib/response.py | 2 +- Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/urllib/response.py b/Lib/urllib/response.py --- a/Lib/urllib/response.py +++ b/Lib/urllib/response.py @@ -64,11 +64,11 @@ self.hookargs = hookargs def close(self): - addbase.close(self) if self.closehook: self.closehook(*self.hookargs) self.closehook = None self.hookargs = None + addbase.close(self) class addinfo(addbase): """class to add an info() method to an open file.""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #11199: Fix the with urllib which hangs on particular ftp urls. + - Issue #14222: Use the new time.steady() function instead of time.time() for timeout in queue and threading modules to not be affected of system time update. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 21:30:37 2012 From: python-checkins at python.org (matthias.klose) Date: Thu, 15 Mar 2012 21:30:37 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2314327=3A_Call_AC?= =?utf8?q?=5FCANONICAL=5FHOST_in_configure=2Eac_and_check_in?= Message-ID: http://hg.python.org/cpython/rev/04aa26c572ba changeset: 75713:04aa26c572ba user: Matthias Klose date: Thu Mar 15 21:30:11 2012 +0100 summary: - Issue #14327: Call AC_CANONICAL_HOST in configure.ac and check in config.{guess,sub}. files: Misc/NEWS | 3 + config.guess | 1530 ++++++++++++++++++++++++++++++++ config.sub | 1773 ++++++++++++++++++++++++++++++++++++++ configure | 142 ++- configure.ac | 2 + 5 files changed, 3421 insertions(+), 29 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -115,6 +115,9 @@ - Issue #14324: Fix configure tests for cross builds. +- Issue #14327: Call AC_CANONICAL_HOST in configure.ac and check in + config.{guess,sub}. + Extension Modules ----------------- diff --git a/config.guess b/config.guess new file mode 100755 --- /dev/null +++ b/config.guess @@ -0,0 +1,1530 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi at noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf at swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green at stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green at stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/config.sub new file mode 100755 --- /dev/null +++ b/config.sub @@ -0,0 +1,1773 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 \ + | ns16k | ns32k \ + | open8 \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i386-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure --- a/configure +++ b/configure @@ -696,6 +696,14 @@ CONFIG_ARGS SOVERSION VERSION +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build HAS_HG HGBRANCH HGTAG @@ -1377,6 +1385,10 @@ _ACEOF cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi @@ -2760,6 +2772,107 @@ ac_config_headers="$ac_config_headers pyconfig.h" +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + if test "$prefix" != "/"; then prefix=`echo "$prefix" | sed -e 's/\/$//g'` @@ -5261,35 +5374,6 @@ INSTALL="${srcdir}/install-sh -c" fi esac -ac_aux_dir= -for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,8 @@ AC_CONFIG_SRCDIR([Include/object.h]) AC_CONFIG_HEADER(pyconfig.h) +AC_CANONICAL_HOST + dnl Ensure that if prefix is specified, it does not end in a slash. If dnl it does, we get path names containing '//' which is both ugly and dnl can cause trouble. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 21:38:28 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 21:38:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_perform_yield_from_delegati?= =?utf8?q?on_by_repeating_YIELD=5FFROM_opcode_=28closes_=2314230=29?= Message-ID: http://hg.python.org/cpython/rev/72556ff86828 changeset: 75714:72556ff86828 parent: 75712:9e7374779e19 user: Benjamin Peterson date: Thu Mar 15 15:37:39 2012 -0500 summary: perform yield from delegation by repeating YIELD_FROM opcode (closes #14230) This allows generators that are using yield from to be seen by debuggers. It also kills the f_yieldfrom field on frame objects. Patch mostly from Mark Shannon with a few tweaks by me. files: Include/frameobject.h | 1 - Include/genobject.h | 3 +- Lib/test/test_pep380.py | 23 +++- Lib/test/test_sys.py | 2 +- Objects/frameobject.c | 4 - Objects/genobject.c | 179 +++++++++------------------ Python/ceval.c | 58 +++----- Python/compile.c | 6 +- Python/import.c | 3 +- 9 files changed, 113 insertions(+), 166 deletions(-) diff --git a/Include/frameobject.h b/Include/frameobject.h --- a/Include/frameobject.h +++ b/Include/frameobject.h @@ -27,7 +27,6 @@ to the current stack top. */ PyObject **f_stacktop; PyObject *f_trace; /* Trace function */ - PyObject *f_yieldfrom; /* Iterator being delegated to by yield from */ /* In a generator, we need to be able to swap between the exception state inside the generator and the exception state of the calling diff --git a/Include/genobject.h b/Include/genobject.h --- a/Include/genobject.h +++ b/Include/genobject.h @@ -19,7 +19,7 @@ /* True if generator is being executed. */ char gi_running; - + /* The code object backing the generator */ PyObject *gi_code; @@ -35,6 +35,7 @@ PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *); PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *); PyAPI_FUNC(int) PyGen_FetchStopIterationValue(PyObject **); +PyObject *_PyGen_Send(PyGenObject *, PyObject *); #ifdef __cplusplus } diff --git a/Lib/test/test_pep380.py b/Lib/test/test_pep380.py --- a/Lib/test/test_pep380.py +++ b/Lib/test/test_pep380.py @@ -10,7 +10,7 @@ import unittest import io import sys -import traceback +import inspect import parser from test.support import captured_stderr @@ -919,6 +919,27 @@ next(g1) g1.close() + def test_delegator_is_visible_to_debugger(self): + def call_stack(): + return [f[3] for f in inspect.stack()] + + def gen(): + yield call_stack() + yield call_stack() + yield call_stack() + + def spam(g): + yield from g + + def eggs(g): + yield from g + + for stack in spam(gen()): + self.assertTrue('spam' in stack) + + for stack in spam(eggs(gen())): + self.assertTrue('spam' in stack and 'eggs' in stack) + def test_main(): from test import support diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -730,7 +730,7 @@ nfrees = len(x.f_code.co_freevars) extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ ncells + nfrees - 1 - check(x, size(vh + '13P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) + check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) # function def func(): pass check(func, size(h + '12P')) diff --git a/Objects/frameobject.c b/Objects/frameobject.c --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -444,7 +444,6 @@ Py_CLEAR(f->f_exc_type); Py_CLEAR(f->f_exc_value); Py_CLEAR(f->f_exc_traceback); - Py_CLEAR(f->f_yieldfrom); co = f->f_code; if (co->co_zombieframe == NULL) @@ -476,7 +475,6 @@ Py_VISIT(f->f_exc_type); Py_VISIT(f->f_exc_value); Py_VISIT(f->f_exc_traceback); - Py_VISIT(f->f_yieldfrom); /* locals */ slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars); @@ -510,7 +508,6 @@ Py_CLEAR(f->f_exc_value); Py_CLEAR(f->f_exc_traceback); Py_CLEAR(f->f_trace); - Py_CLEAR(f->f_yieldfrom); /* locals */ slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars); @@ -714,7 +711,6 @@ f->f_lasti = -1; f->f_lineno = code->co_firstlineno; f->f_iblock = 0; - f->f_yieldfrom = NULL; _PyObject_GC_TRACK(f); return f; diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -6,7 +6,6 @@ #include "opcode.h" static PyObject *gen_close(PyGenObject *gen, PyObject *args); -static void gen_undelegate(PyGenObject *gen); static int gen_traverse(PyGenObject *gen, visitproc visit, void *arg) @@ -41,15 +40,6 @@ PyObject_GC_Del(gen); } -static int -gen_running(PyGenObject *gen) -{ - if (gen->gi_running) { - PyErr_SetString(PyExc_ValueError, "generator already executing"); - return 1; - } - return 0; -} static PyObject * gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) @@ -58,7 +48,11 @@ PyFrameObject *f = gen->gi_frame; PyObject *result; - assert(!gen->gi_running); + if (gen->gi_running) { + PyErr_SetString(PyExc_ValueError, + "generator already executing"); + return NULL; + } if (f==NULL || f->f_stacktop == NULL) { /* Only set exception if called from send() */ if (arg && !exc) @@ -136,45 +130,10 @@ "send(arg) -> send 'arg' into generator,\n\ return next yielded value or raise StopIteration."); -static PyObject * -gen_send(PyGenObject *gen, PyObject *arg) +PyObject * +_PyGen_Send(PyGenObject *gen, PyObject *arg) { - int exc = 0; - PyObject *ret; - PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL; - if (gen_running(gen)) - return NULL; - /* XXX (ncoghlan): Are the incref/decref on arg and yf strictly needed? - * Or would it be valid to rely on borrowed references? - */ - Py_INCREF(arg); - if (yf) { - Py_INCREF(yf); - gen->gi_running = 1; - if (PyGen_CheckExact(yf)) { - ret = gen_send((PyGenObject *)yf, arg); - } else { - if (arg == Py_None) - ret = PyIter_Next(yf); - else - ret = PyObject_CallMethod(yf, "send", "O", arg); - } - gen->gi_running = 0; - if (ret) { - Py_DECREF(yf); - goto done; - } - gen_undelegate(gen); - Py_CLEAR(arg); - if (PyGen_FetchStopIterationValue(&arg) < 0) { - exc = 1; - } - Py_DECREF(yf); - } - ret = gen_send_ex(gen, arg, exc); -done: - Py_XDECREF(arg); - return ret; + return gen_send_ex(gen, arg, 0); } PyDoc_STRVAR(close_doc, @@ -186,49 +145,61 @@ */ static int -gen_close_iter(PyGenObject *gen, PyObject *yf) +gen_close_iter(PyObject *yf) { PyObject *retval = NULL; - int err = 0; - + if (PyGen_CheckExact(yf)) { retval = gen_close((PyGenObject *)yf, NULL); - if (!retval) - err = -1; + if (retval == NULL) + return -1; } else { - PyObject *meth; - gen->gi_running = 1; - meth = PyObject_GetAttrString(yf, "close"); + PyObject *meth = PyObject_GetAttrString(yf, "close"); if (meth == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) PyErr_WriteUnraisable(yf); - } PyErr_Clear(); } else { retval = PyObject_CallFunction(meth, ""); Py_DECREF(meth); - if (!retval) - err = -1; + if (retval == NULL) + return -1; } - gen->gi_running = 0; } Py_XDECREF(retval); - return err; -} + return 0; +} + +static PyObject * +gen_yf(PyGenObject *gen) +{ + PyObject *yf = NULL; + PyFrameObject *f = gen->gi_frame; + + if (f) { + PyObject *bytecode = f->f_code->co_code; + unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); + + if (code[f->f_lasti + 1] != YIELD_FROM) + return NULL; + yf = f->f_stacktop[-1]; + Py_INCREF(yf); + } + + return yf; +} static PyObject * gen_close(PyGenObject *gen, PyObject *args) { PyObject *retval; - PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL; + PyObject *yf = gen_yf(gen); int err = 0; - if (gen_running(gen)) - return NULL; if (yf) { - Py_INCREF(yf); - err = gen_close_iter(gen, yf); - gen_undelegate(gen); + gen->gi_running = 1; + err = gen_close_iter(yf); + gen->gi_running = 0; Py_DECREF(yf); } if (err == 0) @@ -241,8 +212,7 @@ return NULL; } if (PyErr_ExceptionMatches(PyExc_StopIteration) - || PyErr_ExceptionMatches(PyExc_GeneratorExit)) - { + || PyErr_ExceptionMatches(PyExc_GeneratorExit)) { PyErr_Clear(); /* ignore these errors */ Py_INCREF(Py_None); return Py_None; @@ -323,29 +293,27 @@ PyObject *typ; PyObject *tb = NULL; PyObject *val = NULL; - PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL; + PyObject *yf = gen_yf(gen); if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) return NULL; - if (gen_running(gen)) - return NULL; - if (yf) { PyObject *ret; int err; - Py_INCREF(yf); if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) { - err = gen_close_iter(gen, yf); + gen->gi_running = 1; + err = gen_close_iter(yf); + gen->gi_running = 0; Py_DECREF(yf); - gen_undelegate(gen); if (err < 0) return gen_send_ex(gen, Py_None, 1); goto throw_here; } - gen->gi_running = 1; if (PyGen_CheckExact(yf)) { + gen->gi_running = 1; ret = gen_throw((PyGenObject *)yf, args); + gen->gi_running = 0; } else { PyObject *meth = PyObject_GetAttrString(yf, "throw"); if (meth == NULL) { @@ -355,18 +323,22 @@ } PyErr_Clear(); Py_DECREF(yf); - gen_undelegate(gen); - gen->gi_running = 0; goto throw_here; } + gen->gi_running = 1; ret = PyObject_CallObject(meth, args); + gen->gi_running = 0; Py_DECREF(meth); } - gen->gi_running = 0; Py_DECREF(yf); if (!ret) { PyObject *val; - gen_undelegate(gen); + /* Pop subiterator from stack */ + ret = *(--gen->gi_frame->f_stacktop); + assert(ret == yf); + Py_DECREF(ret); + /* Termination repetition of YIELD_FROM */ + gen->gi_frame->f_lasti++; if (PyGen_FetchStopIterationValue(&val) == 0) { ret = gen_send_ex(gen, val, 0); Py_DECREF(val); @@ -441,45 +413,12 @@ { PyObject *val = NULL; PyObject *ret; - int exc = 0; - PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL; - if (gen_running(gen)) - return NULL; - if (yf) { - Py_INCREF(yf); - /* ceval.c ensures that yf is an iterator */ - gen->gi_running = 1; - ret = Py_TYPE(yf)->tp_iternext(yf); - gen->gi_running = 0; - if (ret) { - Py_DECREF(yf); - return ret; - } - gen_undelegate(gen); - if (PyGen_FetchStopIterationValue(&val) < 0) - exc = 1; - Py_DECREF(yf); - } - ret = gen_send_ex(gen, val, exc); + ret = gen_send_ex(gen, val, 0); Py_XDECREF(val); return ret; } /* - * In certain recursive situations, a generator may lose its frame - * before we get a chance to clear f_yieldfrom, so we use this - * helper function. - */ - -static void -gen_undelegate(PyGenObject *gen) { - if (gen->gi_frame) { - Py_XDECREF(gen->gi_frame->f_yieldfrom); - gen->gi_frame->f_yieldfrom = NULL; - } -} - -/* * If StopIteration exception is set, fetches its 'value' * attribute if any, otherwise sets pvalue to None. * @@ -492,7 +431,7 @@ PyGen_FetchStopIterationValue(PyObject **pvalue) { PyObject *et, *ev, *tb; PyObject *value = NULL; - + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { PyErr_Fetch(&et, &ev, &tb); Py_XDECREF(et); @@ -548,7 +487,7 @@ }; static PyMethodDef gen_methods[] = { - {"send",(PyCFunction)gen_send, METH_O, send_doc}, + {"send",(PyCFunction)_PyGen_Send, METH_O, send_doc}, {"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc}, {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, {NULL, NULL} /* Sentinel */ diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1170,6 +1170,8 @@ f->f_lasti to -1 (i.e. the index *before* the first instruction) and YIELD_VALUE doesn't fiddle with f_lasti any more. So this does work. Promise. + YIELD_FROM sets f_lasti to itself, in order to repeated yield + multiple values. When the PREDICT() macros are enabled, some opcode pairs follow in direct succession without updating f->f_lasti. A successful @@ -1830,49 +1832,35 @@ TARGET(YIELD_FROM) u = POP(); - x = PyObject_GetIter(u); + x = TOP(); + /* send u to x */ + if (PyGen_CheckExact(x)) { + retval = _PyGen_Send((PyGenObject *)x, u); + } else { + if (u == Py_None) + retval = PyIter_Next(x); + else + retval = PyObject_CallMethod(x, "send", "O", u); + } Py_DECREF(u); - if (x == NULL) - break; - /* x is now the iterator, make the first next() call */ - retval = (*Py_TYPE(x)->tp_iternext)(x); if (!retval) { - PyObject *et, *ev, *tb; - /* iter may be exhausted */ - Py_CLEAR(x); - if (PyErr_Occurred() && - !PyErr_ExceptionMatches(PyExc_StopIteration)) { - /* some other exception */ + PyObject *val; + x = POP(); /* Remove iter from stack */ + Py_DECREF(x); + err = PyGen_FetchStopIterationValue(&val); + if (err < 0) { + x = NULL; break; } - /* try to get return value from exception */ - PyErr_Fetch(&et, &ev, &tb); - Py_XDECREF(et); - Py_XDECREF(tb); - /* u is return value */ - u = NULL; - if (ev) { - u = PyObject_GetAttrString(ev, "value"); - Py_DECREF(ev); - if (u == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { - /* some other exception */ - break; - } - PyErr_Clear(); - } - } - if (u == NULL) { - u = Py_None; - Py_INCREF(u); - } - PUSH(u); + x = val; + PUSH(x); continue; } - /* x is iterator, retval is value to be yielded */ - f->f_yieldfrom = x; + /* x remains on stack, retval is value to be yielded */ f->f_stacktop = stack_pointer; why = WHY_YIELD; + /* and repeat... */ + f->f_lasti--; goto fast_yield; TARGET(YIELD_VALUE) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -840,9 +840,9 @@ case IMPORT_STAR: return -1; case YIELD_VALUE: + return 0; case YIELD_FROM: - return 0; - + return -1; case POP_BLOCK: return 0; case POP_EXCEPT: @@ -3323,6 +3323,8 @@ ADDOP_O(c, LOAD_CONST, Py_None, consts); } if (e->kind == YieldFrom_kind) { + ADDOP(c, GET_ITER); + ADDOP_O(c, LOAD_CONST, Py_None, consts); ADDOP(c, YIELD_FROM); } else { diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -104,7 +104,8 @@ Python 3.2a2 3180 (add DELETE_DEREF) Python 3.3a0 3190 __class__ super closure changed Python 3.3a0 3200 (__qualname__ added) - 3210 (added size modulo 2**32 to the pyc header) + Python 3.3a1 3210 (added size modulo 2**32 to the pyc header) + 3220 (changed PEP 380 implementation) */ /* MAGIC must change whenever the bytecode emitted by the compiler may no -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 21:38:29 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 21:38:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_space?= Message-ID: http://hg.python.org/cpython/rev/ef3e4cdbb75c changeset: 75715:ef3e4cdbb75c user: Benjamin Peterson date: Thu Mar 15 15:37:54 2012 -0500 summary: space files: Objects/genobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -53,7 +53,7 @@ "generator already executing"); return NULL; } - if (f==NULL || f->f_stacktop == NULL) { + if (f == NULL || f->f_stacktop == NULL) { /* Only set exception if called from send() */ if (arg && !exc) PyErr_SetNone(PyExc_StopIteration); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 21:38:29 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 21:38:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/2774f41c6d65 changeset: 75716:2774f41c6d65 parent: 75715:ef3e4cdbb75c parent: 75713:04aa26c572ba user: Benjamin Peterson date: Thu Mar 15 15:38:17 2012 -0500 summary: merge heads files: Misc/NEWS | 3 + config.guess | 1530 ++++++++++++++++++++++++++++++++ config.sub | 1773 ++++++++++++++++++++++++++++++++++++++ configure | 142 ++- configure.ac | 2 + 5 files changed, 3421 insertions(+), 29 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -115,6 +115,9 @@ - Issue #14324: Fix configure tests for cross builds. +- Issue #14327: Call AC_CANONICAL_HOST in configure.ac and check in + config.{guess,sub}. + Extension Modules ----------------- diff --git a/config.guess b/config.guess new file mode 100755 --- /dev/null +++ b/config.guess @@ -0,0 +1,1530 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi at noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf at swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green at stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green at stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/config.sub new file mode 100755 --- /dev/null +++ b/config.sub @@ -0,0 +1,1773 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 \ + | ns16k | ns32k \ + | open8 \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i386-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure --- a/configure +++ b/configure @@ -696,6 +696,14 @@ CONFIG_ARGS SOVERSION VERSION +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build HAS_HG HGBRANCH HGTAG @@ -1377,6 +1385,10 @@ _ACEOF cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi @@ -2760,6 +2772,107 @@ ac_config_headers="$ac_config_headers pyconfig.h" +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + if test "$prefix" != "/"; then prefix=`echo "$prefix" | sed -e 's/\/$//g'` @@ -5261,35 +5374,6 @@ INSTALL="${srcdir}/install-sh -c" fi esac -ac_aux_dir= -for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,8 @@ AC_CONFIG_SRCDIR([Include/object.h]) AC_CONFIG_HEADER(pyconfig.h) +AC_CANONICAL_HOST + dnl Ensure that if prefix is specified, it does not end in a slash. If dnl it does, we get path names containing '//' which is both ugly and dnl can cause trouble. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 21:40:54 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 15 Mar 2012 21:40:54 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_comment?= Message-ID: http://hg.python.org/cpython/rev/f7727fc043a9 changeset: 75717:f7727fc043a9 user: Benjamin Peterson date: Thu Mar 15 15:40:37 2012 -0500 summary: fix comment files: Python/import.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -104,8 +104,8 @@ Python 3.2a2 3180 (add DELETE_DEREF) Python 3.3a0 3190 __class__ super closure changed Python 3.3a0 3200 (__qualname__ added) - Python 3.3a1 3210 (added size modulo 2**32 to the pyc header) - 3220 (changed PEP 380 implementation) + 3210 (added size modulo 2**32 to the pyc header) + Python 3.3a1 3220 (changed PEP 380 implementation) */ /* MAGIC must change whenever the bytecode emitted by the compiler may no -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 15 22:19:37 2012 From: python-checkins at python.org (matthias.klose) Date: Thu, 15 Mar 2012 22:19:37 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2314327=3A_Call_AC?= =?utf8?q?=5FCANONICAL=5FHOST_in_configure=2Eac_and_check_in?= Message-ID: http://hg.python.org/cpython/rev/d0cce5a2c0cf changeset: 75718:d0cce5a2c0cf user: Matthias Klose date: Thu Mar 15 22:19:28 2012 +0100 summary: - Issue #14327: Call AC_CANONICAL_HOST in configure.ac and check in config.{guess,sub}. Don't use uname calls for cross builds. files: Misc/NEWS | 2 +- configure | 44 ++++++++++++++++++++++++++------------- configure.ac | 42 ++++++++++++++++++++++++++----------- 3 files changed, 59 insertions(+), 29 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -116,7 +116,7 @@ - Issue #14324: Fix configure tests for cross builds. - Issue #14327: Call AC_CANONICAL_HOST in configure.ac and check in - config.{guess,sub}. + config.{guess,sub}. Don't use uname calls for cross builds. Extension Modules ----------------- diff --git a/configure b/configure --- a/configure +++ b/configure @@ -3150,6 +3150,25 @@ $as_echo_n "checking MACHDEP... " >&6; } if test -z "$MACHDEP" then + # avoid using uname for cross builds + if test "$cross_compiling" = yes; then + # ac_sys_system and ac_sys_release are only used for setting + # `define_xopen_source' in the case statement below. For the + # current supported cross builds, this macro is not adjusted. + case "$host" in + *-*-linux*) + ac_sys_system=Linux + ;; + *-*-cygwin*) + ac_sys_system=Cygwin + ;; + *) + # for now, limit cross builds to known configurations + MACHDEP="unknown" + as_fn_error $? "cross build not supported for $host" "$LINENO" 5 + esac + ac_sys_release= + else ac_sys_system=`uname -s` if test "$ac_sys_system" = "AIX" \ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then @@ -3157,19 +3176,20 @@ else ac_sys_release=`uname -r` fi - ac_md_system=`echo $ac_sys_system | - tr -d '/ ' | tr '[A-Z]' '[a-z]'` - ac_md_release=`echo $ac_sys_release | - tr -d '/ ' | sed 's/^[A-Z]\.//' | sed 's/\..*//'` - MACHDEP="$ac_md_system$ac_md_release" - - case $MACHDEP in + fi + ac_md_system=`echo $ac_sys_system | + tr -d '/ ' | tr '[A-Z]' '[a-z]'` + ac_md_release=`echo $ac_sys_release | + tr -d '/ ' | sed 's/^[A-Z]\.//' | sed 's/\..*//'` + MACHDEP="$ac_md_system$ac_md_release" + + case $MACHDEP in linux*) MACHDEP="linux";; cygwin*) MACHDEP="cygwin";; darwin*) MACHDEP="darwin";; irix646) MACHDEP="irix6";; '') MACHDEP="unknown";; - esac + esac fi # Some systems cannot stand _XOPEN_SOURCE being defined at all; they @@ -3305,12 +3325,6 @@ CONFIGURE_MACOSX_DEPLOYMENT_TARGET= EXPORT_MACOSX_DEPLOYMENT_TARGET='#' -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking machine type as reported by uname -m" >&5 -$as_echo_n "checking machine type as reported by uname -m... " >&6; } -ac_sys_machine=`uname -m` -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_sys_machine" >&5 -$as_echo "$ac_sys_machine" >&6; } - # checks for alternative programs # compiler flags are generated in two sets, BASECFLAGS and OPT. OPT is just @@ -5733,7 +5747,7 @@ # if using gcc on alpha, use -mieee to get (near) full IEEE 754 # support. Without this, treatment of subnormals doesn't follow # the standard. - case $ac_sys_machine in + case $host in alpha*) BASECFLAGS="$BASECFLAGS -mieee" ;; diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -292,6 +292,25 @@ AC_MSG_CHECKING(MACHDEP) if test -z "$MACHDEP" then + # avoid using uname for cross builds + if test "$cross_compiling" = yes; then + # ac_sys_system and ac_sys_release are only used for setting + # `define_xopen_source' in the case statement below. For the + # current supported cross builds, this macro is not adjusted. + case "$host" in + *-*-linux*) + ac_sys_system=Linux + ;; + *-*-cygwin*) + ac_sys_system=Cygwin + ;; + *) + # for now, limit cross builds to known configurations + MACHDEP="unknown" + AC_MSG_ERROR([cross build not supported for $host]) + esac + ac_sys_release= + else ac_sys_system=`uname -s` if test "$ac_sys_system" = "AIX" \ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then @@ -299,19 +318,20 @@ else ac_sys_release=`uname -r` fi - ac_md_system=`echo $ac_sys_system | - tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'` - ac_md_release=`echo $ac_sys_release | - tr -d '[/ ]' | sed 's/^[[A-Z]]\.//' | sed 's/\..*//'` - MACHDEP="$ac_md_system$ac_md_release" - - case $MACHDEP in + fi + ac_md_system=`echo $ac_sys_system | + tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'` + ac_md_release=`echo $ac_sys_release | + tr -d '[/ ]' | sed 's/^[[A-Z]]\.//' | sed 's/\..*//'` + MACHDEP="$ac_md_system$ac_md_release" + + case $MACHDEP in linux*) MACHDEP="linux";; cygwin*) MACHDEP="cygwin";; darwin*) MACHDEP="darwin";; irix646) MACHDEP="irix6";; '') MACHDEP="unknown";; - esac + esac fi # Some systems cannot stand _XOPEN_SOURCE being defined at all; they @@ -439,10 +459,6 @@ CONFIGURE_MACOSX_DEPLOYMENT_TARGET= EXPORT_MACOSX_DEPLOYMENT_TARGET='#' -AC_MSG_CHECKING(machine type as reported by uname -m) -ac_sys_machine=`uname -m` -AC_MSG_RESULT($ac_sys_machine) - # checks for alternative programs # compiler flags are generated in two sets, BASECFLAGS and OPT. OPT is just @@ -1010,7 +1026,7 @@ # if using gcc on alpha, use -mieee to get (near) full IEEE 754 # support. Without this, treatment of subnormals doesn't follow # the standard. - case $ac_sys_machine in + case $host in alpha*) BASECFLAGS="$BASECFLAGS -mieee" ;; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 02:15:45 2012 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 16 Mar 2012 02:15:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Explain_the_use?= =?utf8?q?_of_charset_parameter_with_Content-Type_header=2E_Issue11082?= Message-ID: http://hg.python.org/cpython/rev/057cf78ed576 changeset: 75719:057cf78ed576 branch: 3.2 parent: 75711:891184abbf6e user: Senthil Kumaran date: Thu Mar 15 18:11:16 2012 -0700 summary: Explain the use of charset parameter with Content-Type header. Issue11082 files: Doc/library/urllib.parse.rst | 7 +- Doc/library/urllib.request.rst | 70 +++++++++++++++------ Lib/urllib/request.py | 5 +- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -512,9 +512,10 @@ Convert a mapping object or a sequence of two-element tuples, which may either be a :class:`str` or a :class:`bytes`, to a "percent-encoded" - string. The resultant string must be converted to bytes using the - user-specified encoding before it is sent to :func:`urlopen` as the optional - *data* argument. + string. If the resultant string is to be used as a *data* for POST + operation with :func:`urlopen` function, then it should be properly encoded + to bytes, otherwise it would result in a :exc:`TypeError`. + The resulting string is a series of ``key=value`` pairs separated by ``'&'`` characters, where both *key* and *value* are quoted using :func:`quote_plus` above. When a sequence of two-element tuples is used as the *query* diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -2,9 +2,10 @@ ============================================================= .. module:: urllib.request - :synopsis: Next generation URL opening library. + :synopsis: Extensible library for opening URLs. .. moduleauthor:: Jeremy Hylton .. sectionauthor:: Moshe Zadka +.. sectionauthor:: Senthil Kumaran The :mod:`urllib.request` module defines functions and classes which help in @@ -20,16 +21,26 @@ Open the URL *url*, which can be either a string or a :class:`Request` object. - *data* may be a bytes object specifying additional data to send to the + *data* must be a bytes object specifying additional data to be sent to the server, or ``None`` if no such data is needed. *data* may also be an iterable object and in that case Content-Length value must be specified in the headers. Currently HTTP requests are the only ones that use *data*; the HTTP request will be a POST instead of a GET when the *data* parameter is - provided. *data* should be a buffer in the standard + provided. + + *data* should be a buffer in the standard :mimetype:`application/x-www-form-urlencoded` format. The :func:`urllib.parse.urlencode` function takes a mapping or sequence of - 2-tuples and returns a string in this format. urllib.request module uses - HTTP/1.1 and includes ``Connection:close`` header in its HTTP requests. + 2-tuples and returns a string in this format. It should be encoded to bytes + before being used as the *data* parameter. The charset parameter in + ``Content-Type`` header may be used to specify the encoding. If charset + parameter is not sent with the Content-Type header, the server following the + HTTP 1.1 recommendation may assume that the data is encoded in ISO-8859-1 + encoding. It is advisable to use charset parameter with encoding used in + ``Content-Type`` header with the :class:`Request`. + + urllib.request module uses HTTP/1.1 and includes ``Connection:close`` header + in its HTTP requests. The optional *timeout* parameter specifies a timeout in seconds for blocking operations like the connection attempt (if not specified, @@ -66,9 +77,10 @@ are handled through the proxy when they are set. The legacy ``urllib.urlopen`` function from Python 2.6 and earlier has been - discontinued; :func:`urlopen` corresponds to the old ``urllib2.urlopen``. - Proxy handling, which was done by passing a dictionary parameter to - ``urllib.urlopen``, can be obtained by using :class:`ProxyHandler` objects. + discontinued; :func:`urllib.request.urlopen` corresponds to the old + ``urllib2.urlopen``. Proxy handling, which was done by passing a dictionary + parameter to ``urllib.urlopen``, can be obtained by using + :class:`ProxyHandler` objects. .. versionchanged:: 3.2 *cafile* and *capath* were added. @@ -83,10 +95,11 @@ .. function:: install_opener(opener) Install an :class:`OpenerDirector` instance as the default global opener. - Installing an opener is only necessary if you want urlopen to use that opener; - otherwise, simply call :meth:`OpenerDirector.open` instead of :func:`urlopen`. - The code does not check for a real :class:`OpenerDirector`, and any class with - the appropriate interface will work. + Installing an opener is only necessary if you want urlopen to use that + opener; otherwise, simply call :meth:`OpenerDirector.open` instead of + :func:`~urllib.request.urlopen`. The code does not check for a real + :class:`OpenerDirector`, and any class with the appropriate interface will + work. .. function:: build_opener([handler, ...]) @@ -138,13 +151,21 @@ *url* should be a string containing a valid URL. - *data* may be a bytes object specifying additional data to send to the + *data* must be a bytes object specifying additional data to send to the server, or ``None`` if no such data is needed. Currently HTTP requests are the only ones that use *data*; the HTTP request will be a POST instead of a GET when the *data* parameter is provided. *data* should be a buffer in the - standard :mimetype:`application/x-www-form-urlencoded` format. The - :func:`urllib.parse.urlencode` function takes a mapping or sequence of - 2-tuples and returns a string in this format. + standard :mimetype:`application/x-www-form-urlencoded` format. + + The :func:`urllib.parse.urlencode` function takes a mapping or sequence of + 2-tuples and returns a string in this format. It should be encoded to bytes + before being used as the *data* parameter. The charset parameter in + ``Content-Type`` header may be used to specify the encoding. If charset + parameter is not sent with the Content-Type header, the server following the + HTTP 1.1 recommendation may assume that the data is encoded in ISO-8859-1 + encoding. It is advisable to use charset parameter with encoding used in + ``Content-Type`` header with the :class:`Request`. + *headers* should be a dictionary, and will be treated as if :meth:`add_header` was called with each key and value as arguments. @@ -156,6 +177,9 @@ :mod:`urllib`'s default user agent string is ``"Python-urllib/2.6"`` (on Python 2.6). + An example of using ``Content-Type`` header with *data* argument would be + sending a dictionary like ``{"Content-Type":" application/x-www-form-urlencoded;charset=utf-8"}`` + The final two arguments are only of interest for correct handling of third-party HTTP cookies: @@ -1052,8 +1076,9 @@ opener.open('http://www.example.com/') Also, remember that a few standard headers (:mailheader:`Content-Length`, -:mailheader:`Content-Type` and :mailheader:`Host`) are added when the -:class:`Request` is passed to :func:`urlopen` (or :meth:`OpenerDirector.open`). +:mailheader:`Content-Type` without charset parameter and :mailheader:`Host`) +are added when the :class:`Request` is passed to :func:`urlopen` (or +:meth:`OpenerDirector.open`). .. _urllib-examples: @@ -1071,9 +1096,12 @@ >>> import urllib.request >>> import urllib.parse - >>> params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) - >>> params = params.encode('utf-8') - >>> f = urllib.request.urlopen("http://www.musi-cal.com/cgi-bin/query", params) + >>> data = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) + >>> data = data.encode('utf-8') + >>> request = urllib.request.Request("http://requestb.in/xrbl82xr") + >>> # adding charset parameter to the Content-Type header. + >>> request.add_header("Content-Type","application/x-www-form-urlencoded;charset=utf-8") + >>> f = urllib.request.urlopen(request, data) >>> print(f.read().decode('utf-8')) The following example uses an explicitly specified HTTP proxy, overriding diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1062,8 +1062,9 @@ if request.data is not None: # POST data = request.data if isinstance(data, str): - raise TypeError("POST data should be bytes" - " or an iterable of bytes. It cannot be str.") + msg = "POST data should be bytes or an iterable of bytes."\ + "It cannot be str" + raise TypeError(msg) if not request.has_header('Content-type'): request.add_unredirected_header( 'Content-type', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 02:15:45 2012 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 16 Mar 2012 02:15:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Explain_the_use_of_charset_parameter_with_Content-Type_heade?= =?utf8?q?r=3A_issue11082?= Message-ID: http://hg.python.org/cpython/rev/90e35b91756d changeset: 75720:90e35b91756d parent: 75718:d0cce5a2c0cf parent: 75719:057cf78ed576 user: Senthil Kumaran date: Thu Mar 15 18:15:34 2012 -0700 summary: Explain the use of charset parameter with Content-Type header: issue11082 files: Doc/library/urllib.parse.rst | 7 +- Doc/library/urllib.request.rst | 74 +++++++++++++++------ Lib/urllib/request.py | 5 +- 3 files changed, 58 insertions(+), 28 deletions(-) diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -512,9 +512,10 @@ Convert a mapping object or a sequence of two-element tuples, which may either be a :class:`str` or a :class:`bytes`, to a "percent-encoded" - string. The resultant string must be converted to bytes using the - user-specified encoding before it is sent to :func:`urlopen` as the optional - *data* argument. + string. If the resultant string is to be used as a *data* for POST + operation with :func:`urlopen` function, then it should be properly encoded + to bytes, otherwise it would result in a :exc:`TypeError`. + The resulting string is a series of ``key=value`` pairs separated by ``'&'`` characters, where both *key* and *value* are quoted using :func:`quote_plus` above. When a sequence of two-element tuples is used as the *query* diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -2,9 +2,10 @@ ============================================================= .. module:: urllib.request - :synopsis: Next generation URL opening library. + :synopsis: Extensible library for opening URLs. .. moduleauthor:: Jeremy Hylton .. sectionauthor:: Moshe Zadka +.. sectionauthor:: Senthil Kumaran The :mod:`urllib.request` module defines functions and classes which help in @@ -20,16 +21,26 @@ Open the URL *url*, which can be either a string or a :class:`Request` object. - *data* may be a bytes object specifying additional data to send to the + *data* must be a bytes object specifying additional data to be sent to the server, or ``None`` if no such data is needed. *data* may also be an iterable object and in that case Content-Length value must be specified in the headers. Currently HTTP requests are the only ones that use *data*; the HTTP request will be a POST instead of a GET when the *data* parameter is - provided. *data* should be a buffer in the standard + provided. + + *data* should be a buffer in the standard :mimetype:`application/x-www-form-urlencoded` format. The :func:`urllib.parse.urlencode` function takes a mapping or sequence of - 2-tuples and returns a string in this format. urllib.request module uses - HTTP/1.1 and includes ``Connection:close`` header in its HTTP requests. + 2-tuples and returns a string in this format. It should be encoded to bytes + before being used as the *data* parameter. The charset parameter in + ``Content-Type`` header may be used to specify the encoding. If charset + parameter is not sent with the Content-Type header, the server following the + HTTP 1.1 recommendation may assume that the data is encoded in ISO-8859-1 + encoding. It is advisable to use charset parameter with encoding used in + ``Content-Type`` header with the :class:`Request`. + + urllib.request module uses HTTP/1.1 and includes ``Connection:close`` header + in its HTTP requests. The optional *timeout* parameter specifies a timeout in seconds for blocking operations like the connection attempt (if not specified, @@ -66,9 +77,10 @@ are handled through the proxy when they are set. The legacy ``urllib.urlopen`` function from Python 2.6 and earlier has been - discontinued; :func:`urlopen` corresponds to the old ``urllib2.urlopen``. - Proxy handling, which was done by passing a dictionary parameter to - ``urllib.urlopen``, can be obtained by using :class:`ProxyHandler` objects. + discontinued; :func:`urllib.request.urlopen` corresponds to the old + ``urllib2.urlopen``. Proxy handling, which was done by passing a dictionary + parameter to ``urllib.urlopen``, can be obtained by using + :class:`ProxyHandler` objects. .. versionchanged:: 3.2 *cafile* and *capath* were added. @@ -83,10 +95,11 @@ .. function:: install_opener(opener) Install an :class:`OpenerDirector` instance as the default global opener. - Installing an opener is only necessary if you want urlopen to use that opener; - otherwise, simply call :meth:`OpenerDirector.open` instead of :func:`urlopen`. - The code does not check for a real :class:`OpenerDirector`, and any class with - the appropriate interface will work. + Installing an opener is only necessary if you want urlopen to use that + opener; otherwise, simply call :meth:`OpenerDirector.open` instead of + :func:`~urllib.request.urlopen`. The code does not check for a real + :class:`OpenerDirector`, and any class with the appropriate interface will + work. .. function:: build_opener([handler, ...]) @@ -138,13 +151,21 @@ *url* should be a string containing a valid URL. - *data* may be a bytes object specifying additional data to send to the + *data* must be a bytes object specifying additional data to send to the server, or ``None`` if no such data is needed. Currently HTTP requests are the only ones that use *data*; the HTTP request will be a POST instead of a GET when the *data* parameter is provided. *data* should be a buffer in the - standard :mimetype:`application/x-www-form-urlencoded` format. The - :func:`urllib.parse.urlencode` function takes a mapping or sequence of - 2-tuples and returns a string in this format. + standard :mimetype:`application/x-www-form-urlencoded` format. + + The :func:`urllib.parse.urlencode` function takes a mapping or sequence of + 2-tuples and returns a string in this format. It should be encoded to bytes + before being used as the *data* parameter. The charset parameter in + ``Content-Type`` header may be used to specify the encoding. If charset + parameter is not sent with the Content-Type header, the server following the + HTTP 1.1 recommendation may assume that the data is encoded in ISO-8859-1 + encoding. It is advisable to use charset parameter with encoding used in + ``Content-Type`` header with the :class:`Request`. + *headers* should be a dictionary, and will be treated as if :meth:`add_header` was called with each key and value as arguments. @@ -156,8 +177,11 @@ :mod:`urllib`'s default user agent string is ``"Python-urllib/2.6"`` (on Python 2.6). - The following two arguments, *origin_req_host* and *unverifiable*, - are only of interest for correct handling of third-party HTTP cookies: + An example of using ``Content-Type`` header with *data* argument would be + sending a dictionary like ``{"Content-Type":" application/x-www-form-urlencoded;charset=utf-8"}`` + + The final two arguments are only of interest for correct handling + of third-party HTTP cookies: *origin_req_host* should be the request-host of the origin transaction, as defined by :rfc:`2965`. It defaults to @@ -1107,8 +1131,9 @@ opener.open('http://www.example.com/') Also, remember that a few standard headers (:mailheader:`Content-Length`, -:mailheader:`Content-Type` and :mailheader:`Host`) are added when the -:class:`Request` is passed to :func:`urlopen` (or :meth:`OpenerDirector.open`). +:mailheader:`Content-Type` without charset parameter and :mailheader:`Host`) +are added when the :class:`Request` is passed to :func:`urlopen` (or +:meth:`OpenerDirector.open`). .. _urllib-examples: @@ -1126,9 +1151,12 @@ >>> import urllib.request >>> import urllib.parse - >>> params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) - >>> params = params.encode('utf-8') - >>> f = urllib.request.urlopen("http://www.musi-cal.com/cgi-bin/query", params) + >>> data = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) + >>> data = data.encode('utf-8') + >>> request = urllib.request.Request("http://requestb.in/xrbl82xr") + >>> # adding charset parameter to the Content-Type header. + >>> request.add_header("Content-Type","application/x-www-form-urlencoded;charset=utf-8") + >>> f = urllib.request.urlopen(request, data) >>> print(f.read().decode('utf-8')) The following example uses an explicitly specified HTTP proxy, overriding diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1172,8 +1172,9 @@ if request.data is not None: # POST data = request.data if isinstance(data, str): - raise TypeError("POST data should be bytes" - " or an iterable of bytes. It cannot be str.") + msg = "POST data should be bytes or an iterable of bytes."\ + "It cannot be str" + raise TypeError(msg) if not request.has_header('Content-type'): request.add_unredirected_header( 'Content-type', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 04:55:14 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 04:55:14 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Closes_Issue_=2314246=3A_?= =?utf8?q?=5Felementtree_parser_will_now_handle_io=2EStringIO?= Message-ID: http://hg.python.org/cpython/rev/7bdf5c96fdc0 changeset: 75721:7bdf5c96fdc0 user: Eli Bendersky date: Fri Mar 16 05:53:30 2012 +0200 summary: Closes Issue #14246: _elementtree parser will now handle io.StringIO files: Lib/test/test_xml_etree.py | 14 ++++++++++++++ Modules/_elementtree.c | 23 ++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -16,6 +16,7 @@ import sys import html +import io import unittest from test import support @@ -2026,6 +2027,18 @@ del e[::2] self.assertEqual(self._subelem_tags(e), ['a1']) + +class StringIOTest(unittest.TestCase): + def test_read_from_stringio(self): + tree = ET.ElementTree() + stream = io.StringIO() + stream.write('''''') + stream.seek(0) + tree.parse(stream) + + self.assertEqual(tree.getroot().tag, 'site') + + # -------------------------------------------------------------------- @@ -2077,6 +2090,7 @@ test_classes = [ ElementSlicingTest, + StringIOTest, ElementTreeTest, TreeBuilderTest] if module is pyET: diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -2682,6 +2682,7 @@ PyObject* reader; PyObject* buffer; + PyObject* temp; PyObject* res; PyObject* fileobj; @@ -2703,7 +2704,27 @@ return NULL; } - if (!PyBytes_CheckExact(buffer) || PyBytes_GET_SIZE(buffer) == 0) { + if (PyUnicode_CheckExact(buffer)) { + /* A unicode object is encoded into bytes using UTF-8 */ + if (PyUnicode_GET_SIZE(buffer) == 0) { + Py_DECREF(buffer); + break; + } + temp = PyUnicode_AsEncodedString(buffer, "utf-8", "surrogatepass"); + if (!temp) { + /* Propagate exception from PyUnicode_AsEncodedString */ + Py_DECREF(buffer); + Py_DECREF(reader); + return NULL; + } + + /* Here we no longer need the original buffer since it contains + * unicode. Make it point to the encoded bytes object. + */ + Py_DECREF(buffer); + buffer = temp; + } + else if (!PyBytes_CheckExact(buffer) || PyBytes_GET_SIZE(buffer) == 0) { Py_DECREF(buffer); break; } -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Mar 16 05:41:31 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 16 Mar 2012 05:41:31 +0100 Subject: [Python-checkins] Daily reference leaks (90e35b91756d): sum=96 Message-ID: results for 90e35b91756d on branch "default" -------------------------------------------- test_pickle leaked [24, 24, 24] references, sum=72 test_pickletools leaked [8, 8, 8] references, sum=24 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogURug8O', '-x'] From python-checkins at python.org Fri Mar 16 07:21:49 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 07:21:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314207=3A_the_Parse?= =?utf8?q?Error_exception_raised_by_=5Felementtree_was_made?= Message-ID: http://hg.python.org/cpython/rev/b76fa310e73d changeset: 75722:b76fa310e73d user: Eli Bendersky date: Fri Mar 16 08:20:05 2012 +0200 summary: Issue #14207: the ParseError exception raised by _elementtree was made consistent to the one raised by the Python module (the 'code' attribute was added). In addition, the exception is now documented. Added a test to check that ParseError has the required attributes, and threw away the equivalent doctest which is no longer required. files: Doc/library/xml.etree.elementtree.rst | 19 ++++++- Lib/test/test_xml_etree.py | 42 +++++++------- Modules/_elementtree.c | 35 +++++++++-- 3 files changed, 67 insertions(+), 29 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -198,7 +198,6 @@ Element Objects --------------- - .. class:: Element(tag, attrib={}, **extra) Element class. This class defines the Element interface, and provides a @@ -643,6 +642,24 @@ >>> parser.close() 4 +Exceptions +---------- + +.. class:: ParseError + + XML parse error, raised by the various parsing methods in this module when + parsing fails. The string representation of an instance of this exception + will contain a user-friendly error message. In addition, it will have + the following attributes available: + + .. attribute:: code + + A numeric error code from the expat parser. See the documentation of + :mod:`xml.parsers.expat` for the list of error codes and their meanings. + + .. attribute:: position + + A tuple of *line*, *column* numbers, specifying where the error occurred. .. rubric:: Footnotes diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1055,26 +1055,6 @@ 'text' """ -def error(xml): - """ - - Test error handling. - - >>> issubclass(ET.ParseError, SyntaxError) - True - >>> error("foo").position - (1, 0) - >>> error("&foo;").position - (1, 5) - >>> error("foobar<").position - (1, 6) - - """ - try: - ET.XML(xml) - except ET.ParseError: - return sys.exc_info()[1] - def namespace(): """ Test namespace issues. @@ -2039,6 +2019,27 @@ self.assertEqual(tree.getroot().tag, 'site') +class ParseErrorTest(unittest.TestCase): + def test_subclass(self): + self.assertIsInstance(ET.ParseError(), SyntaxError) + + def _get_error(self, s): + try: + ET.fromstring(s) + except ET.ParseError as e: + return e + + def test_error_position(self): + self.assertEqual(self._get_error('foo').position, (1, 0)) + self.assertEqual(self._get_error('&foo;').position, (1, 5)) + self.assertEqual(self._get_error('foobar<').position, (1, 6)) + + def test_error_code(self): + import xml.parsers.expat.errors as ERRORS + self.assertEqual(self._get_error('foo').code, + ERRORS.codes[ERRORS.XML_ERROR_SYNTAX]) + + # -------------------------------------------------------------------- @@ -2091,6 +2092,7 @@ test_classes = [ ElementSlicingTest, StringIOTest, + ParseErrorTest, ElementTreeTest, TreeBuilderTest] if module is pyET: diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -2177,13 +2177,18 @@ return value; } +/* Set the ParseError exception with the given parameters. + * If message is not NULL, it's used as the error string. Otherwise, the + * message string is the default for the given error_code. +*/ static void -expat_set_error(const char* message, int line, int column) +expat_set_error(enum XML_Error error_code, int line, int column, char *message) { - PyObject *errmsg, *error, *position; + PyObject *errmsg, *error, *position, *code; errmsg = PyUnicode_FromFormat("%s: line %d, column %d", - message, line, column); + message ? message : EXPAT(ErrorString)(error_code), + line, column); if (errmsg == NULL) return; @@ -2192,7 +2197,19 @@ if (!error) return; - /* add position attribute */ + /* Add code and position attributes */ + code = PyLong_FromLong((long)error_code); + if (!code) { + Py_DECREF(error); + return; + } + if (PyObject_SetAttrString(error, "code", code) == -1) { + Py_DECREF(error); + Py_DECREF(code); + return; + } + Py_DECREF(code); + position = Py_BuildValue("(ii)", line, column); if (!position) { Py_DECREF(error); @@ -2244,9 +2261,10 @@ char message[128] = "undefined entity "; strncat(message, data_in, data_len < 100?data_len:100); expat_set_error( - message, + XML_ERROR_UNDEFINED_ENTITY, EXPAT(GetErrorLineNumber)(self->parser), - EXPAT(GetErrorColumnNumber)(self->parser) + EXPAT(GetErrorColumnNumber)(self->parser), + message ); } @@ -2629,9 +2647,10 @@ if (!ok) { expat_set_error( - EXPAT(ErrorString)(EXPAT(GetErrorCode)(self->parser)), + EXPAT(GetErrorCode)(self->parser), EXPAT(GetErrorLineNumber)(self->parser), - EXPAT(GetErrorColumnNumber)(self->parser) + EXPAT(GetErrorColumnNumber)(self->parser), + NULL ); return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 07:44:19 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 07:44:19 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzkyNTc6?= =?utf8?q?_clarify_the_events_iterparse_accepts?= Message-ID: http://hg.python.org/cpython/rev/84e4d76bd146 changeset: 75723:84e4d76bd146 branch: 3.2 parent: 75719:057cf78ed576 user: Eli Bendersky date: Fri Mar 16 08:41:30 2012 +0200 summary: Issue #9257: clarify the events iterparse accepts files: Doc/library/xml.etree.elementtree.rst | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -95,11 +95,14 @@ .. function:: iterparse(source, events=None, parser=None) Parses an XML section into an element tree incrementally, and reports what's - going on to the user. *source* is a filename or :term:`file object` containing - XML data. *events* is a list of events to report back. If omitted, only "end" - events are reported. *parser* is an optional parser instance. If not - given, the standard :class:`XMLParser` parser is used. Returns an - :term:`iterator` providing ``(event, elem)`` pairs. + going on to the user. *source* is a filename or :term:`file object` + containing XML data. *events* is a list of events to report back. The + supported events are the strings ``"start"``, ``"end"``, ``"start-ns"`` + and ``"end-ns"`` (the "ns" events are used to get detailed namespace + information). If *events* is omitted, only ``"end"`` events are reported. + *parser* is an optional parser instance. If not given, the standard + :class:`XMLParser` parser is used. Returns an :term:`iterator` providing + ``(event, elem)`` pairs. .. note:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 07:44:20 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 07:44:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=239257=3A_clarify_the_events_iterparse_accepts?= Message-ID: http://hg.python.org/cpython/rev/00c7142ee54a changeset: 75724:00c7142ee54a parent: 75722:b76fa310e73d parent: 75723:84e4d76bd146 user: Eli Bendersky date: Fri Mar 16 08:42:36 2012 +0200 summary: Issue #9257: clarify the events iterparse accepts files: Doc/library/xml.etree.elementtree.rst | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -96,11 +96,14 @@ .. function:: iterparse(source, events=None, parser=None) Parses an XML section into an element tree incrementally, and reports what's - going on to the user. *source* is a filename or :term:`file object` containing - XML data. *events* is a list of events to report back. If omitted, only "end" - events are reported. *parser* is an optional parser instance. If not - given, the standard :class:`XMLParser` parser is used. Returns an - :term:`iterator` providing ``(event, elem)`` pairs. + going on to the user. *source* is a filename or :term:`file object` + containing XML data. *events* is a list of events to report back. The + supported events are the strings ``"start"``, ``"end"``, ``"start-ns"`` + and ``"end-ns"`` (the "ns" events are used to get detailed namespace + information). If *events* is omitted, only ``"end"`` events are reported. + *parser* is an optional parser instance. If not given, the standard + :class:`XMLParser` parser is used. Returns an :term:`iterator` providing + ``(event, elem)`` pairs. .. note:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 08:19:27 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 08:19:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2313709=3A_some_fixe?= =?utf8?q?s_to_the_ctypes_documentation=2E_In_addition_to_fixing?= Message-ID: http://hg.python.org/cpython/rev/d2460ff173ff changeset: 75725:d2460ff173ff user: Eli Bendersky date: Fri Mar 16 09:17:43 2012 +0200 summary: Issue #13709: some fixes to the ctypes documentation. In addition to fixing the problems pointed in the issue, I removed the confusing Windows/Linux distinction. It serves no real goal in the documentation, and is probably wrong anyway since for Windows the WINFUNCTYPE constructor should be used. In addition, the "look, this is faster on Linux" comment is misleading since it's not explained. The outcome may just be an artifact of qsort implementation for this particular input, and may change between C runtime version releases. files: Doc/library/ctypes.rst | 94 ++++------------------------- 1 files changed, 14 insertions(+), 80 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -926,21 +926,21 @@ :mod:`ctypes` allows to create C callable function pointers from Python callables. These are sometimes called *callback functions*. -First, you must create a class for the callback function, the class knows the +First, you must create a class for the callback function. The class knows the calling convention, the return type, and the number and types of arguments this function will receive. -The CFUNCTYPE factory function creates types for callback functions using the -normal cdecl calling convention, and, on Windows, the WINFUNCTYPE factory -function creates types for callback functions using the stdcall calling -convention. +The :func:`CFUNCTYPE` factory function creates types for callback functions +using the ``cdecl`` calling convention. On Windows, the :func:`WINFUNCTYPE` +factory function creates types for callback functions using the ``stdcall`` +calling convention. Both of these factory functions are called with the result type as first argument, and the callback functions expected argument types as the remaining arguments. I will present an example here which uses the standard C library's -:c:func:`qsort` function, this is used to sort items with the help of a callback +:c:func:`qsort` function, that is used to sort items with the help of a callback function. :c:func:`qsort` will be used to sort an array of integers:: >>> IntArray5 = c_int * 5 @@ -953,7 +953,7 @@ items in the data array, the size of one item, and a pointer to the comparison function, the callback. The callback will then be called with two pointers to items, and it must return a negative integer if the first item is smaller than -the second, a zero if they are equal, and a positive integer else. +the second, a zero if they are equal, and a positive integer otherwise. So our callback function receives pointers to integers, and must return an integer. First we create the ``type`` for the callback function:: @@ -961,36 +961,8 @@ >>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int)) >>> -For the first implementation of the callback function, we simply print the -arguments we get, and return 0 (incremental development ;-):: - - >>> def py_cmp_func(a, b): - ... print("py_cmp_func", a, b) - ... return 0 - ... - >>> - -Create the C callable callback:: - - >>> cmp_func = CMPFUNC(py_cmp_func) - >>> - -And we're ready to go:: - - >>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +WINDOWS - py_cmp_func - py_cmp_func - py_cmp_func - py_cmp_func - py_cmp_func - py_cmp_func - py_cmp_func - py_cmp_func - py_cmp_func - py_cmp_func - >>> - -We know how to access the contents of a pointer, so lets redefine our callback:: +To get started, here is a simple callback that shows the values it gets +passed:: >>> def py_cmp_func(a, b): ... print("py_cmp_func", a[0], b[0]) @@ -999,23 +971,7 @@ >>> cmp_func = CMPFUNC(py_cmp_func) >>> -Here is what we get on Windows:: - - >>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +WINDOWS - py_cmp_func 7 1 - py_cmp_func 33 1 - py_cmp_func 99 1 - py_cmp_func 5 1 - py_cmp_func 7 5 - py_cmp_func 33 5 - py_cmp_func 99 5 - py_cmp_func 7 99 - py_cmp_func 33 99 - py_cmp_func 7 33 - >>> - -It is funny to see that on linux the sort function seems to work much more -efficiently, it is doing less comparisons:: +The result:: >>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +LINUX py_cmp_func 5 1 @@ -1025,32 +981,13 @@ py_cmp_func 1 7 >>> -Ah, we're nearly done! The last step is to actually compare the two items and -return a useful result:: +Now we can actually compare the two items and return a useful result:: >>> def py_cmp_func(a, b): ... print("py_cmp_func", a[0], b[0]) ... return a[0] - b[0] ... >>> - -Final run on Windows:: - - >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) # doctest: +WINDOWS - py_cmp_func 33 7 - py_cmp_func 99 33 - py_cmp_func 5 99 - py_cmp_func 1 99 - py_cmp_func 33 7 - py_cmp_func 1 33 - py_cmp_func 5 33 - py_cmp_func 5 7 - py_cmp_func 1 7 - py_cmp_func 5 1 - >>> - -and on Linux:: - >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) # doctest: +LINUX py_cmp_func 5 1 py_cmp_func 33 99 @@ -1059,9 +996,6 @@ py_cmp_func 5 7 >>> -It is quite interesting to see that the Windows :func:`qsort` function needs -more comparisons than the linux version! - As we can easily check, our array is sorted now:: >>> for i in ia: print(i, end=" ") @@ -1071,9 +1005,9 @@ **Important note for callback functions:** -Make sure you keep references to CFUNCTYPE objects as long as they are used from -C code. :mod:`ctypes` doesn't, and if you don't, they may be garbage collected, -crashing your program when a callback is made. +Make sure you keep references to :func:`CFUNCTYPE` objects as long as they are +used from C code. :mod:`ctypes` doesn't, and if you don't, they may be garbage +collected, crashing your program when a callback is made. .. _ctypes-accessing-values-exported-from-dlls: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 09:15:33 2012 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 16 Mar 2012 09:15:33 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogMi43IC0gSXNzdWUg?= =?utf8?q?=2310484=3A_Fix_the_CGIHTTPServer=27s_PATH=5FINFO_handling_probl?= =?utf8?q?em?= Message-ID: http://hg.python.org/cpython/rev/bab9f29c93fd changeset: 75726:bab9f29c93fd branch: 2.7 parent: 75710:6ce4868861ba user: Senthil Kumaran date: Fri Mar 16 01:07:16 2012 -0700 summary: 2.7 - Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem files: Lib/CGIHTTPServer.py | 9 ++++++++- Lib/test/test_httpservers.py | 1 + Misc/NEWS | 2 ++ 3 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Lib/CGIHTTPServer.py b/Lib/CGIHTTPServer.py --- a/Lib/CGIHTTPServer.py +++ b/Lib/CGIHTTPServer.py @@ -323,7 +323,14 @@ # Filter out blank non trailing parts before consuming the '..'. path_parts = [part for part in path_parts[:-1] if part] + path_parts[-1:] if path_parts: - tail_part = path_parts.pop() + # Special case for CGI's for PATH_INFO + if path.startswith('/cgi-bin') or path.startswith('/htbin'): + tail_part = [] + while path_parts[-1] not in ('cgi-bin','htbin'): + tail_part.insert(0,path_parts.pop()) + tail_part = "/".join(tail_part) + else: + tail_part = path_parts.pop() else: tail_part = '' head_parts = [] diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -429,6 +429,7 @@ '/.//': ('/', ''), 'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), '/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), + '/cgi-bin/file1.py/PATH-INFO': ('/cgi-bin', 'file1.py/PATH-INFO'), 'a': ('/', 'a'), '/a': ('/', 'a'), '//a': ('/', 'a'), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,8 @@ Library ------- +- Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem. + - Issue #11199: Fix the with urllib which hangs on particular ftp urls. - Issue #5219: Prevent event handler cascade in IDLE. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 09:15:39 2012 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 16 Mar 2012 09:15:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_closes_issue104?= =?utf8?q?84_-_Fix_the_http=2Eserver=27s_cgi_PATH=5FINFO_handling_problem?= Message-ID: http://hg.python.org/cpython/rev/88c86869ce92 changeset: 75727:88c86869ce92 branch: 3.2 parent: 75723:84e4d76bd146 user: Senthil Kumaran date: Fri Mar 16 01:13:50 2012 -0700 summary: closes issue10484 - Fix the http.server's cgi PATH_INFO handling problem files: Lib/http/server.py | 9 ++++++++- Lib/test/test_httpservers.py | 1 + Misc/NEWS | 2 ++ 3 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -850,7 +850,14 @@ # Filter out blank non trailing parts before consuming the '..'. path_parts = [part for part in path_parts[:-1] if part] + path_parts[-1:] if path_parts: - tail_part = path_parts.pop() + # Special case for CGI's for PATH_INFO + if path.startswith('/cgi-bin') or path.startswith('/htbin'): + tail_part = [] + while path_parts[-1] not in ('cgi-bin','htbin'): + tail_part.insert(0,path_parts.pop()) + tail_part = "/".join(tail_part) + else: + tail_part = path_parts.pop() else: tail_part = '' head_parts = [] diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -377,6 +377,7 @@ '/.//': ('/', ''), 'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), '/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), + '/cgi-bin/file1.py/PATH-INFO': ('/cgi-bin', 'file1.py/PATH-INFO'), 'a': ('/', 'a'), '/a': ('/', 'a'), '//a': ('/', 'a'), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,8 @@ Library ------- +- Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem. + - Issue #11199: Fix the with urllib which hangs on particular ftp urls. - Issue #14062: Header objects now correctly respect the 'linesep' setting -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 09:15:39 2012 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 16 Mar 2012 09:15:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_closes_issue10484_-_Fix_the_http=2Eserver=27s_cgi_PATH=5FINF?= =?utf8?q?O_handling_problem?= Message-ID: http://hg.python.org/cpython/rev/13c44ad094b4 changeset: 75728:13c44ad094b4 parent: 75725:d2460ff173ff parent: 75727:88c86869ce92 user: Senthil Kumaran date: Fri Mar 16 01:14:51 2012 -0700 summary: closes issue10484 - Fix the http.server's cgi PATH_INFO handling problem files: Lib/http/server.py | 9 ++++++++- Lib/test/test_httpservers.py | 1 + Misc/NEWS | 2 ++ 3 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -865,7 +865,14 @@ # Filter out blank non trailing parts before consuming the '..'. path_parts = [part for part in path_parts[:-1] if part] + path_parts[-1:] if path_parts: - tail_part = path_parts.pop() + # Special case for CGI's for PATH_INFO + if path.startswith('/cgi-bin') or path.startswith('/htbin'): + tail_part = [] + while path_parts[-1] not in ('cgi-bin','htbin'): + tail_part.insert(0,path_parts.pop()) + tail_part = "/".join(tail_part) + else: + tail_part = path_parts.pop() else: tail_part = '' head_parts = [] diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -377,6 +377,7 @@ '/.//': ('/', ''), 'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), '/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), + '/cgi-bin/file1.py/PATH-INFO': ('/cgi-bin', 'file1.py/PATH-INFO'), 'a': ('/', 'a'), '/a': ('/', 'a'), '//a': ('/', 'a'), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem. + - Issue #11199: Fix the with urllib which hangs on particular ftp urls. - Issue #14222: Use the new time.steady() function instead of time.time() for -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 09:19:07 2012 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 16 Mar 2012 09:19:07 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Improve_the_memory_utilizat?= =?utf8?q?ion_=28and_speed=29_of_functools=2Elru=5Fcache=28=29=2E?= Message-ID: http://hg.python.org/cpython/rev/3b2856d8614b changeset: 75729:3b2856d8614b parent: 75725:d2460ff173ff user: Raymond Hettinger date: Fri Mar 16 01:16:31 2012 -0700 summary: Improve the memory utilization (and speed) of functools.lru_cache(). files: Lib/functools.py | 53 +++++++++++++++++++++-------------- Misc/NEWS | 2 + 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -12,7 +12,7 @@ 'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial'] from _functools import partial, reduce -from collections import OrderedDict, namedtuple +from collections import namedtuple try: from _thread import allocate_lock as Lock except: @@ -147,17 +147,20 @@ # to allow the implementation to change (including a possible C version). def decorating_function(user_function, - *, tuple=tuple, sorted=sorted, map=map, len=len, type=type, KeyError=KeyError): + *, tuple=tuple, sorted=sorted, map=map, len=len, type=type): + cache = dict() hits = misses = 0 + cache_get = cache.get # bound method for fast lookup kwd_mark = (object(),) # separates positional and keyword args - lock = Lock() # needed because OrderedDict isn't threadsafe + lock = Lock() # needed because linkedlist isn't threadsafe + root = [] # root of circular doubly linked list + root[:] = [root, root, None, None] # initialize by pointing to self if maxsize is None: - cache = dict() # simple cache without ordering or size limit - @wraps(user_function) def wrapper(*args, **kwds): + # simple caching without ordering or size limit nonlocal hits, misses key = args if kwds: @@ -167,23 +170,18 @@ key += tuple(map(type, args)) if kwds: key += tuple(type(v) for k, v in sorted_items) - try: - result = cache[key] + result = cache_get(key) + if result is not None: hits += 1 return result - except KeyError: - pass result = user_function(*args, **kwds) cache[key] = result misses += 1 return result else: - cache = OrderedDict() # ordered least recent to most recent - cache_popitem = cache.popitem - cache_renew = cache.move_to_end - @wraps(user_function) def wrapper(*args, **kwds): + # size limited caching that tracks accesses by recency nonlocal hits, misses key = args if kwds: @@ -193,20 +191,33 @@ key += tuple(map(type, args)) if kwds: key += tuple(type(v) for k, v in sorted_items) + PREV, NEXT = 0, 1 # names of link fields with lock: - try: - result = cache[key] - cache_renew(key) # record recent use of this key + link = cache_get(key) + if link is not None: + link = cache[key] + # record recent use of the key by moving it to the front of the list + link_prev, link_next, key, result = link + link_prev[NEXT] = link_next + link_next[PREV] = link_prev + last = root[PREV] + last[NEXT] = root[PREV] = link + link[PREV] = last + link[NEXT] = root hits += 1 return result - except KeyError: - pass result = user_function(*args, **kwds) with lock: - cache[key] = result # record recent use of this key + last = root[PREV] + link = [last, root, key, result] + cache[key] = last[NEXT] = root[PREV] = link + if len(cache) > maxsize: + # purge least recently used cache entry + old_prev, old_next, old_key, old_result = root[NEXT] + root[NEXT] = old_next + old_next[PREV] = root + del cache[old_key] misses += 1 - if len(cache) > maxsize: - cache_popitem(0) # purge least recently used cache entry return result def cache_info(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,6 +26,8 @@ - Issue #11199: Fix the with urllib which hangs on particular ftp urls. +- Improve the memory utilization and speed of functools.lru_cache. + - Issue #14222: Use the new time.steady() function instead of time.time() for timeout in queue and threading modules to not be affected of system time update. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 09:19:07 2012 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 16 Mar 2012 09:19:07 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge?= Message-ID: http://hg.python.org/cpython/rev/870c0ef7e8a2 changeset: 75730:870c0ef7e8a2 parent: 75729:3b2856d8614b parent: 75728:13c44ad094b4 user: Raymond Hettinger date: Fri Mar 16 01:18:33 2012 -0700 summary: merge files: Lib/http/server.py | 9 ++++++++- Lib/test/test_httpservers.py | 1 + Misc/NEWS | 2 ++ 3 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -865,7 +865,14 @@ # Filter out blank non trailing parts before consuming the '..'. path_parts = [part for part in path_parts[:-1] if part] + path_parts[-1:] if path_parts: - tail_part = path_parts.pop() + # Special case for CGI's for PATH_INFO + if path.startswith('/cgi-bin') or path.startswith('/htbin'): + tail_part = [] + while path_parts[-1] not in ('cgi-bin','htbin'): + tail_part.insert(0,path_parts.pop()) + tail_part = "/".join(tail_part) + else: + tail_part = path_parts.pop() else: tail_part = '' head_parts = [] diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -377,6 +377,7 @@ '/.//': ('/', ''), 'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), '/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'), + '/cgi-bin/file1.py/PATH-INFO': ('/cgi-bin', 'file1.py/PATH-INFO'), 'a': ('/', 'a'), '/a': ('/', 'a'), '//a': ('/', 'a'), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem. + - Issue #11199: Fix the with urllib which hangs on particular ftp urls. - Improve the memory utilization and speed of functools.lru_cache. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 13:42:01 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 13:42:01 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MjAy?= =?utf8?q?=3A_Greatly_enhance_the_documentation_of_xml=2Edom=2Epulldom=2E?= Message-ID: http://hg.python.org/cpython/rev/172630a3e6d8 changeset: 75731:172630a3e6d8 branch: 3.2 parent: 75727:88c86869ce92 user: Eli Bendersky date: Fri Mar 16 14:37:14 2012 +0200 summary: Issue #14202: Greatly enhance the documentation of xml.dom.pulldom. Patch by Florian Mladitsch files: Doc/library/xml.dom.pulldom.rst | 84 +++++++++++++++++---- 1 files changed, 68 insertions(+), 16 deletions(-) diff --git a/Doc/library/xml.dom.pulldom.rst b/Doc/library/xml.dom.pulldom.rst --- a/Doc/library/xml.dom.pulldom.rst +++ b/Doc/library/xml.dom.pulldom.rst @@ -9,33 +9,72 @@ -------------- -:mod:`xml.dom.pulldom` allows building only selected portions of a Document -Object Model representation of a document from SAX events. +The :mod:`xml.dom.pulldom` module provides a "pull parser" which can also be +asked to produce DOM-accessible fragments of the document where necessary. The +basic concept involves pulling "events" from a stream of incoming XML and +processing them. In contrast to SAX which also employs an event-driven +processing model together with callbacks, the user of a pull parser is +responsible for explicitly pulling events from the stream, looping over those +events until either processing is finished or an error condition occurs. +Example:: -.. class:: PullDOM(documentFactory=None) + from xml.dom import pulldom - :class:`xml.sax.handler.ContentHandler` implementation that ... + doc = pulldom.parse('sales_items.xml') + for event, node in doc: + if event == pulldom.START_ELEMENT and node.tagName == 'item': + if int(node.getAttribute('price')) > 50: + doc.expandNode(node) + print(node.toxml()) +``event`` is a constant and can be one of: -.. class:: DOMEventStream(stream, parser, bufsize) +* :data:`START_ELEMENT` +* :data:`END_ELEMENT` +* :data:`COMMENT` +* :data:`START_DOCUMENT` +* :data:`END_DOCUMENT` +* :data:`CHARACTERS` +* :data:`PROCESSING_INSTRUCTION` +* :data:`IGNORABLE_WHITESPACE` - ... +``node`` is a object of type :class:`xml.dom.minidom.Document`, +:class:`xml.dom.minidom.Element` or :class:`xml.dom.minidom.Text`. + +Since the document is treated as a "flat" stream of events, the document "tree" +is implicitly traversed and the desired elements are found regardless of their +depth in the tree. In other words, one does not need to consider hierarchical issues +such as recursive searching of the document nodes, although if the context of +elements were important, one would either need to maintain some context-related +state (ie. remembering where one is in the document at any given point) or to +make use of the :func:`DOMEventStream.expandNode` method and switch to DOM-related processing. + + +.. class:: PullDom(documentFactory=None) + + Subclass of :class:`xml.sax.handler.ContentHandler`. .. class:: SAX2DOM(documentFactory=None) - :class:`xml.sax.handler.ContentHandler` implementation that ... + Subclass of :class:`xml.sax.handler.ContentHandler`. .. function:: parse(stream_or_string, parser=None, bufsize=None) - ... + Return a :class:`DOMEventStream` from the given input. *stream_or_string* may be + either a file name, or a file-like object. *parser*, if given, must be a + :class:`XmlReader` object. This function will change the document handler of the + parser and activate namespace support; other parser configuration (like + setting an entity resolver) must have been done in advance. + +If you have XML in a string, you can use the :func:`parseString` function instead: .. function:: parseString(string, parser=None) - ... + Return a :class:`DOMEventStream` that represents the (unicode) *string*. .. data:: default_bufsize @@ -51,18 +90,31 @@ DOMEventStream Objects ---------------------- +.. class:: DOMEventStream(stream, parser, bufsize) -.. method:: DOMEventStream.getEvent() - ... + .. method:: DOMEventStream.getEvent() + Return a tuple containing *event* and the current *node* as + :class:`xml.dom.minidom.Document` if event equals START_DOCUMENT, + :class:`xml.dom.minidom.Element` if event equals START_ELEMENT or + END_ELEMENT or :class:`xml.dom.minidom.Text` if event equals CHARACTERS. + The current node does not contain informations about its children, unless + :func:`expandNode` is called. -.. method:: DOMEventStream.expandNode(node) + .. method:: DOMEventStream.expandNode(node) - ... + Expands all children of *node* into *node*. Example:: + xml = 'Foo

Some text

and more

' + doc = pulldom.parseString(xml) + for event, node in doc: + if event == pulldom.START_ELEMENT and node.tagName == 'p': + # Following statement only prints '

' + print(node.toxml()) + doc.exandNode(node) + # Following statement prints node with all its children '

Some text

and more

' + print(node.toxml()) -.. method:: DOMEventStream.reset() + .. method:: DOMEventStream.reset() - ... - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 13:42:03 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 13:42:03 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314202=3A_Greatly_enhance_the_documentation_of_xml?= =?utf8?q?=2Edom=2Epulldom=2E?= Message-ID: http://hg.python.org/cpython/rev/5d118a154ba3 changeset: 75732:5d118a154ba3 parent: 75730:870c0ef7e8a2 parent: 75731:172630a3e6d8 user: Eli Bendersky date: Fri Mar 16 14:40:13 2012 +0200 summary: Issue #14202: Greatly enhance the documentation of xml.dom.pulldom. Patch by Florian Mladitsch files: Doc/library/xml.dom.pulldom.rst | 84 +++++++++++++++++---- 1 files changed, 68 insertions(+), 16 deletions(-) diff --git a/Doc/library/xml.dom.pulldom.rst b/Doc/library/xml.dom.pulldom.rst --- a/Doc/library/xml.dom.pulldom.rst +++ b/Doc/library/xml.dom.pulldom.rst @@ -9,33 +9,72 @@ -------------- -:mod:`xml.dom.pulldom` allows building only selected portions of a Document -Object Model representation of a document from SAX events. +The :mod:`xml.dom.pulldom` module provides a "pull parser" which can also be +asked to produce DOM-accessible fragments of the document where necessary. The +basic concept involves pulling "events" from a stream of incoming XML and +processing them. In contrast to SAX which also employs an event-driven +processing model together with callbacks, the user of a pull parser is +responsible for explicitly pulling events from the stream, looping over those +events until either processing is finished or an error condition occurs. +Example:: -.. class:: PullDOM(documentFactory=None) + from xml.dom import pulldom - :class:`xml.sax.handler.ContentHandler` implementation that ... + doc = pulldom.parse('sales_items.xml') + for event, node in doc: + if event == pulldom.START_ELEMENT and node.tagName == 'item': + if int(node.getAttribute('price')) > 50: + doc.expandNode(node) + print(node.toxml()) +``event`` is a constant and can be one of: -.. class:: DOMEventStream(stream, parser, bufsize) +* :data:`START_ELEMENT` +* :data:`END_ELEMENT` +* :data:`COMMENT` +* :data:`START_DOCUMENT` +* :data:`END_DOCUMENT` +* :data:`CHARACTERS` +* :data:`PROCESSING_INSTRUCTION` +* :data:`IGNORABLE_WHITESPACE` - ... +``node`` is a object of type :class:`xml.dom.minidom.Document`, +:class:`xml.dom.minidom.Element` or :class:`xml.dom.minidom.Text`. + +Since the document is treated as a "flat" stream of events, the document "tree" +is implicitly traversed and the desired elements are found regardless of their +depth in the tree. In other words, one does not need to consider hierarchical issues +such as recursive searching of the document nodes, although if the context of +elements were important, one would either need to maintain some context-related +state (ie. remembering where one is in the document at any given point) or to +make use of the :func:`DOMEventStream.expandNode` method and switch to DOM-related processing. + + +.. class:: PullDom(documentFactory=None) + + Subclass of :class:`xml.sax.handler.ContentHandler`. .. class:: SAX2DOM(documentFactory=None) - :class:`xml.sax.handler.ContentHandler` implementation that ... + Subclass of :class:`xml.sax.handler.ContentHandler`. .. function:: parse(stream_or_string, parser=None, bufsize=None) - ... + Return a :class:`DOMEventStream` from the given input. *stream_or_string* may be + either a file name, or a file-like object. *parser*, if given, must be a + :class:`XmlReader` object. This function will change the document handler of the + parser and activate namespace support; other parser configuration (like + setting an entity resolver) must have been done in advance. + +If you have XML in a string, you can use the :func:`parseString` function instead: .. function:: parseString(string, parser=None) - ... + Return a :class:`DOMEventStream` that represents the (unicode) *string*. .. data:: default_bufsize @@ -51,18 +90,31 @@ DOMEventStream Objects ---------------------- +.. class:: DOMEventStream(stream, parser, bufsize) -.. method:: DOMEventStream.getEvent() - ... + .. method:: DOMEventStream.getEvent() + Return a tuple containing *event* and the current *node* as + :class:`xml.dom.minidom.Document` if event equals START_DOCUMENT, + :class:`xml.dom.minidom.Element` if event equals START_ELEMENT or + END_ELEMENT or :class:`xml.dom.minidom.Text` if event equals CHARACTERS. + The current node does not contain informations about its children, unless + :func:`expandNode` is called. -.. method:: DOMEventStream.expandNode(node) + .. method:: DOMEventStream.expandNode(node) - ... + Expands all children of *node* into *node*. Example:: + xml = 'Foo

Some text

and more

' + doc = pulldom.parseString(xml) + for event, node in doc: + if event == pulldom.START_ELEMENT and node.tagName == 'p': + # Following statement only prints '

' + print(node.toxml()) + doc.exandNode(node) + # Following statement prints node with all its children '

Some text

and more

' + print(node.toxml()) -.. method:: DOMEventStream.reset() + .. method:: DOMEventStream.reset() - ... - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 13:51:59 2012 From: python-checkins at python.org (jean-paul.calderone) Date: Fri, 16 Mar 2012 13:51:59 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314325=3A_Stop_usin?= =?utf8?q?g_python_lists=2C_capsules=2C_and_the_garbage_collector_to?= Message-ID: http://hg.python.org/cpython/rev/9fc456ac20cf changeset: 75733:9fc456ac20cf user: Jean-Paul Calderone date: Fri Mar 16 08:51:42 2012 -0400 summary: Issue #14325: Stop using python lists, capsules, and the garbage collector to deal with PyArg_Parse* cleanup. files: Python/getargs.c | 225 ++++++++++++++-------------------- 1 files changed, 95 insertions(+), 130 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -33,16 +33,33 @@ #define FLAG_COMPAT 1 #define FLAG_SIZE_T 2 +typedef int (*destr_t)(PyObject *, void *); + + +/* Keep track of "objects" that have been allocated or initialized and + which will need to be deallocated or cleaned up somehow if overall + parsing fails. +*/ +typedef struct { + void *item; + destr_t destructor; +} freelistentry_t; + +typedef struct { + int first_available; + freelistentry_t *entries; +} freelist_t; + /* Forward */ static int vgetargs1(PyObject *, const char *, va_list *, int); static void seterror(int, const char *, int *, const char *, const char *); static char *convertitem(PyObject *, const char **, va_list *, int, int *, - char *, size_t, PyObject **); + char *, size_t, freelist_t *); static char *converttuple(PyObject *, const char **, va_list *, int, - int *, char *, size_t, int, PyObject **); + int *, char *, size_t, int, freelist_t *); static char *convertsimple(PyObject *, const char **, va_list *, int, char *, - size_t, PyObject **); + size_t, freelist_t *); static Py_ssize_t convertbuffer(PyObject *, void **p, char **); static int getbuffer(PyObject *, Py_buffer *, char**); @@ -127,111 +144,54 @@ #define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer" #define GETARGS_CAPSULE_NAME_CLEANUP_CONVERT "getargs.cleanup_convert" -static void -cleanup_ptr(PyObject *self) +static int +cleanup_ptr(PyObject *self, void *ptr) { - void *ptr = PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_PTR); if (ptr) { PyMem_FREE(ptr); } -} - -static void -cleanup_buffer(PyObject *self) -{ - Py_buffer *ptr = (Py_buffer *)PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_BUFFER); - if (ptr) { - PyBuffer_Release(ptr); - } -} - -static int -addcleanup(void *ptr, PyObject **freelist, int is_buffer) -{ - PyObject *cobj; - const char *name; - PyCapsule_Destructor destr; - - if (is_buffer) { - destr = cleanup_buffer; - name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER; - } else { - destr = cleanup_ptr; - name = GETARGS_CAPSULE_NAME_CLEANUP_PTR; - } - - if (!*freelist) { - *freelist = PyList_New(0); - if (!*freelist) { - destr(ptr); - return -1; - } - } - - cobj = PyCapsule_New(ptr, name, destr); - if (!cobj) { - destr(ptr); - return -1; - } - if (PyList_Append(*freelist, cobj)) { - Py_DECREF(cobj); - return -1; - } - Py_DECREF(cobj); - return 0; -} - -static void -cleanup_convert(PyObject *self) -{ - typedef int (*destr_t)(PyObject *, void *); - destr_t destr = (destr_t)PyCapsule_GetContext(self); - void *ptr = PyCapsule_GetPointer(self, - GETARGS_CAPSULE_NAME_CLEANUP_CONVERT); - if (ptr && destr) - destr(NULL, ptr); -} - -static int -addcleanup_convert(void *ptr, PyObject **freelist, int (*destr)(PyObject*,void*)) -{ - PyObject *cobj; - if (!*freelist) { - *freelist = PyList_New(0); - if (!*freelist) { - destr(NULL, ptr); - return -1; - } - } - cobj = PyCapsule_New(ptr, GETARGS_CAPSULE_NAME_CLEANUP_CONVERT, - cleanup_convert); - if (!cobj) { - destr(NULL, ptr); - return -1; - } - if (PyCapsule_SetContext(cobj, destr) == -1) { - /* This really should not happen. */ - Py_FatalError("capsule refused setting of context."); - } - if (PyList_Append(*freelist, cobj)) { - Py_DECREF(cobj); /* This will also call destr. */ - return -1; - } - Py_DECREF(cobj); return 0; } static int -cleanreturn(int retval, PyObject *freelist) +cleanup_buffer(PyObject *self, void *ptr) { - if (freelist && retval != 0) { - /* We were successful, reset the destructors so that they - don't get called. */ - Py_ssize_t len = PyList_GET_SIZE(freelist), i; - for (i = 0; i < len; i++) - PyCapsule_SetDestructor(PyList_GET_ITEM(freelist, i), NULL); + Py_buffer *buf = (Py_buffer *)ptr; + if (buf) { + PyBuffer_Release(buf); } - Py_XDECREF(freelist); + return 0; +} + +static int +addcleanup(void *ptr, freelist_t *freelist, destr_t destructor) +{ + int index; + + index = freelist->first_available; + freelist->first_available += 1; + + freelist->entries[index].item = ptr; + freelist->entries[index].destructor = destructor; + + return 0; +} + +static int +cleanreturn(int retval, freelist_t *freelist) +{ + int index; + + if (retval == 0) { + /* A failure occurred, therefore execute all of the cleanup + functions. + */ + for (index = 0; index < freelist->first_available; ++index) { + freelist->entries[index].destructor(NULL, + freelist->entries[index].item); + } + } + PyMem_Free(freelist->entries); return retval; } @@ -250,7 +210,7 @@ const char *formatsave = format; Py_ssize_t i, len; char *msg; - PyObject *freelist = NULL; + freelist_t freelist = {0, NULL}; int compat = flags & FLAG_COMPAT; assert(compat || (args != (PyObject*)NULL)); @@ -306,6 +266,8 @@ format = formatsave; + freelist.entries = PyMem_New(freelistentry_t, max); + if (compat) { if (max == 0) { if (args == NULL) @@ -314,7 +276,7 @@ "%.200s%s takes no arguments", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); - return 0; + return cleanreturn(0, &freelist); } else if (min == 1 && max == 1) { if (args == NULL) { @@ -322,26 +284,26 @@ "%.200s%s takes at least one argument", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); - return 0; + return cleanreturn(0, &freelist); } msg = convertitem(args, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg == NULL) - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); seterror(levels[0], msg, levels+1, fname, message); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } else { PyErr_SetString(PyExc_SystemError, "old style getargs format uses new features"); - return 0; + return cleanreturn(0, &freelist); } } if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_SystemError, "new style getargs format but argument is not a tuple"); - return 0; + return cleanreturn(0, &freelist); } len = PyTuple_GET_SIZE(args); @@ -359,7 +321,7 @@ Py_SAFE_DOWNCAST(len, Py_ssize_t, long)); else PyErr_SetString(PyExc_TypeError, message); - return 0; + return cleanreturn(0, &freelist); } for (i = 0; i < len; i++) { @@ -370,7 +332,7 @@ sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, msg); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } @@ -379,10 +341,10 @@ *format != '|' && *format != ':' && *format != ';') { PyErr_Format(PyExc_SystemError, "bad format string: %.200s", formatsave); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); } @@ -446,7 +408,7 @@ static char * converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, int *levels, char *msgbuf, size_t bufsize, int toplevel, - PyObject **freelist) + freelist_t *freelist) { int level = 0; int n = 0; @@ -521,7 +483,7 @@ static char * convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, - int *levels, char *msgbuf, size_t bufsize, PyObject **freelist) + int *levels, char *msgbuf, size_t bufsize, freelist_t *freelist) { char *msg; const char *format = *p_format; @@ -586,7 +548,7 @@ static char * convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, - char *msgbuf, size_t bufsize, PyObject **freelist) + char *msgbuf, size_t bufsize, freelist_t *freelist) { /* For # codes */ #define FETCH_SIZE int *q=NULL;Py_ssize_t *q2=NULL;\ @@ -863,7 +825,7 @@ if (getbuffer(arg, (Py_buffer*)p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); format++; - if (addcleanup(p, freelist, 1)) { + if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -908,7 +870,7 @@ if (getbuffer(arg, p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); } - if (addcleanup(p, freelist, 1)) { + if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -1120,7 +1082,7 @@ PyErr_NoMemory(); RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, 0)) { + if (addcleanup(*buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr( "(cleanup problem)", @@ -1162,7 +1124,7 @@ PyErr_NoMemory(); RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, 0)) { + if (addcleanup(*buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr("(cleanup problem)", arg, msgbuf, bufsize); @@ -1223,7 +1185,7 @@ return converterr("(unspecified)", arg, msgbuf, bufsize); if (res == Py_CLEANUP_SUPPORTED && - addcleanup_convert(addr, freelist, convert) == -1) + addcleanup(addr, freelist, convert) == -1) return converterr("(cleanup problem)", arg, msgbuf, bufsize); } @@ -1254,7 +1216,7 @@ PyBuffer_Release((Py_buffer*)p); return converterr("contiguous buffer", arg, msgbuf, bufsize); } - if (addcleanup(p, freelist, 1)) { + if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -1442,7 +1404,8 @@ const char *fname, *msg, *custom_msg, *keyword; int min = INT_MAX; int i, len, nargs, nkeywords; - PyObject *freelist = NULL, *current_arg; + PyObject *current_arg; + freelist_t freelist = {0, NULL}; assert(args != NULL && PyTuple_Check(args)); assert(keywords == NULL || PyDict_Check(keywords)); @@ -1466,6 +1429,8 @@ for (len=0; kwlist[len]; len++) continue; + freelist.entries = PyMem_New(freelistentry_t, len); + nargs = PyTuple_GET_SIZE(args); nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords); if (nargs + nkeywords > len) { @@ -1490,7 +1455,7 @@ PyErr_Format(PyExc_RuntimeError, "More keyword list entries (%d) than " "format specifiers (%d)", len, i); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } current_arg = NULL; if (nkeywords) { @@ -1504,11 +1469,11 @@ "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); + return cleanreturn(0, &freelist); else if (i < nargs) current_arg = PyTuple_GET_ITEM(args, i); @@ -1517,7 +1482,7 @@ levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, custom_msg); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } continue; } @@ -1526,14 +1491,14 @@ PyErr_Format(PyExc_TypeError, "Required argument " "'%s' (pos %d) not found", keyword, i+1); - return cleanreturn(0, freelist); + 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); /* We are into optional args, skip thru to any remaining * keyword args */ @@ -1541,7 +1506,7 @@ if (msg) { PyErr_Format(PyExc_RuntimeError, "%s: '%s'", msg, format); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } @@ -1549,7 +1514,7 @@ PyErr_Format(PyExc_RuntimeError, "more argument specifiers than keyword list entries " "(remaining format:'%s')", format); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } /* make sure there are no extraneous keyword arguments */ @@ -1562,7 +1527,7 @@ if (!PyUnicode_Check(key)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } /* check that _PyUnicode_AsString() result is not NULL */ ks = _PyUnicode_AsString(key); @@ -1579,12 +1544,12 @@ "'%U' is an invalid keyword " "argument for this function", key); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } } - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 14:33:49 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 14:33:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Add_a_test_that_makes_sure_?= =?utf8?q?TreeBuilder_can_be_passed_element=5Ffactory_in_the?= Message-ID: http://hg.python.org/cpython/rev/bf508633cf47 changeset: 75734:bf508633cf47 parent: 75732:5d118a154ba3 user: Eli Bendersky date: Fri Mar 16 15:29:50 2012 +0200 summary: Add a test that makes sure TreeBuilder can be passed element_factory in the constructor. Marked as expectedFailure since it currently fails for the C implementation. files: Lib/test/test_xml_etree.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1905,6 +1905,11 @@ parser.feed(self.sample1) self.assertIsNone(parser.close()) + # XXX in _elementtree, the constructor of TreeBuilder expects no + # arguments + @unittest.expectedFailure + def test_element_factory(self): + tb = ET.TreeBuilder(element_factory=lambda: ET.Element()) @unittest.expectedFailure # XXX issue 14007 with C ElementTree def test_doctype(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 14:33:50 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 14:33:50 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/b838fbbdbab8 changeset: 75735:b838fbbdbab8 parent: 75734:bf508633cf47 parent: 75733:9fc456ac20cf user: Eli Bendersky date: Fri Mar 16 15:30:53 2012 +0200 summary: merge heads files: Python/getargs.c | 225 ++++++++++++++-------------------- 1 files changed, 95 insertions(+), 130 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -33,16 +33,33 @@ #define FLAG_COMPAT 1 #define FLAG_SIZE_T 2 +typedef int (*destr_t)(PyObject *, void *); + + +/* Keep track of "objects" that have been allocated or initialized and + which will need to be deallocated or cleaned up somehow if overall + parsing fails. +*/ +typedef struct { + void *item; + destr_t destructor; +} freelistentry_t; + +typedef struct { + int first_available; + freelistentry_t *entries; +} freelist_t; + /* Forward */ static int vgetargs1(PyObject *, const char *, va_list *, int); static void seterror(int, const char *, int *, const char *, const char *); static char *convertitem(PyObject *, const char **, va_list *, int, int *, - char *, size_t, PyObject **); + char *, size_t, freelist_t *); static char *converttuple(PyObject *, const char **, va_list *, int, - int *, char *, size_t, int, PyObject **); + int *, char *, size_t, int, freelist_t *); static char *convertsimple(PyObject *, const char **, va_list *, int, char *, - size_t, PyObject **); + size_t, freelist_t *); static Py_ssize_t convertbuffer(PyObject *, void **p, char **); static int getbuffer(PyObject *, Py_buffer *, char**); @@ -127,111 +144,54 @@ #define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer" #define GETARGS_CAPSULE_NAME_CLEANUP_CONVERT "getargs.cleanup_convert" -static void -cleanup_ptr(PyObject *self) +static int +cleanup_ptr(PyObject *self, void *ptr) { - void *ptr = PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_PTR); if (ptr) { PyMem_FREE(ptr); } -} - -static void -cleanup_buffer(PyObject *self) -{ - Py_buffer *ptr = (Py_buffer *)PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_BUFFER); - if (ptr) { - PyBuffer_Release(ptr); - } -} - -static int -addcleanup(void *ptr, PyObject **freelist, int is_buffer) -{ - PyObject *cobj; - const char *name; - PyCapsule_Destructor destr; - - if (is_buffer) { - destr = cleanup_buffer; - name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER; - } else { - destr = cleanup_ptr; - name = GETARGS_CAPSULE_NAME_CLEANUP_PTR; - } - - if (!*freelist) { - *freelist = PyList_New(0); - if (!*freelist) { - destr(ptr); - return -1; - } - } - - cobj = PyCapsule_New(ptr, name, destr); - if (!cobj) { - destr(ptr); - return -1; - } - if (PyList_Append(*freelist, cobj)) { - Py_DECREF(cobj); - return -1; - } - Py_DECREF(cobj); - return 0; -} - -static void -cleanup_convert(PyObject *self) -{ - typedef int (*destr_t)(PyObject *, void *); - destr_t destr = (destr_t)PyCapsule_GetContext(self); - void *ptr = PyCapsule_GetPointer(self, - GETARGS_CAPSULE_NAME_CLEANUP_CONVERT); - if (ptr && destr) - destr(NULL, ptr); -} - -static int -addcleanup_convert(void *ptr, PyObject **freelist, int (*destr)(PyObject*,void*)) -{ - PyObject *cobj; - if (!*freelist) { - *freelist = PyList_New(0); - if (!*freelist) { - destr(NULL, ptr); - return -1; - } - } - cobj = PyCapsule_New(ptr, GETARGS_CAPSULE_NAME_CLEANUP_CONVERT, - cleanup_convert); - if (!cobj) { - destr(NULL, ptr); - return -1; - } - if (PyCapsule_SetContext(cobj, destr) == -1) { - /* This really should not happen. */ - Py_FatalError("capsule refused setting of context."); - } - if (PyList_Append(*freelist, cobj)) { - Py_DECREF(cobj); /* This will also call destr. */ - return -1; - } - Py_DECREF(cobj); return 0; } static int -cleanreturn(int retval, PyObject *freelist) +cleanup_buffer(PyObject *self, void *ptr) { - if (freelist && retval != 0) { - /* We were successful, reset the destructors so that they - don't get called. */ - Py_ssize_t len = PyList_GET_SIZE(freelist), i; - for (i = 0; i < len; i++) - PyCapsule_SetDestructor(PyList_GET_ITEM(freelist, i), NULL); + Py_buffer *buf = (Py_buffer *)ptr; + if (buf) { + PyBuffer_Release(buf); } - Py_XDECREF(freelist); + return 0; +} + +static int +addcleanup(void *ptr, freelist_t *freelist, destr_t destructor) +{ + int index; + + index = freelist->first_available; + freelist->first_available += 1; + + freelist->entries[index].item = ptr; + freelist->entries[index].destructor = destructor; + + return 0; +} + +static int +cleanreturn(int retval, freelist_t *freelist) +{ + int index; + + if (retval == 0) { + /* A failure occurred, therefore execute all of the cleanup + functions. + */ + for (index = 0; index < freelist->first_available; ++index) { + freelist->entries[index].destructor(NULL, + freelist->entries[index].item); + } + } + PyMem_Free(freelist->entries); return retval; } @@ -250,7 +210,7 @@ const char *formatsave = format; Py_ssize_t i, len; char *msg; - PyObject *freelist = NULL; + freelist_t freelist = {0, NULL}; int compat = flags & FLAG_COMPAT; assert(compat || (args != (PyObject*)NULL)); @@ -306,6 +266,8 @@ format = formatsave; + freelist.entries = PyMem_New(freelistentry_t, max); + if (compat) { if (max == 0) { if (args == NULL) @@ -314,7 +276,7 @@ "%.200s%s takes no arguments", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); - return 0; + return cleanreturn(0, &freelist); } else if (min == 1 && max == 1) { if (args == NULL) { @@ -322,26 +284,26 @@ "%.200s%s takes at least one argument", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); - return 0; + return cleanreturn(0, &freelist); } msg = convertitem(args, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg == NULL) - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); seterror(levels[0], msg, levels+1, fname, message); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } else { PyErr_SetString(PyExc_SystemError, "old style getargs format uses new features"); - return 0; + return cleanreturn(0, &freelist); } } if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_SystemError, "new style getargs format but argument is not a tuple"); - return 0; + return cleanreturn(0, &freelist); } len = PyTuple_GET_SIZE(args); @@ -359,7 +321,7 @@ Py_SAFE_DOWNCAST(len, Py_ssize_t, long)); else PyErr_SetString(PyExc_TypeError, message); - return 0; + return cleanreturn(0, &freelist); } for (i = 0; i < len; i++) { @@ -370,7 +332,7 @@ sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, msg); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } @@ -379,10 +341,10 @@ *format != '|' && *format != ':' && *format != ';') { PyErr_Format(PyExc_SystemError, "bad format string: %.200s", formatsave); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); } @@ -446,7 +408,7 @@ static char * converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, int *levels, char *msgbuf, size_t bufsize, int toplevel, - PyObject **freelist) + freelist_t *freelist) { int level = 0; int n = 0; @@ -521,7 +483,7 @@ static char * convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, - int *levels, char *msgbuf, size_t bufsize, PyObject **freelist) + int *levels, char *msgbuf, size_t bufsize, freelist_t *freelist) { char *msg; const char *format = *p_format; @@ -586,7 +548,7 @@ static char * convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, - char *msgbuf, size_t bufsize, PyObject **freelist) + char *msgbuf, size_t bufsize, freelist_t *freelist) { /* For # codes */ #define FETCH_SIZE int *q=NULL;Py_ssize_t *q2=NULL;\ @@ -863,7 +825,7 @@ if (getbuffer(arg, (Py_buffer*)p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); format++; - if (addcleanup(p, freelist, 1)) { + if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -908,7 +870,7 @@ if (getbuffer(arg, p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); } - if (addcleanup(p, freelist, 1)) { + if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -1120,7 +1082,7 @@ PyErr_NoMemory(); RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, 0)) { + if (addcleanup(*buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr( "(cleanup problem)", @@ -1162,7 +1124,7 @@ PyErr_NoMemory(); RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, 0)) { + if (addcleanup(*buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr("(cleanup problem)", arg, msgbuf, bufsize); @@ -1223,7 +1185,7 @@ return converterr("(unspecified)", arg, msgbuf, bufsize); if (res == Py_CLEANUP_SUPPORTED && - addcleanup_convert(addr, freelist, convert) == -1) + addcleanup(addr, freelist, convert) == -1) return converterr("(cleanup problem)", arg, msgbuf, bufsize); } @@ -1254,7 +1216,7 @@ PyBuffer_Release((Py_buffer*)p); return converterr("contiguous buffer", arg, msgbuf, bufsize); } - if (addcleanup(p, freelist, 1)) { + if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -1442,7 +1404,8 @@ const char *fname, *msg, *custom_msg, *keyword; int min = INT_MAX; int i, len, nargs, nkeywords; - PyObject *freelist = NULL, *current_arg; + PyObject *current_arg; + freelist_t freelist = {0, NULL}; assert(args != NULL && PyTuple_Check(args)); assert(keywords == NULL || PyDict_Check(keywords)); @@ -1466,6 +1429,8 @@ for (len=0; kwlist[len]; len++) continue; + freelist.entries = PyMem_New(freelistentry_t, len); + nargs = PyTuple_GET_SIZE(args); nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords); if (nargs + nkeywords > len) { @@ -1490,7 +1455,7 @@ PyErr_Format(PyExc_RuntimeError, "More keyword list entries (%d) than " "format specifiers (%d)", len, i); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } current_arg = NULL; if (nkeywords) { @@ -1504,11 +1469,11 @@ "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); + return cleanreturn(0, &freelist); else if (i < nargs) current_arg = PyTuple_GET_ITEM(args, i); @@ -1517,7 +1482,7 @@ levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, custom_msg); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } continue; } @@ -1526,14 +1491,14 @@ PyErr_Format(PyExc_TypeError, "Required argument " "'%s' (pos %d) not found", keyword, i+1); - return cleanreturn(0, freelist); + 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); /* We are into optional args, skip thru to any remaining * keyword args */ @@ -1541,7 +1506,7 @@ if (msg) { PyErr_Format(PyExc_RuntimeError, "%s: '%s'", msg, format); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } @@ -1549,7 +1514,7 @@ PyErr_Format(PyExc_RuntimeError, "more argument specifiers than keyword list entries " "(remaining format:'%s')", format); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } /* make sure there are no extraneous keyword arguments */ @@ -1562,7 +1527,7 @@ if (!PyUnicode_Check(key)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } /* check that _PyUnicode_AsString() result is not NULL */ ks = _PyUnicode_AsString(key); @@ -1579,12 +1544,12 @@ "'%U' is an invalid keyword " "argument for this function", key); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } } - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 14:33:50 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 14:33:50 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_trailing_whitespace?= Message-ID: http://hg.python.org/cpython/rev/b13992c7baa7 changeset: 75736:b13992c7baa7 user: Eli Bendersky date: Fri Mar 16 15:32:04 2012 +0200 summary: fix trailing whitespace files: Lib/test/test_xml_etree.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1907,7 +1907,7 @@ # XXX in _elementtree, the constructor of TreeBuilder expects no # arguments - @unittest.expectedFailure + @unittest.expectedFailure def test_element_factory(self): tb = ET.TreeBuilder(element_factory=lambda: ET.Element()) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 15:36:59 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 15:36:59 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_check_to_make_s?= =?utf8?q?ure_the_attribute_is_a_string_=28=2314334=29?= Message-ID: http://hg.python.org/cpython/rev/b7bad204b34f changeset: 75737:b7bad204b34f branch: 3.2 parent: 75731:172630a3e6d8 user: Benjamin Peterson date: Fri Mar 16 09:32:59 2012 -0500 summary: check to make sure the attribute is a string (#14334) files: Lib/test/test_descr.py | 3 +++ Misc/NEWS | 3 +++ Objects/typeobject.c | 7 +++++++ 3 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4393,6 +4393,9 @@ self.assertRaises(AttributeError, getattr, EvilGetattribute(), "attr") + def test_type___getattribute__(self): + self.assertRaises(TypeError, type.__getattribute__, list, type) + def test_abstractmethods(self): # type pretends not to have __abstractmethods__. self.assertRaises(AttributeError, getattr, type, "__abstractmethods__") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not + passed strings. + - Issue #1469629: Allow cycles through an object's __dict__ slot to be collected. (For example if ``x.__dict__ is x``). diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2462,6 +2462,13 @@ PyObject *meta_attribute, *attribute; descrgetfunc meta_get; + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + name->ob_type->tp_name); + return NULL; + } + /* Initialize this type (we'll assume the metatype is initialized) */ if (type->tp_dict == NULL) { if (PyType_Ready(type) < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 15:37:00 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 15:37:00 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiBtZXJnZSAzLjIgKCMxNDMzNCk=?= Message-ID: http://hg.python.org/cpython/rev/e44591015cf0 changeset: 75738:e44591015cf0 parent: 75736:b13992c7baa7 parent: 75737:b7bad204b34f user: Benjamin Peterson date: Fri Mar 16 09:35:38 2012 -0500 summary: merge 3.2 (#14334) files: Lib/test/test_descr.py | 3 +++ Misc/NEWS | 3 +++ Objects/typeobject.c | 7 +++++++ 3 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4400,6 +4400,9 @@ self.assertRaises(AttributeError, getattr, EvilGetattribute(), "attr") + def test_type___getattribute__(self): + self.assertRaises(TypeError, type.__getattribute__, list, type) + def test_abstractmethods(self): # type pretends not to have __abstractmethods__. self.assertRaises(AttributeError, getattr, type, "__abstractmethods__") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ - Give the ast.AST class a __dict__. +- Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not + passed strings. + - Issue #1469629: Allow cycles through an object's __dict__ slot to be collected. (For example if ``x.__dict__ is x``). diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2486,6 +2486,13 @@ PyObject *meta_attribute, *attribute; descrgetfunc meta_get; + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + name->ob_type->tp_name); + return NULL; + } + /* Initialize this type (we'll assume the metatype is initialized) */ if (type->tp_dict == NULL) { if (PyType_Ready(type) < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 15:39:23 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 15:39:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_in_72556ff86828=2C_I_should?= =?utf8?q?_have_updated_the_magic_as_well_as_the_comment_=28=2314230=29?= Message-ID: http://hg.python.org/cpython/rev/c0a6569fdad6 changeset: 75739:c0a6569fdad6 user: Benjamin Peterson date: Fri Mar 16 09:39:12 2012 -0500 summary: in 72556ff86828, I should have updated the magic as well as the comment (#14230) files: Python/import.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -118,7 +118,7 @@ #define STRIFY(name) QUOTE(name) #define MAJOR STRIFY(PY_MAJOR_VERSION) #define MINOR STRIFY(PY_MINOR_VERSION) -#define MAGIC (3210 | ((long)'\r'<<16) | ((long)'\n'<<24)) +#define MAGIC (3220 | ((long)'\r'<<16) | ((long)'\n'<<24)) #define TAG "cpython-" MAJOR MINOR; #define CACHEDIR "__pycache__" /* Current magic word and string tag as globals. */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 15:46:32 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 15:46:32 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_check_to_make_s?= =?utf8?q?ure_the_attribute_is_a_string_=28=2314334=29?= Message-ID: http://hg.python.org/cpython/rev/d1cf6008a565 changeset: 75740:d1cf6008a565 branch: 2.7 parent: 75726:bab9f29c93fd user: Benjamin Peterson date: Fri Mar 16 09:32:59 2012 -0500 summary: check to make sure the attribute is a string (#14334) files: Lib/test/test_descr.py | 3 +++ Misc/NEWS | 3 +++ Objects/typeobject.c | 7 +++++++ 3 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4554,6 +4554,9 @@ self.assertRaises(AttributeError, getattr, EvilGetattribute(), "attr") + def test_type___getattribute__(self): + self.assertRaises(TypeError, type.__getattribute__, list, type) + def test_abstractmethods(self): # type pretends not to have __abstractmethods__. self.assertRaises(AttributeError, getattr, type, "__abstractmethods__") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not + passed strings. + - Issue #14161: fix the __repr__ of file objects to escape the file name. - Issue #1469629: Allow cycles through an object's __dict__ slot to be diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2530,6 +2530,13 @@ PyObject *meta_attribute, *attribute; descrgetfunc meta_get; + if (!PyString_Check(name)) { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + name->ob_type->tp_name); + return NULL; + } + /* Initialize this type (we'll assume the metatype is initialized) */ if (type->tp_dict == NULL) { if (PyType_Ready(type) < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 15:52:47 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 15:52:47 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MjAy?= =?utf8?q?=3A_some_additional_doc_fixes?= Message-ID: http://hg.python.org/cpython/rev/1a740ea4f2a1 changeset: 75741:1a740ea4f2a1 branch: 3.2 parent: 75737:b7bad204b34f user: Eli Bendersky date: Fri Mar 16 16:49:58 2012 +0200 summary: Issue #14202: some additional doc fixes files: Doc/library/xml.dom.pulldom.rst | 27 ++++++++++---------- 1 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Doc/library/xml.dom.pulldom.rst b/Doc/library/xml.dom.pulldom.rst --- a/Doc/library/xml.dom.pulldom.rst +++ b/Doc/library/xml.dom.pulldom.rst @@ -44,11 +44,12 @@ Since the document is treated as a "flat" stream of events, the document "tree" is implicitly traversed and the desired elements are found regardless of their -depth in the tree. In other words, one does not need to consider hierarchical issues -such as recursive searching of the document nodes, although if the context of -elements were important, one would either need to maintain some context-related -state (ie. remembering where one is in the document at any given point) or to -make use of the :func:`DOMEventStream.expandNode` method and switch to DOM-related processing. +depth in the tree. In other words, one does not need to consider hierarchical +issues such as recursive searching of the document nodes, although if the +context of elements were important, one would either need to maintain some +context-related state (i.e. remembering where one is in the document at any +given point) or to make use of the :func:`DOMEventStream.expandNode` method +and switch to DOM-related processing. .. class:: PullDom(documentFactory=None) @@ -71,11 +72,9 @@ If you have XML in a string, you can use the :func:`parseString` function instead: - .. function:: parseString(string, parser=None) - Return a :class:`DOMEventStream` that represents the (unicode) *string*. - + Return a :class:`DOMEventStream` that represents the (Unicode) *string*. .. data:: default_bufsize @@ -84,7 +83,6 @@ The value of this variable can be changed before calling :func:`parse` and the new value will take effect. - .. _domeventstream-objects: DOMEventStream Objects @@ -93,16 +91,17 @@ .. class:: DOMEventStream(stream, parser, bufsize) - .. method:: DOMEventStream.getEvent() + .. method:: getEvent() Return a tuple containing *event* and the current *node* as - :class:`xml.dom.minidom.Document` if event equals START_DOCUMENT, - :class:`xml.dom.minidom.Element` if event equals START_ELEMENT or - END_ELEMENT or :class:`xml.dom.minidom.Text` if event equals CHARACTERS. + :class:`xml.dom.minidom.Document` if event equals :data:`START_DOCUMENT`, + :class:`xml.dom.minidom.Element` if event equals :data:`START_ELEMENT` or + :data:`END_ELEMENT` or :class:`xml.dom.minidom.Text` if event equals + :data:`CHARACTERS`. The current node does not contain informations about its children, unless :func:`expandNode` is called. - .. method:: DOMEventStream.expandNode(node) + .. method:: expandNode(node) Expands all children of *node* into *node*. Example:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 15:52:48 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 16 Mar 2012 15:52:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314202=3A_some_additional_doc_fixes?= Message-ID: http://hg.python.org/cpython/rev/b2e27f21760e changeset: 75742:b2e27f21760e parent: 75739:c0a6569fdad6 parent: 75741:1a740ea4f2a1 user: Eli Bendersky date: Fri Mar 16 16:51:01 2012 +0200 summary: Issue #14202: some additional doc fixes files: Doc/library/xml.dom.pulldom.rst | 27 ++++++++++---------- 1 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Doc/library/xml.dom.pulldom.rst b/Doc/library/xml.dom.pulldom.rst --- a/Doc/library/xml.dom.pulldom.rst +++ b/Doc/library/xml.dom.pulldom.rst @@ -44,11 +44,12 @@ Since the document is treated as a "flat" stream of events, the document "tree" is implicitly traversed and the desired elements are found regardless of their -depth in the tree. In other words, one does not need to consider hierarchical issues -such as recursive searching of the document nodes, although if the context of -elements were important, one would either need to maintain some context-related -state (ie. remembering where one is in the document at any given point) or to -make use of the :func:`DOMEventStream.expandNode` method and switch to DOM-related processing. +depth in the tree. In other words, one does not need to consider hierarchical +issues such as recursive searching of the document nodes, although if the +context of elements were important, one would either need to maintain some +context-related state (i.e. remembering where one is in the document at any +given point) or to make use of the :func:`DOMEventStream.expandNode` method +and switch to DOM-related processing. .. class:: PullDom(documentFactory=None) @@ -71,11 +72,9 @@ If you have XML in a string, you can use the :func:`parseString` function instead: - .. function:: parseString(string, parser=None) - Return a :class:`DOMEventStream` that represents the (unicode) *string*. - + Return a :class:`DOMEventStream` that represents the (Unicode) *string*. .. data:: default_bufsize @@ -84,7 +83,6 @@ The value of this variable can be changed before calling :func:`parse` and the new value will take effect. - .. _domeventstream-objects: DOMEventStream Objects @@ -93,16 +91,17 @@ .. class:: DOMEventStream(stream, parser, bufsize) - .. method:: DOMEventStream.getEvent() + .. method:: getEvent() Return a tuple containing *event* and the current *node* as - :class:`xml.dom.minidom.Document` if event equals START_DOCUMENT, - :class:`xml.dom.minidom.Element` if event equals START_ELEMENT or - END_ELEMENT or :class:`xml.dom.minidom.Text` if event equals CHARACTERS. + :class:`xml.dom.minidom.Document` if event equals :data:`START_DOCUMENT`, + :class:`xml.dom.minidom.Element` if event equals :data:`START_ELEMENT` or + :data:`END_ELEMENT` or :class:`xml.dom.minidom.Text` if event equals + :data:`CHARACTERS`. The current node does not contain informations about its children, unless :func:`expandNode` is called. - .. method:: DOMEventStream.expandNode(node) + .. method:: expandNode(node) Expands all children of *node* into *node*. Example:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 16:13:40 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 16:13:40 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_condition_=28=2314296?= =?utf8?q?=29?= Message-ID: http://hg.python.org/cpython/rev/17980cb07625 changeset: 75743:17980cb07625 parent: 75739:c0a6569fdad6 user: Benjamin Peterson date: Fri Mar 16 10:12:55 2012 -0500 summary: fix condition (#14296) files: Modules/posixmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -107,7 +107,7 @@ #include #endif -#if defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY) +#if !defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY) #undef HAVE_SCHED_SETAFFINITY #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 16:13:41 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 16:13:41 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/8a5b03b77828 changeset: 75744:8a5b03b77828 parent: 75743:17980cb07625 parent: 75742:b2e27f21760e user: Benjamin Peterson date: Fri Mar 16 10:13:30 2012 -0500 summary: merge heads files: Doc/library/xml.dom.pulldom.rst | 27 ++++++++++---------- 1 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Doc/library/xml.dom.pulldom.rst b/Doc/library/xml.dom.pulldom.rst --- a/Doc/library/xml.dom.pulldom.rst +++ b/Doc/library/xml.dom.pulldom.rst @@ -44,11 +44,12 @@ Since the document is treated as a "flat" stream of events, the document "tree" is implicitly traversed and the desired elements are found regardless of their -depth in the tree. In other words, one does not need to consider hierarchical issues -such as recursive searching of the document nodes, although if the context of -elements were important, one would either need to maintain some context-related -state (ie. remembering where one is in the document at any given point) or to -make use of the :func:`DOMEventStream.expandNode` method and switch to DOM-related processing. +depth in the tree. In other words, one does not need to consider hierarchical +issues such as recursive searching of the document nodes, although if the +context of elements were important, one would either need to maintain some +context-related state (i.e. remembering where one is in the document at any +given point) or to make use of the :func:`DOMEventStream.expandNode` method +and switch to DOM-related processing. .. class:: PullDom(documentFactory=None) @@ -71,11 +72,9 @@ If you have XML in a string, you can use the :func:`parseString` function instead: - .. function:: parseString(string, parser=None) - Return a :class:`DOMEventStream` that represents the (unicode) *string*. - + Return a :class:`DOMEventStream` that represents the (Unicode) *string*. .. data:: default_bufsize @@ -84,7 +83,6 @@ The value of this variable can be changed before calling :func:`parse` and the new value will take effect. - .. _domeventstream-objects: DOMEventStream Objects @@ -93,16 +91,17 @@ .. class:: DOMEventStream(stream, parser, bufsize) - .. method:: DOMEventStream.getEvent() + .. method:: getEvent() Return a tuple containing *event* and the current *node* as - :class:`xml.dom.minidom.Document` if event equals START_DOCUMENT, - :class:`xml.dom.minidom.Element` if event equals START_ELEMENT or - END_ELEMENT or :class:`xml.dom.minidom.Text` if event equals CHARACTERS. + :class:`xml.dom.minidom.Document` if event equals :data:`START_DOCUMENT`, + :class:`xml.dom.minidom.Element` if event equals :data:`START_ELEMENT` or + :data:`END_ELEMENT` or :class:`xml.dom.minidom.Text` if event equals + :data:`CHARACTERS`. The current node does not contain informations about its children, unless :func:`expandNode` is called. - .. method:: DOMEventStream.expandNode(node) + .. method:: expandNode(node) Expands all children of *node* into *node*. Example:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 16:58:57 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 16:58:57 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_check_for_strin?= =?utf8?q?g_attribute_names_in_old-style_classes_=28closes_=2314334=29?= Message-ID: http://hg.python.org/cpython/rev/3d4d52e47431 changeset: 75745:3d4d52e47431 branch: 2.7 parent: 75740:d1cf6008a565 user: Benjamin Peterson date: Fri Mar 16 10:58:46 2012 -0500 summary: check for string attribute names in old-style classes (closes #14334) files: Lib/test/test_class.py | 7 +++++++ Misc/NEWS | 3 ++- Objects/classobject.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -628,6 +628,13 @@ a = A(hash(A.f.im_func)^(-1)) hash(a.f) + def testAttrSlots(self): + class C: + pass + for c in C, C(): + self.assertRaises(TypeError, type(c).__getattribute__, c, []) + self.assertRaises(TypeError, type(c).__setattr__, c, [], []) + def test_main(): with test_support.check_py3k_warnings( (".+__(get|set|del)slice__ has been removed", DeprecationWarning), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,7 +10,8 @@ ----------------- - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not - passed strings. + passed strings. Also fix segfaults in the __getattribute__ and __setattr__ + methods of old-style classes. - Issue #14161: fix the __repr__ of file objects to escape the file name. diff --git a/Objects/classobject.c b/Objects/classobject.c --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -225,10 +225,16 @@ class_getattr(register PyClassObject *op, PyObject *name) { register PyObject *v; - register char *sname = PyString_AsString(name); + register char *sname; PyClassObject *klass; descrgetfunc f; + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, "attribute name must be a string"); + return NULL; + } + + sname = PyString_AsString(name); if (sname[0] == '_' && sname[1] == '_') { if (strcmp(sname, "__dict__") == 0) { if (PyEval_GetRestricted()) { @@ -336,6 +342,10 @@ "classes are read-only in restricted mode"); return -1; } + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, "attribute name must be a string"); + return -1; + } sname = PyString_AsString(name); if (sname[0] == '_' && sname[1] == '_') { Py_ssize_t n = PyString_Size(name); @@ -699,7 +709,14 @@ instance_getattr1(register PyInstanceObject *inst, PyObject *name) { register PyObject *v; - register char *sname = PyString_AsString(name); + register char *sname; + + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, "attribute name must be a string"); + return NULL; + } + + sname = PyString_AsString(name); if (sname[0] == '_' && sname[1] == '_') { if (strcmp(sname, "__dict__") == 0) { if (PyEval_GetRestricted()) { @@ -810,7 +827,14 @@ instance_setattr(PyInstanceObject *inst, PyObject *name, PyObject *v) { PyObject *func, *args, *res, *tmp; - char *sname = PyString_AsString(name); + char *sname; + + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, "attribute name must be a string"); + return -1; + } + + sname = PyString_AsString(name); if (sname[0] == '_' && sname[1] == '_') { Py_ssize_t n = PyString_Size(name); if (sname[n-1] == '_' && sname[n-2] == '_') { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 18:24:27 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 18:24:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_check_result_of_PyMem=5FNew?= Message-ID: http://hg.python.org/cpython/rev/2b8994c2851a changeset: 75746:2b8994c2851a parent: 75744:8a5b03b77828 user: Benjamin Peterson date: Fri Mar 16 12:21:02 2012 -0500 summary: check result of PyMem_New files: Python/getargs.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -267,6 +267,10 @@ format = formatsave; freelist.entries = PyMem_New(freelistentry_t, max); + if (freelist.entries == NULL) { + PyErr_NoMemory(); + return 0; + } if (compat) { if (max == 0) { @@ -1430,6 +1434,10 @@ continue; freelist.entries = PyMem_New(freelistentry_t, len); + if (freelist.entries == NULL) { + PyErr_NoMemory(); + return 0; + } nargs = PyTuple_GET_SIZE(args); nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 18:24:28 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 18:24:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_use_memory_macros?= Message-ID: http://hg.python.org/cpython/rev/212f20284724 changeset: 75747:212f20284724 user: Benjamin Peterson date: Fri Mar 16 12:23:39 2012 -0500 summary: use memory macros files: Python/getargs.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -191,7 +191,7 @@ freelist->entries[index].item); } } - PyMem_Free(freelist->entries); + PyMem_FREE(freelist->entries); return retval; } @@ -266,7 +266,7 @@ format = formatsave; - freelist.entries = PyMem_New(freelistentry_t, max); + freelist.entries = PyMem_NEW(freelistentry_t, max); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; @@ -1433,7 +1433,7 @@ for (len=0; kwlist[len]; len++) continue; - freelist.entries = PyMem_New(freelistentry_t, len); + freelist.entries = PyMem_NEW(freelistentry_t, len); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 18:24:29 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 18:24:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_kill_capsule_names_that_we_?= =?utf8?q?don=27t_need_anymore?= Message-ID: http://hg.python.org/cpython/rev/55564dea55e5 changeset: 75748:55564dea55e5 user: Benjamin Peterson date: Fri Mar 16 12:24:01 2012 -0500 summary: kill capsule names that we don't need anymore files: Python/getargs.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -140,10 +140,6 @@ /* Handle cleanup of allocated memory in case of exception */ -#define GETARGS_CAPSULE_NAME_CLEANUP_PTR "getargs.cleanup_ptr" -#define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer" -#define GETARGS_CAPSULE_NAME_CLEANUP_CONVERT "getargs.cleanup_convert" - static int cleanup_ptr(PyObject *self, void *ptr) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 19:21:46 2012 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 16 Mar 2012 19:21:46 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Eliminate_duplicate_link_lo?= =?utf8?q?okup=2E__Minor_cleanup=2E?= Message-ID: http://hg.python.org/cpython/rev/6bccfd5ccfb0 changeset: 75749:6bccfd5ccfb0 user: Raymond Hettinger date: Fri Mar 16 11:21:39 2012 -0700 summary: Eliminate duplicate link lookup. Minor cleanup. files: Lib/functools.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -191,11 +191,11 @@ key += tuple(map(type, args)) if kwds: key += tuple(type(v) for k, v in sorted_items) - PREV, NEXT = 0, 1 # names of link fields + PREV = 0 # names of link fields + NEXT = 1 with lock: link = cache_get(key) if link is not None: - link = cache[key] # record recent use of the key by moving it to the front of the list link_prev, link_next, key, result = link link_prev[NEXT] = link_next -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 19:26:09 2012 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 16 Mar 2012 19:26:09 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_plug_memory_leak_=28closes_?= =?utf8?q?=2314325=29?= Message-ID: http://hg.python.org/cpython/rev/d08f0f3ab23e changeset: 75750:d08f0f3ab23e user: Benjamin Peterson date: Fri Mar 16 13:25:58 2012 -0500 summary: plug memory leak (closes #14325) files: Python/getargs.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1445,7 +1445,7 @@ len, (len == 1) ? "" : "s", nargs + nkeywords); - return 0; + return cleanreturn(0, &freelist); } /* convert tuple args and keyword args in same loop, using kwlist to drive process */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 16 19:48:19 2012 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 16 Mar 2012 19:48:19 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Minor_code_cleanup=2E?= Message-ID: http://hg.python.org/cpython/rev/8b2668e60aef changeset: 75751:8b2668e60aef user: Raymond Hettinger date: Fri Mar 16 11:48:12 2012 -0700 summary: Minor code cleanup. files: Lib/functools.py | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -156,6 +156,7 @@ lock = Lock() # needed because linkedlist isn't threadsafe root = [] # root of circular doubly linked list root[:] = [root, root, None, None] # initialize by pointing to self + PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names of link fields if maxsize is None: @wraps(user_function) @@ -191,8 +192,6 @@ key += tuple(map(type, args)) if kwds: key += tuple(type(v) for k, v in sorted_items) - PREV = 0 # names of link fields - NEXT = 1 with lock: link = cache_get(key) if link is not None: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Mar 17 00:08:08 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 17 Mar 2012 00:08:08 +0100 Subject: [Python-checkins] Daily reference leaks (7e576ad85663): sum=9199468 Message-ID: results for 7e576ad85663 on branch "default" -------------------------------------------- test_builtin leaked [880, 880, 880] references, sum=2640 test_support leaked [4, 0, 0] references, sum=4 test_ast leaked [3043281, 3043281, 3043281] references, sum=9129843 test_compile leaked [22295, 22295, 22295] references, sum=66885 test_pickle leaked [24, 24, 24] references, sum=72 test_pickletools leaked [8, 8, 8] references, sum=24 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogiEmRF1', '-x'] From python-checkins at python.org Sat Mar 17 00:23:04 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 17 Mar 2012 00:23:04 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_clear_the_root_with_the_cac?= =?utf8?q?he?= Message-ID: http://hg.python.org/cpython/rev/087da2a353e6 changeset: 75752:087da2a353e6 parent: 75750:d08f0f3ab23e user: Benjamin Peterson date: Fri Mar 16 18:22:26 2012 -0500 summary: clear the root with the cache files: Lib/functools.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -227,9 +227,11 @@ def cache_clear(): """Clear the cache and cache statistics""" - nonlocal hits, misses + nonlocal hits, misses, root with lock: cache.clear() + root = [] + root[:] = [root, root, None, None] hits = misses = 0 wrapper.cache_info = cache_info -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 00:23:06 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 17 Mar 2012 00:23:06 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/13e2d09e0612 changeset: 75753:13e2d09e0612 parent: 75752:087da2a353e6 parent: 75751:8b2668e60aef user: Benjamin Peterson date: Fri Mar 16 18:22:53 2012 -0500 summary: merge heads files: Lib/functools.py | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -156,6 +156,7 @@ lock = Lock() # needed because linkedlist isn't threadsafe root = [] # root of circular doubly linked list root[:] = [root, root, None, None] # initialize by pointing to self + PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names of link fields if maxsize is None: @wraps(user_function) @@ -191,8 +192,6 @@ key += tuple(map(type, args)) if kwds: key += tuple(type(v) for k, v in sorted_items) - PREV = 0 # names of link fields - NEXT = 1 with lock: link = cache_get(key) if link is not None: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 00:28:43 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 17 Mar 2012 00:28:43 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314335=3A_multiproc?= =?utf8?q?essing=27s_custom_Pickler_subclass_now_inherits_from_the?= Message-ID: http://hg.python.org/cpython/rev/b2a8310de718 changeset: 75754:b2a8310de718 parent: 75751:8b2668e60aef user: Antoine Pitrou date: Sat Mar 17 00:23:04 2012 +0100 summary: Issue #14335: multiprocessing's custom Pickler subclass now inherits from the C-accelerated implementation. Patch by sbt. files: Lib/multiprocessing/forking.py | 18 +++++++++--------- Misc/NEWS | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Lib/multiprocessing/forking.py b/Lib/multiprocessing/forking.py --- a/Lib/multiprocessing/forking.py +++ b/Lib/multiprocessing/forking.py @@ -55,18 +55,18 @@ # Try making some callable types picklable # -from pickle import _Pickler as Pickler +from pickle import Pickler +from copyreg import dispatch_table + class ForkingPickler(Pickler): - dispatch = Pickler.dispatch.copy() + _extra_reducers = {} + def __init__(self, *args): + Pickler.__init__(self, *args) + self.dispatch_table = dispatch_table.copy() + self.dispatch_table.update(self._extra_reducers) @classmethod def register(cls, type, reduce): - def dispatcher(self, obj): - rv = reduce(obj) - if isinstance(rv, str): - self.save_global(obj, rv) - else: - self.save_reduce(obj=obj, *rv) - cls.dispatch[type] = dispatcher + cls._extra_reducers[type] = reduce def _reduce_method(m): if m.__self__ is None: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ Library ------- +- Issue #14335: multiprocessing's custom Pickler subclass now inherits from + the C-accelerated implementation. Patch by sbt. + - Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem. - Issue #11199: Fix the with urllib which hangs on particular ftp urls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 00:28:44 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 17 Mar 2012 00:28:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merge?= Message-ID: http://hg.python.org/cpython/rev/fb76bb09ad0f changeset: 75755:fb76bb09ad0f parent: 75754:b2a8310de718 parent: 75753:13e2d09e0612 user: Antoine Pitrou date: Sat Mar 17 00:24:12 2012 +0100 summary: Merge files: Lib/functools.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -226,9 +226,11 @@ def cache_clear(): """Clear the cache and cache statistics""" - nonlocal hits, misses + nonlocal hits, misses, root with lock: cache.clear() + root = [] + root[:] = [root, root, None, None] hits = misses = 0 wrapper.cache_info = cache_info -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 00:45:41 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 17 Mar 2012 00:45:41 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_cleanup_Ellipsis_and_NotImp?= =?utf8?q?lemented_strings_after_we=27re_done?= Message-ID: http://hg.python.org/cpython/rev/9e5fb0b274d8 changeset: 75756:9e5fb0b274d8 user: Benjamin Peterson date: Fri Mar 16 18:45:31 2012 -0500 summary: cleanup Ellipsis and NotImplemented strings after we're done files: Modules/_pickle.c | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2815,18 +2815,24 @@ save_ellipsis(PicklerObject *self, PyObject *obj) { PyObject *str = PyUnicode_FromString("Ellipsis"); + int res; if (str == NULL) return -1; - return save_global(self, Py_Ellipsis, str); + res = save_global(self, Py_Ellipsis, str); + Py_DECREF(str); + return res; } static int save_notimplemented(PicklerObject *self, PyObject *obj) { PyObject *str = PyUnicode_FromString("NotImplemented"); + int res; if (str == NULL) return -1; - return save_global(self, Py_NotImplemented, str); + res = save_global(self, Py_NotImplemented, str); + Py_DECREF(str); + return res; } static int -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 00:53:10 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 17 Mar 2012 00:53:10 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Refactor_calculation_of_the?= =?utf8?q?_cache_key=2E__Minor_code_cleanups=2E?= Message-ID: http://hg.python.org/cpython/rev/51b0711ee672 changeset: 75757:51b0711ee672 user: Raymond Hettinger date: Fri Mar 16 16:53:05 2012 -0700 summary: Refactor calculation of the cache key. Minor code cleanups. files: Lib/functools.py | 46 ++++++++++++++++------------------- 1 files changed, 21 insertions(+), 25 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -146,31 +146,35 @@ # The internals of the lru_cache are encapsulated for thread safety and # to allow the implementation to change (including a possible C version). - def decorating_function(user_function, - *, tuple=tuple, sorted=sorted, map=map, len=len, type=type): + def decorating_function(user_function): cache = dict() hits = misses = 0 - cache_get = cache.get # bound method for fast lookup - kwd_mark = (object(),) # separates positional and keyword args - lock = Lock() # needed because linkedlist isn't threadsafe - root = [] # root of circular doubly linked list + cache_get = cache.get # bound method to lookup key or return None + _len = len # localize the global len() function + kwd_mark = (object(),) # separate positional and keyword args + lock = Lock() # because linkedlist updates aren't threadsafe + root = [] # root of the circular doubly linked list root[:] = [root, root, None, None] # initialize by pointing to self - PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names of link fields + PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields + + def make_key(args, kwds, typed, tuple=tuple, sorted=sorted, type=type): + key = args + if kwds: + sorted_items = tuple(sorted(kwds.items())) + key += kwd_mark + sorted_items + if typed: + key += tuple(type(v) for v in args) + if kwds: + key += tuple(type(v) for k, v in sorted_items) + return key if maxsize is None: @wraps(user_function) def wrapper(*args, **kwds): # simple caching without ordering or size limit nonlocal hits, misses - key = args - if kwds: - sorted_items = tuple(sorted(kwds.items())) - key += kwd_mark + sorted_items - if typed: - key += tuple(map(type, args)) - if kwds: - key += tuple(type(v) for k, v in sorted_items) + key = make_key(args, kwds, typed) if kwds or typed else args result = cache_get(key) if result is not None: hits += 1 @@ -184,14 +188,7 @@ def wrapper(*args, **kwds): # size limited caching that tracks accesses by recency nonlocal hits, misses - key = args - if kwds: - sorted_items = tuple(sorted(kwds.items())) - key += kwd_mark + sorted_items - if typed: - key += tuple(map(type, args)) - if kwds: - key += tuple(type(v) for k, v in sorted_items) + key = make_key(args, kwds, typed) if kwds or typed else args with lock: link = cache_get(key) if link is not None: @@ -210,7 +207,7 @@ last = root[PREV] link = [last, root, key, result] cache[key] = last[NEXT] = root[PREV] = link - if len(cache) > maxsize: + if _len(cache) > maxsize: # purge least recently used cache entry old_prev, old_next, old_key, old_result = root[NEXT] root[NEXT] = old_next @@ -229,7 +226,6 @@ nonlocal hits, misses, root with lock: cache.clear() - root = [] root[:] = [root, root, None, None] hits = misses = 0 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 01:05:48 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 17 Mar 2012 01:05:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Unique_sentinel_value_for_c?= =?utf8?q?ache=2Eget=28=29?= Message-ID: http://hg.python.org/cpython/rev/2d6eeb4ce0c8 changeset: 75758:2d6eeb4ce0c8 user: Raymond Hettinger date: Fri Mar 16 17:04:11 2012 -0700 summary: Unique sentinel value for cache.get() files: Lib/functools.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -175,8 +175,8 @@ # simple caching without ordering or size limit nonlocal hits, misses key = make_key(args, kwds, typed) if kwds or typed else args - result = cache_get(key) - if result is not None: + result = cache_get(key, root) # root used here as a unique not-found sentinel + if result is not root: hits += 1 return result result = user_function(*args, **kwds) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 01:05:48 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 17 Mar 2012 01:05:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_whitespace?= Message-ID: http://hg.python.org/cpython/rev/41919f2a136b changeset: 75759:41919f2a136b user: Raymond Hettinger date: Fri Mar 16 17:05:17 2012 -0700 summary: Fix whitespace files: Lib/functools.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -175,7 +175,7 @@ # simple caching without ordering or size limit nonlocal hits, misses key = make_key(args, kwds, typed) if kwds or typed else args - result = cache_get(key, root) # root used here as a unique not-found sentinel + result = cache_get(key, root) # root used here as a unique not-found sentinel if result is not root: hits += 1 return result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 01:08:42 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 17 Mar 2012 01:08:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Root_variable_is_not_change?= =?utf8?q?d=2E?= Message-ID: http://hg.python.org/cpython/rev/c28a2ef28ba7 changeset: 75760:c28a2ef28ba7 user: Raymond Hettinger date: Fri Mar 16 17:08:37 2012 -0700 summary: Root variable is not changed. files: Lib/functools.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -223,7 +223,7 @@ def cache_clear(): """Clear the cache and cache statistics""" - nonlocal hits, misses, root + nonlocal hits, misses with lock: cache.clear() root[:] = [root, root, None, None] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 02:16:16 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 17 Mar 2012 02:16:16 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_simply_this_slightly?= Message-ID: http://hg.python.org/cpython/rev/1bb05dd557b1 changeset: 75761:1bb05dd557b1 user: Benjamin Peterson date: Fri Mar 16 20:15:54 2012 -0500 summary: simply this slightly files: Objects/typeobject.c | 15 ++++++--------- 1 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2949,13 +2949,13 @@ return NULL; if (type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) { - static PyObject *comma = NULL; PyObject *abstract_methods = NULL; PyObject *builtins; PyObject *sorted; PyObject *sorted_methods = NULL; PyObject *joined = NULL; - _Py_IDENTIFIER(join); + PyObject *comma; + _Py_static_string(comma_id, ", "); /* Compute ", ".join(sorted(type.__abstractmethods__)) into joined. */ @@ -2973,13 +2973,10 @@ NULL); if (sorted_methods == NULL) goto error; - if (comma == NULL) { - comma = PyUnicode_InternFromString(", "); - if (comma == NULL) - goto error; - } - joined = _PyObject_CallMethodId(comma, &PyId_join, - "O", sorted_methods); + comma = _PyUnicode_FromId(&comma_id); + if (comma == NULL) + goto error; + joined = PyUnicode_Join(comma, sorted_methods); if (joined == NULL) goto error; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 02:40:22 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 02:40:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=2312788=3A_fix_error_in_te?= =?utf8?q?st=5Fpolicy_when_run_under_refleak_detection?= Message-ID: http://hg.python.org/cpython/rev/474338602bd8 changeset: 75762:474338602bd8 user: R David Murray date: Fri Mar 16 21:39:57 2012 -0400 summary: #12788: fix error in test_policy when run under refleak detection files: Lib/test/test_email/test_policy.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py --- a/Lib/test/test_email/test_policy.py +++ b/Lib/test/test_email/test_policy.py @@ -118,7 +118,9 @@ self.assertEqual(foo.defects, [defect1, defect2]) class MyPolicy(email.policy.Policy): - defects = [] + defects = None + def __init__(self, *args, **kw): + super().__init__(*args, defects=[], **kw) def register_defect(self, obj, defect): self.defects.append(defect) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:06:24 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:06:24 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzExNzgwOiBkb2N1?= =?utf8?q?ment_that_email=2Eencoders_throw_TypeError_on_multipart_messages?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/1be426a555ca changeset: 75763:1be426a555ca branch: 3.2 parent: 75741:1a740ea4f2a1 user: R David Murray date: Fri Mar 16 22:03:17 2012 -0400 summary: #11780: document that email.encoders throw TypeError on multipart messages. files: Doc/library/email.encoders.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -18,6 +18,10 @@ payload, encode it, and reset the payload to this newly encoded value. They should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. +Note that these functions are not meaningful for a multipart message. They +must be applied to individual subparts instead, and will throw a +:exc:`TypeError` if passed a message whose type is multipart. + Here are the encoding functions provided: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:06:24 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:06:24 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2311780=3A_document_that_email=2Eencoders_throw_TypeE?= =?utf8?q?rror_on_multipart?= Message-ID: http://hg.python.org/cpython/rev/060eda590fa0 changeset: 75764:060eda590fa0 parent: 75762:474338602bd8 parent: 75763:1be426a555ca user: R David Murray date: Fri Mar 16 22:04:25 2012 -0400 summary: Merge #11780: document that email.encoders throw TypeError on multipart messages. files: Doc/library/email.encoders.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -18,6 +18,10 @@ payload, encode it, and reset the payload to this newly encoded value. They should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. +Note that these functions are not meaningful for a multipart message. They +must be applied to individual subparts instead, and will throw a +:exc:`TypeError` if passed a message whose type is multipart. + Here are the encoding functions provided: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:06:25 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:06:25 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzExNzgwOiBkb2N1?= =?utf8?q?ment_that_email=2Eencoders_throw_TypeError_on_multipart_messages?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/c894e2ea9ff7 changeset: 75765:c894e2ea9ff7 branch: 2.7 parent: 75745:3d4d52e47431 user: R David Murray date: Fri Mar 16 22:06:08 2012 -0400 summary: #11780: document that email.encoders throw TypeError on multipart messages. files: Doc/library/email.encoders.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -18,6 +18,10 @@ payload, encode it, and reset the payload to this newly encoded value. They should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. +Note that these functions are not meaningful for a multipart message. They +must be applied to individual subparts instead, and will throw a +:exc:`TypeError` if passed a message whose type is multipart. + Here are the encoding functions provided: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:11:40 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:11:40 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzExNzgwOiBzL3Ro?= =?utf8?q?row/raise/?= Message-ID: http://hg.python.org/cpython/rev/195b67c26ce7 changeset: 75766:195b67c26ce7 branch: 3.2 parent: 75763:1be426a555ca user: R David Murray date: Fri Mar 16 22:10:00 2012 -0400 summary: #11780: s/throw/raise/ files: Doc/library/email.encoders.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -19,7 +19,7 @@ should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. Note that these functions are not meaningful for a multipart message. They -must be applied to individual subparts instead, and will throw a +must be applied to individual subparts instead, and will raise a :exc:`TypeError` if passed a message whose type is multipart. Here are the encoding functions provided: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:11:43 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:11:43 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2311780=3A_s/throw/raise/?= Message-ID: http://hg.python.org/cpython/rev/63c46a8547fb changeset: 75767:63c46a8547fb parent: 75764:060eda590fa0 parent: 75766:195b67c26ce7 user: R David Murray date: Fri Mar 16 22:10:44 2012 -0400 summary: Merge #11780: s/throw/raise/ files: Doc/library/email.encoders.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -19,7 +19,7 @@ should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. Note that these functions are not meaningful for a multipart message. They -must be applied to individual subparts instead, and will throw a +must be applied to individual subparts instead, and will raise a :exc:`TypeError` if passed a message whose type is multipart. Here are the encoding functions provided: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:11:44 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:11:44 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzExNzgwOiBzL3Ro?= =?utf8?q?row/raise/?= Message-ID: http://hg.python.org/cpython/rev/55993cd25564 changeset: 75768:55993cd25564 branch: 2.7 parent: 75765:c894e2ea9ff7 user: R David Murray date: Fri Mar 16 22:11:22 2012 -0400 summary: #11780: s/throw/raise/ files: Doc/library/email.encoders.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -19,7 +19,7 @@ should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. Note that these functions are not meaningful for a multipart message. They -must be applied to individual subparts instead, and will throw a +must be applied to individual subparts instead, and will raise a :exc:`TypeError` if passed a message whose type is multipart. Here are the encoding functions provided: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:46:41 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:46:41 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzExNjg2OiBhZGQg?= =?utf8?q?missing_entries_to_email_=5F=5Fall=5F=5F_lists=2E?= Message-ID: http://hg.python.org/cpython/rev/63a6d35fcac8 changeset: 75769:63a6d35fcac8 branch: 3.2 parent: 75766:195b67c26ce7 user: R David Murray date: Fri Mar 16 22:43:05 2012 -0400 summary: #11686: add missing entries to email __all__ lists. Original patch by Steffen Daode Nurpmeso files: Lib/email/__init__.py | 1 + Lib/email/feedparser.py | 2 +- Lib/email/generator.py | 2 +- Lib/email/parser.py | 2 +- Lib/email/test/test_email.py | 13 +++++-------- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Lib/email/__init__.py b/Lib/email/__init__.py --- a/Lib/email/__init__.py +++ b/Lib/email/__init__.py @@ -11,6 +11,7 @@ 'charset', 'encoders', 'errors', + 'feedparser', 'generator', 'header', 'iterators', diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -19,7 +19,7 @@ object's .defects attribute. """ -__all__ = ['FeedParser'] +__all__ = ['FeedParser', 'BytesFeedParser'] import re diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -4,7 +4,7 @@ """Classes to generate plain text from a message object tree.""" -__all__ = ['Generator', 'DecodedGenerator'] +__all__ = ['Generator', 'DecodedGenerator', 'BytesGenerator'] import re import sys diff --git a/Lib/email/parser.py b/Lib/email/parser.py --- a/Lib/email/parser.py +++ b/Lib/email/parser.py @@ -4,7 +4,7 @@ """A parser of RFC 2822 and MIME email messages.""" -__all__ = ['Parser', 'HeaderParser'] +__all__ = ['Parser', 'HeaderParser', 'BytesParser'] import warnings from io import StringIO, TextIOWrapper diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -2518,14 +2518,11 @@ def test__all__(self): module = __import__('email') - # Can't use sorted() here due to Python 2.3 compatibility - all = module.__all__[:] - all.sort() - self.assertEqual(all, [ - 'base64mime', 'charset', 'encoders', 'errors', 'generator', - 'header', 'iterators', 'message', 'message_from_binary_file', - 'message_from_bytes', 'message_from_file', - 'message_from_string', 'mime', 'parser', + self.assertEqual(sorted(module.__all__), [ + 'base64mime', 'charset', 'encoders', 'errors', 'feedparser', + 'generator', 'header', 'iterators', 'message', + 'message_from_binary_file', 'message_from_bytes', + 'message_from_file', 'message_from_string', 'mime', 'parser', 'quoprimime', 'utils', ]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:46:41 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:46:41 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2311686=3A_add_missing_entries_to_email_=5F=5Fall=5F?= =?utf8?q?=5F_lists=2E?= Message-ID: http://hg.python.org/cpython/rev/561fc3b4cc2a changeset: 75770:561fc3b4cc2a parent: 75767:63c46a8547fb parent: 75769:63a6d35fcac8 user: R David Murray date: Fri Mar 16 22:46:14 2012 -0400 summary: Merge #11686: add missing entries to email __all__ lists. Original patch by Steffen Daode Nurpmeso files: Lib/email/__init__.py | 1 + Lib/email/feedparser.py | 2 +- Lib/email/generator.py | 2 +- Lib/test/test_email/test_email.py | 13 +++++-------- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Lib/email/__init__.py b/Lib/email/__init__.py --- a/Lib/email/__init__.py +++ b/Lib/email/__init__.py @@ -11,6 +11,7 @@ 'charset', 'encoders', 'errors', + 'feedparser', 'generator', 'header', 'iterators', diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -19,7 +19,7 @@ object's .defects attribute. """ -__all__ = ['FeedParser'] +__all__ = ['FeedParser', 'BytesFeedParser'] import re diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -4,7 +4,7 @@ """Classes to generate plain text from a message object tree.""" -__all__ = ['Generator', 'DecodedGenerator'] +__all__ = ['Generator', 'DecodedGenerator', 'BytesGenerator'] import re import sys diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -2600,14 +2600,11 @@ def test__all__(self): module = __import__('email') - # Can't use sorted() here due to Python 2.3 compatibility - all = module.__all__[:] - all.sort() - self.assertEqual(all, [ - 'base64mime', 'charset', 'encoders', 'errors', 'generator', - 'header', 'iterators', 'message', 'message_from_binary_file', - 'message_from_bytes', 'message_from_file', - 'message_from_string', 'mime', 'parser', + self.assertEqual(sorted(module.__all__), [ + 'base64mime', 'charset', 'encoders', 'errors', 'feedparser', + 'generator', 'header', 'iterators', 'message', + 'message_from_binary_file', 'message_from_bytes', + 'message_from_file', 'message_from_string', 'mime', 'parser', 'quoprimime', 'utils', ]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:51:13 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:51:13 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzExNjg2OiBuZXdz?= =?utf8?q?_entry=2E?= Message-ID: http://hg.python.org/cpython/rev/32d3ecacdabf changeset: 75771:32d3ecacdabf branch: 3.2 parent: 75769:63a6d35fcac8 user: R David Murray date: Fri Mar 16 22:49:54 2012 -0400 summary: #11686: news entry. files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #11686: Added missing entries to email package __all__ lists + (mostly the new Bytes classes). + - Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem. - Issue #11199: Fix the with urllib which hangs on particular ftp urls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 03:51:14 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 03:51:14 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2311686=3A_news_entry=2E?= Message-ID: http://hg.python.org/cpython/rev/26c8c43dd774 changeset: 75772:26c8c43dd774 parent: 75770:561fc3b4cc2a parent: 75771:32d3ecacdabf user: R David Murray date: Fri Mar 16 22:51:00 2012 -0400 summary: Merge #11686: news entry. files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ Library ------- +- Issue #11686: Added missing entries to email package __all__ lists + (mostly the new Bytes classes). + - Issue #14335: multiprocessing's custom Pickler subclass now inherits from the C-accelerated implementation. Patch by sbt. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Mar 17 05:43:08 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 17 Mar 2012 05:43:08 +0100 Subject: [Python-checkins] Daily reference leaks (63c46a8547fb): sum=0 Message-ID: results for 63c46a8547fb on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogPycK1R', '-x'] From python-checkins at python.org Sat Mar 17 06:06:17 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 17 Mar 2012 06:06:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_make_extra_arguments_to_obj?= =?utf8?b?ZWN0Ll9faW5pdF9fL19fbmV3X18gdG8gZXJyb3JzIGluIG1vc3QgY2FzZXM=?= Message-ID: http://hg.python.org/cpython/rev/25b71858cb14 changeset: 75773:25b71858cb14 parent: 75770:561fc3b4cc2a user: Benjamin Peterson date: Sat Mar 17 00:05:44 2012 -0500 summary: make extra arguments to object.__init__/__new__ to errors in most cases (finishes #1683368) files: Lib/test/test_descr.py | 20 +++++++++++++ Misc/NEWS | 3 ++ Objects/typeobject.c | 45 ++++++----------------------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4502,6 +4502,26 @@ for o in gc.get_objects(): self.assertIsNot(type(o), X) + def test_object_new_and_init_with_parameters(self): + # See issue #1683368 + class OverrideNeither: + pass + self.assertRaises(TypeError, OverrideNeither, 1) + self.assertRaises(TypeError, OverrideNeither, kw=1) + class OverrideNew: + def __new__(cls, foo, kw=0, *args, **kwds): + return object.__new__(cls, *args, **kwds) + class OverrideInit: + def __init__(self, foo, kw=0, *args, **kwargs): + return object.__init__(self, *args, **kwargs) + class OverrideBoth(OverrideNew, OverrideInit): + pass + for case in OverrideNew, OverrideInit, OverrideBoth: + case(1) + case(1, kw=2) + self.assertRaises(TypeError, case, 1, 2, 3) + self.assertRaises(TypeError, case, 1, 2, foo=3) + class DictProxyTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #1683368: object.__new__ and object.__init__ raise a TypeError if they + are passed arguments and their complementary method is not overridden. + - Give the ast.AST class a __dict__. - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2905,22 +2905,11 @@ object_init(PyObject *self, PyObject *args, PyObject *kwds) { int err = 0; - if (excess_args(args, kwds)) { - PyTypeObject *type = Py_TYPE(self); - if (type->tp_init != object_init && - type->tp_new != object_new) - { - err = PyErr_WarnEx(PyExc_DeprecationWarning, - "object.__init__() takes no parameters", - 1); - } - else if (type->tp_init != object_init || - type->tp_new == object_new) - { - PyErr_SetString(PyExc_TypeError, - "object.__init__() takes no parameters"); - err = -1; - } + PyTypeObject *type = Py_TYPE(self); + if (excess_args(args, kwds) && + (type->tp_new == object_new || type->tp_init != object_init)) { + PyErr_SetString(PyExc_TypeError, "object.__init__() takes no parameters"); + err = -1; } return err; } @@ -2928,26 +2917,12 @@ static PyObject * object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - int err = 0; - if (excess_args(args, kwds)) { - if (type->tp_new != object_new && - type->tp_init != object_init) - { - err = PyErr_WarnEx(PyExc_DeprecationWarning, - "object.__new__() takes no parameters", - 1); - } - else if (type->tp_new != object_new || - type->tp_init == object_init) - { - PyErr_SetString(PyExc_TypeError, - "object.__new__() takes no parameters"); - err = -1; - } - } - if (err < 0) + if (excess_args(args, kwds) && + (type->tp_init == object_init || type->tp_new != object_new)) { + PyErr_SetString(PyExc_TypeError, "object.__new__() takes no parameters"); return NULL; - + } + if (type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) { PyObject *abstract_methods = NULL; PyObject *builtins; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 06:06:17 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 17 Mar 2012 06:06:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/7c6d6f49b6bc changeset: 75774:7c6d6f49b6bc parent: 75773:25b71858cb14 parent: 75772:26c8c43dd774 user: Benjamin Peterson date: Sat Mar 17 00:05:59 2012 -0500 summary: merge heads files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,9 @@ Library ------- +- Issue #11686: Added missing entries to email package __all__ lists + (mostly the new Bytes classes). + - Issue #14335: multiprocessing's custom Pickler subclass now inherits from the C-accelerated implementation. Patch by sbt. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 06:12:26 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 17 Mar 2012 06:12:26 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Minor_beautification=2E?= Message-ID: http://hg.python.org/cpython/rev/70672d21b9fd changeset: 75775:70672d21b9fd user: Raymond Hettinger date: Fri Mar 16 22:12:20 2012 -0700 summary: Minor beautification. files: Lib/functools.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -120,7 +120,7 @@ except ImportError: pass -_CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize") +_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"]) def lru_cache(maxsize=100, typed=False): """Least-recently-used cache decorator. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 08:24:15 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 17 Mar 2012 08:24:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Section-off_the_source_for_?= =?utf8?q?better_readability=2E?= Message-ID: http://hg.python.org/cpython/rev/66803fd0a6bc changeset: 75776:66803fd0a6bc user: Raymond Hettinger date: Sat Mar 17 00:24:09 2012 -0700 summary: Section-off the source for better readability. files: Lib/functools.py | 23 +++++++++++++++++++++++ 1 files changed, 23 insertions(+), 0 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -18,6 +18,11 @@ except: from _dummy_thread import allocate_lock as Lock + +################################################################################ +### update_wrapper() and wraps() decorator +################################################################################ + # update_wrapper() and wraps() are tools to help write # wrapper functions that can handle naive introspection @@ -66,6 +71,11 @@ return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) + +################################################################################ +### total_ordering class decorator +################################################################################ + def total_ordering(cls): """Class decorator that fills in missing ordering methods""" convert = { @@ -94,6 +104,11 @@ setattr(cls, opname, opfunc) return cls + +################################################################################ +### cmp_to_key() function converter +################################################################################ + def cmp_to_key(mycmp): """Convert a cmp= function into a key= function""" class K(object): @@ -120,6 +135,11 @@ except ImportError: pass + +################################################################################ +### LRU Cache function decorator +################################################################################ + _CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"]) def lru_cache(maxsize=100, typed=False): @@ -170,6 +190,7 @@ return key if maxsize is None: + @wraps(user_function) def wrapper(*args, **kwds): # simple caching without ordering or size limit @@ -183,7 +204,9 @@ cache[key] = result misses += 1 return result + else: + @wraps(user_function) def wrapper(*args, **kwds): # size limited caching that tracks accesses by recency -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 08:41:25 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sat, 17 Mar 2012 08:41:25 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A__explain_json?= =?utf8?q?=2Edumps_for_non-string_keys_in_dicts=2E_closes_issue6566=2E_Pat?= =?utf8?q?ch?= Message-ID: http://hg.python.org/cpython/rev/7c818b4cd98a changeset: 75777:7c818b4cd98a branch: 2.7 parent: 75768:55993cd25564 user: Senthil Kumaran date: Sat Mar 17 00:37:38 2012 -0700 summary: explain json.dumps for non-string keys in dicts. closes issue6566. Patch contributed Kirubakaran Athmanathan files: Doc/library/json.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -170,6 +170,14 @@ :class:`unicode` instance. The other arguments have the same meaning as in :func:`dump`. + .. note:: + + Keys in key/value pairs of JSON are always of the type :class:`str`. When + a dictionary is converted into JSON, all the keys of the dictionary are + coerced to strings. As a result of this, if a dictionary is convered + into JSON and then back into a dictionary, the dictionary may not equal + the original one. That is, ``loads(dumps(x)) != x`` if x has non-string + keys. .. function:: load(fp[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 08:41:26 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sat, 17 Mar 2012 08:41:26 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_3=2E2_explain_j?= =?utf8?q?son=2Edumps_for_non-string_keys_in_dicts=2E_closes_issue6566=2E_?= =?utf8?q?Patch?= Message-ID: http://hg.python.org/cpython/rev/613919591a05 changeset: 75778:613919591a05 branch: 3.2 parent: 75771:32d3ecacdabf user: Senthil Kumaran date: Sat Mar 17 00:40:34 2012 -0700 summary: 3.2 explain json.dumps for non-string keys in dicts. closes issue6566. Patch contributed Kirubakaran Athmanathan files: Doc/library/json.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -168,6 +168,14 @@ so trying to serialize multiple objects with repeated calls to :func:`dump` using the same *fp* will result in an invalid JSON file. + .. note:: + + Keys in key/value pairs of JSON are always of the type :class:`str`. When + a dictionary is converted into JSON, all the keys of the dictionary are + coerced to strings. As a result of this, if a dictionary is convered + into JSON and then back into a dictionary, the dictionary may not equal + the original one. That is, ``loads(dumps(x)) != x`` if x has non-string + keys. .. function:: load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 08:41:27 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sat, 17 Mar 2012 08:41:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_from_3=2E2_-_issue6566?= Message-ID: http://hg.python.org/cpython/rev/0554183066b5 changeset: 75779:0554183066b5 parent: 75776:66803fd0a6bc parent: 75778:613919591a05 user: Senthil Kumaran date: Sat Mar 17 00:41:15 2012 -0700 summary: merge from 3.2 - issue6566 files: Doc/library/json.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -168,6 +168,14 @@ so trying to serialize multiple objects with repeated calls to :func:`dump` using the same *fp* will result in an invalid JSON file. + .. note:: + + Keys in key/value pairs of JSON are always of the type :class:`str`. When + a dictionary is converted into JSON, all the keys of the dictionary are + coerced to strings. As a result of this, if a dictionary is convered + into JSON and then back into a dictionary, the dictionary may not equal + the original one. That is, ``loads(dumps(x)) != x`` if x has non-string + keys. .. function:: load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 14:16:27 2012 From: python-checkins at python.org (eli.bendersky) Date: Sat, 17 Mar 2012 14:16:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_updated_whatsnew/3=2E3=2Ers?= =?utf8?q?t_with_the_new_methods_added_to_list_and_bytearray?= Message-ID: http://hg.python.org/cpython/rev/958a98bf924e changeset: 75780:958a98bf924e user: Eli Bendersky date: Sat Mar 17 15:14:35 2012 +0200 summary: updated whatsnew/3.3.rst with the new methods added to list and bytearray (issue 10516) files: Doc/whatsnew/3.3.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -481,6 +481,10 @@ (:issue:`14205`) +* New methods have been added to :class:`list` and :class:`bytearray`: + ``copy()`` and ``clear()``. + + (:issue:`10516`) New and Improved Modules ======================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 16:58:15 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 16:58:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314306?= =?utf8?q?=3A_clarify_expensiveness_of_try-except_and_update_code_snippet?= Message-ID: http://hg.python.org/cpython/rev/9a7dcfbcf726 changeset: 75781:9a7dcfbcf726 branch: 3.2 parent: 75778:613919591a05 user: Georg Brandl date: Sat Mar 17 16:58:05 2012 +0100 summary: Closes #14306: clarify expensiveness of try-except and update code snippet files: Doc/faq/design.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -284,8 +284,9 @@ How fast are exceptions? ------------------------ -A try/except block is extremely efficient. Actually catching an exception is -expensive. In versions of Python prior to 2.0 it was common to use this idiom:: +A try/except block is extremely efficient if no exceptions are raised. Actually +catching an exception is expensive. In versions of Python prior to 2.0 it was +common to use this idiom:: try: value = mydict[key] @@ -296,11 +297,10 @@ This only made sense when you expected the dict to have the key almost all the time. If that wasn't the case, you coded it like this:: - if mydict.has_key(key): + if key in mydict: value = mydict[key] else: - mydict[key] = getvalue(key) - value = mydict[key] + value = mydict[key] = getvalue(key) For this specific case, you could also use ``value = dict.setdefault(key, getvalue(key))``, but only if the ``getvalue()`` call is cheap enough because it -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 16:58:17 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 16:58:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/1d663bddfd69 changeset: 75782:1d663bddfd69 parent: 75780:958a98bf924e parent: 75781:9a7dcfbcf726 user: Georg Brandl date: Sat Mar 17 16:58:12 2012 +0100 summary: merge with 3.2 files: Doc/faq/design.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -284,8 +284,9 @@ How fast are exceptions? ------------------------ -A try/except block is extremely efficient. Actually catching an exception is -expensive. In versions of Python prior to 2.0 it was common to use this idiom:: +A try/except block is extremely efficient if no exceptions are raised. Actually +catching an exception is expensive. In versions of Python prior to 2.0 it was +common to use this idiom:: try: value = mydict[key] @@ -296,11 +297,10 @@ This only made sense when you expected the dict to have the key almost all the time. If that wasn't the case, you coded it like this:: - if mydict.has_key(key): + if key in mydict: value = mydict[key] else: - mydict[key] = getvalue(key) - value = mydict[key] + value = mydict[key] = getvalue(key) For this specific case, you could also use ``value = dict.setdefault(key, getvalue(key))``, but only if the ``getvalue()`` call is cheap enough because it -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 16:58:54 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 16:58:54 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314306?= =?utf8?q?=3A_clarify_expensiveness_of_try-except_and_update_code_snippet?= Message-ID: http://hg.python.org/cpython/rev/7a93f6ee2ebc changeset: 75783:7a93f6ee2ebc branch: 2.7 parent: 75777:7c818b4cd98a user: Georg Brandl date: Sat Mar 17 16:58:05 2012 +0100 summary: Closes #14306: clarify expensiveness of try-except and update code snippet files: Doc/faq/design.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -297,8 +297,9 @@ How fast are exceptions? ------------------------ -A try/except block is extremely efficient. Actually catching an exception is -expensive. In versions of Python prior to 2.0 it was common to use this idiom:: +A try/except block is extremely efficient if no exceptions are raised. Actually +catching an exception is expensive. In versions of Python prior to 2.0 it was +common to use this idiom:: try: value = mydict[key] @@ -309,11 +310,10 @@ This only made sense when you expected the dict to have the key almost all the time. If that wasn't the case, you coded it like this:: - if mydict.has_key(key): + if key in mydict: value = mydict[key] else: - mydict[key] = getvalue(key) - value = mydict[key] + value = mydict[key] = getvalue(key) .. note:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 17:26:39 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 17:26:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314342?= =?utf8?q?=3A_remove_out-of-date_section_about_avoiding_recursion_errors?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/8172d7dce0ed changeset: 75784:8172d7dce0ed branch: 3.2 parent: 75781:9a7dcfbcf726 user: Georg Brandl date: Sat Mar 17 17:25:47 2012 +0100 summary: Closes #14342: remove out-of-date section about avoiding recursion errors. files: Doc/library/re.rst | 22 ---------------------- 1 files changed, 0 insertions(+), 22 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1090,28 +1090,6 @@ (\S+) - (\d+) errors, (\d+) warnings -Avoiding recursion -^^^^^^^^^^^^^^^^^^ - -If you create regular expressions that require the engine to perform a lot of -recursion, you may encounter a :exc:`RuntimeError` exception with the message -``maximum recursion limit exceeded``. For example, :: - - >>> s = 'Begin ' + 1000*'a very long string ' + 'end' - >>> re.match('Begin (\w| )*? end', s).end() - Traceback (most recent call last): - File "", line 1, in ? - File "/usr/local/lib/python3.2/re.py", line 132, in match - return _compile(pattern, flags).match(string) - RuntimeError: maximum recursion limit exceeded - -You can often restructure your regular expression to avoid recursion. - -Simple uses of the ``*?`` pattern are special-cased to avoid recursion. Thus, -the above regular expression can avoid recursion by being recast as ``Begin -[a-zA-Z0-9_ ]*?end``. As a further benefit, such regular expressions will run -faster than their recursive equivalents. - .. _search-vs-match: search() vs. match() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 17:26:40 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 17:26:40 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314343?= =?utf8?q?=3A_avoid_shadowing_builtin_input=28=29_in_example_code=2E?= Message-ID: http://hg.python.org/cpython/rev/6cf5f963e0c4 changeset: 75785:6cf5f963e0c4 branch: 3.2 user: Georg Brandl date: Sat Mar 17 17:26:27 2012 +0100 summary: Closes #14343: avoid shadowing builtin input() in example code. files: Doc/library/re.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1136,7 +1136,7 @@ First, here is the input. Normally it may come from a file, here we are using triple-quoted string syntax: - >>> input = """Ross McFluff: 834.345.1254 155 Elm Street + >>> text = """Ross McFluff: 834.345.1254 155 Elm Street ... ... Ronald Heathmore: 892.345.3428 436 Finley Avenue ... Frank Burger: 925.541.7625 662 South Dogwood Way @@ -1150,7 +1150,7 @@ .. doctest:: :options: +NORMALIZE_WHITESPACE - >>> entries = re.split("\n+", input) + >>> entries = re.split("\n+", text) >>> entries ['Ross McFluff: 834.345.1254 155 Elm Street', 'Ronald Heathmore: 892.345.3428 436 Finley Avenue', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 17:26:41 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 17:26:41 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/64e1eeca4cb7 changeset: 75786:64e1eeca4cb7 parent: 75782:1d663bddfd69 parent: 75785:6cf5f963e0c4 user: Georg Brandl date: Sat Mar 17 17:26:36 2012 +0100 summary: merge with 3.2 files: Doc/library/re.rst | 26 ++------------------------ 1 files changed, 2 insertions(+), 24 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1093,28 +1093,6 @@ (\S+) - (\d+) errors, (\d+) warnings -Avoiding recursion -^^^^^^^^^^^^^^^^^^ - -If you create regular expressions that require the engine to perform a lot of -recursion, you may encounter a :exc:`RuntimeError` exception with the message -``maximum recursion limit exceeded``. For example, :: - - >>> s = 'Begin ' + 1000*'a very long string ' + 'end' - >>> re.match('Begin (\w| )*? end', s).end() - Traceback (most recent call last): - File "", line 1, in ? - File "/usr/local/lib/python3.2/re.py", line 132, in match - return _compile(pattern, flags).match(string) - RuntimeError: maximum recursion limit exceeded - -You can often restructure your regular expression to avoid recursion. - -Simple uses of the ``*?`` pattern are special-cased to avoid recursion. Thus, -the above regular expression can avoid recursion by being recast as ``Begin -[a-zA-Z0-9_ ]*?end``. As a further benefit, such regular expressions will run -faster than their recursive equivalents. - .. _search-vs-match: search() vs. match() @@ -1161,7 +1139,7 @@ First, here is the input. Normally it may come from a file, here we are using triple-quoted string syntax: - >>> input = """Ross McFluff: 834.345.1254 155 Elm Street + >>> text = """Ross McFluff: 834.345.1254 155 Elm Street ... ... Ronald Heathmore: 892.345.3428 436 Finley Avenue ... Frank Burger: 925.541.7625 662 South Dogwood Way @@ -1175,7 +1153,7 @@ .. doctest:: :options: +NORMALIZE_WHITESPACE - >>> entries = re.split("\n+", input) + >>> entries = re.split("\n+", text) >>> entries ['Ross McFluff: 834.345.1254 155 Elm Street', 'Ronald Heathmore: 892.345.3428 436 Finley Avenue', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 17:27:47 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 17:27:47 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314342?= =?utf8?q?=3A_remove_out-of-date_section_about_avoiding_recursion_errors?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/276f79e4b215 changeset: 75787:276f79e4b215 branch: 2.7 parent: 75783:7a93f6ee2ebc user: Georg Brandl date: Sat Mar 17 17:25:47 2012 +0100 summary: Closes #14342: remove out-of-date section about avoiding recursion errors. files: Doc/library/re.rst | 22 ---------------------- 1 files changed, 0 insertions(+), 22 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1077,28 +1077,6 @@ (\S+) - (\d+) errors, (\d+) warnings -Avoiding recursion -^^^^^^^^^^^^^^^^^^ - -If you create regular expressions that require the engine to perform a lot of -recursion, you may encounter a :exc:`RuntimeError` exception with the message -``maximum recursion limit`` exceeded. For example, :: - - >>> s = 'Begin ' + 1000*'a very long string ' + 'end' - >>> re.match('Begin (\w| )*? end', s).end() - Traceback (most recent call last): - File "", line 1, in ? - File "/usr/local/lib/python2.5/re.py", line 132, in match - return _compile(pattern, flags).match(string) - RuntimeError: maximum recursion limit exceeded - -You can often restructure your regular expression to avoid recursion. - -Starting with Python 2.3, simple uses of the ``*?`` pattern are special-cased to -avoid recursion. Thus, the above regular expression can avoid recursion by -being recast as ``Begin [a-zA-Z0-9_ ]*?end``. As a further benefit, such -regular expressions will run faster than their recursive equivalents. - .. _search-vs-match: search() vs. match() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 17:27:47 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 17:27:47 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314343?= =?utf8?q?=3A_avoid_shadowing_builtin_input=28=29_in_example_code=2E?= Message-ID: http://hg.python.org/cpython/rev/483319c711d4 changeset: 75788:483319c711d4 branch: 2.7 user: Georg Brandl date: Sat Mar 17 17:26:27 2012 +0100 summary: Closes #14343: avoid shadowing builtin input() in example code. files: Doc/library/re.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1123,7 +1123,7 @@ First, here is the input. Normally it may come from a file, here we are using triple-quoted string syntax: - >>> input = """Ross McFluff: 834.345.1254 155 Elm Street + >>> text = """Ross McFluff: 834.345.1254 155 Elm Street ... ... Ronald Heathmore: 892.345.3428 436 Finley Avenue ... Frank Burger: 925.541.7625 662 South Dogwood Way @@ -1137,7 +1137,7 @@ .. doctest:: :options: +NORMALIZE_WHITESPACE - >>> entries = re.split("\n+", input) + >>> entries = re.split("\n+", text) >>> entries ['Ross McFluff: 834.345.1254 155 Elm Street', 'Ronald Heathmore: 892.345.3428 436 Finley Avenue', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 17:29:44 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 17:29:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314250?= =?utf8?q?=3A_regex=2Eflags_has_not_only_explicit_flags_but_also_implicit_?= =?utf8?q?flags?= Message-ID: http://hg.python.org/cpython/rev/b3b3a4a7d7b2 changeset: 75789:b3b3a4a7d7b2 branch: 3.2 parent: 75785:6cf5f963e0c4 user: Georg Brandl date: Sat Mar 17 17:29:27 2012 +0100 summary: Closes #14250: regex.flags has not only explicit flags but also implicit flags and those from the pattern files: Doc/library/re.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -784,8 +784,9 @@ .. attribute:: regex.flags - The flags argument used when the RE object was compiled, or ``0`` if no flags - were provided. + The regex matching flags. This is a combination of the flags given to + :func:`.compile`, any ``(?...)`` inline flags in the pattern, and implicit + flags such as :data:`UNICODE` if the pattern is a Unicode string. .. attribute:: regex.groups -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 17:29:44 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 17:29:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/84fb54c27a9c changeset: 75790:84fb54c27a9c parent: 75786:64e1eeca4cb7 parent: 75789:b3b3a4a7d7b2 user: Georg Brandl date: Sat Mar 17 17:29:39 2012 +0100 summary: merge with 3.2 files: Doc/library/re.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -787,8 +787,9 @@ .. attribute:: regex.flags - The flags argument used when the RE object was compiled, or ``0`` if no flags - were provided. + The regex matching flags. This is a combination of the flags given to + :func:`.compile`, any ``(?...)`` inline flags in the pattern, and implicit + flags such as :data:`UNICODE` if the pattern is a Unicode string. .. attribute:: regex.groups -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 17:31:31 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 17:31:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314250?= =?utf8?q?=3A_regex=2Eflags_has_not_only_explicit_flags_but_also_those_fro?= =?utf8?q?m_the?= Message-ID: http://hg.python.org/cpython/rev/ac00531a63aa changeset: 75791:ac00531a63aa branch: 2.7 parent: 75788:483319c711d4 user: Georg Brandl date: Sat Mar 17 17:31:32 2012 +0100 summary: Closes #14250: regex.flags has not only explicit flags but also those from the pattern files: Doc/library/re.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -766,8 +766,8 @@ .. attribute:: RegexObject.flags - The flags argument used when the RE object was compiled, or ``0`` if no flags - were provided. + The regex matching flags. This is a combination of the flags given to + :func:`.compile` and any ``(?...)`` inline flags in the pattern. .. attribute:: RegexObject.groups -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 18:31:25 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 17 Mar 2012 18:31:25 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0MzQ2?= =?utf8?q?=3A_Fix_some_typos_in_the_Mac/README_file=2E?= Message-ID: http://hg.python.org/cpython/rev/3decf67e1a28 changeset: 75792:3decf67e1a28 branch: 2.7 user: Ned Deily date: Sat Mar 17 10:25:27 2012 -0700 summary: Issue #14346: Fix some typos in the Mac/README file. (Patch by Dionysios Kalofonos) files: Mac/README | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mac/README b/Mac/README --- a/Mac/README +++ b/Mac/README @@ -70,7 +70,7 @@ $ make $ make install -This flag can be used a framework build of python, but also with a classic +This flag can be used with a framework build of python, but also with a classic unix build. Either way you will have to build python on Mac OS X 10.4 (or later) with Xcode 2.1 (or later). You also have to install the 10.4u SDK when installing Xcode. @@ -221,8 +221,8 @@ Go to the directory "Mac/OSX/BuildScript". There you'll find a script "build-installer.py" that does all the work. This will download and build -a number of 3th-party libaries, configures and builds a framework Python, -installs it, creates the installer pacakge files and then packs this in a +a number of 3rd-party libaries, configures and builds a framework Python, +installs it, creates the installer package files and then packs this in a DMG image. The script will build a universal binary, you'll therefore have to run this @@ -258,8 +258,8 @@ Uninstalling a framework install, including the binary installer ================================================================ -Uninstalling a framework can be done by manually removing all bits that got installed, -that's true for both installations from source and installations using the binary installer. +Uninstalling a framework can be done by manually removing all bits that got installed. +That's true for both installations from source and installations using the binary installer. Sadly enough OSX does not have a central uninstaller. The main bit of a framework install is the framework itself, installed in -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 18:31:26 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 17 Mar 2012 18:31:26 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MzQ2?= =?utf8?q?=3A_Fix_some_typos_in_the_Mac/README_file=2E?= Message-ID: http://hg.python.org/cpython/rev/7464c8cf7466 changeset: 75793:7464c8cf7466 branch: 3.2 parent: 75789:b3b3a4a7d7b2 user: Ned Deily date: Sat Mar 17 10:29:41 2012 -0700 summary: Issue #14346: Fix some typos in the Mac/README file. (Patch by Dionysios Kalofonos) files: Mac/README | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mac/README b/Mac/README --- a/Mac/README +++ b/Mac/README @@ -66,7 +66,7 @@ $ make $ make install -This flag can be used a framework build of python, but also with a classic +This flag can be used with a framework build of python, but also with a classic unix build. Either way you will have to build python on Mac OS X 10.4 (or later) with Xcode 2.1 (or later). You also have to install the 10.4u SDK when installing Xcode. @@ -214,8 +214,8 @@ Go to the directory "Mac/OSX/BuildScript". There you'll find a script "build-installer.py" that does all the work. This will download and build -a number of 3th-party libaries, configures and builds a framework Python, -installs it, creates the installer pacakge files and then packs this in a +a number of 3rd-party libaries, configures and builds a framework Python, +installs it, creates the installer package files and then packs this in a DMG image. The script will build a universal binary, you'll therefore have to run this @@ -251,8 +251,8 @@ Uninstalling a framework install, including the binary installer ================================================================ -Uninstalling a framework can be done by manually removing all bits that got installed, -that's true for both installations from source and installations using the binary installer. +Uninstalling a framework can be done by manually removing all bits that got installed. +That's true for both installations from source and installations using the binary installer. Sadly enough OSX does not have a central uninstaller. The main bit of a framework install is the framework itself, installed in -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 18:31:27 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 17 Mar 2012 18:31:27 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314346=3A_merge?= Message-ID: http://hg.python.org/cpython/rev/4b222467acf4 changeset: 75794:4b222467acf4 parent: 75790:84fb54c27a9c parent: 75793:7464c8cf7466 user: Ned Deily date: Sat Mar 17 10:30:48 2012 -0700 summary: Issue #14346: merge files: Mac/README | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mac/README b/Mac/README --- a/Mac/README +++ b/Mac/README @@ -66,7 +66,7 @@ $ make $ make install -This flag can be used a framework build of python, but also with a classic +This flag can be used with a framework build of python, but also with a classic unix build. Either way you will have to build python on Mac OS X 10.4 (or later) with Xcode 2.1 (or later). You also have to install the 10.4u SDK when installing Xcode. @@ -214,8 +214,8 @@ Go to the directory "Mac/OSX/BuildScript". There you'll find a script "build-installer.py" that does all the work. This will download and build -a number of 3th-party libaries, configures and builds a framework Python, -installs it, creates the installer pacakge files and then packs this in a +a number of 3rd-party libaries, configures and builds a framework Python, +installs it, creates the installer package files and then packs this in a DMG image. The script will build a universal binary, you'll therefore have to run this @@ -251,8 +251,8 @@ Uninstalling a framework install, including the binary installer ================================================================ -Uninstalling a framework can be done by manually removing all bits that got installed, -that's true for both installations from source and installations using the binary installer. +Uninstalling a framework can be done by manually removing all bits that got installed. +That's true for both installations from source and installations using the binary installer. Sadly enough OSX does not have a central uninstaller. The main bit of a framework install is the framework itself, installed in -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 18:38:13 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 18:38:13 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Move_MANIFEST_p?= =?utf8?q?arsing_change_to_the_right_position=2E?= Message-ID: http://hg.python.org/cpython/rev/4aff5493758b changeset: 75795:4aff5493758b branch: 3.2 parent: 75793:7464c8cf7466 user: Georg Brandl date: Sat Mar 17 18:38:13 2012 +0100 summary: Move MANIFEST parsing change to the right position. files: Misc/NEWS | 33 +++++++++++++++++++-------------- 1 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -66,32 +66,36 @@ - Issue #13447: Add a test file to host regression tests for bugs in the scripts found in the Tools directory. +- Issue #8033: sqlite3: Fix 64-bit integer handling in user functions + on 32-bit architectures. Initial patch by Philippe Devalkeneer. + +Extension Modules +----------------- + +- Issue #14212: The re module didn't retain a reference to buffers it was + scanning, resulting in segfaults. + + +What's New in Python 3.2.3 release candidate 2? +=============================================== + +*Release date: XX-Mar-2012* + +Library +------- + - Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils on Windows. -- Issue #8033: sqlite3: Fix 64-bit integer handling in user functions - on 32-bit architectures. Initial patch by Philippe Devalkeneer. - Extension Modules ----------------- -- Issue #14212: The re module didn't retain a reference to buffers it was - scanning, resulting in segfaults. - - -What's New in Python 3.2.3 release candidate 2? -=============================================== - -*Release date: XX-Mar-2012* - -Library -------- - - Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project. + What's New in Python 3.2.3 release candidate 1? =============================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 18:39:20 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2012 18:39:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/c359f06e0944 changeset: 75796:c359f06e0944 parent: 75794:4b222467acf4 parent: 75795:4aff5493758b user: Georg Brandl date: Sat Mar 17 18:39:20 2012 +0100 summary: merge with 3.2 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 18:52:59 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 17 Mar 2012 18:52:59 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314347=3A_Update_Mi?= =?utf8?q?sc/README_list_of_files=2E?= Message-ID: http://hg.python.org/cpython/rev/65a0a6fab127 changeset: 75797:65a0a6fab127 user: Ned Deily date: Sat Mar 17 10:52:08 2012 -0700 summary: Issue #14347: Update Misc/README list of files. (Initial patch by Dionysios Kalofonos) files: Misc/README | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Misc/README b/Misc/README --- a/Misc/README +++ b/Misc/README @@ -8,7 +8,6 @@ ---------------- ACKS Acknowledgements -build.sh Script to build and test latest Python from the repository gdbinit Handy stuff to put in your .gdbinit file, if you use gdb HISTORY News from previous releases -- oldest last indent.pro GNU indent profile approximating my C style @@ -19,6 +18,8 @@ python.pc.in Package configuration info template for pkg-config python-wing*.wpr Wing IDE project file README The file you're reading now +README.AIX Information about using Python on AIX +README.coverity Information about running Coverity's Prevent on Python README.valgrind Information for Valgrind users, see valgrind-python.supp RPM (Old) tools to build RPMs svnmap.txt Map of old SVN revs and branches to hg changeset ids -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 20:12:14 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 20:12:14 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=2314344=3A_fixed_the_repr_?= =?utf8?q?of_email=2Epolicy_objects=2E?= Message-ID: http://hg.python.org/cpython/rev/97b0cf9df420 changeset: 75798:97b0cf9df420 user: R David Murray date: Sat Mar 17 15:11:59 2012 -0400 summary: #14344: fixed the repr of email.policy objects. files: Lib/email/policy.py | 2 +- Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/email/policy.py b/Lib/email/policy.py --- a/Lib/email/policy.py +++ b/Lib/email/policy.py @@ -52,7 +52,7 @@ def __repr__(self): args = [ "{}={!r}".format(name, value) for name, value in self.__dict__.items() ] - return "{}({})".format(self.__class__.__name__, args if args else '') + return "{}({})".format(self.__class__.__name__, ', '.join(args)) def clone(self, **kw): """Return a new instance with specified attributes changed. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,8 @@ Library ------- +- Issue #14344: fixed the repr of email.policy objects. + - Issue #11686: Added missing entries to email package __all__ lists (mostly the new Bytes classes). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 21:45:34 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 21:45:34 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzE0MzMzOiBmaXgg?= =?utf8?q?test=5Fqueue_so_it_can_be_run_via_standard_unittest_test_discove?= =?utf8?b?cnku?= Message-ID: http://hg.python.org/cpython/rev/118f7bdd631b changeset: 75799:118f7bdd631b branch: 3.2 parent: 75795:4aff5493758b user: R David Murray date: Sat Mar 17 16:38:39 2012 -0400 summary: #14333: fix test_queue so it can be run via standard unittest test discovery. files: Lib/test/test_queue.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py --- a/Lib/test/test_queue.py +++ b/Lib/test/test_queue.py @@ -82,7 +82,7 @@ self.fail("trigger thread ended but event never set") -class BaseQueueTest(unittest.TestCase, BlockingTestMixin): +class BaseQueueTestMixin(BlockingTestMixin): def setUp(self): self.cum = 0 self.cumlock = threading.Lock() @@ -229,13 +229,13 @@ with self.assertRaises(queue.Full): q.put_nowait(4) -class QueueTest(BaseQueueTest): +class QueueTest(BaseQueueTestMixin, unittest.TestCase): type2test = queue.Queue -class LifoQueueTest(BaseQueueTest): +class LifoQueueTest(BaseQueueTestMixin, unittest.TestCase): type2test = queue.LifoQueue -class PriorityQueueTest(BaseQueueTest): +class PriorityQueueTest(BaseQueueTestMixin, unittest.TestCase): type2test = queue.PriorityQueue -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 21:45:35 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 21:45:35 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2314333=3A_fix_test=5Fqueue_so_it_can_be_run_via_stan?= =?utf8?q?dard_unittest_test?= Message-ID: http://hg.python.org/cpython/rev/3ea4d7adb3e7 changeset: 75800:3ea4d7adb3e7 parent: 75798:97b0cf9df420 parent: 75799:118f7bdd631b user: R David Murray date: Sat Mar 17 16:39:44 2012 -0400 summary: Merge #14333: fix test_queue so it can be run via standard unittest test discovery. files: Lib/test/test_queue.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py --- a/Lib/test/test_queue.py +++ b/Lib/test/test_queue.py @@ -82,7 +82,7 @@ self.fail("trigger thread ended but event never set") -class BaseQueueTest(unittest.TestCase, BlockingTestMixin): +class BaseQueueTestMixin(BlockingTestMixin): def setUp(self): self.cum = 0 self.cumlock = threading.Lock() @@ -229,13 +229,13 @@ with self.assertRaises(queue.Full): q.put_nowait(4) -class QueueTest(BaseQueueTest): +class QueueTest(BaseQueueTestMixin, unittest.TestCase): type2test = queue.Queue -class LifoQueueTest(BaseQueueTest): +class LifoQueueTest(BaseQueueTestMixin, unittest.TestCase): type2test = queue.LifoQueue -class PriorityQueueTest(BaseQueueTest): +class PriorityQueueTest(BaseQueueTestMixin, unittest.TestCase): type2test = queue.PriorityQueue -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 21:45:36 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 17 Mar 2012 21:45:36 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzE0MzMzOiBmaXgg?= =?utf8?q?test=5Fqueue_so_it_can_be_run_via_standard_unittest_test_discove?= =?utf8?b?cnku?= Message-ID: http://hg.python.org/cpython/rev/340053208864 changeset: 75801:340053208864 branch: 2.7 parent: 75792:3decf67e1a28 user: R David Murray date: Sat Mar 17 16:44:16 2012 -0400 summary: #14333: fix test_queue so it can be run via standard unittest test discovery. files: Lib/test/test_queue.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py --- a/Lib/test/test_queue.py +++ b/Lib/test/test_queue.py @@ -79,7 +79,7 @@ self.fail("trigger thread ended but event never set") -class BaseQueueTest(unittest.TestCase, BlockingTestMixin): +class BaseQueueTest(BlockingTestMixin): def setUp(self): self.cum = 0 self.cumlock = threading.Lock() @@ -191,13 +191,13 @@ self.simple_queue_test(q) -class QueueTest(BaseQueueTest): +class QueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.Queue -class LifoQueueTest(BaseQueueTest): +class LifoQueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.LifoQueue -class PriorityQueueTest(BaseQueueTest): +class PriorityQueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.PriorityQueue -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 23:12:15 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 17 Mar 2012 23:12:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Low_overhead_path_for_maxsi?= =?utf8?b?emU9PTA=?= Message-ID: http://hg.python.org/cpython/rev/7080f443bd37 changeset: 75802:7080f443bd37 parent: 75800:3ea4d7adb3e7 user: Raymond Hettinger date: Sat Mar 17 15:10:24 2012 -0700 summary: Low overhead path for maxsize==0 files: Lib/functools.py | 15 +++++++++++++-- 1 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -170,15 +170,16 @@ cache = dict() hits = misses = 0 + kwd_mark = (object(),) # separate positional and keyword args cache_get = cache.get # bound method to lookup key or return None _len = len # localize the global len() function - kwd_mark = (object(),) # separate positional and keyword args lock = Lock() # because linkedlist updates aren't threadsafe root = [] # root of the circular doubly linked list root[:] = [root, root, None, None] # initialize by pointing to self PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields def make_key(args, kwds, typed, tuple=tuple, sorted=sorted, type=type): + # helper function to build a cache key from positional and keyword args key = args if kwds: sorted_items = tuple(sorted(kwds.items())) @@ -189,7 +190,17 @@ key += tuple(type(v) for k, v in sorted_items) return key - if maxsize is None: + if maxsize == 0: + + @wraps(user_function) + def wrapper(*args, **kwds): + # no caching, just do a statistics update after a successful call + nonlocal misses + result = user_function(*args, **kwds) + misses += 1 + return result + + elif maxsize is None: @wraps(user_function) def wrapper(*args, **kwds): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 23:12:16 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 17 Mar 2012 23:12:16 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_whitespace?= Message-ID: http://hg.python.org/cpython/rev/b26056192653 changeset: 75803:b26056192653 user: Raymond Hettinger date: Sat Mar 17 15:11:09 2012 -0700 summary: Fix whitespace files: Lib/functools.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -196,7 +196,7 @@ def wrapper(*args, **kwds): # no caching, just do a statistics update after a successful call nonlocal misses - result = user_function(*args, **kwds) + result = user_function(*args, **kwds) misses += 1 return result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 23:24:22 2012 From: python-checkins at python.org (barry.warsaw) Date: Sat, 17 Mar 2012 23:24:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E6=29=3A_Update_Docs_and?= =?utf8?q?_NEWS_for_2=2E6=2E8rc2=2E?= Message-ID: http://hg.python.org/cpython/rev/10a3d094b150 changeset: 75804:10a3d094b150 branch: 2.6 parent: 75673:9c8d066013ea user: Barry Warsaw date: Sat Mar 17 18:16:58 2012 -0400 summary: Update Docs and NEWS for 2.6.8rc2. files: Lib/pydoc_topics.py | 2 +- Misc/NEWS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc_topics.py b/Lib/pydoc_topics.py --- a/Lib/pydoc_topics.py +++ b/Lib/pydoc_topics.py @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Thu Feb 23 10:54:32 2012 +# Autogenerated by Sphinx on Sat Mar 17 14:18:25 2012 topics = {'assert': u'\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', 'assignment': u'\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list is recursively defined as\nfollows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets. (This rule is relaxed as of\n Python 1.5; in earlier versions, the object had to be a tuple.\n Since strings are sequences, an assignment like ``a, b = "xy"`` is\n now legal as long as the string has the right length.)\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` statement in the\n current code block: the name is bound to the object in the current\n local namespace.\n\n * Otherwise: the name is bound to the object in the current global\n namespace.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield a plain integer. If it is negative, the\n sequence\'s length is added to it. The resulting value must be a\n nonnegative integer less than the sequence\'s length, and the\n sequence is asked to assign the assigned object to its item with\n that index. If the index is out of range, ``IndexError`` is raised\n (assignment to a subscripted sequence cannot add new items to a\n list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to (small) integers. If either\n bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print x\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': u'\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,7 +5,7 @@ What's New in Python 2.6.8 rc 2? ================================ -*Release date: 2012-XX-XX* +*Release date: 2012-03-17* Library ------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 23:24:23 2012 From: python-checkins at python.org (barry.warsaw) Date: Sat, 17 Mar 2012 23:24:23 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi42KTogQnVtcCB0byAyLjYu?= =?utf8?q?8rc2?= Message-ID: http://hg.python.org/cpython/rev/1d1b7b9fad48 changeset: 75805:1d1b7b9fad48 branch: 2.6 user: Barry Warsaw date: Sat Mar 17 18:19:15 2012 -0400 summary: Bump to 2.6.8rc2 files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/RPM/python-2.6.spec | 2 +- README | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -24,10 +24,10 @@ #define PY_MINOR_VERSION 6 #define PY_MICRO_VERSION 8 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "2.6.8rc1" +#define PY_VERSION "2.6.8rc2" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository) */ diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -22,5 +22,5 @@ # #--start constants-- -__version__ = "2.6.8rc1" +__version__ = "2.6.8rc2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "2.6.8rc1" +IDLE_VERSION = "2.6.8rc2" diff --git a/Misc/RPM/python-2.6.spec b/Misc/RPM/python-2.6.spec --- a/Misc/RPM/python-2.6.spec +++ b/Misc/RPM/python-2.6.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 2.6.8rc1 +%define version 2.6.8rc2 %define libvers 2.6 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 2.6.8 rc 1 +This is Python version 2.6.8 rc 2 ================================= Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 23:24:24 2012 From: python-checkins at python.org (barry.warsaw) Date: Sat, 17 Mar 2012 23:24:24 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E6=29=3A_Added_tag_v2=2E?= =?utf8?q?6=2E8rc2_for_changeset_1d1b7b9fad48?= Message-ID: http://hg.python.org/cpython/rev/bd9e1a02e3e3 changeset: 75806:bd9e1a02e3e3 branch: 2.6 user: Barry Warsaw date: Sat Mar 17 18:19:42 2012 -0400 summary: Added tag v2.6.8rc2 for changeset 1d1b7b9fad48 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -139,3 +139,4 @@ 9f8771e0905277f8b3c2799113a062fda4164995 v2.6.6 caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 5356b6c7fd66664679f9bd71f7cd085239934e43 v2.6.8rc1 +1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 23:24:25 2012 From: python-checkins at python.org (barry.warsaw) Date: Sat, 17 Mar 2012 23:24:25 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi42IC0+IDIuNyk6?= =?utf8?q?_null_merge_from_2=2E6?= Message-ID: http://hg.python.org/cpython/rev/2db868824018 changeset: 75807:2db868824018 branch: 2.7 parent: 75791:ac00531a63aa parent: 75806:bd9e1a02e3e3 user: Barry Warsaw date: Sat Mar 17 18:23:22 2012 -0400 summary: null merge from 2.6 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 23:24:25 2012 From: python-checkins at python.org (barry.warsaw) Date: Sat, 17 Mar 2012 23:24:25 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_null_merge?= Message-ID: http://hg.python.org/cpython/rev/f59ab537a5dc changeset: 75808:f59ab537a5dc branch: 2.7 parent: 75801:340053208864 parent: 75807:2db868824018 user: Barry Warsaw date: Sat Mar 17 18:24:09 2012 -0400 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 17 23:34:20 2012 From: python-checkins at python.org (barry.warsaw) Date: Sat, 17 Mar 2012 23:34:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E6=29=3A_Added_tag_v2=2E?= =?utf8?q?6=2E8rc2_for_changeset_bd9e1a02e3e3?= Message-ID: http://hg.python.org/cpython/rev/6144a0748a95 changeset: 75809:6144a0748a95 branch: 2.6 parent: 75806:bd9e1a02e3e3 user: Barry Warsaw date: Sat Mar 17 18:34:05 2012 -0400 summary: Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -140,3 +140,4 @@ caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 5356b6c7fd66664679f9bd71f7cd085239934e43 v2.6.8rc1 1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 +bd9e1a02e3e329fa7b6da06113090a401909c4ea v2.6.8rc2 -- Repository URL: http://hg.python.org/cpython From barry at python.org Sat Mar 17 23:43:16 2012 From: barry at python.org (Barry Warsaw) Date: Sat, 17 Mar 2012 18:43:16 -0400 Subject: [Python-checkins] cpython (2.6): Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 In-Reply-To: References: Message-ID: <20120317184316.7245fcce@limelight.wooz.org> On Mar 17, 2012, at 11:34 PM, barry.warsaw wrote: >http://hg.python.org/cpython/rev/6144a0748a95 >changeset: 75809:6144a0748a95 >branch: 2.6 >parent: 75806:bd9e1a02e3e3 >user: Barry Warsaw >date: Sat Mar 17 18:34:05 2012 -0400 >summary: > Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 > >files: > .hgtags | 1 + > 1 files changed, 1 insertions(+), 0 deletions(-) > > >diff --git a/.hgtags b/.hgtags >--- a/.hgtags >+++ b/.hgtags >@@ -140,3 +140,4 @@ > caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 > 5356b6c7fd66664679f9bd71f7cd085239934e43 v2.6.8rc1 > 1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 >+bd9e1a02e3e329fa7b6da06113090a401909c4ea v2.6.8rc2 I don't know why Mercurial does this. Here's what *I* did: * After I committed the last of my PEP 101 changes to the 2.6 branch, I did release.py --tag 2.6.8rc2. It sure looks like that added the tag. * Then I switched to the 2.7 branch, pulled and merged the changes from 2.6, `hg revert -ar .` then marked all conflicts as resolved `hg resolve -am`. AFAICT, that's the way to null merge 2.6 to 2.7. * Then I pushed my changes. * Switching back to my 2.6 branch, I then tried to `release -export 2.6.8rc2` and got an error that v2.6.8rc2 tag wasn't found. At this point I *retagged* for 2.6.8rc2, switch to default and pushed. This makes me a little wary about what's actually in the 2.6.8rc2 tarball, but I'm building and testing it now, and from visual inspection it *looks* okay, so I'm inclined to chalk this up to either a Mercurial wart, or my boneheaded use of it. Cheers, -Barry From g.brandl at gmx.net Sun Mar 18 00:03:57 2012 From: g.brandl at gmx.net (Georg Brandl) Date: Sun, 18 Mar 2012 00:03:57 +0100 Subject: [Python-checkins] cpython (2.6): Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 In-Reply-To: <20120317184316.7245fcce@limelight.wooz.org> References: <20120317184316.7245fcce@limelight.wooz.org> Message-ID: On 03/17/2012 11:43 PM, Barry Warsaw wrote: > On Mar 17, 2012, at 11:34 PM, barry.warsaw wrote: > >>http://hg.python.org/cpython/rev/6144a0748a95 >>changeset: 75809:6144a0748a95 >>branch: 2.6 >>parent: 75806:bd9e1a02e3e3 >>user: Barry Warsaw >>date: Sat Mar 17 18:34:05 2012 -0400 >>summary: >> Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 >> >>files: >> .hgtags | 1 + >> 1 files changed, 1 insertions(+), 0 deletions(-) >> >> >>diff --git a/.hgtags b/.hgtags >>--- a/.hgtags >>+++ b/.hgtags >>@@ -140,3 +140,4 @@ >> caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 >> 5356b6c7fd66664679f9bd71f7cd085239934e43 v2.6.8rc1 >> 1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 >>+bd9e1a02e3e329fa7b6da06113090a401909c4ea v2.6.8rc2 It seems you did this with 2.6.8rc1 already. It also has two tags. > I don't know why Mercurial does this. Here's what *I* did: > > * After I committed the last of my PEP 101 changes to the 2.6 branch, I did > release.py --tag 2.6.8rc2. It sure looks like that added the tag. > > * Then I switched to the 2.7 branch, pulled and merged the changes from 2.6, > `hg revert -ar .` then marked all conflicts as resolved `hg resolve -am`. > AFAICT, that's the way to null merge 2.6 to 2.7. > > * Then I pushed my changes. > > * Switching back to my 2.6 branch, I then tried to `release -export 2.6.8rc2` > and got an error that v2.6.8rc2 tag wasn't found. At this point I > *retagged* for 2.6.8rc2, switch to default and pushed. > > This makes me a little wary about what's actually in the 2.6.8rc2 tarball, but > I'm building and testing it now, and from visual inspection it *looks* okay, > so I'm inclined to chalk this up to either a Mercurial wart, or my boneheaded > use of it. I'm afraid it's the latter: tags are entries in .hgtags. So when you completely null-merge your 2.6 changes into 2.7, you are basically removing the tag from the 2.7 branch. And since to find tags, Mercurial looks in the .hgtags files of all active branch heads, you are basically hiding the tag when you merge 2.6 into 2.7, at which point it becomes an inactive branch head. Georg From barry at python.org Sun Mar 18 00:13:18 2012 From: barry at python.org (Barry Warsaw) Date: Sat, 17 Mar 2012 19:13:18 -0400 Subject: [Python-checkins] cpython (2.6): Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 In-Reply-To: References: <20120317184316.7245fcce@limelight.wooz.org> Message-ID: <20120317191318.29f88bc2@limelight.wooz.org> On Mar 18, 2012, at 12:03 AM, Georg Brandl wrote: >I'm afraid it's the latter: tags are entries in .hgtags. So when you >completely null-merge your 2.6 changes into 2.7, you are basically removing >the tag from the 2.7 branch. And since to find tags, Mercurial looks in the >.hgtags files of all active branch heads, you are basically hiding the tag >when you merge 2.6 into 2.7, at which point it becomes an inactive branch >head. D'oh. Okay, so leave the .hgtags file alone when null merging 2.6->2.7. Actually, that probably applies to all forward merges, so I think this would be useful information for either the devguide or PEP 101, or both. I updated the latter right at the --tag step. Thanks, -Barry From python-checkins at python.org Sun Mar 18 00:13:43 2012 From: python-checkins at python.org (barry.warsaw) Date: Sun, 18 Mar 2012 00:13:43 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Warn_about_null_merging_and_th?= =?utf8?q?e_=2Ehgtags_file=2E?= Message-ID: http://hg.python.org/peps/rev/ee90eb960aba changeset: 4142:ee90eb960aba user: Barry Warsaw date: Sat Mar 17 19:13:39 2012 -0400 summary: Warn about null merging and the .hgtags file. files: pep-0101.txt | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/pep-0101.txt b/pep-0101.txt --- a/pep-0101.txt +++ b/pep-0101.txt @@ -200,6 +200,11 @@ $ .../release/release.py --tag X.Y.ZaN + NOTE: when forward, i.e. "null" merging your changes to newer branches, + e.g. 2.6 -> 2.7, do *not* revert your changes to the .hgtags file or you + will not be able to run the --export command below. Revert everything + else but leave .hgtags alone. + ___ If this is a final major release, branch the tree for X.Y. When making a major release (e.g., for 3.2), you must create the -- Repository URL: http://hg.python.org/peps From merwok at netwok.org Sun Mar 18 00:15:04 2012 From: merwok at netwok.org (=?UTF-8?B?w4lyaWMgQXJhdWpv?=) Date: Sat, 17 Mar 2012 19:15:04 -0400 Subject: [Python-checkins] cpython (2.6): Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 In-Reply-To: References: <20120317184316.7245fcce@limelight.wooz.org> Message-ID: <4F651AF8.8030700@netwok.org> Hi, Le 17/03/2012 19:03, Georg Brandl a ?crit : > On 03/17/2012 11:43 PM, Barry Warsaw wrote: > I'm afraid it's the latter: tags are entries in .hgtags. So when you completely > null-merge your 2.6 changes into 2.7, you are basically removing the tag from > the 2.7 branch. And since to find tags, Mercurial looks in the .hgtags files > of all active branch heads, you are basically hiding the tag when you merge > 2.6 into 2.7, at which point it becomes an inactive branch head. The plus side to this concept of tags as entries in a file is that it?s trivial to add the missing 2.6 tags in the 2.7 branch. Note that duplicate entries in .hgtags (when a tag was redone) should not be ?cleaned up?: the presence of the old changeset hash greatly helps conflict resolution. (If someone pulled the repo with the old tag and later pulls and updates, then they don?t have to find out which hash is the right tag, they just accept all changes from the updated file into their local file.) This problem in the future can be avoided by merging all changesets from X.Y to X.Y+1, not null-merging, unless I misunderstand something. Cheers From python-checkins at python.org Sun Mar 18 02:25:20 2012 From: python-checkins at python.org (eric.araujo) Date: Sun, 18 Mar 2012 02:25:20 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Post-release_version_bum?= =?utf8?q?p_=28this_time_in_the_code_too=29?= Message-ID: http://hg.python.org/distutils2/rev/e0d1ba9899d5 changeset: 1312:e0d1ba9899d5 user: ?ric Araujo date: Sat Mar 17 21:24:58 2012 -0400 summary: Post-release version bump (this time in the code too) files: distutils2/__init__.py | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distutils2/__init__.py b/distutils2/__init__.py --- a/distutils2/__init__.py +++ b/distutils2/__init__.py @@ -13,5 +13,5 @@ __all__ = ['__version__', 'logger'] -__version__ = "1.0a3" +__version__ = "1.0a5.dev0" logger = getLogger('distutils2') diff --git a/setup.cfg b/setup.cfg --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = Distutils2 -version = 1.0a4 +version = 1.0a5.dev0 summary = Python Packaging Library description-file = README.txt home-page = http://wiki.python.org/moin/Distutils2 -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Mar 18 02:25:20 2012 From: python-checkins at python.org (eric.araujo) Date: Sun, 18 Mar 2012 02:25:20 +0100 Subject: [Python-checkins] =?utf8?q?distutils2=3A_Add_missing_report_numbe?= =?utf8?q?r?= Message-ID: http://hg.python.org/distutils2/rev/f4b4e4778a43 changeset: 1311:f4b4e4778a43 user: ?ric Araujo date: Sat Mar 17 21:24:36 2012 -0400 summary: Add missing report number files: CHANGES.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt --- a/CHANGES.txt +++ b/CHANGES.txt @@ -173,7 +173,7 @@ - #14264: Stop removing trailing zeroes in versions [tarek] - #14268: Fix small error in a test [tarek] - Drop support for Python 2.4 [tarek, ?ric] -- Out-of-date documentation removed, people should look at +- #13009: Out-of-date documentation removed, people should look at http://docs.python.org/dev/packaging [?ric] -- Repository URL: http://hg.python.org/distutils2 From barry at python.org Sun Mar 18 05:13:10 2012 From: barry at python.org (Barry Warsaw) Date: Sun, 18 Mar 2012 00:13:10 -0400 Subject: [Python-checkins] cpython (2.6): Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 In-Reply-To: <4F651AF8.8030700@netwok.org> References: <20120317184316.7245fcce@limelight.wooz.org> <4F651AF8.8030700@netwok.org> Message-ID: <20120318001310.1ce284b5@limelight.wooz.org> On Mar 17, 2012, at 07:15 PM, ?ric Araujo wrote: >Note that duplicate entries in .hgtags (when a tag was redone) should >not be ?cleaned up?: the presence of the old changeset hash greatly >helps conflict resolution. (If someone pulled the repo with the old tag >and later pulls and updates, then they don?t have to find out which hash >is the right tag, they just accept all changes from the updated file >into their local file.) But if someone wants to grab the 2.6.8rc2 tag, which changeset do they get? I guess the last one... maybe? >This problem in the future can be avoided by merging all changesets from >X.Y to X.Y+1, not null-merging, unless I misunderstand something. Except in this case, there's probably not much useful in the 2.6.8 changes that are appropriate for 2.7. -Barry From solipsis at pitrou.net Sun Mar 18 05:44:17 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 18 Mar 2012 05:44:17 +0100 Subject: [Python-checkins] Daily reference leaks (b26056192653): sum=0 Message-ID: results for b26056192653 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogUC4xux', '-x'] From g.brandl at gmx.net Sun Mar 18 07:28:34 2012 From: g.brandl at gmx.net (Georg Brandl) Date: Sun, 18 Mar 2012 07:28:34 +0100 Subject: [Python-checkins] cpython (2.6): Added tag v2.6.8rc2 for changeset bd9e1a02e3e3 In-Reply-To: <20120318001310.1ce284b5@limelight.wooz.org> References: <20120317184316.7245fcce@limelight.wooz.org> <4F651AF8.8030700@netwok.org> <20120318001310.1ce284b5@limelight.wooz.org> Message-ID: On 03/18/2012 05:13 AM, Barry Warsaw wrote: > On Mar 17, 2012, at 07:15 PM, ?ric Araujo wrote: > >>Note that duplicate entries in .hgtags (when a tag was redone) should >>not be ?cleaned up?: the presence of the old changeset hash greatly >>helps conflict resolution. (If someone pulled the repo with the old tag >>and later pulls and updates, then they don?t have to find out which hash >>is the right tag, they just accept all changes from the updated file >>into their local file.) > > But if someone wants to grab the 2.6.8rc2 tag, which changeset do they get? I > guess the last one... maybe? Yes, the last entry in .hgtags counts. I would recommend to clean up the file though. >>This problem in the future can be avoided by merging all changesets from >>X.Y to X.Y+1, not null-merging, unless I misunderstand something. Well, null-merging is nothing but merging all changesets, but then reverting everything. You just have to be careful not to revert .hgtags. Georg From python-checkins at python.org Sun Mar 18 07:32:28 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 07:32:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E6=29=3A_Remove_duplicat?= =?utf8?q?e_hgtags_entries_for_2=2E6=2E8rc=7B1=2C2=7D=2E?= Message-ID: http://hg.python.org/cpython/rev/ecae43294a0e changeset: 75810:ecae43294a0e branch: 2.6 user: Georg Brandl date: Sun Mar 18 07:31:17 2012 +0100 summary: Remove duplicate hgtags entries for 2.6.8rc{1,2}. files: .hgtags | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -138,6 +138,4 @@ e189dc8fd66154ef46d9cd22584d56669b544ca3 v2.6.6rc2 9f8771e0905277f8b3c2799113a062fda4164995 v2.6.6 caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 -5356b6c7fd66664679f9bd71f7cd085239934e43 v2.6.8rc1 1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 -bd9e1a02e3e329fa7b6da06113090a401909c4ea v2.6.8rc2 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 07:32:29 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 07:32:29 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi42IC0+IDIuNyk6?= =?utf8?q?_Merge_2=2E6=2E8rc_tags_into_2=2E7=2E?= Message-ID: http://hg.python.org/cpython/rev/064977e473a5 changeset: 75811:064977e473a5 branch: 2.7 parent: 75808:f59ab537a5dc parent: 75810:ecae43294a0e user: Georg Brandl date: Sun Mar 18 07:32:22 2012 +0100 summary: Merge 2.6.8rc tags into 2.7. files: .hgtags | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -137,6 +137,8 @@ c1dc9e7986a2a8e1070ec7bee748520febef382e v2.6.6rc1 e189dc8fd66154ef46d9cd22584d56669b544ca3 v2.6.6rc2 9f8771e0905277f8b3c2799113a062fda4164995 v2.6.6 +caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 +1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 b4107eb00b4271fb73a9e1b736d4f23460950778 v2.7a1 adc85ebc7271cc22e24e816782bb2b8d7fa3a6b3 v2.7a2 4180557b7a9bb9dd5341a18af199f843f199e46e v2.7a3 -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Sun Mar 18 14:49:25 2012 From: ncoghlan at gmail.com (Nick Coghlan) Date: Sun, 18 Mar 2012 23:49:25 +1000 Subject: [Python-checkins] cpython (2.7): Closes #14306: clarify expensiveness of try-except and update code snippet In-Reply-To: References: Message-ID: On Sun, Mar 18, 2012 at 1:58 AM, georg.brandl wrote: > +catching an exception is expensive. ?In versions of Python prior to 2.0 it was > +common to use this idiom:: Actually, given the "prior to 2.0" caveat, "mydict.has_key(key)" is right: the "key in mydict" version was only added in 2.2. This answer probably needs more improvements than just modernising the example that is already there. Cheers, Nick. -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From python-checkins at python.org Sun Mar 18 14:57:22 2012 From: python-checkins at python.org (ross.lagerwall) Date: Sun, 18 Mar 2012 14:57:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_14359=3A_Only_use_O?= =?utf8?q?=5FCLOEXEC_in_=5Fposixmodule=2Ec_if_it_is_defined=2E?= Message-ID: http://hg.python.org/cpython/rev/fe1dfc066a38 changeset: 75812:fe1dfc066a38 parent: 75803:b26056192653 user: Ross Lagerwall date: Sun Mar 18 15:55:10 2012 +0200 summary: Issue 14359: Only use O_CLOEXEC in _posixmodule.c if it is defined. Based on patch from Herv? Coatanhay. files: Modules/_posixsubprocess.c | 13 ++++++++++++- 1 files changed, 12 insertions(+), 1 deletions(-) diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -204,7 +204,18 @@ int fd_dir_fd; if (start_fd >= end_fd) return; - fd_dir_fd = open(FD_DIR, O_RDONLY | O_CLOEXEC, 0); +#ifdef O_CLOEXEC + fd_dir_fd = open(FD_DIR, O_RDONLY | O_CLOEXEC, 0); +#else + fd_dir_fd = open(FD_DIR, O_RDONLY, 0); +#ifdef FD_CLOEXEC + { + int old = fcntl(fd_dir_fd, F_GETFD); + if (old != -1) + fcntl(fd_dir_fd, F_SETFD, old | FD_CLOEXEC); + } +#endif +#endif if (fd_dir_fd == -1) { /* No way to get a list of open fds. */ _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep); -- Repository URL: http://hg.python.org/cpython From g.brandl at gmx.net Sun Mar 18 16:03:06 2012 From: g.brandl at gmx.net (Georg Brandl) Date: Sun, 18 Mar 2012 16:03:06 +0100 Subject: [Python-checkins] cpython (2.7): Closes #14306: clarify expensiveness of try-except and update code snippet In-Reply-To: References: Message-ID: On 03/18/2012 02:49 PM, Nick Coghlan wrote: > On Sun, Mar 18, 2012 at 1:58 AM, georg.brandl > wrote: >> +catching an exception is expensive. In versions of Python prior to 2.0 it was >> +common to use this idiom:: > > Actually, given the "prior to 2.0" caveat, "mydict.has_key(key)" is > right: the "key in mydict" version was only added in 2.2. > > This answer probably needs more improvements than just modernising the > example that is already there. Yep. I also wondered what was left out, since the past tense "was common..." suggests that something is missing. But for the moment I just wanted to get rid of legacy code that might induce people to use has_key(). Georg From python-checkins at python.org Sun Mar 18 20:40:09 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 20:40:09 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzE0MTE0OiBkb24n?= =?utf8?q?t_include_copybutton=2Ejs_in_the_htmlhelp_output=2E?= Message-ID: http://hg.python.org/cpython/rev/b585c33077d2 changeset: 75813:b585c33077d2 branch: 3.2 parent: 75243:7615f497881a user: Ezio Melotti date: Sat Feb 25 19:24:24 2012 +0200 summary: #14114: don't include copybutton.js in the htmlhelp output. files: Doc/tools/sphinxext/layout.html | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tools/sphinxext/layout.html b/Doc/tools/sphinxext/layout.html --- a/Doc/tools/sphinxext/layout.html +++ b/Doc/tools/sphinxext/layout.html @@ -6,7 +6,7 @@ {% endblock %} {% block extrahead %} - + {% if not embedded %}{% endif %} {{ super() }} {% endblock %} {% block footer %} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 20:40:09 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 20:40:09 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_long-standi?= =?utf8?q?ng_bugs_with_MANIFEST=2Ein_parsing_on_Windows_=28=236884=29=2E?= Message-ID: http://hg.python.org/cpython/rev/edcdef70c44e changeset: 75814:edcdef70c44e branch: 3.2 user: ?ric Araujo date: Sat Feb 25 16:28:05 2012 +0100 summary: Fix long-standing bugs with MANIFEST.in parsing on Windows (#6884). These regex changes fix a number of issues for distutils on Windows: - #6884: impossible to include a file starting with 'build' - #9691 and #14004: sdist includes too many files - #13193: test_filelist failures This commit replaces the incorrect changes done in 0a94e2f807c7 and 90b30d62caf2 to fix #13193; we were too eager to fix the test failures and I did not study the code enough before greenlighting patches. This time we have unit tests from the problems reported by users to be sure we have the right fix. Thanks to Nadeem Vawda for his help. files: Lib/distutils/filelist.py | 22 +- Lib/distutils/tests/test_filelist.py | 128 +++++++++++--- Lib/distutils/tests/test_sdist.py | 27 +- Misc/NEWS | 3 + 4 files changed, 133 insertions(+), 47 deletions(-) diff --git a/Lib/distutils/filelist.py b/Lib/distutils/filelist.py --- a/Lib/distutils/filelist.py +++ b/Lib/distutils/filelist.py @@ -201,6 +201,7 @@ Return True if files are found, False otherwise. """ + # XXX docstring lying about what the special chars are? files_found = False pattern_re = translate_pattern(pattern, anchor, prefix, is_regex) self.debug_print("include_pattern: applying regex r'%s'" % @@ -284,11 +285,14 @@ # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, # and by extension they shouldn't match such "special characters" under # any OS. So change all non-escaped dots in the RE to match any - # character except the special characters. - # XXX currently the "special characters" are just slash -- i.e. this is - # Unix-only. - pattern_re = re.sub(r'((? http://hg.python.org/cpython/rev/ebffdfa529cd changeset: 75815:ebffdfa529cd branch: 3.2 user: Georg Brandl date: Sat Feb 25 18:30:26 2012 +0100 summary: 3.2.3rc1 done files: Include/patchlevel.h | 2 +- Misc/NEWS | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.2.3rc1" +#define PY_VERSION "3.2.3rc1+" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,10 +2,25 @@ Python News +++++++++++ +What's New in Python 3.2.3? +=========================== + +*Release date: XX-XXX-2012* + +Core and Builtins +----------------- + +Library +------- + +- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils + on Windows. + + What's New in Python 3.2.3 release candidate 1? =============================================== -*Release date: 24-Feb-2011* +*Release date: 24-Feb-2012* Core and Builtins ----------------- @@ -124,9 +139,6 @@ Library ------- -- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils - on Windows. - - Issue #8033: sqlite3: Fix 64-bit integer handling in user functions on 32-bit architectures. Initial patch by Philippe Devalkeneer. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 20:40:11 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 20:40:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Transplant_from?= =?utf8?q?_main_repo_d6c197edd99b=3A_Fixes_Issue_=2314234=3A_CVE-2012-0876?= =?utf8?q?=3A?= Message-ID: http://hg.python.org/cpython/rev/cf7337a49a07 changeset: 75816:cf7337a49a07 branch: 3.2 user: Georg Brandl date: Thu Mar 15 08:31:00 2012 +0100 summary: Transplant from main repo d6c197edd99b: Fixes Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes files: Misc/NEWS | 11 +- Modules/expat/expat.h | 9 + Modules/expat/pyexpatns.h | 1 + Modules/expat/xmlparse.c | 177 +++++++++++++++++-------- Modules/pyexpat.c | 2 + 5 files changed, 140 insertions(+), 60 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -7,12 +7,20 @@ *Release date: XX-XXX-2012* -Core and Builtins ------------------ + +What's New in Python 3.2.3 release candidate 2? +=============================================== + +*Release date: XX-Mar-2012* Library ------- +- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash + table internal to the pyexpat module's copy of the expat library to avoid a + denial of service due to hash collisions. Patch by David Malcolm with some + modifications by the expat project. + - Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils on Windows. diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -883,6 +883,15 @@ XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing); +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt); + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/expat/pyexpatns.h b/Modules/expat/pyexpatns.h --- a/Modules/expat/pyexpatns.h +++ b/Modules/expat/pyexpatns.h @@ -97,6 +97,7 @@ #define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler #define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler #define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg +#define XML_SetHashSalt PyExpat_XML_SetHashSalt #define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler #define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler #define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -17,6 +17,8 @@ #include #include /* memset(), memcpy() */ #include +#include /* UINT_MAX */ +#include /* time() */ #include "expat.h" @@ -387,12 +389,13 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +dtdCopy(XML_Parser oldParser, + DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); static int -copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); - +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize); +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); static void FASTCALL hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); static void FASTCALL hashTableClear(HASH_TABLE *); @@ -425,6 +428,9 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, const char *end); +static unsigned long generate_hash_secret_salt(void); +static XML_Bool startParsing(XML_Parser parser); + static XML_Parser parserCreate(const XML_Char *encodingName, const XML_Memory_Handling_Suite *memsuite, @@ -542,6 +548,7 @@ XML_Bool m_useForeignDTD; enum XML_ParamEntityParsing m_paramEntityParsing; #endif + unsigned long m_hash_secret_salt; }; #define MALLOC(s) (parser->m_mem.malloc_fcn((s))) @@ -649,6 +656,7 @@ #define useForeignDTD (parser->m_useForeignDTD) #define paramEntityParsing (parser->m_paramEntityParsing) #endif /* XML_DTD */ +#define hash_secret_salt (parser->m_hash_secret_salt) XML_Parser XMLCALL XML_ParserCreate(const XML_Char *encodingName) @@ -671,22 +679,36 @@ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' }; -XML_Parser XMLCALL -XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) +static unsigned long +generate_hash_secret_salt(void) { - XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); - if (parser != NULL && ns) { + unsigned int seed = time(NULL) % UINT_MAX; + srand(seed); + return rand(); +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) +{ + /* hash functions must be initialized before setContext() is called */ + + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { /* implicit context only set for root parser, since child parsers (i.e. external entity parsers) will inherit it */ - if (!setContext(parser, implicitContext)) { - XML_ParserFree(parser); - return NULL; - } + return setContext(parser, implicitContext); } - return parser; + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + return parserCreate(encodingName, memsuite, nameSep, NULL); } static XML_Parser @@ -860,6 +882,7 @@ useForeignDTD = XML_FALSE; paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #endif + hash_secret_salt = 0; } /* moves list of bindings to freeBindingList */ @@ -907,7 +930,7 @@ poolClear(&temp2Pool); parserInit(parser, encodingName); dtdReset(_dtd, &parser->m_mem); - return setContext(parser, implicitContext); + return XML_TRUE; } enum XML_Status XMLCALL @@ -976,6 +999,12 @@ int oldInEntityValue = prologState.inEntityValue; #endif XML_Bool oldns_triplets = ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt = hash_secret_salt; #ifdef XML_DTD if (!context) @@ -1029,13 +1058,14 @@ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; defaultExpandInternalEntities = oldDefaultExpandInternalEntities; ns_triplets = oldns_triplets; + hash_secret_salt = oldhash_secret_salt; parentParser = oldParser; #ifdef XML_DTD paramEntityParsing = oldParamEntityParsing; prologState.inEntityValue = oldInEntityValue; if (context) { #endif /* XML_DTD */ - if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) || !setContext(parser, context)) { XML_ParserFree(parser); return NULL; @@ -1420,6 +1450,17 @@ #endif } +int XMLCALL +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; + hash_secret_salt = hash_salt; + return 1; +} + enum XML_Status XMLCALL XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { @@ -1430,6 +1471,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -1488,11 +1534,13 @@ break; case XML_INITIALIZED: case XML_PARSING: - result = XML_STATUS_OK; if (isFinal) { ps_parsing = XML_FINISHED; - return result; + return XML_STATUS_OK; } + /* fall through */ + default: + result = XML_STATUS_OK; } } @@ -1553,6 +1601,11 @@ case XML_FINISHED: errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } default: ps_parsing = XML_PARSING; } @@ -2231,7 +2284,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&dtd->pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -2618,12 +2671,12 @@ const XML_Char *localPart; /* lookup the element type name */ - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); if (!elementType) { const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); if (!name) return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!elementType) return XML_ERROR_NO_MEMORY; @@ -2792,9 +2845,9 @@ if (s[-1] == 2) { /* prefixed */ ATTRIBUTE_ID *id; const BINDING *b; - unsigned long uriHash = 0; + unsigned long uriHash = hash_secret_salt; ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); if (!id) return XML_ERROR_NO_MEMORY; b = id->prefix->binding; @@ -2818,7 +2871,7 @@ } while (*s++); { /* Check hash table for duplicate of expanded name (uriName). - Derived from code in lookup(HASH_TABLE *table, ...). + Derived from code in lookup(parser, HASH_TABLE *table, ...). */ unsigned char step = 0; unsigned long mask = nsAttsSize - 1; @@ -3756,7 +3809,8 @@ case XML_ROLE_DOCTYPE_PUBLIC_ID: #ifdef XML_DTD useForeignDTD = XML_FALSE; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -3811,7 +3865,8 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -3855,7 +3910,7 @@ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; dtd->hasParamEntityRefs = XML_TRUE; if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!entity) @@ -4069,7 +4124,8 @@ break; #else /* XML_DTD */ if (!declEntity) { - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) @@ -4144,7 +4200,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4176,7 +4232,7 @@ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); if (!name) return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(&dtd->paramEntities, + declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, sizeof(ENTITY)); if (!declEntity) return XML_ERROR_NO_MEMORY; @@ -4358,7 +4414,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&dtd->pool); /* first, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal, @@ -4882,7 +4938,7 @@ next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); poolDiscard(&temp2Pool); /* First, determine if a check for an existing declaration is needed; if yes, check that the entity exists, and that it is internal. @@ -4991,7 +5047,7 @@ result = XML_ERROR_NO_MEMORY; goto endEntityValue; } - entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); poolDiscard(&tempPool); if (!entity) { /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ @@ -5281,7 +5337,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return 0; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!prefix) return 0; @@ -5310,7 +5366,7 @@ return NULL; /* skip quotation mark - its storage will be re-used (like in name[-1]) */ ++name; - id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); if (!id) return NULL; if (id->name != name) @@ -5328,7 +5384,7 @@ if (name[5] == XML_T('\0')) id->prefix = &dtd->defaultPrefix; else - id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); id->xmlns = XML_TRUE; } else { @@ -5343,7 +5399,7 @@ } if (!poolAppendChar(&dtd->pool, XML_T('\0'))) return NULL; - id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); if (!id->prefix) return NULL; @@ -5441,7 +5497,7 @@ ENTITY *e; if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); if (e) e->open = XML_TRUE; if (*s != XML_T('\0')) @@ -5456,7 +5512,7 @@ else { if (!poolAppendChar(&tempPool, XML_T('\0'))) return XML_FALSE; - prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), sizeof(PREFIX)); if (!prefix) return XML_FALSE; @@ -5620,7 +5676,7 @@ The new DTD has already been initialized. */ static int -dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) { HASH_TABLE_ITER iter; @@ -5635,7 +5691,7 @@ name = poolCopyString(&(newDtd->pool), oldP->name); if (!name) return 0; - if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) return 0; } @@ -5657,7 +5713,7 @@ if (!name) return 0; ++name; - newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); if (!newA) return 0; @@ -5667,7 +5723,7 @@ if (oldA->prefix == &oldDtd->defaultPrefix) newA->prefix = &newDtd->defaultPrefix; else - newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); } } @@ -5686,7 +5742,7 @@ name = poolCopyString(&(newDtd->pool), oldE->name); if (!name) return 0; - newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); if (!newE) return 0; @@ -5700,14 +5756,14 @@ } if (oldE->idAtt) newE->idAtt = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; if (oldE->prefix) - newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { newE->defaultAtts[i].id = (ATTRIBUTE_ID *) - lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -5721,13 +5777,15 @@ } /* Copy the entity tables. */ - if (!copyEntityTable(&(newDtd->generalEntities), + if (!copyEntityTable(oldParser, + &(newDtd->generalEntities), &(newDtd->pool), &(oldDtd->generalEntities))) return 0; #ifdef XML_DTD - if (!copyEntityTable(&(newDtd->paramEntities), + if (!copyEntityTable(oldParser, + &(newDtd->paramEntities), &(newDtd->pool), &(oldDtd->paramEntities))) return 0; @@ -5750,7 +5808,8 @@ } /* End dtdCopy */ static int -copyEntityTable(HASH_TABLE *newTable, +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable) { @@ -5769,7 +5828,7 @@ name = poolCopyString(newPool, oldE->name); if (!name) return 0; - newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); if (!newE) return 0; if (oldE->systemId) { @@ -5827,16 +5886,16 @@ } static unsigned long FASTCALL -hash(KEY s) +hash(XML_Parser parser, KEY s) { - unsigned long h = 0; + unsigned long h = hash_secret_salt; while (*s) h = CHAR_HASH(h, *s++); return h; } static NAMED * -lookup(HASH_TABLE *table, KEY name, size_t createSize) +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { size_t i; if (table->size == 0) { @@ -5853,10 +5912,10 @@ return NULL; } memset(table->v, 0, tsize); - i = hash(name) & ((unsigned long)table->size - 1); + i = hash(parser, name) & ((unsigned long)table->size - 1); } else { - unsigned long h = hash(name); + unsigned long h = hash(parser, name); unsigned long mask = (unsigned long)table->size - 1; unsigned char step = 0; i = h & mask; @@ -5882,7 +5941,7 @@ memset(newV, 0, tsize); for (i = 0; i < table->size; i++) if (table->v[i]) { - unsigned long newHash = hash(table->v[i]->name); + unsigned long newHash = hash(parser, table->v[i]->name); size_t j = newHash & newMask; step = 0; while (newV[j]) { @@ -6257,7 +6316,7 @@ if (!name) return NULL; - ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); if (!ret) return NULL; if (ret->name != name) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1150,6 +1150,8 @@ else { self->itself = XML_ParserCreate(encoding); } + XML_SetHashSalt(self->itself, + (unsigned long)_Py_HashSecret.prefix); self->intern = intern; Py_XINCREF(self->intern); PyObject_GC_Track(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 20:40:12 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 20:40:12 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fixes_Issue_142?= =?utf8?q?34=3A_fix_for_the_previous_commit=2C_keep_compilation_when?= Message-ID: http://hg.python.org/cpython/rev/d54508a86a5d changeset: 75817:d54508a86a5d branch: 3.2 user: Gregory P. Smith date: Wed Mar 14 18:10:37 2012 -0700 summary: Fixes Issue 14234: fix for the previous commit, keep compilation when using --with-system-expat working when the system expat does not have salted hash support. files: Modules/expat/expat.h | 2 ++ Modules/pyexpat.c | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -892,6 +892,8 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); +#define XML_HAS_SET_HASH_SALT /* Python Only: Defined for pyexpat.c. */ + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then XML_GetErrorCode returns information about the error. */ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1150,8 +1150,13 @@ else { self->itself = XML_ParserCreate(encoding); } +#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) + /* This feature was added upstream in libexpat 2.1.0. Our expat copy + * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT + * to indicate that we can still use it. */ XML_SetHashSalt(self->itself, (unsigned long)_Py_HashSecret.prefix); +#endif self->intern = intern; Py_XINCREF(self->intern); PyObject_GC_Track(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 20:40:13 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 20:40:13 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogQnVtcCB0byAzLjIu?= =?utf8?q?3rc2=2E?= Message-ID: http://hg.python.org/cpython/rev/428f05cb7277 changeset: 75818:428f05cb7277 branch: 3.2 tag: v3.2.3rc2 user: Georg Brandl date: Sun Mar 18 07:34:49 2012 +0100 summary: Bump to 3.2.3rc2. files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 17 +++++++---------- Misc/RPM/python-3.2.spec | 2 +- README | 2 +- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 2 #define PY_MICRO_VERSION 3 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.2.3rc1+" +#define PY_VERSION "3.2.3rc2" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.2.3rc1" +__version__ = "3.2.3rc2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.2.3rc1" +IDLE_VERSION = "3.2.3rc2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,28 +2,25 @@ Python News +++++++++++ -What's New in Python 3.2.3? -=========================== - -*Release date: XX-XXX-2012* - - What's New in Python 3.2.3 release candidate 2? =============================================== -*Release date: XX-Mar-2012* +*Release date: 18-Mar-2012* Library ------- +- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils + on Windows. + +Extension Modules +----------------- + - Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash table internal to the pyexpat module's copy of the expat library to avoid a denial of service due to hash collisions. Patch by David Malcolm with some modifications by the expat project. -- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils - on Windows. - What's New in Python 3.2.3 release candidate 1? =============================================== diff --git a/Misc/RPM/python-3.2.spec b/Misc/RPM/python-3.2.spec --- a/Misc/RPM/python-3.2.spec +++ b/Misc/RPM/python-3.2.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.2.3rc1 +%define version 3.2.3rc2 %define libvers 3.2 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.2.3 rc1 +This is Python version 3.2.3 rc2 ================================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 20:40:14 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 20:40:14 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Added_tag_v3=2E?= =?utf8?q?2=2E3rc2_for_changeset_428f05cb7277?= Message-ID: http://hg.python.org/cpython/rev/29a4d7580d1a changeset: 75819:29a4d7580d1a branch: 3.2 user: Georg Brandl date: Sun Mar 18 07:35:01 2012 +0100 summary: Added tag v3.2.3rc2 for changeset 428f05cb7277 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -95,3 +95,4 @@ c860feaa348d663e598986894ee4680480577e15 v3.2.2rc1 137e45f15c0bd262c9ad4c032d97425bc0589456 v3.2.2 7085403daf439adb3f9e70ef13f6bedb1c447376 v3.2.3rc1 +428f05cb7277e1d42bb9dd8d1af6b6270ebc6112 v3.2.3rc2 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 20:40:17 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 20:40:17 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Post-release_up?= =?utf8?q?dates_for_3=2E2=2E3rc2=2E?= Message-ID: http://hg.python.org/cpython/rev/b5e52995f76a changeset: 75820:b5e52995f76a branch: 3.2 user: Georg Brandl date: Sun Mar 18 08:36:53 2012 +0100 summary: Post-release updates for 3.2.3rc2. files: Include/patchlevel.h | 2 +- Misc/NEWS | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.2.3rc2" +#define PY_VERSION "3.2.3rc2+" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,18 @@ Python News +++++++++++ +What's New in Python 3.2.3? +=========================== + +*Release date: XX-Mar-2012* + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.2.3 release candidate 2? =============================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 20:40:18 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 20:40:18 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_Merge_3=2E2=2E3rc2_from_release_clone=2E?= Message-ID: http://hg.python.org/cpython/rev/d238a3d3bf43 changeset: 75821:d238a3d3bf43 branch: 3.2 parent: 75799:118f7bdd631b parent: 75820:b5e52995f76a user: Georg Brandl date: Sun Mar 18 20:37:43 2012 +0100 summary: Merge 3.2.3rc2 from release clone. files: .hgtags | 1 + Include/patchlevel.h | 4 +- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 32 +++++++++++++++++++++++++++ Misc/RPM/python-3.2.spec | 2 +- README | 2 +- 7 files changed, 39 insertions(+), 6 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -95,3 +95,4 @@ c860feaa348d663e598986894ee4680480577e15 v3.2.2rc1 137e45f15c0bd262c9ad4c032d97425bc0589456 v3.2.2 7085403daf439adb3f9e70ef13f6bedb1c447376 v3.2.3rc1 +428f05cb7277e1d42bb9dd8d1af6b6270ebc6112 v3.2.3rc2 diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 2 #define PY_MICRO_VERSION 3 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.2.3rc1" +#define PY_VERSION "3.2.3rc2+" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.2.3rc1" +__version__ = "3.2.3rc2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.2.3rc1" +IDLE_VERSION = "3.2.3rc2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,6 +96,38 @@ modifications by the expat project. +What's New in Python 3.2.3? +=========================== + +*Release date: XX-Mar-2012* + +Core and Builtins +----------------- + +Library +------- + + +What's New in Python 3.2.3 release candidate 2? +=============================================== + +*Release date: 18-Mar-2012* + +Library +------- + +- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils + on Windows. + +Extension Modules +----------------- + +- Issue #14234: CVE-2012-0876: Randomize hashes of xml attributes in the hash + table internal to the pyexpat module's copy of the expat library to avoid a + denial of service due to hash collisions. Patch by David Malcolm with some + modifications by the expat project. + + What's New in Python 3.2.3 release candidate 1? =============================================== diff --git a/Misc/RPM/python-3.2.spec b/Misc/RPM/python-3.2.spec --- a/Misc/RPM/python-3.2.spec +++ b/Misc/RPM/python-3.2.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.2.3rc1 +%define version 3.2.3rc2 %define libvers 3.2 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.2.3 rc1 +This is Python version 3.2.3 rc2 ================================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 20:40:19 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2012 20:40:19 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Dummy-merge_=28except_=2Ehgtags=29_3=2E2=2E3rc2_changes=2E?= Message-ID: http://hg.python.org/cpython/rev/3945d73ad525 changeset: 75822:3945d73ad525 parent: 75812:fe1dfc066a38 parent: 75821:d238a3d3bf43 user: Georg Brandl date: Sun Mar 18 20:39:46 2012 +0100 summary: Dummy-merge (except .hgtags) 3.2.3rc2 changes. files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -95,4 +95,5 @@ c860feaa348d663e598986894ee4680480577e15 v3.2.2rc1 137e45f15c0bd262c9ad4c032d97425bc0589456 v3.2.2 7085403daf439adb3f9e70ef13f6bedb1c447376 v3.2.3rc1 +428f05cb7277e1d42bb9dd8d1af6b6270ebc6112 v3.2.3rc2 f1a9a6505731714f0e157453ff850e3b71615c45 v3.3.0a1 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 18 23:58:04 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 18 Mar 2012 23:58:04 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogQWRkIDIuNy4zcmMy?= =?utf8?q?_uuid?= Message-ID: http://hg.python.org/cpython/rev/86fb192f38b1 changeset: 75823:86fb192f38b1 branch: 2.7 parent: 75811:064977e473a5 user: Martin v. L?wis date: Sun Mar 18 23:46:56 2012 +0100 summary: Add 2.7.3rc2 uuid files: Tools/msi/uuids.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py --- a/Tools/msi/uuids.py +++ b/Tools/msi/uuids.py @@ -56,6 +56,7 @@ '2.7.2121':'{B2E1F06E-F719-4786-972A-488A336EB2A0}', # 2.7.2rc1 '2.7.2150':'{2E295B5B-1AD4-4d36-97C2-A316084722CF}', # 2.7.2 '2.7.3121':'{1ACB88BF-1425-4f11-B664-6C89A3D7699C}', # 2.7.3rc1 + '2.7.3122':'{B12311BE-6364-4b2a-A49A-551EEE10F3E4}', # 2.7.3rc2 '2.7.3150':'{C0C31BCC-56FB-42a7-8766-D29E1BD74C7C}', # 2.7.3 '2.7.4121':'{47F45F45-72D7-4e54-AF41-26767EDE95CF}', # 2.7.4rc1 '2.7.4150':'{84ADC96C-B7E0-4938-9D6E-2B640D5DA224}', # 2.7.4 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 00:14:29 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 19 Mar 2012 00:14:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fixes_Issue_=23?= =?utf8?q?14331=3A_Use_significantly_less_stack_space_when_importing_modul?= =?utf8?q?es_by?= Message-ID: http://hg.python.org/cpython/rev/daed636a3536 changeset: 75824:daed636a3536 branch: 3.2 parent: 75821:d238a3d3bf43 user: Gregory P. Smith date: Sun Mar 18 16:06:53 2012 -0700 summary: Fixes Issue #14331: Use significantly less stack space when importing modules by allocating path buffers on the heap instead of the stack. files: Misc/NEWS | 3 + Python/import.c | 166 +++++++++++++++++++++++++++-------- 2 files changed, 130 insertions(+), 39 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #14331: Use significantly less stack space when importing modules by + allocating path buffers on the heap instead of the stack. + - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not passed strings. diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1291,7 +1291,7 @@ { struct stat st; FILE *fpc; - char buf[MAXPATHLEN+1]; + char *buf; char *cpathname; PyCodeObject *co; PyObject *m; @@ -1310,6 +1310,10 @@ */ st.st_mtime &= 0xFFFFFFFF; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } cpathname = make_compiled_pathname( pathname, buf, (size_t)MAXPATHLEN + 1, !Py_OptimizeFlag); if (cpathname != NULL && @@ -1317,9 +1321,9 @@ co = read_compiled_module(cpathname, fpc); fclose(fpc); if (co == NULL) - return NULL; + goto error_exit; if (update_compiled_module(co, pathname) < 0) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # precompiled from %s\n", name, cpathname); @@ -1328,7 +1332,7 @@ else { co = parse_source_module(pathname, fp); if (co == NULL) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # from %s\n", name, pathname); @@ -1342,7 +1346,12 @@ name, (PyObject *)co, pathname, cpathname); Py_DECREF(co); + PyMem_FREE(buf); return m; + +error_exit: + PyMem_FREE(buf); + return NULL; } /* Get source file -> unicode or None @@ -1351,7 +1360,7 @@ static PyObject * get_sourcefile(char *file) { - char py[MAXPATHLEN + 1]; + char *py = NULL; Py_ssize_t len; PyObject *u; struct stat statbuf; @@ -1366,6 +1375,10 @@ return PyUnicode_DecodeFSDefault(file); } + py = PyMem_MALLOC(MAXPATHLEN+1); + if (py == NULL) { + return PyErr_NoMemory(); + } /* Start by trying to turn PEP 3147 path into source path. If that * fails, just chop off the trailing character, i.e. legacy pyc path * to py. @@ -1382,6 +1395,7 @@ else { u = PyUnicode_DecodeFSDefault(file); } + PyMem_FREE(py); return u; } @@ -1401,7 +1415,7 @@ PyObject *file = NULL; PyObject *path = NULL; int err; - char buf[MAXPATHLEN+1]; + char *buf = NULL; FILE *fp = NULL; struct filedescr *fdp; @@ -1423,8 +1437,13 @@ err = PyDict_SetItemString(d, "__path__", path); if (err != 0) goto error; + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } buf[0] = '\0'; - fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL); + fdp = find_module(name, "__init__", path, buf, MAXPATHLEN+1, &fp, NULL); if (fdp == NULL) { if (PyErr_ExceptionMatches(PyExc_ImportError)) { PyErr_Clear(); @@ -1442,6 +1461,8 @@ error: m = NULL; cleanup: + if (buf) + PyMem_FREE(buf); Py_XDECREF(path); Py_XDECREF(file); return m; @@ -1571,7 +1592,7 @@ static struct filedescr fd_frozen = {"", "", PY_FROZEN}; static struct filedescr fd_builtin = {"", "", C_BUILTIN}; static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; - char name[MAXPATHLEN+1]; + char *name; #if defined(PYOS_OS2) size_t saved_len; size_t saved_namelen; @@ -1585,6 +1606,11 @@ "module name is too long"); return NULL; } + name = PyMem_MALLOC(MAXPATHLEN+1); + if (name == NULL) { + PyErr_NoMemory(); + return NULL; + } strcpy(name, subname); /* sys.meta_path import hook */ @@ -1596,7 +1622,7 @@ PyErr_SetString(PyExc_RuntimeError, "sys.meta_path must be a list of " "import hooks"); - return NULL; + goto error_exit; } Py_INCREF(meta_path); /* zap guard */ npath = PyList_Size(meta_path); @@ -1609,12 +1635,13 @@ path : Py_None); if (loader == NULL) { Py_DECREF(meta_path); - return NULL; /* true error */ + goto error_exit; /* true error */ } if (loader != Py_None) { /* a loader was found */ *p_loader = loader; Py_DECREF(meta_path); + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1624,18 +1651,21 @@ if (find_frozen(fullname) != NULL) { strcpy(buf, fullname); + PyMem_FREE(name); return &fd_frozen; } if (path == NULL) { if (is_builtin(name)) { strcpy(buf, name); + PyMem_FREE(name); return &fd_builtin; } #ifdef MS_COREDLL fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen); if (fp != NULL) { *p_fp = fp; + PyMem_FREE(name); return fdp; } #endif @@ -1645,7 +1675,7 @@ if (path == NULL || !PyList_Check(path)) { PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list of directory names"); - return NULL; + goto error_exit; } path_hooks = PySys_GetObject("path_hooks"); @@ -1653,14 +1683,14 @@ PyErr_SetString(PyExc_RuntimeError, "sys.path_hooks must be a list of " "import hooks"); - return NULL; + goto error_exit; } path_importer_cache = PySys_GetObject("path_importer_cache"); if (path_importer_cache == NULL || !PyDict_Check(path_importer_cache)) { PyErr_SetString(PyExc_RuntimeError, "sys.path_importer_cache must be a dict"); - return NULL; + goto error_exit; } npath = PyList_Size(path); @@ -1671,11 +1701,11 @@ const char *base; Py_ssize_t size; if (!v) - return NULL; + goto error_exit; if (PyUnicode_Check(v)) { v = PyUnicode_EncodeFSDefault(v); if (v == NULL) - return NULL; + goto error_exit; } else if (!PyBytes_Check(v)) continue; @@ -1703,7 +1733,7 @@ importer = get_path_importer(path_importer_cache, path_hooks, origv); if (importer == NULL) { - return NULL; + goto error_exit; } /* Note: importer is a borrowed reference */ if (importer != Py_None) { @@ -1712,10 +1742,11 @@ "find_module", "s", fullname); if (loader == NULL) - return NULL; /* error */ + goto error_exit; /* error */ if (loader != Py_None) { /* a loader was found */ *p_loader = loader; + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1740,19 +1771,20 @@ S_ISDIR(statbuf.st_mode) && /* it's a directory */ case_ok(buf, len, namelen, name)) { /* case matches */ if (find_init_module(buf)) { /* and has __init__.py */ + PyMem_FREE(name); return &fd_package; } else { int err; PyObject *unicode = PyUnicode_DecodeFSDefault(buf); if (unicode == NULL) - return NULL; + goto error_exit; err = PyErr_WarnFormat(PyExc_ImportWarning, 1, "Not importing directory '%U': missing __init__.py", unicode); Py_DECREF(unicode); if (err) - return NULL; + goto error_exit; } } #endif @@ -1833,10 +1865,15 @@ if (fp == NULL) { PyErr_Format(PyExc_ImportError, "No module named %.200s", name); - return NULL; + goto error_exit; } *p_fp = fp; + PyMem_FREE(name); return fdp; + +error_exit: + PyMem_FREE(name); + return NULL; } /* case_ok(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name) @@ -2416,7 +2453,7 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) { - char buf[MAXPATHLEN+1]; + char *buf; Py_ssize_t buflen = 0; PyObject *parent, *head, *next, *tail; @@ -2430,14 +2467,18 @@ return NULL; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } parent = get_parent(globals, buf, &buflen, level); if (parent == NULL) - return NULL; + goto error_exit; head = load_next(parent, level < 0 ? Py_None : parent, &name, buf, &buflen); if (head == NULL) - return NULL; + goto error_exit; tail = head; Py_INCREF(tail); @@ -2446,7 +2487,7 @@ Py_DECREF(tail); if (next == NULL) { Py_DECREF(head); - return NULL; + goto error_exit; } tail = next; } @@ -2458,7 +2499,7 @@ Py_DECREF(head); PyErr_SetString(PyExc_ValueError, "Empty module name"); - return NULL; + goto error_exit; } if (fromlist != NULL) { @@ -2468,16 +2509,22 @@ if (fromlist == NULL) { Py_DECREF(tail); + PyMem_FREE(buf); return head; } Py_DECREF(head); if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) { Py_DECREF(tail); - return NULL; + goto error_exit; } + PyMem_FREE(buf); return tail; + +error_exit: + PyMem_FREE(buf); + return NULL; } PyObject * @@ -2880,7 +2927,7 @@ } else { PyObject *path, *loader = NULL; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; @@ -2895,11 +2942,16 @@ } } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); if (fdp == NULL) { + PyMem_FREE(buf); if (!PyErr_ExceptionMatches(PyExc_ImportError)) return NULL; PyErr_Clear(); @@ -2914,6 +2966,7 @@ Py_XDECREF(m); m = NULL; } + PyMem_FREE(buf); } return m; @@ -2931,7 +2984,7 @@ PyObject *modules = PyImport_GetModuleDict(); PyObject *path = NULL, *loader = NULL, *existing_m = NULL; char *name, *subname; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; PyObject *newm; @@ -2991,6 +3044,11 @@ if (path == NULL) PyErr_Clear(); } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + Py_XDECREF(path); + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); @@ -2998,6 +3056,7 @@ if (fdp == NULL) { Py_XDECREF(loader); imp_modules_reloading_clear(); + PyMem_FREE(buf); return NULL; } @@ -3015,6 +3074,7 @@ PyDict_SetItemString(modules, name, m); } imp_modules_reloading_clear(); + PyMem_FREE(buf); return newm; } @@ -3168,26 +3228,32 @@ PyObject *fob, *ret; PyObject *pathobj; struct filedescr *fdp; - char pathname[MAXPATHLEN+1]; + char *pathname; FILE *fp = NULL; int fd = -1; char *found_encoding = NULL; char *encoding = NULL; + pathname = PyMem_MALLOC(MAXPATHLEN+1); + if (pathname == NULL) { + return PyErr_NoMemory(); + } pathname[0] = '\0'; if (path == Py_None) path = NULL; fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL); if (fdp == NULL) - return NULL; + goto error_exit; if (fp != NULL) { fd = fileno(fp); if (fd != -1) fd = dup(fd); fclose(fp); fp = NULL; - if (fd == -1) - return PyErr_SetFromErrno(PyExc_OSError); + if (fd == -1) { + PyErr_SetFromErrno(PyExc_OSError); + goto error_exit; + } } if (fd != -1) { if (strchr(fdp->mode, 'b') == NULL) { @@ -3197,7 +3263,7 @@ lseek(fd, 0, 0); /* Reset position */ if (found_encoding == NULL && PyErr_Occurred()) { close(fd); - return NULL; + goto error_exit; } encoding = (found_encoding != NULL) ? found_encoding : (char*)PyUnicode_GetDefaultEncoding(); @@ -3207,7 +3273,7 @@ if (fob == NULL) { close(fd); PyMem_FREE(found_encoding); - return NULL; + goto error_exit; } } else { @@ -3218,8 +3284,12 @@ ret = Py_BuildValue("NN(ssi)", fob, pathobj, fdp->suffix, fdp->mode, fdp->type); PyMem_FREE(found_encoding); - + PyMem_FREE(pathname); return ret; + +error_exit: + PyMem_FREE(pathname); + return NULL; } static PyObject * @@ -3509,7 +3579,7 @@ { static char *kwlist[] = {"path", "debug_override", NULL}; - char buf[MAXPATHLEN+1]; + char *buf; PyObject *pathbytes; char *cpathname; PyObject *debug_override = NULL; @@ -3526,6 +3596,10 @@ return NULL; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } cpathname = make_compiled_pathname( PyBytes_AS_STRING(pathbytes), buf, MAXPATHLEN+1, debug); @@ -3533,9 +3607,14 @@ if (cpathname == NULL) { PyErr_Format(PyExc_SystemError, "path buffer too short"); + PyMem_FREE(buf); return NULL; } - return PyUnicode_DecodeFSDefault(buf); + { + PyObject *ret = PyUnicode_DecodeFSDefault(buf); + PyMem_FREE(buf); + return ret; + } } PyDoc_STRVAR(doc_cache_from_source, @@ -3556,7 +3635,7 @@ PyObject *pathname_obj; char *pathname; - char buf[MAXPATHLEN+1]; + char *buf; if (!PyArg_ParseTupleAndKeywords( args, kws, "O&", kwlist, @@ -3564,14 +3643,23 @@ return NULL; pathname = PyBytes_AS_STRING(pathname_obj); + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } if (make_source_pathname(pathname, buf) == NULL) { PyErr_Format(PyExc_ValueError, "Not a PEP 3147 pyc path: %s", pathname); Py_DECREF(pathname_obj); + PyMem_FREE(buf); return NULL; } Py_DECREF(pathname_obj); - return PyUnicode_FromString(buf); + { + PyObject *ret = PyUnicode_FromString(buf); + PyMem_FREE(buf); + return ret; + } } PyDoc_STRVAR(doc_source_from_cache, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 00:14:30 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 19 Mar 2012 00:14:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fixes_Issue_=23?= =?utf8?q?14331=3A_Use_significantly_less_stack_space_when_importing_modul?= =?utf8?q?es_by?= Message-ID: http://hg.python.org/cpython/rev/ad030571e6c0 changeset: 75825:ad030571e6c0 branch: 2.7 parent: 75823:86fb192f38b1 user: Gregory P. Smith date: Sun Mar 18 16:07:10 2012 -0700 summary: Fixes Issue #14331: Use significantly less stack space when importing modules by allocating path buffers on the heap instead of the stack. files: Misc/NEWS | 3 + Python/import.c | 126 +++++++++++++++++++++++++++-------- 2 files changed, 98 insertions(+), 31 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #14331: Use significantly less stack space when importing modules by + allocating path buffers on the heap instead of the stack. + - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not passed strings. Also fix segfaults in the __getattribute__ and __setattr__ methods of old-style classes. diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -996,7 +996,7 @@ { struct stat st; FILE *fpc; - char buf[MAXPATHLEN+1]; + char *buf; char *cpathname; PyCodeObject *co; PyObject *m; @@ -1015,6 +1015,10 @@ */ st.st_mtime &= 0xFFFFFFFF; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } cpathname = make_compiled_pathname(pathname, buf, (size_t)MAXPATHLEN + 1); if (cpathname != NULL && @@ -1022,9 +1026,9 @@ co = read_compiled_module(cpathname, fpc); fclose(fpc); if (co == NULL) - return NULL; + goto error_exit; if (update_compiled_module(co, pathname) < 0) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # precompiled from %s\n", name, cpathname); @@ -1033,7 +1037,7 @@ else { co = parse_source_module(pathname, fp); if (co == NULL) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # from %s\n", name, pathname); @@ -1046,7 +1050,12 @@ m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname); Py_DECREF(co); + PyMem_FREE(buf); return m; + +error_exit: + PyMem_FREE(buf); + return NULL; } @@ -1066,7 +1075,7 @@ PyObject *file = NULL; PyObject *path = NULL; int err; - char buf[MAXPATHLEN+1]; + char *buf = NULL; FILE *fp = NULL; struct filedescr *fdp; @@ -1088,8 +1097,13 @@ err = PyDict_SetItemString(d, "__path__", path); if (err != 0) goto error; + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } buf[0] = '\0'; - fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL); + fdp = find_module(name, "__init__", path, buf, MAXPATHLEN+1, &fp, NULL); if (fdp == NULL) { if (PyErr_ExceptionMatches(PyExc_ImportError)) { PyErr_Clear(); @@ -1107,6 +1121,8 @@ error: m = NULL; cleanup: + if (buf) + PyMem_FREE(buf); Py_XDECREF(path); Py_XDECREF(file); return m; @@ -1235,7 +1251,7 @@ static struct filedescr fd_frozen = {"", "", PY_FROZEN}; static struct filedescr fd_builtin = {"", "", C_BUILTIN}; static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; - char name[MAXPATHLEN+1]; + char *name; #if defined(PYOS_OS2) size_t saved_len; size_t saved_namelen; @@ -1249,6 +1265,10 @@ "module name is too long"); return NULL; } + name = PyMem_MALLOC(MAXPATHLEN+1); + if (name == NULL) { + return PyErr_NoMemory(); + } strcpy(name, subname); /* sys.meta_path import hook */ @@ -1260,7 +1280,7 @@ PyErr_SetString(PyExc_RuntimeError, "sys.meta_path must be a list of " "import hooks"); - return NULL; + goto error_exit; } Py_INCREF(meta_path); /* zap guard */ npath = PyList_Size(meta_path); @@ -1273,12 +1293,13 @@ path : Py_None); if (loader == NULL) { Py_DECREF(meta_path); - return NULL; /* true error */ + goto error_exit; /* true error */ } if (loader != Py_None) { /* a loader was found */ *p_loader = loader; Py_DECREF(meta_path); + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1292,7 +1313,7 @@ if (PyString_Size(path) + 1 + strlen(name) >= (size_t)buflen) { PyErr_SetString(PyExc_ImportError, "full frozen module name too long"); - return NULL; + goto error_exit; } strcpy(buf, PyString_AsString(path)); strcat(buf, "."); @@ -1300,19 +1321,22 @@ strcpy(name, buf); if (find_frozen(name) != NULL) { strcpy(buf, name); + PyMem_FREE(name); return &fd_frozen; } PyErr_Format(PyExc_ImportError, "No frozen submodule named %.200s", name); - return NULL; + goto error_exit; } if (path == NULL) { if (is_builtin(name)) { strcpy(buf, name); + PyMem_FREE(name); return &fd_builtin; } if ((find_frozen(name)) != NULL) { strcpy(buf, name); + PyMem_FREE(name); return &fd_frozen; } @@ -1320,6 +1344,7 @@ fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen); if (fp != NULL) { *p_fp = fp; + PyMem_FREE(name); return fdp; } #endif @@ -1328,7 +1353,7 @@ if (path == NULL || !PyList_Check(path)) { PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list of directory names"); - return NULL; + goto error_exit; } path_hooks = PySys_GetObject("path_hooks"); @@ -1336,14 +1361,14 @@ PyErr_SetString(PyExc_RuntimeError, "sys.path_hooks must be a list of " "import hooks"); - return NULL; + goto error_exit; } path_importer_cache = PySys_GetObject("path_importer_cache"); if (path_importer_cache == NULL || !PyDict_Check(path_importer_cache)) { PyErr_SetString(PyExc_RuntimeError, "sys.path_importer_cache must be a dict"); - return NULL; + goto error_exit; } npath = PyList_Size(path); @@ -1352,13 +1377,13 @@ PyObject *copy = NULL; PyObject *v = PyList_GetItem(path, i); if (!v) - return NULL; + goto error_exit; #ifdef Py_USING_UNICODE if (PyUnicode_Check(v)) { copy = PyUnicode_Encode(PyUnicode_AS_UNICODE(v), PyUnicode_GET_SIZE(v), Py_FileSystemDefaultEncoding, NULL); if (copy == NULL) - return NULL; + goto error_exit; v = copy; } else @@ -1384,7 +1409,7 @@ path_hooks, v); if (importer == NULL) { Py_XDECREF(copy); - return NULL; + goto error_exit; } /* Note: importer is a borrowed reference */ if (importer != Py_None) { @@ -1394,10 +1419,11 @@ "s", fullname); Py_XDECREF(copy); if (loader == NULL) - return NULL; /* error */ + goto error_exit; /* error */ if (loader != Py_None) { /* a loader was found */ *p_loader = loader; + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1421,6 +1447,7 @@ case_ok(buf, len, namelen, name)) { /* case matches */ if (find_init_module(buf)) { /* and has __init__.py */ Py_XDECREF(copy); + PyMem_FREE(name); return &fd_package; } else { @@ -1431,7 +1458,7 @@ if (PyErr_Warn(PyExc_ImportWarning, warnstr)) { Py_XDECREF(copy); - return NULL; + goto error_exit; } } } @@ -1506,10 +1533,15 @@ if (fp == NULL) { PyErr_Format(PyExc_ImportError, "No module named %.200s", name); - return NULL; + goto error_exit; } *p_fp = fp; + PyMem_FREE(name); return fdp; + +error_exit: + PyMem_FREE(name); + return NULL; } /* Helpers for main.c @@ -2116,7 +2148,7 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) { - char buf[MAXPATHLEN+1]; + char *buf; Py_ssize_t buflen = 0; PyObject *parent, *head, *next, *tail; @@ -2130,14 +2162,18 @@ return NULL; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } parent = get_parent(globals, buf, &buflen, level); if (parent == NULL) - return NULL; + goto error_exit; head = load_next(parent, level < 0 ? Py_None : parent, &name, buf, &buflen); if (head == NULL) - return NULL; + goto error_exit; tail = head; Py_INCREF(tail); @@ -2146,7 +2182,7 @@ Py_DECREF(tail); if (next == NULL) { Py_DECREF(head); - return NULL; + goto error_exit; } tail = next; } @@ -2158,7 +2194,7 @@ Py_DECREF(head); PyErr_SetString(PyExc_ValueError, "Empty module name"); - return NULL; + goto error_exit; } if (fromlist != NULL) { @@ -2168,16 +2204,22 @@ if (fromlist == NULL) { Py_DECREF(tail); + PyMem_FREE(buf); return head; } Py_DECREF(head); if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) { Py_DECREF(tail); - return NULL; + goto error_exit; } + PyMem_FREE(buf); return tail; + +error_exit: + PyMem_FREE(buf); + return NULL; } PyObject * @@ -2567,7 +2609,7 @@ } else { PyObject *path, *loader = NULL; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; @@ -2582,11 +2624,16 @@ } } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); if (fdp == NULL) { + PyMem_FREE(buf); if (!PyErr_ExceptionMatches(PyExc_ImportError)) return NULL; PyErr_Clear(); @@ -2601,6 +2648,7 @@ Py_XDECREF(m); m = NULL; } + PyMem_FREE(buf); } return m; @@ -2618,7 +2666,7 @@ PyObject *modules = PyImport_GetModuleDict(); PyObject *path = NULL, *loader = NULL, *existing_m = NULL; char *name, *subname; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; PyObject *newm; @@ -2678,6 +2726,11 @@ if (path == NULL) PyErr_Clear(); } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + Py_XDECREF(path); + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); @@ -2685,6 +2738,7 @@ if (fdp == NULL) { Py_XDECREF(loader); imp_modules_reloading_clear(); + PyMem_FREE(buf); return NULL; } @@ -2702,6 +2756,7 @@ PyDict_SetItemString(modules, name, m); } imp_modules_reloading_clear(); + PyMem_FREE(buf); return newm; } @@ -2832,19 +2887,27 @@ extern int fclose(FILE *); PyObject *fob, *ret; struct filedescr *fdp; - char pathname[MAXPATHLEN+1]; + char *pathname; FILE *fp = NULL; + pathname = PyMem_MALLOC(MAXPATHLEN+1); + if (pathname == NULL) { + return PyErr_NoMemory(); + } pathname[0] = '\0'; if (path == Py_None) path = NULL; fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL); - if (fdp == NULL) + if (fdp == NULL) { + PyMem_FREE(pathname); return NULL; + } if (fp != NULL) { fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose); - if (fob == NULL) + if (fob == NULL) { + PyMem_FREE(pathname); return NULL; + } } else { fob = Py_None; @@ -2853,6 +2916,7 @@ ret = Py_BuildValue("Os(ssi)", fob, pathname, fdp->suffix, fdp->mode, fdp->type); Py_DECREF(fob); + PyMem_FREE(pathname); return ret; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 00:14:31 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 19 Mar 2012 00:14:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Empty_merge=3B_imports_rewritten_in_3=2E3=2E_issue_=2314331_?= =?utf8?q?may_no_longer_apply=2E?= Message-ID: http://hg.python.org/cpython/rev/5ad5625715b5 changeset: 75826:5ad5625715b5 parent: 75822:3945d73ad525 parent: 75824:daed636a3536 user: Gregory P. Smith date: Sun Mar 18 16:14:17 2012 -0700 summary: Empty merge; imports rewritten in 3.3. issue #14331 may no longer apply. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 01:50:55 2012 From: python-checkins at python.org (r.david.murray) Date: Mon, 19 Mar 2012 01:50:55 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzE0MzU1OiByZW1v?= =?utf8?q?ve_obsolete_doc_reference_to_previously_removed_init=5Ffrozen=2E?= Message-ID: http://hg.python.org/cpython/rev/66e2dab98041 changeset: 75827:66e2dab98041 branch: 3.2 parent: 75824:daed636a3536 user: R David Murray date: Sun Mar 18 20:50:03 2012 -0400 summary: #14355: remove obsolete doc reference to previously removed init_frozen. Patch by Eric Snow. files: Doc/library/imp.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/imp.rst b/Doc/library/imp.rst --- a/Doc/library/imp.rst +++ b/Doc/library/imp.rst @@ -256,7 +256,7 @@ .. data:: PY_FROZEN - The module was found as a frozen module (see :func:`init_frozen`). + The module was found as a frozen module. .. class:: NullImporter(path_string) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 01:50:56 2012 From: python-checkins at python.org (r.david.murray) Date: Mon, 19 Mar 2012 01:50:56 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2314355=3A_remove_obsolete_doc_reference_to_previousl?= =?utf8?q?y_removed_init=5Ffrozen=2E?= Message-ID: http://hg.python.org/cpython/rev/1e827a176306 changeset: 75828:1e827a176306 parent: 75826:5ad5625715b5 parent: 75827:66e2dab98041 user: R David Murray date: Sun Mar 18 20:50:36 2012 -0400 summary: Merge #14355: remove obsolete doc reference to previously removed init_frozen. Patch by Eric Snow. files: Doc/library/imp.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/imp.rst b/Doc/library/imp.rst --- a/Doc/library/imp.rst +++ b/Doc/library/imp.rst @@ -256,7 +256,7 @@ .. data:: PY_FROZEN - The module was found as a frozen module (see :func:`init_frozen`). + The module was found as a frozen module. .. class:: NullImporter(path_string) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 02:23:33 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 19 Mar 2012 02:23:33 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogQWRkIDIuNy4zIGFu?= =?utf8?q?d_2=2E7=2E4_UUIDs?= Message-ID: http://hg.python.org/cpython/rev/911d0f5a6abc changeset: 75829:911d0f5a6abc branch: 2.7 parent: 75700:c05839b1ae68 user: Martin v. L?wis date: Sat Feb 25 10:37:41 2012 +0100 summary: Add 2.7.3 and 2.7.4 UUIDs files: Tools/msi/uuids.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py --- a/Tools/msi/uuids.py +++ b/Tools/msi/uuids.py @@ -55,4 +55,8 @@ '2.7.1150':'{32939827-d8e5-470a-b126-870db3c69fdf}', # 2.7.1 '2.7.2121':'{B2E1F06E-F719-4786-972A-488A336EB2A0}', # 2.7.2rc1 '2.7.2150':'{2E295B5B-1AD4-4d36-97C2-A316084722CF}', # 2.7.2 + '2.7.3121':'{1ACB88BF-1425-4f11-B664-6C89A3D7699C}', # 2.7.3rc1 + '2.7.3150':'{C0C31BCC-56FB-42a7-8766-D29E1BD74C7C}', # 2.7.3 + '2.7.4121':'{47F45F45-72D7-4e54-AF41-26767EDE95CF}', # 2.7.4rc1 + '2.7.4150':'{84ADC96C-B7E0-4938-9D6E-2B640D5DA224}', # 2.7.4 } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 02:23:34 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 19 Mar 2012 02:23:34 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogQWRkIDIuNy4zcmMy?= =?utf8?q?_uuid?= Message-ID: http://hg.python.org/cpython/rev/e6061a297db7 changeset: 75830:e6061a297db7 branch: 2.7 user: Martin v. L?wis date: Sun Mar 18 23:46:56 2012 +0100 summary: Add 2.7.3rc2 uuid files: Tools/msi/uuids.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py --- a/Tools/msi/uuids.py +++ b/Tools/msi/uuids.py @@ -56,6 +56,7 @@ '2.7.2121':'{B2E1F06E-F719-4786-972A-488A336EB2A0}', # 2.7.2rc1 '2.7.2150':'{2E295B5B-1AD4-4d36-97C2-A316084722CF}', # 2.7.2 '2.7.3121':'{1ACB88BF-1425-4f11-B664-6C89A3D7699C}', # 2.7.3rc1 + '2.7.3122':'{B12311BE-6364-4b2a-A49A-551EEE10F3E4}', # 2.7.3rc2 '2.7.3150':'{C0C31BCC-56FB-42a7-8766-D29E1BD74C7C}', # 2.7.3 '2.7.4121':'{47F45F45-72D7-4e54-AF41-26767EDE95CF}', # 2.7.4rc1 '2.7.4150':'{84ADC96C-B7E0-4938-9D6E-2B640D5DA224}', # 2.7.4 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 02:23:35 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 19 Mar 2012 02:23:35 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_merge_2=2E7=2E3_release_branch?= Message-ID: http://hg.python.org/cpython/rev/9f0bf9992664 changeset: 75831:9f0bf9992664 branch: 2.7 parent: 75745:3d4d52e47431 parent: 75830:e6061a297db7 user: Benjamin Peterson date: Sun Mar 18 21:22:45 2012 -0400 summary: merge 2.7.3 release branch files: Tools/msi/uuids.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py --- a/Tools/msi/uuids.py +++ b/Tools/msi/uuids.py @@ -56,6 +56,7 @@ '2.7.2121':'{B2E1F06E-F719-4786-972A-488A336EB2A0}', # 2.7.2rc1 '2.7.2150':'{2E295B5B-1AD4-4d36-97C2-A316084722CF}', # 2.7.2 '2.7.3121':'{1ACB88BF-1425-4f11-B664-6C89A3D7699C}', # 2.7.3rc1 + '2.7.3122':'{B12311BE-6364-4b2a-A49A-551EEE10F3E4}', # 2.7.3rc2 '2.7.3150':'{C0C31BCC-56FB-42a7-8766-D29E1BD74C7C}', # 2.7.3 '2.7.4121':'{47F45F45-72D7-4e54-AF41-26767EDE95CF}', # 2.7.4rc1 '2.7.4150':'{84ADC96C-B7E0-4938-9D6E-2B640D5DA224}', # 2.7.4 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 02:23:35 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 19 Mar 2012 02:23:35 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/22db03646d9b changeset: 75832:22db03646d9b branch: 2.7 parent: 75831:9f0bf9992664 parent: 75825:ad030571e6c0 user: Benjamin Peterson date: Sun Mar 18 21:23:22 2012 -0400 summary: merge heads files: .hgtags | 2 + Doc/faq/design.rst | 10 +- Doc/library/email.encoders.rst | 4 + Doc/library/json.rst | 8 + Doc/library/re.rst | 30 +---- Lib/test/test_queue.py | 8 +- Mac/README | 10 +- Misc/NEWS | 3 + Python/import.c | 126 +++++++++++++++----- 9 files changed, 130 insertions(+), 71 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -137,6 +137,8 @@ c1dc9e7986a2a8e1070ec7bee748520febef382e v2.6.6rc1 e189dc8fd66154ef46d9cd22584d56669b544ca3 v2.6.6rc2 9f8771e0905277f8b3c2799113a062fda4164995 v2.6.6 +caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 +1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 b4107eb00b4271fb73a9e1b736d4f23460950778 v2.7a1 adc85ebc7271cc22e24e816782bb2b8d7fa3a6b3 v2.7a2 4180557b7a9bb9dd5341a18af199f843f199e46e v2.7a3 diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -297,8 +297,9 @@ How fast are exceptions? ------------------------ -A try/except block is extremely efficient. Actually catching an exception is -expensive. In versions of Python prior to 2.0 it was common to use this idiom:: +A try/except block is extremely efficient if no exceptions are raised. Actually +catching an exception is expensive. In versions of Python prior to 2.0 it was +common to use this idiom:: try: value = mydict[key] @@ -309,11 +310,10 @@ This only made sense when you expected the dict to have the key almost all the time. If that wasn't the case, you coded it like this:: - if mydict.has_key(key): + if key in mydict: value = mydict[key] else: - mydict[key] = getvalue(key) - value = mydict[key] + value = mydict[key] = getvalue(key) .. note:: diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -18,6 +18,10 @@ payload, encode it, and reset the payload to this newly encoded value. They should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. +Note that these functions are not meaningful for a multipart message. They +must be applied to individual subparts instead, and will raise a +:exc:`TypeError` if passed a message whose type is multipart. + Here are the encoding functions provided: diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -170,6 +170,14 @@ :class:`unicode` instance. The other arguments have the same meaning as in :func:`dump`. + .. note:: + + Keys in key/value pairs of JSON are always of the type :class:`str`. When + a dictionary is converted into JSON, all the keys of the dictionary are + coerced to strings. As a result of this, if a dictionary is convered + into JSON and then back into a dictionary, the dictionary may not equal + the original one. That is, ``loads(dumps(x)) != x`` if x has non-string + keys. .. function:: load(fp[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]]) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -766,8 +766,8 @@ .. attribute:: RegexObject.flags - The flags argument used when the RE object was compiled, or ``0`` if no flags - were provided. + The regex matching flags. This is a combination of the flags given to + :func:`.compile` and any ``(?...)`` inline flags in the pattern. .. attribute:: RegexObject.groups @@ -1077,28 +1077,6 @@ (\S+) - (\d+) errors, (\d+) warnings -Avoiding recursion -^^^^^^^^^^^^^^^^^^ - -If you create regular expressions that require the engine to perform a lot of -recursion, you may encounter a :exc:`RuntimeError` exception with the message -``maximum recursion limit`` exceeded. For example, :: - - >>> s = 'Begin ' + 1000*'a very long string ' + 'end' - >>> re.match('Begin (\w| )*? end', s).end() - Traceback (most recent call last): - File "", line 1, in ? - File "/usr/local/lib/python2.5/re.py", line 132, in match - return _compile(pattern, flags).match(string) - RuntimeError: maximum recursion limit exceeded - -You can often restructure your regular expression to avoid recursion. - -Starting with Python 2.3, simple uses of the ``*?`` pattern are special-cased to -avoid recursion. Thus, the above regular expression can avoid recursion by -being recast as ``Begin [a-zA-Z0-9_ ]*?end``. As a further benefit, such -regular expressions will run faster than their recursive equivalents. - .. _search-vs-match: search() vs. match() @@ -1145,7 +1123,7 @@ First, here is the input. Normally it may come from a file, here we are using triple-quoted string syntax: - >>> input = """Ross McFluff: 834.345.1254 155 Elm Street + >>> text = """Ross McFluff: 834.345.1254 155 Elm Street ... ... Ronald Heathmore: 892.345.3428 436 Finley Avenue ... Frank Burger: 925.541.7625 662 South Dogwood Way @@ -1159,7 +1137,7 @@ .. doctest:: :options: +NORMALIZE_WHITESPACE - >>> entries = re.split("\n+", input) + >>> entries = re.split("\n+", text) >>> entries ['Ross McFluff: 834.345.1254 155 Elm Street', 'Ronald Heathmore: 892.345.3428 436 Finley Avenue', diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py --- a/Lib/test/test_queue.py +++ b/Lib/test/test_queue.py @@ -79,7 +79,7 @@ self.fail("trigger thread ended but event never set") -class BaseQueueTest(unittest.TestCase, BlockingTestMixin): +class BaseQueueTest(BlockingTestMixin): def setUp(self): self.cum = 0 self.cumlock = threading.Lock() @@ -191,13 +191,13 @@ self.simple_queue_test(q) -class QueueTest(BaseQueueTest): +class QueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.Queue -class LifoQueueTest(BaseQueueTest): +class LifoQueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.LifoQueue -class PriorityQueueTest(BaseQueueTest): +class PriorityQueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.PriorityQueue diff --git a/Mac/README b/Mac/README --- a/Mac/README +++ b/Mac/README @@ -70,7 +70,7 @@ $ make $ make install -This flag can be used a framework build of python, but also with a classic +This flag can be used with a framework build of python, but also with a classic unix build. Either way you will have to build python on Mac OS X 10.4 (or later) with Xcode 2.1 (or later). You also have to install the 10.4u SDK when installing Xcode. @@ -221,8 +221,8 @@ Go to the directory "Mac/OSX/BuildScript". There you'll find a script "build-installer.py" that does all the work. This will download and build -a number of 3th-party libaries, configures and builds a framework Python, -installs it, creates the installer pacakge files and then packs this in a +a number of 3rd-party libaries, configures and builds a framework Python, +installs it, creates the installer package files and then packs this in a DMG image. The script will build a universal binary, you'll therefore have to run this @@ -258,8 +258,8 @@ Uninstalling a framework install, including the binary installer ================================================================ -Uninstalling a framework can be done by manually removing all bits that got installed, -that's true for both installations from source and installations using the binary installer. +Uninstalling a framework can be done by manually removing all bits that got installed. +That's true for both installations from source and installations using the binary installer. Sadly enough OSX does not have a central uninstaller. The main bit of a framework install is the framework itself, installed in diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #14331: Use significantly less stack space when importing modules by + allocating path buffers on the heap instead of the stack. + - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not passed strings. Also fix segfaults in the __getattribute__ and __setattr__ methods of old-style classes. diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -996,7 +996,7 @@ { struct stat st; FILE *fpc; - char buf[MAXPATHLEN+1]; + char *buf; char *cpathname; PyCodeObject *co; PyObject *m; @@ -1015,6 +1015,10 @@ */ st.st_mtime &= 0xFFFFFFFF; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } cpathname = make_compiled_pathname(pathname, buf, (size_t)MAXPATHLEN + 1); if (cpathname != NULL && @@ -1022,9 +1026,9 @@ co = read_compiled_module(cpathname, fpc); fclose(fpc); if (co == NULL) - return NULL; + goto error_exit; if (update_compiled_module(co, pathname) < 0) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # precompiled from %s\n", name, cpathname); @@ -1033,7 +1037,7 @@ else { co = parse_source_module(pathname, fp); if (co == NULL) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # from %s\n", name, pathname); @@ -1046,7 +1050,12 @@ m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname); Py_DECREF(co); + PyMem_FREE(buf); return m; + +error_exit: + PyMem_FREE(buf); + return NULL; } @@ -1066,7 +1075,7 @@ PyObject *file = NULL; PyObject *path = NULL; int err; - char buf[MAXPATHLEN+1]; + char *buf = NULL; FILE *fp = NULL; struct filedescr *fdp; @@ -1088,8 +1097,13 @@ err = PyDict_SetItemString(d, "__path__", path); if (err != 0) goto error; + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } buf[0] = '\0'; - fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL); + fdp = find_module(name, "__init__", path, buf, MAXPATHLEN+1, &fp, NULL); if (fdp == NULL) { if (PyErr_ExceptionMatches(PyExc_ImportError)) { PyErr_Clear(); @@ -1107,6 +1121,8 @@ error: m = NULL; cleanup: + if (buf) + PyMem_FREE(buf); Py_XDECREF(path); Py_XDECREF(file); return m; @@ -1235,7 +1251,7 @@ static struct filedescr fd_frozen = {"", "", PY_FROZEN}; static struct filedescr fd_builtin = {"", "", C_BUILTIN}; static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; - char name[MAXPATHLEN+1]; + char *name; #if defined(PYOS_OS2) size_t saved_len; size_t saved_namelen; @@ -1249,6 +1265,10 @@ "module name is too long"); return NULL; } + name = PyMem_MALLOC(MAXPATHLEN+1); + if (name == NULL) { + return PyErr_NoMemory(); + } strcpy(name, subname); /* sys.meta_path import hook */ @@ -1260,7 +1280,7 @@ PyErr_SetString(PyExc_RuntimeError, "sys.meta_path must be a list of " "import hooks"); - return NULL; + goto error_exit; } Py_INCREF(meta_path); /* zap guard */ npath = PyList_Size(meta_path); @@ -1273,12 +1293,13 @@ path : Py_None); if (loader == NULL) { Py_DECREF(meta_path); - return NULL; /* true error */ + goto error_exit; /* true error */ } if (loader != Py_None) { /* a loader was found */ *p_loader = loader; Py_DECREF(meta_path); + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1292,7 +1313,7 @@ if (PyString_Size(path) + 1 + strlen(name) >= (size_t)buflen) { PyErr_SetString(PyExc_ImportError, "full frozen module name too long"); - return NULL; + goto error_exit; } strcpy(buf, PyString_AsString(path)); strcat(buf, "."); @@ -1300,19 +1321,22 @@ strcpy(name, buf); if (find_frozen(name) != NULL) { strcpy(buf, name); + PyMem_FREE(name); return &fd_frozen; } PyErr_Format(PyExc_ImportError, "No frozen submodule named %.200s", name); - return NULL; + goto error_exit; } if (path == NULL) { if (is_builtin(name)) { strcpy(buf, name); + PyMem_FREE(name); return &fd_builtin; } if ((find_frozen(name)) != NULL) { strcpy(buf, name); + PyMem_FREE(name); return &fd_frozen; } @@ -1320,6 +1344,7 @@ fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen); if (fp != NULL) { *p_fp = fp; + PyMem_FREE(name); return fdp; } #endif @@ -1328,7 +1353,7 @@ if (path == NULL || !PyList_Check(path)) { PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list of directory names"); - return NULL; + goto error_exit; } path_hooks = PySys_GetObject("path_hooks"); @@ -1336,14 +1361,14 @@ PyErr_SetString(PyExc_RuntimeError, "sys.path_hooks must be a list of " "import hooks"); - return NULL; + goto error_exit; } path_importer_cache = PySys_GetObject("path_importer_cache"); if (path_importer_cache == NULL || !PyDict_Check(path_importer_cache)) { PyErr_SetString(PyExc_RuntimeError, "sys.path_importer_cache must be a dict"); - return NULL; + goto error_exit; } npath = PyList_Size(path); @@ -1352,13 +1377,13 @@ PyObject *copy = NULL; PyObject *v = PyList_GetItem(path, i); if (!v) - return NULL; + goto error_exit; #ifdef Py_USING_UNICODE if (PyUnicode_Check(v)) { copy = PyUnicode_Encode(PyUnicode_AS_UNICODE(v), PyUnicode_GET_SIZE(v), Py_FileSystemDefaultEncoding, NULL); if (copy == NULL) - return NULL; + goto error_exit; v = copy; } else @@ -1384,7 +1409,7 @@ path_hooks, v); if (importer == NULL) { Py_XDECREF(copy); - return NULL; + goto error_exit; } /* Note: importer is a borrowed reference */ if (importer != Py_None) { @@ -1394,10 +1419,11 @@ "s", fullname); Py_XDECREF(copy); if (loader == NULL) - return NULL; /* error */ + goto error_exit; /* error */ if (loader != Py_None) { /* a loader was found */ *p_loader = loader; + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1421,6 +1447,7 @@ case_ok(buf, len, namelen, name)) { /* case matches */ if (find_init_module(buf)) { /* and has __init__.py */ Py_XDECREF(copy); + PyMem_FREE(name); return &fd_package; } else { @@ -1431,7 +1458,7 @@ if (PyErr_Warn(PyExc_ImportWarning, warnstr)) { Py_XDECREF(copy); - return NULL; + goto error_exit; } } } @@ -1506,10 +1533,15 @@ if (fp == NULL) { PyErr_Format(PyExc_ImportError, "No module named %.200s", name); - return NULL; + goto error_exit; } *p_fp = fp; + PyMem_FREE(name); return fdp; + +error_exit: + PyMem_FREE(name); + return NULL; } /* Helpers for main.c @@ -2116,7 +2148,7 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) { - char buf[MAXPATHLEN+1]; + char *buf; Py_ssize_t buflen = 0; PyObject *parent, *head, *next, *tail; @@ -2130,14 +2162,18 @@ return NULL; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } parent = get_parent(globals, buf, &buflen, level); if (parent == NULL) - return NULL; + goto error_exit; head = load_next(parent, level < 0 ? Py_None : parent, &name, buf, &buflen); if (head == NULL) - return NULL; + goto error_exit; tail = head; Py_INCREF(tail); @@ -2146,7 +2182,7 @@ Py_DECREF(tail); if (next == NULL) { Py_DECREF(head); - return NULL; + goto error_exit; } tail = next; } @@ -2158,7 +2194,7 @@ Py_DECREF(head); PyErr_SetString(PyExc_ValueError, "Empty module name"); - return NULL; + goto error_exit; } if (fromlist != NULL) { @@ -2168,16 +2204,22 @@ if (fromlist == NULL) { Py_DECREF(tail); + PyMem_FREE(buf); return head; } Py_DECREF(head); if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) { Py_DECREF(tail); - return NULL; + goto error_exit; } + PyMem_FREE(buf); return tail; + +error_exit: + PyMem_FREE(buf); + return NULL; } PyObject * @@ -2567,7 +2609,7 @@ } else { PyObject *path, *loader = NULL; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; @@ -2582,11 +2624,16 @@ } } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); if (fdp == NULL) { + PyMem_FREE(buf); if (!PyErr_ExceptionMatches(PyExc_ImportError)) return NULL; PyErr_Clear(); @@ -2601,6 +2648,7 @@ Py_XDECREF(m); m = NULL; } + PyMem_FREE(buf); } return m; @@ -2618,7 +2666,7 @@ PyObject *modules = PyImport_GetModuleDict(); PyObject *path = NULL, *loader = NULL, *existing_m = NULL; char *name, *subname; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; PyObject *newm; @@ -2678,6 +2726,11 @@ if (path == NULL) PyErr_Clear(); } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + Py_XDECREF(path); + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); @@ -2685,6 +2738,7 @@ if (fdp == NULL) { Py_XDECREF(loader); imp_modules_reloading_clear(); + PyMem_FREE(buf); return NULL; } @@ -2702,6 +2756,7 @@ PyDict_SetItemString(modules, name, m); } imp_modules_reloading_clear(); + PyMem_FREE(buf); return newm; } @@ -2832,19 +2887,27 @@ extern int fclose(FILE *); PyObject *fob, *ret; struct filedescr *fdp; - char pathname[MAXPATHLEN+1]; + char *pathname; FILE *fp = NULL; + pathname = PyMem_MALLOC(MAXPATHLEN+1); + if (pathname == NULL) { + return PyErr_NoMemory(); + } pathname[0] = '\0'; if (path == Py_None) path = NULL; fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL); - if (fdp == NULL) + if (fdp == NULL) { + PyMem_FREE(pathname); return NULL; + } if (fp != NULL) { fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose); - if (fob == NULL) + if (fob == NULL) { + PyMem_FREE(pathname); return NULL; + } } else { fob = Py_None; @@ -2853,6 +2916,7 @@ ret = Py_BuildValue("Os(ssi)", fob, pathname, fdp->suffix, fdp->mode, fdp->type); Py_DECREF(fob); + PyMem_FREE(pathname); return ret; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 03:26:16 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 19 Mar 2012 03:26:16 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_all_OSErrors_should_indicat?= =?utf8?q?e_there_are_no_extended_attributes_=28closes_=2314358=29?= Message-ID: http://hg.python.org/cpython/rev/ada766b07686 changeset: 75833:ada766b07686 parent: 75828:1e827a176306 user: Benjamin Peterson date: Sun Mar 18 22:26:05 2012 -0400 summary: all OSErrors should indicate there are no extended attributes (closes #14358) files: Lib/test/test_os.py | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1752,9 +1752,7 @@ with open(support.TESTFN, "wb") as fp: try: os.fsetxattr(fp.fileno(), b"user.test", b"") - except OSError as e: - if e.errno != errno.ENOTSUP: - raise + except OSError: return False finally: support.unlink(support.TESTFN) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 05:13:54 2012 From: python-checkins at python.org (ross.lagerwall) Date: Mon, 19 Mar 2012 05:13:54 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MzU5?= =?utf8?q?=3A_Only_use_O=5FCLOEXEC_in_=5Fposixmodule=2Ec_if_it_is_defined?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/09371e2ae84d changeset: 75834:09371e2ae84d branch: 3.2 parent: 75827:66e2dab98041 user: Ross Lagerwall date: Mon Mar 19 06:08:43 2012 +0200 summary: Issue #14359: Only use O_CLOEXEC in _posixmodule.c if it is defined. Based on patch from Herv? Coatanhay. files: Misc/ACKS | 1 + Misc/NEWS | 6 ++++++ Modules/_posixsubprocess.c | 13 ++++++++++++- 3 files changed, 19 insertions(+), 1 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -173,6 +173,7 @@ Andrew Clegg Brad Clements Steve Clift +Herv? Coatanhay Nick Coghlan Josh Cogliati Dave Cole diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -78,6 +78,12 @@ - Issue #14212: The re module didn't retain a reference to buffers it was scanning, resulting in segfaults. +Build +----- + +- Issue #14359: Only use O_CLOEXEC in _posixmodule.c if it is defined. + Based on patch from Herv? Coatanhay. + What's New in Python 3.2.3 release candidate 2? =============================================== diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -202,7 +202,18 @@ int fd_dir_fd; if (start_fd >= end_fd) return; - fd_dir_fd = open(FD_DIR, O_RDONLY | O_CLOEXEC, 0); +#ifdef O_CLOEXEC + fd_dir_fd = open(FD_DIR, O_RDONLY | O_CLOEXEC, 0); +#else + fd_dir_fd = open(FD_DIR, O_RDONLY, 0); +#ifdef FD_CLOEXEC + { + int old = fcntl(fd_dir_fd, F_GETFD); + if (old != -1) + fcntl(fd_dir_fd, F_SETFD, old | FD_CLOEXEC); + } +#endif +#endif if (fd_dir_fd == -1) { /* No way to get a list of open fds. */ _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 19 05:13:58 2012 From: python-checkins at python.org (ross.lagerwall) Date: Mon, 19 Mar 2012 05:13:58 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_with_3=2E2_for_=2314359=2E?= Message-ID: http://hg.python.org/cpython/rev/0d5fcbfd646f changeset: 75835:0d5fcbfd646f parent: 75833:ada766b07686 parent: 75834:09371e2ae84d user: Ross Lagerwall date: Mon Mar 19 06:13:13 2012 +0200 summary: Merge with 3.2 for #14359. files: Misc/ACKS | 1 + Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -188,6 +188,7 @@ Brad Clements Robbie Clemons Steve Clift +Herv? Coatanhay Nick Coghlan Josh Cogliati Dave Cole diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -129,6 +129,9 @@ Build ----- +- Issue #14359: Only use O_CLOEXEC in _posixmodule.c if it is defined. + Based on patch from Herv? Coatanhay. + - Issue #14321: Do not run pgen during the build if files are up to date. - Issue #14324: Fix configure tests for cross builds. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Mar 19 05:55:45 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 19 Mar 2012 05:55:45 +0100 Subject: [Python-checkins] Daily reference leaks (ada766b07686): sum=0 Message-ID: results for ada766b07686 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogszpTKD', '-x'] From python-checkins at python.org Mon Mar 19 13:17:15 2012 From: python-checkins at python.org (victor.stinner) Date: Mon, 19 Mar 2012 13:17:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_time=2Esteady=28=29_doc=3A_?= =?utf8?q?don=27t_repeat_the_default_value?= Message-ID: http://hg.python.org/cpython/rev/0741add59487 changeset: 75836:0741add59487 user: Victor Stinner date: Mon Mar 19 13:17:24 2012 +0100 summary: time.steady() doc: don't repeat the default value files: Doc/library/time.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -236,7 +236,7 @@ adjusted. The reference point of the returned value is undefined so only the difference of consecutive calls is valid. - If available, a monotonic clock is used. By default, if *strict* is False, + If available, a monotonic clock is used. By default, the function falls back to another clock if the monotonic clock failed or is not available. If *strict* is True, raise an :exc:`OSError` on error or :exc:`NotImplementedError` if no monotonic clock is available. -- Repository URL: http://hg.python.org/cpython From brett at python.org Mon Mar 19 15:56:02 2012 From: brett at python.org (Brett Cannon) Date: Mon, 19 Mar 2012 10:56:02 -0400 Subject: [Python-checkins] cpython: Issue #14347: Update Misc/README list of files. In-Reply-To: References: Message-ID: The two files that were added back in should probably just disappear (README.aix and README.coverty). Anyone disagree? On Sat, Mar 17, 2012 at 13:52, ned.deily wrote: > http://hg.python.org/cpython/rev/65a0a6fab127 > changeset: 75797:65a0a6fab127 > user: Ned Deily > date: Sat Mar 17 10:52:08 2012 -0700 > summary: > Issue #14347: Update Misc/README list of files. > (Initial patch by Dionysios Kalofonos) > > files: > Misc/README | 3 ++- > 1 files changed, 2 insertions(+), 1 deletions(-) > > > diff --git a/Misc/README b/Misc/README > --- a/Misc/README > +++ b/Misc/README > @@ -8,7 +8,6 @@ > ---------------- > > ACKS Acknowledgements > -build.sh Script to build and test latest Python from the > repository > gdbinit Handy stuff to put in your .gdbinit file, if you > use gdb > HISTORY News from previous releases -- oldest last > indent.pro GNU indent profile approximating my C style > @@ -19,6 +18,8 @@ > python.pc.in Package configuration info template for > pkg-config > python-wing*.wpr Wing IDE project file > README The file you're reading now > +README.AIX Information about using Python on AIX > +README.coverity Information about running Coverity's Prevent on > Python > README.valgrind Information for Valgrind users, see > valgrind-python.supp > RPM (Old) tools to build RPMs > svnmap.txt Map of old SVN revs and branches to hg changeset > ids > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From eric at trueblade.com Mon Mar 19 16:19:10 2012 From: eric at trueblade.com (Eric V. Smith) Date: Mon, 19 Mar 2012 11:19:10 -0400 Subject: [Python-checkins] cpython: time.steady() doc: don't repeat the default value In-Reply-To: References: Message-ID: <4F674E6E.4040800@trueblade.com> On 03/19/2012 08:17 AM, victor.stinner wrote: > http://hg.python.org/cpython/rev/0741add59487 > changeset: 75836:0741add59487 > user: Victor Stinner > date: Mon Mar 19 13:17:24 2012 +0100 > summary: > time.steady() doc: don't repeat the default value > > files: > Doc/library/time.rst | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > > diff --git a/Doc/library/time.rst b/Doc/library/time.rst > --- a/Doc/library/time.rst > +++ b/Doc/library/time.rst > @@ -236,7 +236,7 @@ > adjusted. The reference point of the returned value is undefined so only the > difference of consecutive calls is valid. > > - If available, a monotonic clock is used. By default, if *strict* is False, > + If available, a monotonic clock is used. By default, > the function falls back to another clock if the monotonic clock failed or is > not available. If *strict* is True, raise an :exc:`OSError` on error or > :exc:`NotImplementedError` if no monotonic clock is available. I still think this is not a great phrasing. Why use "by default", instead of "if strict is False"? My concern is that to me "time.steady(False)" doesn't appear to be using any default value, yet the "By default" part of the sentence applies. Eric. From jimjjewett at gmail.com Mon Mar 19 22:01:19 2012 From: jimjjewett at gmail.com (Jim Jewett) Date: Mon, 19 Mar 2012 17:01:19 -0400 Subject: [Python-checkins] cpython (2.7): Fixes Issue 14234: fix for the previous commit, keep compilation when In-Reply-To: References: Message-ID: Does this mean that if Python is updated before expat, python will compile out the expat randomization, and therefore not use if even after expat is updated? -jJ On Thu, Mar 15, 2012 at 2:01 PM, benjamin.peterson wrote: > http://hg.python.org/cpython/rev/ada6bfbeceb8 > changeset: ? 75699:ada6bfbeceb8 > branch: ? ? ?2.7 > user: ? ? ? ?Gregory P. Smith > date: ? ? ? ?Wed Mar 14 18:12:23 2012 -0700 > summary: > ?Fixes Issue 14234: fix for the previous commit, keep compilation when > using --with-system-expat working when the system expat does not have > salted hash support. > > files: > ?Modules/expat/expat.h | ?2 ++ > ?Modules/pyexpat.c ? ? | ?5 +++++ > ?2 files changed, 7 insertions(+), 0 deletions(-) > > > diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h > --- a/Modules/expat/expat.h > +++ b/Modules/expat/expat.h > @@ -892,6 +892,8 @@ > ?XML_SetHashSalt(XML_Parser parser, > ? ? ? ? ? ? ? ? unsigned long hash_salt); > > +#define XML_HAS_SET_HASH_SALT ?/* Python Only: Defined for pyexpat.c. */ > + > ?/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then > ? ?XML_GetErrorCode returns information about the error. > ?*/ > diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c > --- a/Modules/pyexpat.c > +++ b/Modules/pyexpat.c > @@ -1302,8 +1302,13 @@ > ? ? else { > ? ? ? ? self->itself = XML_ParserCreate(encoding); > ? ? } > +#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) > + ? ?/* This feature was added upstream in libexpat 2.1.0. ?Our expat copy > + ? ? * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT > + ? ? * to indicate that we can still use it. */ > ? ? XML_SetHashSalt(self->itself, > ? ? ? ? ? ? ? ? ? ? (unsigned long)_Py_HashSecret.prefix); > +#endif > ? ? self->intern = intern; > ? ? Py_XINCREF(self->intern); > ?#ifdef Py_TPFLAGS_HAVE_GC > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > From benjamin at python.org Mon Mar 19 22:03:37 2012 From: benjamin at python.org (Benjamin Peterson) Date: Mon, 19 Mar 2012 16:03:37 -0500 Subject: [Python-checkins] cpython (2.7): Fixes Issue 14234: fix for the previous commit, keep compilation when In-Reply-To: References: Message-ID: 2012/3/19 Jim Jewett : > Does this mean that if Python is updated before expat, python will > compile out the expat randomization, and therefore not use if even > after expat is updated? If you're using --with-system-expat -- Regards, Benjamin From solipsis at pitrou.net Tue Mar 20 05:44:21 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 20 Mar 2012 05:44:21 +0100 Subject: [Python-checkins] Daily reference leaks (0741add59487): sum=0 Message-ID: results for 0741add59487 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog4WESyg', '-x'] From python-checkins at python.org Tue Mar 20 15:41:13 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 20 Mar 2012 15:41:13 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_merge_tag?= Message-ID: http://hg.python.org/cpython/rev/48172fcea164 changeset: 75837:48172fcea164 branch: 2.7 parent: 75830:e6061a297db7 parent: 75702:32d54230e010 user: Benjamin Peterson date: Tue Mar 20 10:40:26 2012 -0400 summary: merge tag files: .hgtags | 1 + Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 2 +- Misc/RPM/python-2.7.spec | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -151,3 +151,4 @@ f48756685406e8d0fa9d23d841fceb07e36a5656 v2.7.2rc1 8527427914a29d895bcb30be76a465143993a793 v2.7.2 b2c6aff96e1251a4f03cf866e7e75fb8232869f2 v2.7.3rc1 +d46c1973d3c407ecaa6a8ee16d3fad3ef506b51f v2.7.3rc2 diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -24,10 +24,10 @@ #define PY_MINOR_VERSION 7 #define PY_MICRO_VERSION 3 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "2.7.3rc1" +#define PY_VERSION "2.7.3rc2" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -15,5 +15,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "2.7.3rc1" +__version__ = "2.7.3rc2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "2.7.3rc1" +IDLE_VERSION = "2.7.3rc2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,7 +5,7 @@ What's New in Python 2.7.3 release candidate 2? =============================================== -*Release date: 2012-03-XX* +*Release date: 2012-03-17* Library ------- diff --git a/Misc/RPM/python-2.7.spec b/Misc/RPM/python-2.7.spec --- a/Misc/RPM/python-2.7.spec +++ b/Misc/RPM/python-2.7.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 2.7.3rc1 +%define version 2.7.3rc2 %define libvers 2.7 #--end constants-- %define release 1pydotorg -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 20 15:41:14 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 20 Mar 2012 15:41:14 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_merge_from_release_branch?= Message-ID: http://hg.python.org/cpython/rev/44a8385a8241 changeset: 75838:44a8385a8241 branch: 2.7 parent: 75832:22db03646d9b parent: 75837:48172fcea164 user: Benjamin Peterson date: Tue Mar 20 10:40:55 2012 -0400 summary: merge from release branch files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 20 16:44:36 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Tue, 20 Mar 2012 16:44:36 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_issue_=2313694=3A_async?= =?utf8?q?hronous_connect_in_asyncore=2Edispatcher_does_not_set_addr=2E?= Message-ID: http://hg.python.org/cpython/rev/1c0058991740 changeset: 75839:1c0058991740 parent: 75836:0741add59487 user: Giampaolo Rodola' date: Tue Mar 20 16:44:24 2012 +0100 summary: Fix issue #13694: asynchronous connect in asyncore.dispatcher does not set addr. files: Lib/asyncore.py | 1 + Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -337,6 +337,7 @@ err = self.socket.connect_ex(address) if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ or err == EINVAL and os.name in ('nt', 'ce'): + self.addr = address return if err in (0, EISCONN): self.addr = address diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,9 @@ Library ------- +- Issue #13694: asynchronous connect in asyncore.dispatcher does not set addr + attribute. + - Issue #14344: fixed the repr of email.policy objects. - Issue #11686: Added missing entries to email package __all__ lists -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 20 16:47:02 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Tue, 20 Mar 2012 16:47:02 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Fix_issue_=2313?= =?utf8?q?694=3A_asynchronous_connect_in_asyncore=2Edispatcher_does_not_se?= =?utf8?q?t_addr=2E?= Message-ID: http://hg.python.org/cpython/rev/4e5ddde76dbe changeset: 75840:4e5ddde76dbe branch: 2.7 parent: 75838:44a8385a8241 user: Giampaolo Rodola' date: Tue Mar 20 16:46:57 2012 +0100 summary: Fix issue #13694: asynchronous connect in asyncore.dispatcher does not set addr. files: Lib/asyncore.py | 1 + Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -345,6 +345,7 @@ err = self.socket.connect_ex(address) if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ or err == EINVAL and os.name in ('nt', 'ce'): + self.addr = address return if err in (0, EISCONN): self.addr = address diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ Library ------- +- Issue #13694: asynchronous connect in asyncore.dispatcher does not set addr + attribute. + - Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem. - Issue #11199: Fix the with urllib which hangs on particular ftp urls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 20 16:50:04 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Tue, 20 Mar 2012 16:50:04 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_issue_=2313?= =?utf8?q?694=3A_asynchronous_connect_in_asyncore=2Edispatcher_does_not_se?= =?utf8?q?t_addr=2E?= Message-ID: http://hg.python.org/cpython/rev/a5add01e96be changeset: 75841:a5add01e96be branch: 3.2 parent: 75834:09371e2ae84d user: Giampaolo Rodola' date: Tue Mar 20 16:49:55 2012 +0100 summary: Fix issue #13694: asynchronous connect in asyncore.dispatcher does not set addr. files: Lib/asyncore.py | 1 + Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -345,6 +345,7 @@ err = self.socket.connect_ex(address) if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ or err == EINVAL and os.name in ('nt', 'ce'): + self.addr = address return if err in (0, EISCONN): self.addr = address diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,9 @@ Library ------- +- Issue #13694: asynchronous connect in asyncore.dispatcher does not set addr + attribute. + - Issue #11686: Added missing entries to email package __all__ lists (mostly the new Bytes classes). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 20 21:06:28 2012 From: python-checkins at python.org (larry.hastings) Date: Tue, 20 Mar 2012 21:06:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314328=3A_Add_keywo?= =?utf8?q?rd-only_parameters_to_PyArg=5FParseTupleAndKeywords=2E?= Message-ID: http://hg.python.org/cpython/rev/052779d34945 changeset: 75842:052779d34945 parent: 75839:1c0058991740 user: Larry Hastings date: Tue Mar 20 20:06:16 2012 +0000 summary: Issue #14328: Add keyword-only parameters to PyArg_ParseTupleAndKeywords. They're optional-only for now (unlike in pure Python) but that's all I needed. The syntax can easily be relaxed if we want to support required keyword-only arguments for extension types in the future. files: Doc/c-api/arg.rst | 9 +++ Lib/test/test_getargs2.py | 74 ++++++++++++++++++++++++++- Modules/_testcapimodule.c | 20 ++++++- Python/getargs.c | 34 ++++++++++++- 4 files changed, 134 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -338,6 +338,15 @@ :c:func:`PyArg_ParseTuple` does not touch the contents of the corresponding C variable(s). +``$`` + :c:func:`PyArg_ParseTupleAndKeywords` only: + Indicates that the remaining arguments in the Python argument list are + keyword-only. Currently, all keyword-only arguments must also be optional + arguments, so ``|`` must always be specified before ``$`` in the format + string. + + .. versionadded:: 3.3 + ``:`` The list of format units ends here; the string after the colon is used as the function name in error messages (the "associated value" of the exception that diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -1,6 +1,6 @@ import unittest from test import support -from _testcapi import getargs_keywords +from _testcapi import getargs_keywords, getargs_keyword_only """ > How about the following counterproposal. This also changes some of @@ -293,6 +293,77 @@ else: self.fail('TypeError should have been raised') +class KeywordOnly_TestCase(unittest.TestCase): + def test_positional_args(self): + # using all possible positional args + self.assertEqual( + getargs_keyword_only(1, 2), + (1, 2, -1) + ) + + def test_mixed_args(self): + # positional and keyword args + self.assertEqual( + getargs_keyword_only(1, 2, keyword_only=3), + (1, 2, 3) + ) + + def test_keyword_args(self): + # all keywords + self.assertEqual( + getargs_keyword_only(required=1, optional=2, keyword_only=3), + (1, 2, 3) + ) + + def test_optional_args(self): + # missing optional keyword args, skipping tuples + self.assertEqual( + getargs_keyword_only(required=1, optional=2), + (1, 2, -1) + ) + self.assertEqual( + getargs_keyword_only(required=1, keyword_only=3), + (1, -1, 3) + ) + + def test_required_args(self): + self.assertEqual( + getargs_keyword_only(1), + (1, -1, -1) + ) + self.assertEqual( + getargs_keyword_only(required=1), + (1, -1, -1) + ) + # required arg missing + with self.assertRaisesRegex(TypeError, + "Required argument 'required' \(pos 1\) not found"): + getargs_keyword_only(optional=2) + + with self.assertRaisesRegex(TypeError, + "Required argument 'required' \(pos 1\) not found"): + getargs_keyword_only(keyword_only=3) + + def test_too_many_args(self): + with self.assertRaisesRegex(TypeError, + "Function takes at most 2 positional arguments \(3 given\)"): + getargs_keyword_only(1, 2, 3) + + with self.assertRaisesRegex(TypeError, + "function takes at most 3 arguments \(4 given\)"): + getargs_keyword_only(1, 2, 3, keyword_only=5) + + def test_invalid_keyword(self): + # extraneous keyword arg + with self.assertRaisesRegex(TypeError, + "'monster' is an invalid keyword argument for this function"): + getargs_keyword_only(1, 2, monster=666) + + def test_surrogate_keyword(self): + with self.assertRaisesRegex(TypeError, + "'\udc80' is an invalid keyword argument for this function"): + getargs_keyword_only(1, 2, **{'\uDC80': 10}) + class Bytes_TestCase(unittest.TestCase): def test_c(self): from _testcapi import getargs_c @@ -441,6 +512,7 @@ Unsigned_TestCase, Tuple_TestCase, Keywords_TestCase, + KeywordOnly_TestCase, Bytes_TestCase, Unicode_TestCase, ] diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -801,7 +801,8 @@ } /* test PyArg_ParseTupleAndKeywords */ -static PyObject *getargs_keywords(PyObject *self, PyObject *args, PyObject *kwargs) +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"; @@ -816,6 +817,21 @@ int_args[5], int_args[6], int_args[7], int_args[8], int_args[9]); } +/* test PyArg_ParseTupleAndKeywords keyword-only arguments */ +static PyObject * +getargs_keyword_only(PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *keywords[] = {"required", "optional", "keyword_only", NULL}; + int required = -1; + int optional = -1; + int keyword_only = -1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i$i", keywords, + &required, &optional, &keyword_only)) + return NULL; + return Py_BuildValue("iii", required, optional, keyword_only); +} + /* Functions to call PyArg_ParseTuple with integer format codes, and return the result. */ @@ -2400,6 +2416,8 @@ {"getargs_tuple", getargs_tuple, METH_VARARGS}, {"getargs_keywords", (PyCFunction)getargs_keywords, METH_VARARGS|METH_KEYWORDS}, + {"getargs_keyword_only", (PyCFunction)getargs_keyword_only, + METH_VARARGS|METH_KEYWORDS}, {"getargs_b", getargs_b, METH_VARARGS}, {"getargs_B", getargs_B, METH_VARARGS}, {"getargs_h", getargs_h, METH_VARARGS}, diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1403,6 +1403,7 @@ int levels[32]; const char *fname, *msg, *custom_msg, *keyword; int min = INT_MAX; + int max = INT_MAX; int i, len, nargs, nkeywords; PyObject *current_arg; freelist_t freelist = {0, NULL}; @@ -1452,8 +1453,39 @@ for (i = 0; i < len; i++) { keyword = kwlist[i]; if (*format == '|') { + if (min != INT_MAX) { + PyErr_SetString(PyExc_RuntimeError, + "Invalid format string (| specified twice)"); + return cleanreturn(0, &freelist); + } + min = i; format++; + + if (max != INT_MAX) { + PyErr_SetString(PyExc_RuntimeError, + "Invalid format string ($ before |)"); + return cleanreturn(0, &freelist); + } + } + if (*format == '$') { + if (max != INT_MAX) { + PyErr_SetString(PyExc_RuntimeError, + "Invalid format string ($ specified twice)"); + return cleanreturn(0, &freelist); + } + + max = i; + format++; + + if (max < nargs) { + PyErr_Format(PyExc_TypeError, + "Function takes %s %d positional arguments" + " (%d given)", + (min != INT_MAX) ? "at most" : "exactly", + max, nargs); + return cleanreturn(0, &freelist); + } } if (IS_END_OF_FORMAT(*format)) { PyErr_Format(PyExc_RuntimeError, @@ -1514,7 +1546,7 @@ } } - if (!IS_END_OF_FORMAT(*format) && *format != '|') { + if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) { PyErr_Format(PyExc_RuntimeError, "more argument specifiers than keyword list entries " "(remaining format:'%s')", format); -- Repository URL: http://hg.python.org/cpython From benjamin at python.org Tue Mar 20 21:09:04 2012 From: benjamin at python.org (Benjamin Peterson) Date: Tue, 20 Mar 2012 16:09:04 -0400 Subject: [Python-checkins] cpython: Issue #14328: Add keyword-only parameters to PyArg_ParseTupleAndKeywords. In-Reply-To: References: Message-ID: 2012/3/20 larry.hastings : > http://hg.python.org/cpython/rev/052779d34945 > changeset: ? 75842:052779d34945 > parent: ? ? ?75839:1c0058991740 > user: ? ? ? ?Larry Hastings > date: ? ? ? ?Tue Mar 20 20:06:16 2012 +0000 > summary: > ?Issue #14328: Add keyword-only parameters to PyArg_ParseTupleAndKeywords. > > They're optional-only for now (unlike in pure Python) but that's all > I needed. ?The syntax can easily be relaxed if we want to support > required keyword-only arguments for extension types in the future. > > files: > ?Doc/c-api/arg.rst ? ? ? ? | ? 9 +++ > ?Lib/test/test_getargs2.py | ?74 ++++++++++++++++++++++++++- > ?Modules/_testcapimodule.c | ?20 ++++++- > ?Python/getargs.c ? ? ? ? ?| ?34 ++++++++++++- > ?4 files changed, 134 insertions(+), 3 deletions(-) Forgot about Misc/NEWS? -- Regards, Benjamin From python-checkins at python.org Tue Mar 20 21:10:44 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 20 Mar 2012 21:10:44 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/f1e1b32d6301 changeset: 75843:f1e1b32d6301 parent: 75842:052779d34945 parent: 75841:a5add01e96be user: Benjamin Peterson date: Tue Mar 20 16:10:36 2012 -0400 summary: merge 3.2 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 20 21:16:49 2012 From: python-checkins at python.org (r.david.murray) Date: Tue, 20 Mar 2012 21:16:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=2314269=3A_smtpd_now_confo?= =?utf8?q?rms_to_the_RFC_and_requires_HELO_before_MAIL=2E?= Message-ID: http://hg.python.org/cpython/rev/241c33b6cb95 changeset: 75844:241c33b6cb95 user: R David Murray date: Tue Mar 20 16:16:29 2012 -0400 summary: #14269: smtpd now conforms to the RFC and requires HELO before MAIL. This is a backward incompatible change, but since it is an RFC conformance bug and all real mail servers that I know of do conform to the RFC in this regard, I believe it is an acceptable change for a feature release. Patch by Jason Killen. files: Lib/smtpd.py | 12 +++++++ Lib/test/test_smtpd.py | 48 +++++++++++++++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + 4 files changed, 63 insertions(+), 1 deletions(-) diff --git a/Lib/smtpd.py b/Lib/smtpd.py --- a/Lib/smtpd.py +++ b/Lib/smtpd.py @@ -374,6 +374,10 @@ return address def smtp_MAIL(self, arg): + if not self.seen_greeting: + self.push('503 Error: send HELO first'); + return + print('===> MAIL', arg, file=DEBUGSTREAM) address = self.__getaddr('FROM:', arg) if arg else None if not address: @@ -387,6 +391,10 @@ self.push('250 Ok') def smtp_RCPT(self, arg): + if not self.seen_greeting: + self.push('503 Error: send HELO first'); + return + print('===> RCPT', arg, file=DEBUGSTREAM) if not self.mailfrom: self.push('503 Error: need MAIL command') @@ -411,6 +419,10 @@ self.push('250 Ok') def smtp_DATA(self, arg): + if not self.seen_greeting: + self.push('503 Error: send HELO first'); + return + if not self.rcpttos: self.push('503 Error: need RCPT command') return diff --git a/Lib/test/test_smtpd.py b/Lib/test/test_smtpd.py --- a/Lib/test/test_smtpd.py +++ b/Lib/test/test_smtpd.py @@ -39,6 +39,7 @@ channel.socket.queue_recv(line) channel.handle_read() + write_line(b'HELO test.example') write_line(b'MAIL From:eggs at example') write_line(b'RCPT To:spam at example') write_line(b'DATA') @@ -104,6 +105,11 @@ self.write_line(b'NOOP') self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') + def test_HELO_NOOP(self): + self.write_line(b'HELO example') + self.write_line(b'NOOP') + self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') + def test_NOOP_bad_syntax(self): self.write_line(b'NOOP hi') self.assertEqual(self.channel.socket.last, @@ -113,17 +119,23 @@ self.write_line(b'QUIT') self.assertEqual(self.channel.socket.last, b'221 Bye\r\n') + def test_HELO_QUIT(self): + self.write_line(b'HELO example') + self.write_line(b'QUIT') + self.assertEqual(self.channel.socket.last, b'221 Bye\r\n') + def test_QUIT_arg_ignored(self): self.write_line(b'QUIT bye bye') self.assertEqual(self.channel.socket.last, b'221 Bye\r\n') def test_bad_state(self): self.channel.smtp_state = 'BAD STATE' - self.write_line(b'HELO') + self.write_line(b'HELO example') self.assertEqual(self.channel.socket.last, b'451 Internal confusion\r\n') def test_command_too_long(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from ' + b'a' * self.channel.command_size_limit + b'@example') @@ -133,6 +145,7 @@ def test_data_too_long(self): # Small hack. Setting limit to 2K octets here will save us some time. self.channel.data_size_limit = 2048 + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'DATA') @@ -142,43 +155,61 @@ b'552 Error: Too much mail data\r\n') def test_need_MAIL(self): + self.write_line(b'HELO example') self.write_line(b'RCPT to:spam at example') self.assertEqual(self.channel.socket.last, b'503 Error: need MAIL command\r\n') def test_MAIL_syntax(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from eggs at example') self.assertEqual(self.channel.socket.last, b'501 Syntax: MAIL FROM:
\r\n') def test_MAIL_missing_from(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from:') self.assertEqual(self.channel.socket.last, b'501 Syntax: MAIL FROM:
\r\n') def test_MAIL_chevrons(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from:') self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') def test_nested_MAIL(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from:eggs at example') self.write_line(b'MAIL from:spam at example') self.assertEqual(self.channel.socket.last, b'503 Error: nested MAIL command\r\n') + def test_no_HELO_MAIL(self): + self.write_line(b'MAIL from:') + self.assertEqual(self.channel.socket.last, + b'503 Error: send HELO first\r\n') + def test_need_RCPT(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'DATA') self.assertEqual(self.channel.socket.last, b'503 Error: need RCPT command\r\n') def test_RCPT_syntax(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT to eggs at example') self.assertEqual(self.channel.socket.last, b'501 Syntax: RCPT TO:
\r\n') + def test_no_HELO_RCPT(self): + self.write_line(b'RCPT to eggs at example') + self.assertEqual(self.channel.socket.last, + b'503 Error: send HELO first\r\n') + def test_data_dialog(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') self.write_line(b'RCPT To:spam at example') @@ -193,12 +224,19 @@ [('peer', 'eggs at example', ['spam at example'], 'data\nmore')]) def test_DATA_syntax(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'DATA spam') self.assertEqual(self.channel.socket.last, b'501 Syntax: DATA\r\n') + def test_no_HELO_DATA(self): + self.write_line(b'DATA spam') + self.assertEqual(self.channel.socket.last, + b'503 Error: send HELO first\r\n') + def test_data_transparency_section_4_5_2(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'DATA') @@ -206,6 +244,7 @@ self.assertEqual(self.channel.received_data, '.') def test_multiple_RCPT(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'RCPT To:ham at example') @@ -216,6 +255,7 @@ def test_manual_status(self): # checks that the Channel is able to return a custom status message + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'DATA') @@ -223,6 +263,7 @@ self.assertEqual(self.channel.socket.last, b'250 Okish\r\n') def test_RSET(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'RSET') @@ -234,6 +275,11 @@ self.assertEqual(self.server.messages, [('peer', 'foo at example', ['eggs at example'], 'data')]) + def test_HELO_RSET(self): + self.write_line(b'HELO example') + self.write_line(b'RSET') + self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') + def test_RSET_syntax(self): self.write_line(b'RSET hi') self.assertEqual(self.channel.socket.last, b'501 Syntax: RSET\r\n') diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -531,6 +531,7 @@ Lawrence Kesteloot Vivek Khera Mads Kiilerich +Jason Killen Taek Joo Kim W. Trevor King Paul Kippes diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,9 @@ Library ------- +- Issue #14269: SMTPD now conforms to the RFC and requires a HELO command + before MAIL, RCPT, or DATA. + - Issue #13694: asynchronous connect in asyncore.dispatcher does not set addr attribute. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 20 22:04:54 2012 From: python-checkins at python.org (andrew.svetlov) Date: Tue, 20 Mar 2012 22:04:54 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=233573=3A_idle_now_doesn?= =?utf8?q?=27t_hungs_if_launched_as=3A_idle_-e_=3Cdirectory=3E?= Message-ID: http://hg.python.org/cpython/rev/01404295138d changeset: 75845:01404295138d user: Andrew Svetlov date: Tue Mar 20 23:03:26 2012 +0200 summary: #3573: idle now doesn't hungs if launched as: idle -e Patch by Guilherme Polo. files: Lib/idlelib/PyShell.py | 6 ++++-- Misc/NEWS | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1403,8 +1403,10 @@ if enable_edit: if not (cmd or script): - for filename in args: - flist.open(filename) + for filename in args[:]: + if flist.open(filename) is None: + # filename is a directory actually, disconsider it + args.remove(filename) if not args: flist.new() if enable_shell: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)) + + Thanks to Guilherme Polo for patch and to Roger Serwy for review. + - Issue #1683368: object.__new__ and object.__init__ raise a TypeError if they are passed arguments and their complementary method is not overridden. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Mar 21 05:45:25 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 21 Mar 2012 05:45:25 +0100 Subject: [Python-checkins] Daily reference leaks (01404295138d): sum=0 Message-ID: results for 01404295138d on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogIjjZR4', '-x'] From python-checkins at python.org Wed Mar 21 12:32:11 2012 From: python-checkins at python.org (andrew.svetlov) Date: Wed, 21 Mar 2012 12:32:11 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzM1NzM6IGlkbGUg?= =?utf8?q?now_doesn=27t_hungs_if_launched_as=3A_idle_-e_=3Cdirectory=3E?= Message-ID: http://hg.python.org/cpython/rev/a95b19b3b4cd changeset: 75846:a95b19b3b4cd branch: 3.2 parent: 75841:a5add01e96be user: Andrew Svetlov date: Wed Mar 21 13:23:41 2012 +0200 summary: #3573: idle now doesn't hungs if launched as: idle -e Patch by Guilherme Polo. files: Lib/idlelib/NEWS.txt | 7 +++++++ Lib/idlelib/PyShell.py | 6 ++++-- Misc/NEWS | 3 +++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,3 +1,10 @@ +What's New in IDLE 3.2.3? +========================= + +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)). + + What's New in IDLE 3.2.1? ========================= diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1389,8 +1389,10 @@ if enable_edit: if not (cmd or script): - for filename in args: - flist.open(filename) + for filename in args[:]: + if flist.open(filename) is None: + # filename is a directory actually, disconsider it + args.remove(filename) if not args: flist.new() if enable_shell: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,9 @@ Library ------- +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)) (Patch by Guilherme Polo) + - Issue #13694: asynchronous connect in asyncore.dispatcher does not set addr attribute. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 12:32:12 2012 From: python-checkins at python.org (andrew.svetlov) Date: Wed, 21 Mar 2012 12:32:12 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_from_3=2E2_for_issue_=233573=2C_fix_Misc/NEWS_as_Ned_D?= =?utf8?q?eily_guess=2E?= Message-ID: http://hg.python.org/cpython/rev/cdcd1f7f0882 changeset: 75847:cdcd1f7f0882 parent: 75845:01404295138d parent: 75846:a95b19b3b4cd user: Andrew Svetlov date: Wed Mar 21 13:31:12 2012 +0200 summary: Merge from 3.2 for issue #3573, fix Misc/NEWS as Ned Deily guess. files: Lib/idlelib/NEWS.txt | 7 +++++++ Misc/NEWS | 8 +++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,3 +1,10 @@ +What's New in IDLE 3.2.3? +========================= + +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)). + + What's New in IDLE 3.2.1? ========================= diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,11 +10,6 @@ Core and Builtins ----------------- -- Issue #3573: IDLE hangs when passing invalid command line args - (directory(ies) instead of file(s)) - - Thanks to Guilherme Polo for patch and to Roger Serwy for review. - - Issue #1683368: object.__new__ and object.__init__ raise a TypeError if they are passed arguments and their complementary method is not overridden. @@ -35,6 +30,9 @@ Library ------- +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)) (Patch by Guilherme Polo) + - Issue #14269: SMTPD now conforms to the RFC and requires a HELO command before MAIL, RCPT, or DATA. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 12:36:08 2012 From: python-checkins at python.org (andrew.svetlov) Date: Wed, 21 Mar 2012 12:36:08 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzM1NzM6IGlkbGUg?= =?utf8?q?now_doesn=27t_hungs_if_launched_as=3A_idle_-e_=3Cdirectory=3E?= Message-ID: http://hg.python.org/cpython/rev/a9be863e5734 changeset: 75848:a9be863e5734 branch: 2.7 parent: 75840:4e5ddde76dbe user: Andrew Svetlov date: Wed Mar 21 13:35:08 2012 +0200 summary: #3573: idle now doesn't hungs if launched as: idle -e Patch by Guilherme Polo. files: Lib/idlelib/NEWS.txt | 7 +++++++ Lib/idlelib/PyShell.py | 6 ++++-- Misc/NEWS | 3 +++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,3 +1,10 @@ +What's New in IDLE 2.7.3? +======================= + +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)). + + What's New in IDLE 2.7.2? ======================= diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1412,8 +1412,10 @@ if enable_edit: if not (cmd or script): - for filename in args: - flist.open(filename) + for filename in args[:]: + if flist.open(filename) is None: + # filename is a directory actually, disconsider it + args.remove(filename) if not args: flist.new() if enable_shell: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ Library ------- +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)) (Patch by Guilherme Polo) + - Issue #13694: asynchronous connect in asyncore.dispatcher does not set addr attribute. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 12:58:43 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Wed, 21 Mar 2012 12:58:43 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_non-existing_file_fr?= =?utf8?q?om_pythoncore_project=2E?= Message-ID: http://hg.python.org/cpython/rev/57805d15cc4f changeset: 75849:57805d15cc4f parent: 75847:cdcd1f7f0882 user: krisvale date: Wed Mar 21 11:37:09 2012 +0000 summary: Remove non-existing file from pythoncore project. files: PCbuild/pythoncore.vcproj | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/PCbuild/pythoncore.vcproj b/PCbuild/pythoncore.vcproj --- a/PCbuild/pythoncore.vcproj +++ b/PCbuild/pythoncore.vcproj @@ -735,10 +735,6 @@ > - - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 18:27:55 2012 From: python-checkins at python.org (stefan.krah) Date: Wed, 21 Mar 2012 18:27:55 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=237652=3A_Integrate_?= =?utf8?q?the_decimal_floating_point_libmpdec_library_to_speed?= Message-ID: http://hg.python.org/cpython/rev/7355550d5357 changeset: 75850:7355550d5357 user: Stefan Krah date: Wed Mar 21 18:25:23 2012 +0100 summary: Issue #7652: Integrate the decimal floating point libmpdec library to speed up the decimal module. Performance gains of the new C implementation are between 12x and 80x, depending on the application. files: Doc/library/decimal.rst | 178 +- Doc/library/numeric.rst | 6 +- Doc/whatsnew/3.3.rst | 87 + Include/longintrepr.h | 2 +- Lib/decimal.py | 196 +- Lib/test/support.py | 4 +- Lib/test/test_decimal.py | 4550 ++++- Lib/test/test_fractions.py | 12 +- Lib/test/test_numeric_tower.py | 2 +- Misc/NEWS | 4 + Misc/valgrind-python.supp | 13 + Modules/_decimal/ISSUES.txt | 56 + Modules/_decimal/README.txt | 46 + Modules/_decimal/_decimal.c | 5512 +++++++ Modules/_decimal/docstrings.h | 753 + Modules/_decimal/libmpdec/README.txt | 90 + Modules/_decimal/libmpdec/basearith.c | 635 + Modules/_decimal/libmpdec/basearith.h | 213 + Modules/_decimal/libmpdec/bits.h | 192 + Modules/_decimal/libmpdec/constants.c | 132 + Modules/_decimal/libmpdec/constants.h | 83 + Modules/_decimal/libmpdec/context.c | 286 + Modules/_decimal/libmpdec/convolute.c | 174 + Modules/_decimal/libmpdec/convolute.h | 43 + Modules/_decimal/libmpdec/crt.c | 179 + Modules/_decimal/libmpdec/crt.h | 40 + Modules/_decimal/libmpdec/difradix2.c | 173 + Modules/_decimal/libmpdec/difradix2.h | 41 + Modules/_decimal/libmpdec/fnt.c | 81 + Modules/_decimal/libmpdec/fnt.h | 42 + Modules/_decimal/libmpdec/fourstep.c | 255 + Modules/_decimal/libmpdec/fourstep.h | 41 + Modules/_decimal/libmpdec/io.c | 1575 ++ Modules/_decimal/libmpdec/io.h | 59 + Modules/_decimal/libmpdec/literature/REFERENCES.txt | 51 + Modules/_decimal/libmpdec/literature/bignum.txt | 83 + Modules/_decimal/libmpdec/literature/fnt.py | 208 + Modules/_decimal/libmpdec/literature/matrix-transform.txt | 256 + Modules/_decimal/libmpdec/literature/mulmod-64.txt | 127 + Modules/_decimal/libmpdec/literature/mulmod-ppro.txt | 269 + Modules/_decimal/libmpdec/literature/six-step.txt | 63 + Modules/_decimal/libmpdec/literature/umodarith.lisp | 692 + Modules/_decimal/libmpdec/memory.c | 292 + Modules/_decimal/libmpdec/memory.h | 44 + Modules/_decimal/libmpdec/mpdecimal.c | 7596 ++++++++++ Modules/_decimal/libmpdec/mpdecimal.h | 800 + Modules/_decimal/libmpdec/numbertheory.c | 132 + Modules/_decimal/libmpdec/numbertheory.h | 71 + Modules/_decimal/libmpdec/sixstep.c | 212 + Modules/_decimal/libmpdec/sixstep.h | 41 + Modules/_decimal/libmpdec/transpose.c | 276 + Modules/_decimal/libmpdec/transpose.h | 55 + Modules/_decimal/libmpdec/typearith.h | 669 + Modules/_decimal/libmpdec/umodarith.h | 650 + Modules/_decimal/libmpdec/vccompat.h | 62 + Modules/_decimal/libmpdec/vcdiv64.asm | 48 + Modules/_decimal/libmpdec/vcstdint.h | 232 + Modules/_decimal/tests/README.txt | 15 + Modules/_decimal/tests/bench.py | 116 + Modules/_decimal/tests/deccheck.py | 1074 + Modules/_decimal/tests/formathelper.py | 344 + Modules/_decimal/tests/randdec.py | 559 + Modules/_decimal/tests/randfloat.py | 250 + Modules/_decimal/tests/runall-memorydebugger.sh | 175 + Modules/_decimal/tests/runall.bat | 121 + PCbuild/_decimal.vcproj | 743 + PCbuild/pcbuild.sln | 21 + configure | 171 + configure.ac | 100 + pyconfig.h.in | 13 + setup.py | 113 + 71 files changed, 31440 insertions(+), 1059 deletions(-) diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -9,6 +9,7 @@ .. moduleauthor:: Raymond Hettinger .. moduleauthor:: Aahz .. moduleauthor:: Tim Peters +.. moduleauthor:: Stefan Krah .. sectionauthor:: Raymond D. Hettinger .. import modules for testing inline doctests with the Sphinx doctest builder @@ -20,8 +21,9 @@ # make sure each group gets a fresh context setcontext(Context()) -The :mod:`decimal` module provides support for decimal floating point -arithmetic. It offers several advantages over the :class:`float` datatype: +The :mod:`decimal` module provides support for fast correctly-rounded +decimal floating point arithmetic. It offers several advantages over the +:class:`float` datatype: * Decimal "is based on a floating-point model which was designed with people in mind, and necessarily has a paramount guiding principle -- computers must @@ -92,7 +94,7 @@ considered as informational, or treated as exceptions. The signals in the decimal module are: :const:`Clamped`, :const:`InvalidOperation`, :const:`DivisionByZero`, :const:`Inexact`, :const:`Rounded`, :const:`Subnormal`, -:const:`Overflow`, and :const:`Underflow`. +:const:`Overflow`, :const:`Underflow` and :const:`FloatOperation`. For each signal there is a flag and a trap enabler. When a signal is encountered, its flag is set to one, then, if the trap enabler is @@ -122,7 +124,7 @@ >>> from decimal import * >>> getcontext() - Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, + Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero, InvalidOperation]) @@ -132,7 +134,7 @@ Construction from an integer or a float performs an exact conversion of the value of that integer or float. Decimal numbers include special values such as :const:`NaN` which stands for "Not a number", positive and negative -:const:`Infinity`, and :const:`-0`. +:const:`Infinity`, and :const:`-0`:: >>> getcontext().prec = 28 >>> Decimal(10) @@ -152,6 +154,25 @@ >>> Decimal('-Infinity') Decimal('-Infinity') +If the :exc:`FloatOperation` signal is trapped, accidental mixing of +decimals and floats in constructors or ordering comparisons raises +an exception:: + + >>> c = getcontext() + >>> c.traps[FloatOperation] = True + >>> Decimal(3.14) + Traceback (most recent call last): + File "", line 1, in + decimal.FloatOperation: [] + >>> Decimal('3.5') < 3.7 + Traceback (most recent call last): + File "", line 1, in + decimal.FloatOperation: [] + >>> Decimal('3.5') == 3.5 + True + +.. versionadded:: 3.3 + The significance of a new Decimal is determined solely by the number of digits input. Context precision and rounding only come into play during arithmetic operations. @@ -169,6 +190,16 @@ >>> Decimal('3.1415926535') + Decimal('2.7182818285') Decimal('5.85988') +If the internal limits of the C version are exceeded, constructing +a decimal raises :class:`InvalidOperation`:: + + >>> Decimal("1e9999999999999999999") + Traceback (most recent call last): + File "", line 1, in + decimal.InvalidOperation: [] + +.. versionchanged:: 3.3 + Decimals interact well with much of the rest of Python. Here is a small decimal floating point flying circus: @@ -244,7 +275,7 @@ Decimal('0.142857142857142857142857142857142857142857142857142857142857') >>> ExtendedContext - Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, + Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[]) >>> setcontext(ExtendedContext) >>> Decimal(1) / Decimal(7) @@ -269,7 +300,7 @@ >>> Decimal(355) / Decimal(113) Decimal('3.14159292') >>> getcontext() - Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, + Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[]) The *flags* entry shows that the rational approximation to :const:`Pi` was @@ -358,6 +389,10 @@ The argument to the constructor is now permitted to be a :class:`float` instance. + .. versionchanged:: 3.3 + :class:`float` arguments raise an exception if the :exc:`FloatOperation` + trap is set. By default the trap is off. + Decimal floating point objects share many properties with the other built-in numeric types such as :class:`float` and :class:`int`. All of the usual math operations and special methods apply. Likewise, decimal objects can be @@ -880,39 +915,33 @@ In single threaded environments, it is preferable to not use this context at all. Instead, simply create contexts explicitly as described below. - The default values are precision=28, rounding=ROUND_HALF_EVEN, and enabled traps - for Overflow, InvalidOperation, and DivisionByZero. + The default values are :attr:`prec`\ =\ :const:`28`, + :attr:`rounding`\ =\ :const:`ROUND_HALF_EVEN`, + and enabled traps for :class:`Overflow`, :class:`InvalidOperation`, and + :class:`DivisionByZero`. In addition to the three supplied contexts, new contexts can be created with the :class:`Context` constructor. -.. class:: Context(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=None, clamp=None) +.. class:: Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None) Creates a new context. If a field is not specified or is :const:`None`, the default values are copied from the :const:`DefaultContext`. If the *flags* field is not specified or is :const:`None`, all flags are cleared. - The *prec* field is a positive integer that sets the precision for arithmetic - operations in the context. - - The *rounding* option is one of: - - * :const:`ROUND_CEILING` (towards :const:`Infinity`), - * :const:`ROUND_DOWN` (towards zero), - * :const:`ROUND_FLOOR` (towards :const:`-Infinity`), - * :const:`ROUND_HALF_DOWN` (to nearest with ties going towards zero), - * :const:`ROUND_HALF_EVEN` (to nearest with ties going to nearest even integer), - * :const:`ROUND_HALF_UP` (to nearest with ties going away from zero), or - * :const:`ROUND_UP` (away from zero). - * :const:`ROUND_05UP` (away from zero if last digit after rounding towards zero - would have been 0 or 5; otherwise towards zero) + *prec* is an integer in the range [:const:`1`, :const:`MAX_PREC`] that sets + the precision for arithmetic operations in the context. + + The *rounding* option is one of the constants listed in the section + `Rounding Modes`_. The *traps* and *flags* fields list any signals to be set. Generally, new contexts should only set traps and leave the flags clear. The *Emin* and *Emax* fields are integers specifying the outer limits allowable - for exponents. + for exponents. *Emin* must be in the range [:const:`MIN_EMIN`, :const:`0`], + *Emax* in the range [:const:`0`, :const:`MAX_EMAX`]. The *capitals* field is either :const:`0` or :const:`1` (the default). If set to :const:`1`, exponents are printed with a capital :const:`E`; otherwise, a @@ -951,6 +980,12 @@ Resets all of the flags to :const:`0`. + .. method:: clear_traps() + + Resets all of the traps to :const:`0`. + + .. versionadded:: 3.3 + .. method:: copy() Return a duplicate of the context. @@ -1250,8 +1285,13 @@ With two arguments, compute ``x**y``. If ``x`` is negative then ``y`` must be integral. The result will be inexact unless ``y`` is integral and the result is finite and can be expressed exactly in 'precision' digits. - The result should always be correctly rounded, using the rounding mode of - the current thread's context. + The rounding mode of the context is used. Results are always correctly-rounded + in the Python version. + + .. versionchanged:: 3.3 + The C module computes :meth:`power` in terms of the correctly-rounded + :meth:`exp` and :meth:`ln` functions. The result is well-defined but + only "almost always correctly-rounded". With three arguments, compute ``(x**y) % modulo``. For the three argument form, the following restrictions on the arguments hold: @@ -1339,6 +1379,66 @@ .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +.. _decimal-rounding-modes: + +Constants +--------- + +The constants in this section are only relevant for the C module. They +are also included in the pure Python version for compatibility. + ++--------------------+---------------------+------------------------------+ +| | 32-bit | 64-bit | ++====================+=====================+==============================+ +| .. data:: MAX_PREC | :const:`425000000` | :const:`999999999999999999` | ++--------------------+---------------------+------------------------------+ +| .. data:: MAX_EMAX | :const:`425000000` | :const:`999999999999999999` | ++--------------------+---------------------+------------------------------+ +| .. data:: MIN_EMIN | :const:`-425000000` | :const:`-999999999999999999` | ++--------------------+---------------------+------------------------------+ + +.. data:: HAVE_THREADS + + The default value is True. If Python is compiled without threads, the + C version automatically disables the expensive thread local context + machinery. In this case, the value is False. + +Rounding modes +-------------- + +.. data:: ROUND_CEILING + + Round towards :const:`Infinity`. + +.. data:: ROUND_DOWN + + Round towards zero. + +.. data:: ROUND_FLOOR + + Round towards :const:`-Infinity`. + +.. data:: ROUND_HALF_DOWN + + Round to nearest with ties going towards zero. + +.. data:: ROUND_HALF_EVEN + + Round to nearest with ties going to nearest even integer. + +.. data:: ROUND_HALF_UP + + Round to nearest with ties going away from zero. + +.. data:: ROUND_UP + + Round away from zero. + +.. data:: ROUND_05UP + + Round away from zero if last digit after rounding towards zero would have + been 0 or 5; otherwise round towards zero. + .. _decimal-signals: @@ -1403,7 +1503,6 @@ Infinity / Infinity x % 0 Infinity % x - x._rescale( non-integer ) sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) @@ -1446,6 +1545,23 @@ Occurs when a subnormal result is pushed to zero by rounding. :class:`Inexact` and :class:`Subnormal` are also signaled. + +.. class:: FloatOperation + + Enable stricter semantics for mixing floats and Decimals. + + If the signal is not trapped (default), mixing floats and Decimals is + permitted in the :class:`~decimal.Decimal` constructor, + :meth:`~decimal.Context.create_decimal` and all comparison operators. + Both conversion and comparisons are exact. Any occurrence of a mixed + operation is silently recorded by setting :exc:`FloatOperation` in the + context flags. Explicit conversions with :meth:`~decimal.Decimal.from_float` + or :meth:`~decimal.Context.create_decimal_from_float` do not set the flag. + + Otherwise (the signal is trapped), only equality comparisons and explicit + conversions are silent. All other mixed operations raise :exc:`FloatOperation`. + + The following table summarizes the hierarchy of signals:: exceptions.ArithmeticError(exceptions.Exception) @@ -1458,10 +1574,12 @@ InvalidOperation Rounded Subnormal + FloatOperation .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + .. _decimal-notes: Floating Point Notes @@ -1571,7 +1689,7 @@ the following calculation returns a value equal to zero: >>> 1 / Decimal('Infinity') - Decimal('0E-1000000026') + Decimal('0E-1000026') .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1583,7 +1701,7 @@ The :func:`getcontext` function accesses a different :class:`Context` object for each thread. Having separate thread contexts means that threads may make -changes (such as ``getcontext.prec=10``) without interfering with other threads. +changes (such as ``getcontext().prec=10``) without interfering with other threads. Likewise, the :func:`setcontext` function automatically assigns its target to the current thread. diff --git a/Doc/library/numeric.rst b/Doc/library/numeric.rst --- a/Doc/library/numeric.rst +++ b/Doc/library/numeric.rst @@ -8,9 +8,9 @@ The modules described in this chapter provide numeric and math-related functions and data types. The :mod:`numbers` module defines an abstract hierarchy of numeric types. The :mod:`math` and :mod:`cmath` modules contain various -mathematical functions for floating-point and complex numbers. For users more -interested in decimal accuracy than in speed, the :mod:`decimal` module supports -exact representations of decimal numbers. +mathematical functions for floating-point and complex numbers. The :mod:`decimal` +module supports exact representations of decimal numbers, using arbitrary precision +arithmetic. The following modules are documented in this chapter: diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -596,6 +596,93 @@ (Contributed by I?igo Serna in :issue:`6755`) +decimal +------- + +:issue:`7652` - integrate fast native decimal arithmetic. + C-module and libmpdec written by Stefan Krah. + +The new C version of the decimal module integrates the high speed libmpdec +library for arbitrary precision correctly-rounded decimal arithmetic. +libmpdec conforms to IBM's General Decimal Arithmetic Specification. + +Performance gains range from 12x for database applications to 80x for +numerically intensive applications: + + +---------+-------------+--------------+-------------+ + | | decimal.py | _decimal | speedup | + +=========+=============+==============+=============+ + | pi | 42.75s | 0.58s | 74x | + +---------+-------------+--------------+-------------+ + | telco | 172.19s | 5.68s | 30x | + +---------+-------------+--------------+-------------+ + | psycopg | 3.57s | 0.29s | 12x | + +---------+-------------+--------------+-------------+ + +Features +~~~~~~~~ + +* The :exc:`~decimal.FloatOperation` signal optionally enables stricter + semantics for mixing floats and Decimals. + +* If Python is compiled without threads, the C version automatically + disables the expensive thread local context machinery. In this case, + the variable :data:`~decimal.HAVE_THREADS` is set to False. + +API changes +~~~~~~~~~~~ + +* The C module has the following context limits, depending on the machine + architecture: + + +-------------------+---------------------+------------------------------+ + | | 32-bit | 64-bit | + +===================+=====================+==============================+ + | :const:`MAX_PREC` | :const:`425000000` | :const:`999999999999999999` | + +-------------------+---------------------+------------------------------+ + | :const:`MAX_EMAX` | :const:`425000000` | :const:`999999999999999999` | + +-------------------+---------------------+------------------------------+ + | :const:`MIN_EMIN` | :const:`-425000000` | :const:`-999999999999999999` | + +-------------------+---------------------+------------------------------+ + +* In the context templates (:class:`~decimal.DefaultContext`, + :class:`~decimal.BasicContext` and :class:`~decimal.ExtendedContext`) + the magnitude of :attr:`~decimal.Context.Emax` and + :attr:`~decimal.Context.Emin` has changed to :const:`999999`. + +* The :class:`~decimal.Decimal` constructor in decimal.py does not observe + the context limits and converts values with arbitrary exponents or precision + exactly. Since the C version has internal limits, the following scheme is + used: If possible, values are converted exactly, otherwise + :exc:`~decimal.InvalidOperation` is raised and the result is NaN. In the + latter case it is always possible to use :meth:`~decimal.Context.create_decimal` + in order to obtain a rounded or inexact value. + + +* The power function in decimal.py is always correctly-rounded. In the + C version, it is defined in terms of the correctly-rounded + :meth:`~decimal.Decimal.exp` and :meth:`~decimal.Decimal.ln` functions, + but the final result is only "almost always correctly rounded". + + +* In the C version, the context dictionary containing the signals is a + :class:`~collections.abc.MutableMapping`. For speed reasons, + :attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps` always + refer to the same :class:`~collections.abc.MutableMapping` that the context + was initialized with. If a new signal dictionary is assigned, + :attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps` + are updated with the new values, but they do not reference the RHS + dictionary. + + +* Pickling a :class:`~decimal.Context` produces a different output in order + to have a common interchange format for the Python and C versions. + + +* The order of arguments in the :class:`~decimal.Context` constructor has been + changed to match the order displayed by :func:`repr`. + + faulthandler ------------ diff --git a/Include/longintrepr.h b/Include/longintrepr.h --- a/Include/longintrepr.h +++ b/Include/longintrepr.h @@ -6,7 +6,7 @@ #endif -/* This is published for the benefit of "friend" marshal.c only. */ +/* This is published for the benefit of "friends" marshal.c and _decimal.c. */ /* Parameters of the long integer representation. There are two different sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -46,8 +46,8 @@ Decimal('-0.0123') >>> Decimal(123456) Decimal('123456') ->>> Decimal('123.45e12345678901234567890') -Decimal('1.2345E+12345678901234567892') +>>> Decimal('123.45e12345678') +Decimal('1.2345E+12345680') >>> Decimal('1.33') + Decimal('1.27') Decimal('2.60') >>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41') @@ -122,13 +122,20 @@ # Exceptions 'DecimalException', 'Clamped', 'InvalidOperation', 'DivisionByZero', 'Inexact', 'Rounded', 'Subnormal', 'Overflow', 'Underflow', + 'FloatOperation', # Constants for use in setting up contexts 'ROUND_DOWN', 'ROUND_HALF_UP', 'ROUND_HALF_EVEN', 'ROUND_CEILING', 'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN', 'ROUND_05UP', # Functions for manipulating contexts - 'setcontext', 'getcontext', 'localcontext' + 'setcontext', 'getcontext', 'localcontext', + + # Limits for the C version for compatibility + 'MAX_PREC', 'MAX_EMAX', 'MIN_EMIN', 'MIN_ETINY', + + # C version: compile time choice that enables the thread local context + 'HAVE_THREADS' ] __version__ = '1.70' # Highest version of the spec this complies with @@ -137,6 +144,7 @@ import copy as _copy import math as _math import numbers as _numbers +import sys try: from collections import namedtuple as _namedtuple @@ -154,6 +162,19 @@ ROUND_HALF_DOWN = 'ROUND_HALF_DOWN' ROUND_05UP = 'ROUND_05UP' +# Compatibility with the C version +HAVE_THREADS = True +if sys.maxsize == 2**63-1: + MAX_PREC = 999999999999999999 + MAX_EMAX = 999999999999999999 + MIN_EMIN = -999999999999999999 +else: + MAX_PREC = 425000000 + MAX_EMAX = 425000000 + MIN_EMIN = -425000000 + +MIN_ETINY = MIN_EMIN - (MAX_PREC-1) + # Errors class DecimalException(ArithmeticError): @@ -370,9 +391,24 @@ In all cases, Inexact, Rounded, and Subnormal will also be raised. """ +class FloatOperation(DecimalException): + """Enable stricter semantics for mixing floats and Decimals. + + If the signal is not trapped (default), mixing floats and Decimals is + permitted in the Decimal() constructor, context.create_decimal() and + all comparison operators. Both conversion and comparisons are exact. + Any occurrence of a mixed operation is silently recorded by setting + FloatOperation in the context flags. Explicit conversions with + Decimal.from_float() or context.create_decimal_from_float() do not + set the flag. + + Otherwise (the signal is trapped), only equality comparisons and explicit + conversions are silent. All other mixed operations raise FloatOperation. + """ + # List of public traps and flags _signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded, - Underflow, InvalidOperation, Subnormal] + Underflow, InvalidOperation, Subnormal, FloatOperation] # Map conditions (per the spec) to signals _condition_map = {ConversionSyntax:InvalidOperation, @@ -380,6 +416,10 @@ DivisionUndefined:InvalidOperation, InvalidContext:InvalidOperation} +# Valid rounding modes +_rounding_modes = (ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_CEILING, + ROUND_FLOOR, ROUND_UP, ROUND_HALF_DOWN, ROUND_05UP) + ##### Context Functions ################################################## # The getcontext() and setcontext() function manage access to a thread-local @@ -392,12 +432,11 @@ import threading except ImportError: # Python was compiled without threads; create a mock object instead - import sys class MockThreading(object): def local(self, sys=sys): return sys.modules[__name__] threading = MockThreading() - del sys, MockThreading + del MockThreading try: threading.local @@ -650,6 +689,11 @@ return self if isinstance(value, float): + if context is None: + context = getcontext() + context._raise_error(FloatOperation, + "strict semantics for mixing floats and Decimals are " + "enabled") value = Decimal.from_float(value) self._exp = value._exp self._sign = value._sign @@ -684,7 +728,9 @@ """ if isinstance(f, int): # handle integer inputs return cls(f) - if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float + if not isinstance(f, float): + raise TypeError("argument must be int or float.") + if _math.isinf(f) or _math.isnan(f): return cls(repr(f)) if _math.copysign(1.0, f) == 1.0: sign = 0 @@ -1906,11 +1952,12 @@ def _power_modulo(self, other, modulo, context=None): """Three argument version of __pow__""" - # if can't convert other and modulo to Decimal, raise - # TypeError; there's no point returning NotImplemented (no - # equivalent of __rpow__ for three argument pow) - other = _convert_other(other, raiseit=True) - modulo = _convert_other(modulo, raiseit=True) + other = _convert_other(other) + if other is NotImplemented: + return other + modulo = _convert_other(modulo) + if modulo is NotImplemented: + return modulo if context is None: context = getcontext() @@ -3832,11 +3879,9 @@ clamp - If 1, change exponents if too high (Default 0) """ - def __init__(self, prec=None, rounding=None, - traps=None, flags=None, - Emin=None, Emax=None, - capitals=None, clamp=None, - _ignored_flags=None): + def __init__(self, prec=None, rounding=None, Emin=None, Emax=None, + capitals=None, clamp=None, flags=None, traps=None, + _ignored_flags=None): # Set defaults; for everything except flags and _ignored_flags, # inherit from DefaultContext. try: @@ -3859,17 +3904,78 @@ if traps is None: self.traps = dc.traps.copy() elif not isinstance(traps, dict): - self.traps = dict((s, int(s in traps)) for s in _signals) + self.traps = dict((s, int(s in traps)) for s in _signals + traps) else: self.traps = traps if flags is None: self.flags = dict.fromkeys(_signals, 0) elif not isinstance(flags, dict): - self.flags = dict((s, int(s in flags)) for s in _signals) + self.flags = dict((s, int(s in flags)) for s in _signals + flags) else: self.flags = flags + def _set_integer_check(self, name, value, vmin, vmax): + if not isinstance(value, int): + raise TypeError("%s must be an integer" % name) + if vmin == '-inf': + if value > vmax: + raise ValueError("%s must be in [%s, %d]. got: %s" % (name, vmin, vmax, value)) + elif vmax == 'inf': + if value < vmin: + raise ValueError("%s must be in [%d, %s]. got: %s" % (name, vmin, vmax, value)) + else: + if value < vmin or value > vmax: + raise ValueError("%s must be in [%d, %d]. got %s" % (name, vmin, vmax, value)) + return object.__setattr__(self, name, value) + + def _set_signal_dict(self, name, d): + if not isinstance(d, dict): + raise TypeError("%s must be a signal dict" % d) + for key in d: + if not key in _signals: + raise KeyError("%s is not a valid signal dict" % d) + for key in _signals: + if not key in d: + raise KeyError("%s is not a valid signal dict" % d) + return object.__setattr__(self, name, d) + + def __setattr__(self, name, value): + if name == 'prec': + return self._set_integer_check(name, value, 1, 'inf') + elif name == 'Emin': + return self._set_integer_check(name, value, '-inf', 0) + elif name == 'Emax': + return self._set_integer_check(name, value, 0, 'inf') + elif name == 'capitals': + return self._set_integer_check(name, value, 0, 1) + elif name == 'clamp': + return self._set_integer_check(name, value, 0, 1) + elif name == 'rounding': + if not value in _rounding_modes: + # raise TypeError even for strings to have consistency + # among various implementations. + raise TypeError("%s: invalid rounding mode" % value) + return object.__setattr__(self, name, value) + elif name == 'flags' or name == 'traps': + return self._set_signal_dict(name, value) + elif name == '_ignored_flags': + return object.__setattr__(self, name, value) + else: + raise AttributeError( + "'decimal.Context' object has no attribute '%s'" % name) + + def __delattr__(self, name): + raise AttributeError("%s cannot be deleted" % name) + + # Support for pickling, copy, and deepcopy + def __reduce__(self): + flags = [sig for sig, v in self.flags.items() if v] + traps = [sig for sig, v in self.traps.items() if v] + return (self.__class__, + (self.prec, self.rounding, self.Emin, self.Emax, + self.capitals, self.clamp, flags, traps)) + def __repr__(self): """Show the current context.""" s = [] @@ -3888,18 +3994,24 @@ for flag in self.flags: self.flags[flag] = 0 + def clear_traps(self): + """Reset all traps to zero""" + for flag in self.traps: + self.traps[flag] = 0 + def _shallow_copy(self): """Returns a shallow copy from self.""" - nc = Context(self.prec, self.rounding, self.traps, - self.flags, self.Emin, self.Emax, - self.capitals, self.clamp, self._ignored_flags) + nc = Context(self.prec, self.rounding, self.Emin, self.Emax, + self.capitals, self.clamp, self.flags, self.traps, + self._ignored_flags) return nc def copy(self): """Returns a deep copy from self.""" - nc = Context(self.prec, self.rounding, self.traps.copy(), - self.flags.copy(), self.Emin, self.Emax, - self.capitals, self.clamp, self._ignored_flags) + nc = Context(self.prec, self.rounding, self.Emin, self.Emax, + self.capitals, self.clamp, + self.flags.copy(), self.traps.copy(), + self._ignored_flags) return nc __copy__ = copy @@ -4062,6 +4174,8 @@ >>> ExtendedContext.canonical(Decimal('2.50')) Decimal('2.50') """ + if not isinstance(a, Decimal): + raise TypeError("canonical requires a Decimal as an argument.") return a.canonical(context=self) def compare(self, a, b): @@ -4372,6 +4486,8 @@ >>> ExtendedContext.is_canonical(Decimal('2.50')) True """ + if not isinstance(a, Decimal): + raise TypeError("is_canonical requires a Decimal as an argument.") return a.is_canonical() def is_finite(self, a): @@ -4964,7 +5080,7 @@ +Normal +Infinity - >>> c = Context(ExtendedContext) + >>> c = ExtendedContext.copy() >>> c.Emin = -999 >>> c.Emax = 999 >>> c.number_class(Decimal('Infinity')) @@ -5916,6 +6032,12 @@ if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0: other = other.real if isinstance(other, float): + context = getcontext() + if equality_op: + context.flags[FloatOperation] = 1 + else: + context._raise_error(FloatOperation, + "strict semantics for mixing floats and Decimals are enabled") return self, Decimal.from_float(other) return NotImplemented, NotImplemented @@ -5929,8 +6051,8 @@ prec=28, rounding=ROUND_HALF_EVEN, traps=[DivisionByZero, Overflow, InvalidOperation], flags=[], - Emax=999999999, - Emin=-999999999, + Emax=999999, + Emin=-999999, capitals=1, clamp=0 ) @@ -6080,7 +6202,7 @@ # if format type is 'g' or 'G' then a precision of 0 makes little # sense; convert it to 1. Same if format type is unspecified. if format_dict['precision'] == 0: - if format_dict['type'] is None or format_dict['type'] in 'gG': + if format_dict['type'] is None or format_dict['type'] in 'gGn': format_dict['precision'] = 1 # determine thousands separator, grouping, and decimal separator, and @@ -6254,16 +6376,26 @@ # Constants related to the hash implementation; hash(x) is based # on the reduction of x modulo _PyHASH_MODULUS -import sys _PyHASH_MODULUS = sys.hash_info.modulus # hash values to use for positive and negative infinities, and nans _PyHASH_INF = sys.hash_info.inf _PyHASH_NAN = sys.hash_info.nan -del sys # _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS _PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS) - +del sys + +try: + import _decimal +except ImportError: + pass +else: + s1 = set(dir()) + s2 = set(dir(_decimal)) + for name in s1 - s2: + del globals()[name] + del s1, s2, name + from _decimal import * if __name__ == '__main__': import doctest, decimal diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1416,7 +1416,7 @@ #======================================================================= # doctest driver. -def run_doctest(module, verbosity=None): +def run_doctest(module, verbosity=None, optionflags=0): """Run doctest on the given module. Return (#failures, #tests). If optional argument verbosity is not specified (or is None), pass @@ -1431,7 +1431,7 @@ else: verbosity = None - f, t = doctest.testmod(module, verbose=verbosity) + f, t = doctest.testmod(module, verbose=verbosity, optionflags=optionflags) if f: raise TestFailed("%d of %d doctests failed" % (f, t)) if verbose: diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -16,7 +16,7 @@ Cowlishaw's tests can be downloaded from: - www2.hursley.ibm.com/decimal/dectest.zip + http://speleotrove.com/decimal/dectest.zip This test module can be called from command line with one parameter (Arithmetic or Behaviour) to test each part, or without parameter to test both parts. If @@ -30,37 +30,74 @@ import warnings import pickle, copy import unittest -from decimal import * import numbers +import locale from test.support import (run_unittest, run_doctest, is_resource_enabled, requires_IEEE_754) -from test.support import check_warnings +from test.support import check_warnings, import_fresh_module, TestFailed import random +import time +import warnings try: import threading except ImportError: threading = None + +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) +orig_sys_decimal = sys.modules['decimal'] + +# fractions module must import the correct decimal module. +cfractions = import_fresh_module('fractions', fresh=['fractions']) +sys.modules['decimal'] = P +pfractions = import_fresh_module('fractions', fresh=['fractions']) +sys.modules['decimal'] = C +fractions = {C:cfractions, P:pfractions} +sys.modules['decimal'] = orig_sys_decimal + + # Useful Test Constant -Signals = tuple(getcontext().flags.keys()) - +Signals = { + C: tuple(C.getcontext().flags.keys()) if C else None, + P: tuple(P.getcontext().flags.keys()) +} # Signals ordered with respect to precedence: when an operation # produces multiple signals, signals occurring later in the list # should be handled before those occurring earlier in the list. -OrderedSignals = (Clamped, Rounded, Inexact, Subnormal, - Underflow, Overflow, DivisionByZero, InvalidOperation) +OrderedSignals = { + C: [C.Clamped, C.Rounded, C.Inexact, C.Subnormal, C.Underflow, + C.Overflow, C.DivisionByZero, C.InvalidOperation, + C.FloatOperation] if C else None, + P: [P.Clamped, P.Rounded, P.Inexact, P.Subnormal, P.Underflow, + P.Overflow, P.DivisionByZero, P.InvalidOperation, + P.FloatOperation] +} +def assert_signals(cls, context, attr, expected): + d = getattr(context, attr) + cls.assertTrue(all(d[s] if s in expected else not d[s] for s in d)) + +RoundingModes = { + C: (C.ROUND_UP, C.ROUND_DOWN, C.ROUND_CEILING, C.ROUND_FLOOR, + C.ROUND_HALF_UP, C.ROUND_HALF_DOWN, C.ROUND_HALF_EVEN, + C.ROUND_05UP) if C else None, + P: (P.ROUND_UP, P.ROUND_DOWN, P.ROUND_CEILING, P.ROUND_FLOOR, + P.ROUND_HALF_UP, P.ROUND_HALF_DOWN, P.ROUND_HALF_EVEN, + P.ROUND_05UP) +} # Tests are built around these assumed context defaults. # test_main() restores the original context. -def init(): - global ORIGINAL_CONTEXT - ORIGINAL_CONTEXT = getcontext().copy() - DefaultTestContext = Context( - prec = 9, - rounding = ROUND_HALF_EVEN, - traps = dict.fromkeys(Signals, 0) - ) - setcontext(DefaultTestContext) +ORIGINAL_CONTEXT = { + C: C.getcontext().copy() if C else None, + P: P.getcontext().copy() +} +def init(m): + if not m: return + DefaultTestContext = m.Context( + prec=9, rounding=m.ROUND_HALF_EVEN, traps=dict.fromkeys(Signals[m], 0) + ) + m.setcontext(DefaultTestContext) TESTDATADIR = 'decimaltestdata' if __name__ == '__main__': @@ -72,149 +109,175 @@ skip_expected = not os.path.isdir(directory) -# list of individual .decTest test ids that correspond to tests that -# we're skipping for one reason or another. -skipped_test_ids = set([ - # Skip implementation-specific scaleb tests. - 'scbx164', - 'scbx165', - - # For some operations (currently exp, ln, log10, power), the decNumber - # reference implementation imposes additional restrictions on the context - # and operands. These restrictions are not part of the specification; - # however, the effect of these restrictions does show up in some of the - # testcases. We skip testcases that violate these restrictions, since - # Decimal behaves differently from decNumber for these testcases so these - # testcases would otherwise fail. - 'expx901', - 'expx902', - 'expx903', - 'expx905', - 'lnx901', - 'lnx902', - 'lnx903', - 'lnx905', - 'logx901', - 'logx902', - 'logx903', - 'logx905', - 'powx1183', - 'powx1184', - 'powx4001', - 'powx4002', - 'powx4003', - 'powx4005', - 'powx4008', - 'powx4010', - 'powx4012', - 'powx4014', - ]) - # Make sure it actually raises errors when not expected and caught in flags # Slower, since it runs some things several times. EXTENDEDERRORTEST = False -#Map the test cases' error names to the actual errors -ErrorNames = {'clamped' : Clamped, - 'conversion_syntax' : InvalidOperation, - 'division_by_zero' : DivisionByZero, - 'division_impossible' : InvalidOperation, - 'division_undefined' : InvalidOperation, - 'inexact' : Inexact, - 'invalid_context' : InvalidOperation, - 'invalid_operation' : InvalidOperation, - 'overflow' : Overflow, - 'rounded' : Rounded, - 'subnormal' : Subnormal, - 'underflow' : Underflow} - - -def Nonfunction(*args): - """Doesn't do anything.""" - return None - -RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings. - 'down' : ROUND_DOWN, - 'floor' : ROUND_FLOOR, - 'half_down' : ROUND_HALF_DOWN, - 'half_even' : ROUND_HALF_EVEN, - 'half_up' : ROUND_HALF_UP, - 'up' : ROUND_UP, - '05up' : ROUND_05UP} - -# Name adapter to be able to change the Decimal and Context -# interface without changing the test files from Cowlishaw -nameAdapter = {'and':'logical_and', - 'apply':'_apply', - 'class':'number_class', - 'comparesig':'compare_signal', - 'comparetotal':'compare_total', - 'comparetotmag':'compare_total_mag', - 'copy':'copy_decimal', - 'copyabs':'copy_abs', - 'copynegate':'copy_negate', - 'copysign':'copy_sign', - 'divideint':'divide_int', - 'invert':'logical_invert', - 'iscanonical':'is_canonical', - 'isfinite':'is_finite', - 'isinfinite':'is_infinite', - 'isnan':'is_nan', - 'isnormal':'is_normal', - 'isqnan':'is_qnan', - 'issigned':'is_signed', - 'issnan':'is_snan', - 'issubnormal':'is_subnormal', - 'iszero':'is_zero', - 'maxmag':'max_mag', - 'minmag':'min_mag', - 'nextminus':'next_minus', - 'nextplus':'next_plus', - 'nexttoward':'next_toward', - 'or':'logical_or', - 'reduce':'normalize', - 'remaindernear':'remainder_near', - 'samequantum':'same_quantum', - 'squareroot':'sqrt', - 'toeng':'to_eng_string', - 'tointegral':'to_integral_value', - 'tointegralx':'to_integral_exact', - 'tosci':'to_sci_string', - 'xor':'logical_xor', - } - -# The following functions return True/False rather than a Decimal instance - -LOGICAL_FUNCTIONS = ( - 'is_canonical', - 'is_finite', - 'is_infinite', - 'is_nan', - 'is_normal', - 'is_qnan', - 'is_signed', - 'is_snan', - 'is_subnormal', - 'is_zero', - 'same_quantum', - ) - -class DecimalTest(unittest.TestCase): - """Class which tests the Decimal class against the test cases. - - Changed for unittest. - """ +# Test extra functionality in the C version (-DEXTRA_FUNCTIONALITY). +EXTRA_FUNCTIONALITY = True if hasattr(C, 'DecClamped') else False +requires_extra_functionality = unittest.skipUnless( + EXTRA_FUNCTIONALITY, "test requires build with -DEXTRA_FUNCTIONALITY") +skip_if_extra_functionality = unittest.skipIf( + EXTRA_FUNCTIONALITY, "test requires regular build") + + +class IBMTestCases(unittest.TestCase): + """Class which tests the Decimal class against the IBM test cases.""" + def setUp(self): - self.context = Context() + self.context = self.decimal.Context() + self.readcontext = self.decimal.Context() self.ignore_list = ['#'] - # Basically, a # means return NaN InvalidOperation. - # Different from a sNaN in trim - + + # List of individual .decTest test ids that correspond to tests that + # we're skipping for one reason or another. + self.skipped_test_ids = set([ + # Skip implementation-specific scaleb tests. + 'scbx164', + 'scbx165', + + # For some operations (currently exp, ln, log10, power), the decNumber + # reference implementation imposes additional restrictions on the context + # and operands. These restrictions are not part of the specification; + # however, the effect of these restrictions does show up in some of the + # testcases. We skip testcases that violate these restrictions, since + # Decimal behaves differently from decNumber for these testcases so these + # testcases would otherwise fail. + 'expx901', + 'expx902', + 'expx903', + 'expx905', + 'lnx901', + 'lnx902', + 'lnx903', + 'lnx905', + 'logx901', + 'logx902', + 'logx903', + 'logx905', + 'powx1183', + 'powx1184', + 'powx4001', + 'powx4002', + 'powx4003', + 'powx4005', + 'powx4008', + 'powx4010', + 'powx4012', + 'powx4014', + ]) + + if self.decimal == C: + # status has additional Subnormal, Underflow + self.skipped_test_ids.add('pwsx803') + self.skipped_test_ids.add('pwsx805') + # Correct rounding (skipped for decNumber, too) + self.skipped_test_ids.add('powx4302') + self.skipped_test_ids.add('powx4303') + self.skipped_test_ids.add('powx4342') + self.skipped_test_ids.add('powx4343') + # http://bugs.python.org/issue7049 + self.skipped_test_ids.add('pwmx325') + self.skipped_test_ids.add('pwmx326') + + # Map test directives to setter functions. self.ChangeDict = {'precision' : self.change_precision, - 'rounding' : self.change_rounding_method, - 'maxexponent' : self.change_max_exponent, - 'minexponent' : self.change_min_exponent, - 'clamp' : self.change_clamp} + 'rounding' : self.change_rounding_method, + 'maxexponent' : self.change_max_exponent, + 'minexponent' : self.change_min_exponent, + 'clamp' : self.change_clamp} + + # Name adapter to be able to change the Decimal and Context + # interface without changing the test files from Cowlishaw. + self.NameAdapter = {'and':'logical_and', + 'apply':'_apply', + 'class':'number_class', + 'comparesig':'compare_signal', + 'comparetotal':'compare_total', + 'comparetotmag':'compare_total_mag', + 'copy':'copy_decimal', + 'copyabs':'copy_abs', + 'copynegate':'copy_negate', + 'copysign':'copy_sign', + 'divideint':'divide_int', + 'invert':'logical_invert', + 'iscanonical':'is_canonical', + 'isfinite':'is_finite', + 'isinfinite':'is_infinite', + 'isnan':'is_nan', + 'isnormal':'is_normal', + 'isqnan':'is_qnan', + 'issigned':'is_signed', + 'issnan':'is_snan', + 'issubnormal':'is_subnormal', + 'iszero':'is_zero', + 'maxmag':'max_mag', + 'minmag':'min_mag', + 'nextminus':'next_minus', + 'nextplus':'next_plus', + 'nexttoward':'next_toward', + 'or':'logical_or', + 'reduce':'normalize', + 'remaindernear':'remainder_near', + 'samequantum':'same_quantum', + 'squareroot':'sqrt', + 'toeng':'to_eng_string', + 'tointegral':'to_integral_value', + 'tointegralx':'to_integral_exact', + 'tosci':'to_sci_string', + 'xor':'logical_xor'} + + # Map test-case names to roundings. + self.RoundingDict = {'ceiling' : self.decimal.ROUND_CEILING, + 'down' : self.decimal.ROUND_DOWN, + 'floor' : self.decimal.ROUND_FLOOR, + 'half_down' : self.decimal.ROUND_HALF_DOWN, + 'half_even' : self.decimal.ROUND_HALF_EVEN, + 'half_up' : self.decimal.ROUND_HALF_UP, + 'up' : self.decimal.ROUND_UP, + '05up' : self.decimal.ROUND_05UP} + + # Map the test cases' error names to the actual errors. + self.ErrorNames = {'clamped' : self.decimal.Clamped, + 'conversion_syntax' : self.decimal.InvalidOperation, + 'division_by_zero' : self.decimal.DivisionByZero, + 'division_impossible' : self.decimal.InvalidOperation, + 'division_undefined' : self.decimal.InvalidOperation, + 'inexact' : self.decimal.Inexact, + 'invalid_context' : self.decimal.InvalidOperation, + 'invalid_operation' : self.decimal.InvalidOperation, + 'overflow' : self.decimal.Overflow, + 'rounded' : self.decimal.Rounded, + 'subnormal' : self.decimal.Subnormal, + 'underflow' : self.decimal.Underflow} + + # The following functions return True/False rather than a + # Decimal instance. + self.LogicalFunctions = ('is_canonical', + 'is_finite', + 'is_infinite', + 'is_nan', + 'is_normal', + 'is_qnan', + 'is_signed', + 'is_snan', + 'is_subnormal', + 'is_zero', + 'same_quantum') + + def read_unlimited(self, v, context): + """Work around the limitations of the 32-bit _decimal version. The + guaranteed maximum values for prec, Emax etc. are 425000000, + but higher values usually work, except for rare corner cases. + In particular, all of the IBM tests pass with maximum values + of 1070000000.""" + if self.decimal == C and self.decimal.MAX_EMAX == 425000000: + self.readcontext._unsafe_setprec(1070000000) + self.readcontext._unsafe_setemax(1070000000) + self.readcontext._unsafe_setemin(-1070000000) + return self.readcontext.create_decimal(v) + else: + return self.decimal.Decimal(v, context) def eval_file(self, file): global skip_expected @@ -227,7 +290,7 @@ #print line try: t = self.eval_line(line) - except DecimalException as exception: + except self.decimal.DecimalException as exception: #Exception raised where there shouldn't have been one. self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line) @@ -254,23 +317,23 @@ def eval_directive(self, s): funct, value = (x.strip().lower() for x in s.split(':')) if funct == 'rounding': - value = RoundingDict[value] + value = self.RoundingDict[value] else: try: value = int(value) except ValueError: pass - funct = self.ChangeDict.get(funct, Nonfunction) + funct = self.ChangeDict.get(funct, (lambda *args: None)) funct(value) def eval_equation(self, s): - #global DEFAULT_PRECISION - #print DEFAULT_PRECISION if not TEST_ALL and random.random() < 0.90: return + self.context.clear_flags() + try: Sides = s.split('->') L = Sides[0].strip().split() @@ -283,26 +346,26 @@ ans = L[0] exceptions = L[1:] except (TypeError, AttributeError, IndexError): - raise InvalidOperation + raise self.decimal.InvalidOperation def FixQuotes(val): val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote') val = val.replace("'", '').replace('"', '') val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"') return val - if id in skipped_test_ids: + if id in self.skipped_test_ids: return - fname = nameAdapter.get(funct, funct) + fname = self.NameAdapter.get(funct, funct) if fname == 'rescale': return funct = getattr(self.context, fname) vals = [] conglomerate = '' quote = 0 - theirexceptions = [ErrorNames[x.lower()] for x in exceptions] - - for exception in Signals: + theirexceptions = [self.ErrorNames[x.lower()] for x in exceptions] + + for exception in Signals[self.decimal]: self.context.traps[exception] = 1 #Catch these bugs... for exception in theirexceptions: self.context.traps[exception] = 0 @@ -324,7 +387,7 @@ funct(self.context.create_decimal(v)) except error: pass - except Signals as e: + except Signals[self.decimal] as e: self.fail("Raised %s in %s when %s disabled" % \ (e, s, error)) else: @@ -332,7 +395,7 @@ self.context.traps[error] = 0 v = self.context.create_decimal(v) else: - v = Decimal(v, self.context) + v = self.read_unlimited(v, self.context) vals.append(v) ans = FixQuotes(ans) @@ -344,7 +407,7 @@ funct(*vals) except error: pass - except Signals as e: + except Signals[self.decimal] as e: self.fail("Raised %s in %s when %s disabled" % \ (e, s, error)) else: @@ -352,14 +415,14 @@ self.context.traps[error] = 0 # as above, but add traps cumulatively, to check precedence - ordered_errors = [e for e in OrderedSignals if e in theirexceptions] + ordered_errors = [e for e in OrderedSignals[self.decimal] if e in theirexceptions] for error in ordered_errors: self.context.traps[error] = 1 try: funct(*vals) except error: pass - except Signals as e: + except Signals[self.decimal] as e: self.fail("Raised %s in %s; expected %s" % (type(e), s, error)) else: @@ -373,54 +436,69 @@ print("--", self.context) try: result = str(funct(*vals)) - if fname in LOGICAL_FUNCTIONS: + if fname in self.LogicalFunctions: result = str(int(eval(result))) # 'True', 'False' -> '1', '0' - except Signals as error: + except Signals[self.decimal] as error: self.fail("Raised %s in %s" % (error, s)) except: #Catch any error long enough to state the test case. print("ERROR:", s) raise myexceptions = self.getexceptions() - self.context.clear_flags() myexceptions.sort(key=repr) theirexceptions.sort(key=repr) self.assertEqual(result, ans, 'Incorrect answer for ' + s + ' -- got ' + result) + self.assertEqual(myexceptions, theirexceptions, 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions)) return def getexceptions(self): - return [e for e in Signals if self.context.flags[e]] + return [e for e in Signals[self.decimal] if self.context.flags[e]] def change_precision(self, prec): - self.context.prec = prec + if self.decimal == C and self.decimal.MAX_PREC == 425000000: + self.context._unsafe_setprec(prec) + else: + self.context.prec = prec def change_rounding_method(self, rounding): self.context.rounding = rounding def change_min_exponent(self, exp): - self.context.Emin = exp + if self.decimal == C and self.decimal.MAX_PREC == 425000000: + self.context._unsafe_setemin(exp) + else: + self.context.Emin = exp def change_max_exponent(self, exp): - self.context.Emax = exp + if self.decimal == C and self.decimal.MAX_PREC == 425000000: + self.context._unsafe_setemax(exp) + else: + self.context.Emax = exp def change_clamp(self, clamp): self.context.clamp = clamp - +class CIBMTestCases(IBMTestCases): + decimal = C +class PyIBMTestCases(IBMTestCases): + decimal = P # The following classes test the behaviour of Decimal according to PEP 327 -class DecimalExplicitConstructionTest(unittest.TestCase): +class ExplicitConstructionTest(unittest.TestCase): '''Unit tests for Explicit Construction cases of Decimal.''' def test_explicit_empty(self): + Decimal = self.decimal.Decimal self.assertEqual(Decimal(), Decimal("0")) def test_explicit_from_None(self): + Decimal = self.decimal.Decimal self.assertRaises(TypeError, Decimal, None) def test_explicit_from_int(self): + Decimal = self.decimal.Decimal #positive d = Decimal(45) @@ -438,7 +516,18 @@ d = Decimal(0) self.assertEqual(str(d), '0') + # single word longs + for n in range(0, 32): + for sign in (-1, 1): + for x in range(-5, 5): + i = sign * (2**n + x) + d = Decimal(i) + self.assertEqual(str(d), str(i)) + def test_explicit_from_string(self): + Decimal = self.decimal.Decimal + InvalidOperation = self.decimal.InvalidOperation + localcontext = self.decimal.localcontext #empty self.assertEqual(str(Decimal('')), 'NaN') @@ -458,8 +547,35 @@ #leading and trailing whitespace permitted self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4') self.assertEqual(str(Decimal(' -7.89')), '-7.89') + self.assertEqual(str(Decimal(" 3.45679 ")), '3.45679') + + # unicode whitespace + for lead in ["", ' ', '\u00a0', '\u205f']: + for trail in ["", ' ', '\u00a0', '\u205f']: + self.assertEqual(str(Decimal(lead + '9.311E+28' + trail)), + '9.311E+28') + + with localcontext() as c: + c.traps[InvalidOperation] = True + # Invalid string + self.assertRaises(InvalidOperation, Decimal, "xyz") + # Two arguments max + self.assertRaises(TypeError, Decimal, "1234", "x", "y") + + # space within the numeric part + self.assertRaises(InvalidOperation, Decimal, "1\u00a02\u00a03") + self.assertRaises(InvalidOperation, Decimal, "\u00a01\u00a02\u00a0") + + # unicode whitespace + self.assertRaises(InvalidOperation, Decimal, "\u00a0") + self.assertRaises(InvalidOperation, Decimal, "\u00a0\u00a0") + + # embedded NUL + self.assertRaises(InvalidOperation, Decimal, "12\u00003") + def test_explicit_from_tuples(self): + Decimal = self.decimal.Decimal #zero d = Decimal( (0, (0,), 0) ) @@ -477,6 +593,10 @@ d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) self.assertEqual(str(d), '-4.34913534E-17') + #inf + d = Decimal( (0, (), "F") ) + self.assertEqual(str(d), 'Infinity') + #wrong number of items self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) ) @@ -491,45 +611,63 @@ self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') ) #bad coefficients + self.assertRaises(ValueError, Decimal, (1, "xyz", 2) ) self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) ) self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) ) self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) ) self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) ) + def test_explicit_from_list(self): + Decimal = self.decimal.Decimal + + d = Decimal([0, [0], 0]) + self.assertEqual(str(d), '0') + + d = Decimal([1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25]) + self.assertEqual(str(d), '-4.34913534E-17') + + d = Decimal([1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25]) + self.assertEqual(str(d), '-4.34913534E-17') + + d = Decimal((1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25)) + self.assertEqual(str(d), '-4.34913534E-17') + def test_explicit_from_bool(self): + Decimal = self.decimal.Decimal + self.assertIs(bool(Decimal(0)), False) self.assertIs(bool(Decimal(1)), True) self.assertEqual(Decimal(False), Decimal(0)) self.assertEqual(Decimal(True), Decimal(1)) def test_explicit_from_Decimal(self): + Decimal = self.decimal.Decimal #positive d = Decimal(45) e = Decimal(d) self.assertEqual(str(e), '45') - self.assertNotEqual(id(d), id(e)) #very large positive d = Decimal(500000123) e = Decimal(d) self.assertEqual(str(e), '500000123') - self.assertNotEqual(id(d), id(e)) #negative d = Decimal(-45) e = Decimal(d) self.assertEqual(str(e), '-45') - self.assertNotEqual(id(d), id(e)) #zero d = Decimal(0) e = Decimal(d) self.assertEqual(str(e), '0') - self.assertNotEqual(id(d), id(e)) @requires_IEEE_754 def test_explicit_from_float(self): + + Decimal = self.decimal.Decimal + r = Decimal(0.1) self.assertEqual(type(r), Decimal) self.assertEqual(str(r), @@ -550,8 +688,11 @@ self.assertEqual(x, float(Decimal(x))) # roundtrip def test_explicit_context_create_decimal(self): - - nc = copy.copy(getcontext()) + Decimal = self.decimal.Decimal + InvalidOperation = self.decimal.InvalidOperation + Rounded = self.decimal.Rounded + + nc = copy.copy(self.decimal.getcontext()) nc.prec = 3 # empty @@ -592,7 +733,73 @@ d = nc.create_decimal(prevdec) self.assertEqual(str(d), '5.00E+8') + # more integers + nc.prec = 28 + nc.traps[InvalidOperation] = True + + for v in [-2**63-1, -2**63, -2**31-1, -2**31, 0, + 2**31-1, 2**31, 2**63-1, 2**63]: + d = nc.create_decimal(v) + self.assertTrue(isinstance(d, Decimal)) + self.assertEqual(int(d), v) + + nc.prec = 3 + nc.traps[Rounded] = True + self.assertRaises(Rounded, nc.create_decimal, 1234) + + # from string + nc.prec = 28 + self.assertEqual(str(nc.create_decimal('0E-017')), '0E-17') + self.assertEqual(str(nc.create_decimal('45')), '45') + self.assertEqual(str(nc.create_decimal('-Inf')), '-Infinity') + self.assertEqual(str(nc.create_decimal('NaN123')), 'NaN123') + + # invalid arguments + self.assertRaises(InvalidOperation, nc.create_decimal, "xyz") + self.assertRaises(ValueError, nc.create_decimal, (1, "xyz", -25)) + self.assertRaises(TypeError, nc.create_decimal, "1234", "5678") + + # too many NaN payload digits + nc.prec = 3 + self.assertRaises(InvalidOperation, nc.create_decimal, 'NaN12345') + self.assertRaises(InvalidOperation, nc.create_decimal, + Decimal('NaN12345')) + + nc.traps[InvalidOperation] = False + self.assertEqual(str(nc.create_decimal('NaN12345')), 'NaN') + self.assertTrue(nc.flags[InvalidOperation]) + + nc.flags[InvalidOperation] = False + self.assertEqual(str(nc.create_decimal(Decimal('NaN12345'))), 'NaN') + self.assertTrue(nc.flags[InvalidOperation]) + + def test_explicit_context_create_from_float(self): + + Decimal = self.decimal.Decimal + + nc = self.decimal.Context() + r = nc.create_decimal(0.1) + self.assertEqual(type(r), Decimal) + self.assertEqual(str(r), '0.1000000000000000055511151231') + self.assertTrue(nc.create_decimal(float('nan')).is_qnan()) + self.assertTrue(nc.create_decimal(float('inf')).is_infinite()) + self.assertTrue(nc.create_decimal(float('-inf')).is_infinite()) + self.assertEqual(str(nc.create_decimal(float('nan'))), + str(nc.create_decimal('NaN'))) + self.assertEqual(str(nc.create_decimal(float('inf'))), + str(nc.create_decimal('Infinity'))) + self.assertEqual(str(nc.create_decimal(float('-inf'))), + str(nc.create_decimal('-Infinity'))) + self.assertEqual(str(nc.create_decimal(float('-0.0'))), + str(nc.create_decimal('-0'))) + nc.prec = 100 + for i in range(200): + x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) + self.assertEqual(x, float(nc.create_decimal(x))) # roundtrip + def test_unicode_digits(self): + Decimal = self.decimal.Decimal + test_values = { '\uff11': '1', '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372', @@ -601,29 +808,41 @@ for input, expected in test_values.items(): self.assertEqual(str(Decimal(input)), expected) - -class DecimalImplicitConstructionTest(unittest.TestCase): +class CExplicitConstructionTest(ExplicitConstructionTest): + decimal = C +class PyExplicitConstructionTest(ExplicitConstructionTest): + decimal = P + +class ImplicitConstructionTest(unittest.TestCase): '''Unit tests for Implicit Construction cases of Decimal.''' def test_implicit_from_None(self): - self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals()) + Decimal = self.decimal.Decimal + self.assertRaises(TypeError, eval, 'Decimal(5) + None', locals()) def test_implicit_from_int(self): + Decimal = self.decimal.Decimal + #normal self.assertEqual(str(Decimal(5) + 45), '50') #exceeding precision self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000)) def test_implicit_from_string(self): - self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals()) + Decimal = self.decimal.Decimal + self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', locals()) def test_implicit_from_float(self): - self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals()) + Decimal = self.decimal.Decimal + self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', locals()) def test_implicit_from_Decimal(self): + Decimal = self.decimal.Decimal self.assertEqual(Decimal(5) + Decimal(45), Decimal(50)) def test_rop(self): + Decimal = self.decimal.Decimal + # Allow other classes to be trained to interact with Decimals class E: def __divmod__(self, other): @@ -671,10 +890,16 @@ self.assertEqual(eval('Decimal(10)' + sym + 'E()'), '10' + rop + 'str') - -class DecimalFormatTest(unittest.TestCase): +class CImplicitConstructionTest(ImplicitConstructionTest): + decimal = C +class PyImplicitConstructionTest(ImplicitConstructionTest): + decimal = P + +class FormatTest(unittest.TestCase): '''Unit tests for the format function.''' def test_formatting(self): + Decimal = self.decimal.Decimal + # triples giving a format, a Decimal, and the expected result test_values = [ ('e', '0E-15', '0e-15'), @@ -730,6 +955,7 @@ ('g', '0E-7', '0e-7'), ('g', '-0E2', '-0e+2'), ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig + ('.0n', '3.14159265', '3'), # same for 'n' ('.1g', '3.14159265', '3'), ('.2g', '3.14159265', '3.1'), ('.5g', '3.14159265', '3.1416'), @@ -814,56 +1040,60 @@ # issue 6850 ('a=-7.0', '0.12345', 'aaaa0.1'), - - # Issue 7094: Alternate formatting (specified by #) - ('.0e', '1.0', '1e+0'), - ('#.0e', '1.0', '1.e+0'), - ('.0f', '1.0', '1'), - ('#.0f', '1.0', '1.'), - ('g', '1.1', '1.1'), - ('#g', '1.1', '1.1'), - ('.0g', '1', '1'), - ('#.0g', '1', '1.'), - ('.0%', '1.0', '100%'), - ('#.0%', '1.0', '100.%'), ] for fmt, d, result in test_values: self.assertEqual(format(Decimal(d), fmt), result) + # bytes format argument + self.assertRaises(TypeError, Decimal(1).__format__, b'-020') + def test_n_format(self): + Decimal = self.decimal.Decimal + try: from locale import CHAR_MAX except ImportError: return + def make_grouping(lst): + return ''.join([chr(x) for x in lst]) if self.decimal == C else lst + + def get_fmt(x, override=None, fmt='n'): + if self.decimal == C: + return Decimal(x).__format__(fmt, override) + else: + return Decimal(x).__format__(fmt, _localeconv=override) + # Set up some localeconv-like dictionaries en_US = { 'decimal_point' : '.', - 'grouping' : [3, 3, 0], - 'thousands_sep': ',' + 'grouping' : make_grouping([3, 3, 0]), + 'thousands_sep' : ',' } fr_FR = { 'decimal_point' : ',', - 'grouping' : [CHAR_MAX], + 'grouping' : make_grouping([CHAR_MAX]), 'thousands_sep' : '' } ru_RU = { 'decimal_point' : ',', - 'grouping' : [3, 3, 0], + 'grouping': make_grouping([3, 3, 0]), 'thousands_sep' : ' ' } crazy = { 'decimal_point' : '&', - 'grouping' : [1, 4, 2, CHAR_MAX], + 'grouping': make_grouping([1, 4, 2, CHAR_MAX]), 'thousands_sep' : '-' } - - def get_fmt(x, locale, fmt='n'): - return Decimal.__format__(Decimal(x), fmt, _localeconv=locale) + dotsep_wide = { + 'decimal_point' : b'\xc2\xbf'.decode('utf-8'), + 'grouping': make_grouping([3, 3, 0]), + 'thousands_sep' : b'\xc2\xb4'.decode('utf-8') + } self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7') self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7') @@ -902,11 +1132,33 @@ self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6') self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6') - -class DecimalArithmeticOperatorsTest(unittest.TestCase): + # wide char separator and decimal point + self.assertEqual(get_fmt(Decimal('-1.5'), dotsep_wide, '020n'), + '-0\u00b4000\u00b4000\u00b4000\u00b4001\u00bf5') + + def test_wide_char_separator_decimal_point(self): + # locale with wide char separator and decimal point + Decimal = self.decimal.Decimal + + try: + locale.setlocale(locale.LC_ALL, 'ps_AF') + except locale.Error: + return + + self.assertEqual(format(Decimal('100000000.123'), 'n'), + '100\u066c000\u066c000\u066b123') + locale.resetlocale() + +class CFormatTest(FormatTest): + decimal = C +class PyFormatTest(FormatTest): + decimal = P + +class ArithmeticOperatorsTest(unittest.TestCase): '''Unit tests for all arithmetic operators, binary and unary.''' def test_addition(self): + Decimal = self.decimal.Decimal d1 = Decimal('-11.1') d2 = Decimal('22.2') @@ -934,6 +1186,7 @@ self.assertEqual(d1, Decimal('16.1')) def test_subtraction(self): + Decimal = self.decimal.Decimal d1 = Decimal('-11.1') d2 = Decimal('22.2') @@ -961,6 +1214,7 @@ self.assertEqual(d1, Decimal('-38.3')) def test_multiplication(self): + Decimal = self.decimal.Decimal d1 = Decimal('-5') d2 = Decimal('3') @@ -988,6 +1242,7 @@ self.assertEqual(d1, Decimal('-75')) def test_division(self): + Decimal = self.decimal.Decimal d1 = Decimal('-5') d2 = Decimal('2') @@ -1015,6 +1270,7 @@ self.assertEqual(d1, Decimal('-0.625')) def test_floor_division(self): + Decimal = self.decimal.Decimal d1 = Decimal('5') d2 = Decimal('2') @@ -1042,6 +1298,7 @@ self.assertEqual(d1, Decimal('1')) def test_powering(self): + Decimal = self.decimal.Decimal d1 = Decimal('5') d2 = Decimal('2') @@ -1069,6 +1326,7 @@ self.assertEqual(d1, Decimal('390625')) def test_module(self): + Decimal = self.decimal.Decimal d1 = Decimal('5') d2 = Decimal('2') @@ -1096,6 +1354,7 @@ self.assertEqual(d1, Decimal('1')) def test_floor_div_module(self): + Decimal = self.decimal.Decimal d1 = Decimal('5') d2 = Decimal('2') @@ -1122,6 +1381,8 @@ self.assertEqual(type(q), type(d1)) def test_unary_operators(self): + Decimal = self.decimal.Decimal + self.assertEqual(+Decimal(45), Decimal(+45)) # + self.assertEqual(-Decimal(45), Decimal(-45)) # - self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs @@ -1134,6 +1395,9 @@ # equality comparisons (==, !=) involving only quiet nans # don't signal, but return False or True respectively. + Decimal = self.decimal.Decimal + InvalidOperation = self.decimal.InvalidOperation + localcontext = self.decimal.localcontext n = Decimal('NaN') s = Decimal('sNaN') @@ -1179,53 +1443,124 @@ self.assertRaises(InvalidOperation, op, x, y) def test_copy_sign(self): + Decimal = self.decimal.Decimal + d = Decimal(1).copy_sign(Decimal(-2)) - self.assertEqual(Decimal(1).copy_sign(-2), d) self.assertRaises(TypeError, Decimal(1).copy_sign, '-2') +class CArithmeticOperatorsTest(ArithmeticOperatorsTest): + decimal = C +class PyArithmeticOperatorsTest(ArithmeticOperatorsTest): + decimal = P + # The following are two functions used to test threading in the next class def thfunc1(cls): + Decimal = cls.decimal.Decimal + InvalidOperation = cls.decimal.InvalidOperation + DivisionByZero = cls.decimal.DivisionByZero + Overflow = cls.decimal.Overflow + Underflow = cls.decimal.Underflow + Inexact = cls.decimal.Inexact + getcontext = cls.decimal.getcontext + localcontext = cls.decimal.localcontext + d1 = Decimal(1) d3 = Decimal(3) test1 = d1/d3 + + cls.finish1.set() cls.synchro.wait() + test2 = d1/d3 - cls.finish1.set() - - cls.assertEqual(test1, Decimal('0.3333333333333333333333333333')) - cls.assertEqual(test2, Decimal('0.3333333333333333333333333333')) + with localcontext() as c2: + cls.assertTrue(c2.flags[Inexact]) + cls.assertRaises(DivisionByZero, c2.divide, d1, 0) + cls.assertTrue(c2.flags[DivisionByZero]) + with localcontext() as c3: + cls.assertTrue(c3.flags[Inexact]) + cls.assertTrue(c3.flags[DivisionByZero]) + cls.assertRaises(InvalidOperation, c3.compare, d1, Decimal('sNaN')) + cls.assertTrue(c3.flags[InvalidOperation]) + del c3 + cls.assertFalse(c2.flags[InvalidOperation]) + del c2 + + cls.assertEqual(test1, Decimal('0.333333333333333333333333')) + cls.assertEqual(test2, Decimal('0.333333333333333333333333')) + + c1 = getcontext() + cls.assertTrue(c1.flags[Inexact]) + for sig in Overflow, Underflow, DivisionByZero, InvalidOperation: + cls.assertFalse(c1.flags[sig]) return def thfunc2(cls): + Decimal = cls.decimal.Decimal + InvalidOperation = cls.decimal.InvalidOperation + DivisionByZero = cls.decimal.DivisionByZero + Overflow = cls.decimal.Overflow + Underflow = cls.decimal.Underflow + Inexact = cls.decimal.Inexact + getcontext = cls.decimal.getcontext + localcontext = cls.decimal.localcontext + d1 = Decimal(1) d3 = Decimal(3) test1 = d1/d3 + thiscontext = getcontext() thiscontext.prec = 18 test2 = d1/d3 + + with localcontext() as c2: + cls.assertTrue(c2.flags[Inexact]) + cls.assertRaises(Overflow, c2.multiply, Decimal('1e425000000'), 999) + cls.assertTrue(c2.flags[Overflow]) + with localcontext(thiscontext) as c3: + cls.assertTrue(c3.flags[Inexact]) + cls.assertFalse(c3.flags[Overflow]) + c3.traps[Underflow] = True + cls.assertRaises(Underflow, c3.divide, Decimal('1e-425000000'), 999) + cls.assertTrue(c3.flags[Underflow]) + del c3 + cls.assertFalse(c2.flags[Underflow]) + cls.assertFalse(c2.traps[Underflow]) + del c2 + cls.synchro.set() cls.finish2.set() - cls.assertEqual(test1, Decimal('0.3333333333333333333333333333')) + cls.assertEqual(test1, Decimal('0.333333333333333333333333')) cls.assertEqual(test2, Decimal('0.333333333333333333')) + + cls.assertFalse(thiscontext.traps[Underflow]) + cls.assertTrue(thiscontext.flags[Inexact]) + for sig in Overflow, Underflow, DivisionByZero, InvalidOperation: + cls.assertFalse(thiscontext.flags[sig]) return - -class DecimalUseOfContextTest(unittest.TestCase): - '''Unit tests for Use of Context cases in Decimal.''' - - try: - import threading - except ImportError: - threading = None +class ThreadingTest(unittest.TestCase): + '''Unit tests for thread local contexts in Decimal.''' # Take care executing this test from IDLE, there's an issue in threading # that hangs IDLE and I couldn't find it def test_threading(self): - #Test the "threading isolation" of a Context. + DefaultContext = self.decimal.DefaultContext + + if self.decimal == C and not self.decimal.HAVE_THREADS: + self.skipTest("compiled without threading") + # Test the "threading isolation" of a Context. Also test changing + # the DefaultContext, which acts as a template for the thread-local + # contexts. + save_prec = DefaultContext.prec + save_emax = DefaultContext.Emax + save_emin = DefaultContext.Emin + DefaultContext.prec = 24 + DefaultContext.Emax = 425000000 + DefaultContext.Emin = -425000000 self.synchro = threading.Event() self.finish1 = threading.Event() @@ -1239,17 +1574,29 @@ self.finish1.wait() self.finish2.wait() + + for sig in Signals[self.decimal]: + self.assertFalse(DefaultContext.flags[sig]) + + DefaultContext.prec = save_prec + DefaultContext.Emax = save_emax + DefaultContext.Emin = save_emin return - if threading is None: - del test_threading - - -class DecimalUsabilityTest(unittest.TestCase): + at unittest.skipUnless(threading, 'threading required') +class CThreadingTest(ThreadingTest): + decimal = C + at unittest.skipUnless(threading, 'threading required') +class PyThreadingTest(ThreadingTest): + decimal = P + +class UsabilityTest(unittest.TestCase): '''Unit tests for Usability cases of Decimal.''' def test_comparison_operators(self): + Decimal = self.decimal.Decimal + da = Decimal('23.42') db = Decimal('23.42') dc = Decimal('45') @@ -1283,6 +1630,8 @@ self.assertEqual(a, b) def test_decimal_float_comparison(self): + Decimal = self.decimal.Decimal + da = Decimal('0.25') db = Decimal('3.0') self.assertLess(da, 3.0) @@ -1299,7 +1648,71 @@ self.assertEqual(3.0, db) self.assertNotEqual(0.1, Decimal('0.1')) + def test_decimal_complex_comparison(self): + Decimal = self.decimal.Decimal + + da = Decimal('0.25') + db = Decimal('3.0') + self.assertNotEqual(da, (1.5+0j)) + self.assertNotEqual((1.5+0j), da) + self.assertEqual(da, (0.25+0j)) + self.assertEqual((0.25+0j), da) + self.assertEqual((3.0+0j), db) + self.assertEqual(db, (3.0+0j)) + + self.assertNotEqual(db, (3.0+1j)) + self.assertNotEqual((3.0+1j), db) + + self.assertIs(db.__lt__(3.0+0j), NotImplemented) + self.assertIs(db.__le__(3.0+0j), NotImplemented) + self.assertIs(db.__gt__(3.0+0j), NotImplemented) + self.assertIs(db.__le__(3.0+0j), NotImplemented) + + def test_decimal_fraction_comparison(self): + D = self.decimal.Decimal + F = fractions[self.decimal].Fraction + Context = self.decimal.Context + localcontext = self.decimal.localcontext + InvalidOperation = self.decimal.InvalidOperation + + + emax = C.MAX_EMAX if C else 999999999 + emin = C.MIN_EMIN if C else -999999999 + etiny = C.MIN_ETINY if C else -1999999997 + c = Context(Emax=emax, Emin=emin) + + with localcontext(c): + c.prec = emax + self.assertLess(D(0), F(1,9999999999999999999999999999999999999)) + self.assertLess(F(-1,9999999999999999999999999999999999999), D(0)) + self.assertLess(F(0,1), D("1e" + str(etiny))) + self.assertLess(D("-1e" + str(etiny)), F(0,1)) + self.assertLess(F(0,9999999999999999999999999), D("1e" + str(etiny))) + self.assertLess(D("-1e" + str(etiny)), F(0,9999999999999999999999999)) + + self.assertEqual(D("0.1"), F(1,10)) + self.assertEqual(F(1,10), D("0.1")) + + c.prec = 300 + self.assertNotEqual(D(1)/3, F(1,3)) + self.assertNotEqual(F(1,3), D(1)/3) + + self.assertLessEqual(F(120984237, 9999999999), D("9e" + str(emax))) + self.assertGreaterEqual(D("9e" + str(emax)), F(120984237, 9999999999)) + + self.assertGreater(D('inf'), F(99999999999,123)) + self.assertGreater(D('inf'), F(-99999999999,123)) + self.assertLess(D('-inf'), F(99999999999,123)) + self.assertLess(D('-inf'), F(-99999999999,123)) + + self.assertRaises(InvalidOperation, D('nan').__gt__, F(-9,123)) + self.assertIs(NotImplemented, F(-9,123).__lt__(D('nan'))) + self.assertNotEqual(D('nan'), F(-9,123)) + self.assertNotEqual(F(-9,123), D('nan')) + def test_copy_and_deepcopy_methods(self): + Decimal = self.decimal.Decimal + d = Decimal('43.24') c = copy.copy(d) self.assertEqual(id(c), id(d)) @@ -1307,6 +1720,10 @@ self.assertEqual(id(dc), id(d)) def test_hash_method(self): + + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + def hashit(d): a = hash(d) b = d.__hash__() @@ -1367,24 +1784,27 @@ d = Decimal(s) self.assertEqual(hashit(f), hashit(d)) - # check that the value of the hash doesn't depend on the - # current context (issue #1757) - c = getcontext() - old_precision = c.prec - x = Decimal("123456789.1") - - c.prec = 6 - h1 = hashit(x) - c.prec = 10 - h2 = hashit(x) - c.prec = 16 - h3 = hashit(x) - - self.assertEqual(h1, h2) - self.assertEqual(h1, h3) - c.prec = old_precision + with localcontext() as c: + # check that the value of the hash doesn't depend on the + # current context (issue #1757) + x = Decimal("123456789.1") + + c.prec = 6 + h1 = hashit(x) + c.prec = 10 + h2 = hashit(x) + c.prec = 16 + h3 = hashit(x) + + self.assertEqual(h1, h2) + self.assertEqual(h1, h3) + + c.prec = 10000 + x = 1100 ** 1248 + self.assertEqual(hashit(Decimal(x)), hashit(x)) def test_min_and_max_methods(self): + Decimal = self.decimal.Decimal d1 = Decimal('15.32') d2 = Decimal('28.5') @@ -1404,6 +1824,8 @@ self.assertIs(max(d2,l1), d2) def test_as_nonzero(self): + Decimal = self.decimal.Decimal + #as false self.assertFalse(Decimal(0)) #as true @@ -1411,6 +1833,7 @@ def test_tostring_methods(self): #Test str and repr methods. + Decimal = self.decimal.Decimal d = Decimal('15.32') self.assertEqual(str(d), '15.32') # str @@ -1418,6 +1841,7 @@ def test_tonum_methods(self): #Test float and int methods. + Decimal = self.decimal.Decimal d1 = Decimal('66') d2 = Decimal('15.32') @@ -1440,6 +1864,7 @@ ('-11.0', -11), ('0.0', 0), ('-0E3', 0), + ('89891211712379812736.1', 89891211712379812736), ] for d, i in test_pairs: self.assertEqual(math.floor(Decimal(d)), i) @@ -1459,6 +1884,7 @@ ('-11.0', -11), ('0.0', 0), ('-0E3', 0), + ('89891211712379812736.1', 89891211712379812737), ] for d, i in test_pairs: self.assertEqual(math.ceil(Decimal(d)), i) @@ -1516,9 +1942,8 @@ for d, n, r in test_triples: self.assertEqual(str(round(Decimal(d), n)), r) - - def test_eval_round_trip(self): + Decimal = self.decimal.Decimal #with zero d = Decimal( (0, (0,), 0) ) @@ -1537,6 +1962,7 @@ self.assertEqual(d, eval(repr(d))) def test_as_tuple(self): + Decimal = self.decimal.Decimal #with zero d = Decimal(0) @@ -1550,7 +1976,7 @@ d = Decimal("-4.34913534E-17") self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) - #inf + # XXX non-compliant infinity payload. d = Decimal("Infinity") self.assertEqual(d.as_tuple(), (0, (0,), 'F') ) @@ -1570,14 +1996,2158 @@ d = Decimal( (1, (), 'n') ) self.assertEqual(d.as_tuple(), (1, (), 'n') ) - #coefficient in infinity should be ignored - d = Decimal( (0, (4, 5, 3, 4), 'F') ) - self.assertEqual(d.as_tuple(), (0, (0,), 'F')) - d = Decimal( (1, (0, 2, 7, 1), 'F') ) - self.assertEqual(d.as_tuple(), (1, (0,), 'F')) - - def test_immutability_operations(self): + # XXX coefficient in infinity should raise an error + if self.decimal == P: + d = Decimal( (0, (4, 5, 3, 4), 'F') ) + self.assertEqual(d.as_tuple(), (0, (0,), 'F')) + d = Decimal( (1, (0, 2, 7, 1), 'F') ) + self.assertEqual(d.as_tuple(), (1, (0,), 'F')) + + def test_subclassing(self): + # Different behaviours when subclassing Decimal + Decimal = self.decimal.Decimal + + class MyDecimal(Decimal): + pass + + d1 = MyDecimal(1) + d2 = MyDecimal(2) + d = d1 + d2 + self.assertIs(type(d), Decimal) + + d = d1.max(d2) + self.assertIs(type(d), Decimal) + + d = copy.copy(d1) + self.assertIs(type(d), MyDecimal) + self.assertEqual(d, d1) + + d = copy.deepcopy(d1) + self.assertIs(type(d), MyDecimal) + self.assertEqual(d, d1) + + def test_implicit_context(self): + Decimal = self.decimal.Decimal + getcontext = self.decimal.getcontext + + # Check results when context given implicitly. (Issue 2478) + c = getcontext() + self.assertEqual(str(Decimal(0).sqrt()), + str(c.sqrt(Decimal(0)))) + + def test_conversions_from_int(self): + # Check that methods taking a second Decimal argument will + # always accept an integer in place of a Decimal. + Decimal = self.decimal.Decimal + + self.assertEqual(Decimal(4).compare(3), + Decimal(4).compare(Decimal(3))) + self.assertEqual(Decimal(4).compare_signal(3), + Decimal(4).compare_signal(Decimal(3))) + self.assertEqual(Decimal(4).compare_total(3), + Decimal(4).compare_total(Decimal(3))) + self.assertEqual(Decimal(4).compare_total_mag(3), + Decimal(4).compare_total_mag(Decimal(3))) + self.assertEqual(Decimal(10101).logical_and(1001), + Decimal(10101).logical_and(Decimal(1001))) + self.assertEqual(Decimal(10101).logical_or(1001), + Decimal(10101).logical_or(Decimal(1001))) + self.assertEqual(Decimal(10101).logical_xor(1001), + Decimal(10101).logical_xor(Decimal(1001))) + self.assertEqual(Decimal(567).max(123), + Decimal(567).max(Decimal(123))) + self.assertEqual(Decimal(567).max_mag(123), + Decimal(567).max_mag(Decimal(123))) + self.assertEqual(Decimal(567).min(123), + Decimal(567).min(Decimal(123))) + self.assertEqual(Decimal(567).min_mag(123), + Decimal(567).min_mag(Decimal(123))) + self.assertEqual(Decimal(567).next_toward(123), + Decimal(567).next_toward(Decimal(123))) + self.assertEqual(Decimal(1234).quantize(100), + Decimal(1234).quantize(Decimal(100))) + self.assertEqual(Decimal(768).remainder_near(1234), + Decimal(768).remainder_near(Decimal(1234))) + self.assertEqual(Decimal(123).rotate(1), + Decimal(123).rotate(Decimal(1))) + self.assertEqual(Decimal(1234).same_quantum(1000), + Decimal(1234).same_quantum(Decimal(1000))) + self.assertEqual(Decimal('9.123').scaleb(-100), + Decimal('9.123').scaleb(Decimal(-100))) + self.assertEqual(Decimal(456).shift(-1), + Decimal(456).shift(Decimal(-1))) + + self.assertEqual(Decimal(-12).fma(Decimal(45), 67), + Decimal(-12).fma(Decimal(45), Decimal(67))) + self.assertEqual(Decimal(-12).fma(45, 67), + Decimal(-12).fma(Decimal(45), Decimal(67))) + self.assertEqual(Decimal(-12).fma(45, Decimal(67)), + Decimal(-12).fma(Decimal(45), Decimal(67))) + +class CUsabilityTest(UsabilityTest): + decimal = C +class PyUsabilityTest(UsabilityTest): + decimal = P + +class PythonAPItests(unittest.TestCase): + + def test_abc(self): + Decimal = self.decimal.Decimal + + self.assertTrue(issubclass(Decimal, numbers.Number)) + self.assertFalse(issubclass(Decimal, numbers.Real)) + self.assertIsInstance(Decimal(0), numbers.Number) + self.assertNotIsInstance(Decimal(0), numbers.Real) + + def test_pickle(self): + Decimal = self.decimal.Decimal + + savedecimal = sys.modules['decimal'] + + # Round trip + sys.modules['decimal'] = self.decimal + d = Decimal('-3.141590000') + p = pickle.dumps(d) + e = pickle.loads(p) + self.assertEqual(d, e) + + if C: + # Test interchangeability + x = C.Decimal('-3.123e81723') + y = P.Decimal('-3.123e81723') + + sys.modules['decimal'] = C + sx = pickle.dumps(x) + sys.modules['decimal'] = P + r = pickle.loads(sx) + self.assertIsInstance(r, P.Decimal) + self.assertEqual(r, y) + + sys.modules['decimal'] = P + sy = pickle.dumps(y) + sys.modules['decimal'] = C + r = pickle.loads(sy) + self.assertIsInstance(r, C.Decimal) + self.assertEqual(r, x) + + sys.modules['decimal'] = savedecimal + + def test_int(self): + Decimal = self.decimal.Decimal + ROUND_DOWN = self.decimal.ROUND_DOWN + + for x in range(-250, 250): + s = '%0.2f' % (x / 100.0) + # should work the same as for floats + self.assertEqual(int(Decimal(s)), int(float(s))) + # should work the same as to_integral in the ROUND_DOWN mode + d = Decimal(s) + r = d.to_integral(ROUND_DOWN) + self.assertEqual(Decimal(int(d)), r) + + self.assertRaises(ValueError, int, Decimal('-nan')) + self.assertRaises(ValueError, int, Decimal('snan')) + self.assertRaises(OverflowError, int, Decimal('inf')) + self.assertRaises(OverflowError, int, Decimal('-inf')) + + def test_trunc(self): + Decimal = self.decimal.Decimal + ROUND_DOWN = self.decimal.ROUND_DOWN + + for x in range(-250, 250): + s = '%0.2f' % (x / 100.0) + # should work the same as for floats + self.assertEqual(int(Decimal(s)), int(float(s))) + # should work the same as to_integral in the ROUND_DOWN mode + d = Decimal(s) + r = d.to_integral(ROUND_DOWN) + self.assertEqual(Decimal(math.trunc(d)), r) + + def test_from_float(self): + + Decimal = self.decimal.Decimal + + class MyDecimal(Decimal): + pass + + self.assertTrue(issubclass(MyDecimal, Decimal)) + + r = MyDecimal.from_float(0.1) + self.assertEqual(type(r), MyDecimal) + self.assertEqual(str(r), + '0.1000000000000000055511151231257827021181583404541015625') + bigint = 12345678901234567890123456789 + self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint)) + self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan()) + self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite()) + self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite()) + self.assertEqual(str(MyDecimal.from_float(float('nan'))), + str(Decimal('NaN'))) + self.assertEqual(str(MyDecimal.from_float(float('inf'))), + str(Decimal('Infinity'))) + self.assertEqual(str(MyDecimal.from_float(float('-inf'))), + str(Decimal('-Infinity'))) + self.assertRaises(TypeError, MyDecimal.from_float, 'abc') + for i in range(200): + x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) + self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip + + def test_create_decimal_from_float(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + ROUND_DOWN = self.decimal.ROUND_DOWN + ROUND_UP = self.decimal.ROUND_UP + Inexact = self.decimal.Inexact + + context = Context(prec=5, rounding=ROUND_DOWN) + self.assertEqual( + context.create_decimal_from_float(math.pi), + Decimal('3.1415') + ) + context = Context(prec=5, rounding=ROUND_UP) + self.assertEqual( + context.create_decimal_from_float(math.pi), + Decimal('3.1416') + ) + context = Context(prec=5, traps=[Inexact]) + self.assertRaises( + Inexact, + context.create_decimal_from_float, + math.pi + ) + self.assertEqual(repr(context.create_decimal_from_float(-0.0)), + "Decimal('-0')") + self.assertEqual(repr(context.create_decimal_from_float(1.0)), + "Decimal('1')") + self.assertEqual(repr(context.create_decimal_from_float(10)), + "Decimal('10')") + + def test_quantize(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + InvalidOperation = self.decimal.InvalidOperation + ROUND_DOWN = self.decimal.ROUND_DOWN + + c = Context(Emax=99999, Emin=-99999) + self.assertEqual( + Decimal('7.335').quantize(Decimal('.01')), + Decimal('7.34') + ) + self.assertEqual( + Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN), + Decimal('7.33') + ) + self.assertRaises( + InvalidOperation, + Decimal("10e99999").quantize, Decimal('1e100000'), context=c + ) + + c = Context() + d = Decimal("0.871831e800") + x = d.quantize(context=c, exp=Decimal("1e797"), rounding=ROUND_DOWN) + self.assertEqual(x, Decimal('8.71E+799')) + + def test_complex(self): + Decimal = self.decimal.Decimal + + x = Decimal("9.8182731e181273") + self.assertEqual(x.real, x) + self.assertEqual(x.imag, 0) + self.assertEqual(x.conjugate(), x) + + x = Decimal("1") + self.assertEqual(complex(x), complex(float(1))) + + self.assertRaises(AttributeError, setattr, x, 'real', 100) + self.assertRaises(AttributeError, setattr, x, 'imag', 100) + self.assertRaises(AttributeError, setattr, x, 'conjugate', 100) + self.assertRaises(AttributeError, setattr, x, '__complex__', 100) + + def test_named_parameters(self): + D = self.decimal.Decimal + Context = self.decimal.Context + localcontext = self.decimal.localcontext + InvalidOperation = self.decimal.InvalidOperation + Overflow = self.decimal.Overflow + + xc = Context() + xc.prec = 1 + xc.Emax = 1 + xc.Emin = -1 + + with localcontext() as c: + c.clear_flags() + + self.assertEqual(D(9, xc), 9) + self.assertEqual(D(9, context=xc), 9) + self.assertEqual(D(context=xc, value=9), 9) + self.assertEqual(D(context=xc), 0) + xc.clear_flags() + self.assertRaises(InvalidOperation, D, "xyz", context=xc) + self.assertTrue(xc.flags[InvalidOperation]) + self.assertFalse(c.flags[InvalidOperation]) + + xc.clear_flags() + self.assertEqual(D(2).exp(context=xc), 7) + self.assertRaises(Overflow, D(8).exp, context=xc) + self.assertTrue(xc.flags[Overflow]) + self.assertFalse(c.flags[Overflow]) + + xc.clear_flags() + self.assertEqual(D(2).ln(context=xc), D('0.7')) + self.assertRaises(InvalidOperation, D(-1).ln, context=xc) + self.assertTrue(xc.flags[InvalidOperation]) + self.assertFalse(c.flags[InvalidOperation]) + + self.assertEqual(D(0).log10(context=xc), D('-inf')) + self.assertEqual(D(-1).next_minus(context=xc), -2) + self.assertEqual(D(-1).next_plus(context=xc), D('-0.9')) + self.assertEqual(D("9.73").normalize(context=xc), D('1E+1')) + self.assertEqual(D("9999").to_integral(context=xc), 9999) + self.assertEqual(D("-2000").to_integral_exact(context=xc), -2000) + self.assertEqual(D("123").to_integral_value(context=xc), 123) + self.assertEqual(D("0.0625").sqrt(context=xc), D('0.2')) + + self.assertEqual(D("0.0625").compare(context=xc, other=3), -1) + xc.clear_flags() + self.assertRaises(InvalidOperation, + D("0").compare_signal, D('nan'), context=xc) + self.assertTrue(xc.flags[InvalidOperation]) + self.assertFalse(c.flags[InvalidOperation]) + self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0')) + self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0')) + self.assertEqual(D("0.2").max_mag(D('-0.3'), context=xc), + D('-0.3')) + self.assertEqual(D("0.02").min(D('-0.03'), context=xc), D('-0.0')) + self.assertEqual(D("0.02").min_mag(D('-0.03'), context=xc), + D('0.0')) + self.assertEqual(D("0.2").next_toward(D('-1'), context=xc), D('0.1')) + xc.clear_flags() + self.assertRaises(InvalidOperation, + D("0.2").quantize, D('1e10'), context=xc) + self.assertTrue(xc.flags[InvalidOperation]) + self.assertFalse(c.flags[InvalidOperation]) + self.assertEqual(D("9.99").remainder_near(D('1.5'), context=xc), + D('-0.5')) + + self.assertEqual(D("9.9").fma(third=D('0.9'), context=xc, other=7), + D('7E+1')) + + self.assertRaises(TypeError, D(1).is_canonical, context=xc) + self.assertRaises(TypeError, D(1).is_finite, context=xc) + self.assertRaises(TypeError, D(1).is_infinite, context=xc) + self.assertRaises(TypeError, D(1).is_nan, context=xc) + self.assertRaises(TypeError, D(1).is_qnan, context=xc) + self.assertRaises(TypeError, D(1).is_snan, context=xc) + self.assertRaises(TypeError, D(1).is_signed, context=xc) + self.assertRaises(TypeError, D(1).is_zero, context=xc) + + self.assertFalse(D("0.01").is_normal(context=xc)) + self.assertTrue(D("0.01").is_subnormal(context=xc)) + + self.assertRaises(TypeError, D(1).adjusted, context=xc) + self.assertRaises(TypeError, D(1).conjugate, context=xc) + self.assertRaises(TypeError, D(1).radix, context=xc) + + self.assertEqual(D(-111).logb(context=xc), 2) + self.assertEqual(D(0).logical_invert(context=xc), 1) + self.assertEqual(D('0.01').number_class(context=xc), '+Subnormal') + self.assertEqual(D('0.21').to_eng_string(context=xc), '0.21') + + self.assertEqual(D('11').logical_and(D('10'), context=xc), 0) + self.assertEqual(D('11').logical_or(D('10'), context=xc), 1) + self.assertEqual(D('01').logical_xor(D('10'), context=xc), 1) + self.assertEqual(D('23').rotate(1, context=xc), 3) + self.assertEqual(D('23').rotate(1, context=xc), 3) + xc.clear_flags() + self.assertRaises(Overflow, + D('23').scaleb, 1, context=xc) + self.assertTrue(xc.flags[Overflow]) + self.assertFalse(c.flags[Overflow]) + self.assertEqual(D('23').shift(-1, context=xc), 0) + + self.assertRaises(TypeError, D.from_float, 1.1, context=xc) + self.assertRaises(TypeError, D(0).as_tuple, context=xc) + + if (self.decimal == C): + self.assertRaises(TypeError, D(1).canonical, context=xc) + self.assertEqual(D("-1").copy_abs(context=xc), 1) + self.assertEqual(D("1").copy_negate(context=xc), -1) + else: + self.assertEqual(D(1).canonical(context=xc), 1) + self.assertRaises(TypeError, D("-1").copy_abs, context=xc) + self.assertRaises(TypeError, D("-1").copy_negate, context=xc) + +class CPythonAPItests(PythonAPItests): + decimal = C +class PyPythonAPItests(PythonAPItests): + decimal = P + +class ContextAPItests(unittest.TestCase): + + def test_pickle(self): + + Context = self.decimal.Context + + savedecimal = sys.modules['decimal'] + + # Round trip + sys.modules['decimal'] = self.decimal + c = Context() + e = pickle.loads(pickle.dumps(c)) + + self.assertEqual(c.prec, e.prec) + self.assertEqual(c.Emin, e.Emin) + self.assertEqual(c.Emax, e.Emax) + self.assertEqual(c.rounding, e.rounding) + self.assertEqual(c.capitals, e.capitals) + self.assertEqual(c.clamp, e.clamp) + self.assertEqual(c.flags, e.flags) + self.assertEqual(c.traps, e.traps) + + # Test interchangeability + combinations = [(C, P), (P, C)] if C else [(P, P)] + for dumper, loader in combinations: + for ri, _ in enumerate(RoundingModes[dumper]): + for fi, _ in enumerate(OrderedSignals[dumper]): + for ti, _ in enumerate(OrderedSignals[dumper]): + + prec = random.randrange(1, 100) + emin = random.randrange(-100, 0) + emax = random.randrange(1, 100) + caps = random.randrange(2) + clamp = random.randrange(2) + + # One module dumps + sys.modules['decimal'] = dumper + c = dumper.Context( + prec=prec, Emin=emin, Emax=emax, + rounding=RoundingModes[dumper][ri], + capitals=caps, clamp=clamp, + flags=OrderedSignals[dumper][:fi], + traps=OrderedSignals[dumper][:ti] + ) + s = pickle.dumps(c) + + # The other module loads + sys.modules['decimal'] = loader + d = pickle.loads(s) + self.assertIsInstance(d, loader.Context) + + self.assertEqual(d.prec, prec) + self.assertEqual(d.Emin, emin) + self.assertEqual(d.Emax, emax) + self.assertEqual(d.rounding, RoundingModes[loader][ri]) + self.assertEqual(d.capitals, caps) + self.assertEqual(d.clamp, clamp) + assert_signals(self, d, 'flags', OrderedSignals[loader][:fi]) + assert_signals(self, d, 'traps', OrderedSignals[loader][:ti]) + + sys.modules['decimal'] = savedecimal + + def test_equality_with_other_types(self): + Decimal = self.decimal.Decimal + + self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}]) + self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}]) + + def test_copy(self): + # All copies should be deep + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy() + self.assertNotEqual(id(c), id(d)) + self.assertNotEqual(id(c.flags), id(d.flags)) + self.assertNotEqual(id(c.traps), id(d.traps)) + k1 = set(c.flags.keys()) + k2 = set(d.flags.keys()) + self.assertEqual(k1, k2) + self.assertEqual(c.flags, d.flags) + + def test__clamp(self): + # In Python 3.2, the private attribute `_clamp` was made + # public (issue 8540), with the old `_clamp` becoming a + # property wrapping `clamp`. For the duration of Python 3.2 + # only, the attribute should be gettable/settable via both + # `clamp` and `_clamp`; in Python 3.3, `_clamp` should be + # removed. + Context = self.decimal.Context + c = Context() + self.assertRaises(AttributeError, getattr, c, '_clamp') + + def test_abs(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.abs(Decimal(-1)) + self.assertEqual(c.abs(-1), d) + self.assertRaises(TypeError, c.abs, '-1') + + def test_add(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.add(Decimal(1), Decimal(1)) + self.assertEqual(c.add(1, 1), d) + self.assertEqual(c.add(Decimal(1), 1), d) + self.assertEqual(c.add(1, Decimal(1)), d) + self.assertRaises(TypeError, c.add, '1', 1) + self.assertRaises(TypeError, c.add, 1, '1') + + def test_compare(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.compare(Decimal(1), Decimal(1)) + self.assertEqual(c.compare(1, 1), d) + self.assertEqual(c.compare(Decimal(1), 1), d) + self.assertEqual(c.compare(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare, '1', 1) + self.assertRaises(TypeError, c.compare, 1, '1') + + def test_compare_signal(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.compare_signal(Decimal(1), Decimal(1)) + self.assertEqual(c.compare_signal(1, 1), d) + self.assertEqual(c.compare_signal(Decimal(1), 1), d) + self.assertEqual(c.compare_signal(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare_signal, '1', 1) + self.assertRaises(TypeError, c.compare_signal, 1, '1') + + def test_compare_total(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.compare_total(Decimal(1), Decimal(1)) + self.assertEqual(c.compare_total(1, 1), d) + self.assertEqual(c.compare_total(Decimal(1), 1), d) + self.assertEqual(c.compare_total(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare_total, '1', 1) + self.assertRaises(TypeError, c.compare_total, 1, '1') + + def test_compare_total_mag(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.compare_total_mag(Decimal(1), Decimal(1)) + self.assertEqual(c.compare_total_mag(1, 1), d) + self.assertEqual(c.compare_total_mag(Decimal(1), 1), d) + self.assertEqual(c.compare_total_mag(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare_total_mag, '1', 1) + self.assertRaises(TypeError, c.compare_total_mag, 1, '1') + + def test_copy_abs(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy_abs(Decimal(-1)) + self.assertEqual(c.copy_abs(-1), d) + self.assertRaises(TypeError, c.copy_abs, '-1') + + def test_copy_decimal(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy_decimal(Decimal(-1)) + self.assertEqual(c.copy_decimal(-1), d) + self.assertRaises(TypeError, c.copy_decimal, '-1') + + def test_copy_negate(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy_negate(Decimal(-1)) + self.assertEqual(c.copy_negate(-1), d) + self.assertRaises(TypeError, c.copy_negate, '-1') + + def test_copy_sign(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy_sign(Decimal(1), Decimal(-2)) + self.assertEqual(c.copy_sign(1, -2), d) + self.assertEqual(c.copy_sign(Decimal(1), -2), d) + self.assertEqual(c.copy_sign(1, Decimal(-2)), d) + self.assertRaises(TypeError, c.copy_sign, '1', -2) + self.assertRaises(TypeError, c.copy_sign, 1, '-2') + + def test_divide(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.divide(Decimal(1), Decimal(2)) + self.assertEqual(c.divide(1, 2), d) + self.assertEqual(c.divide(Decimal(1), 2), d) + self.assertEqual(c.divide(1, Decimal(2)), d) + self.assertRaises(TypeError, c.divide, '1', 2) + self.assertRaises(TypeError, c.divide, 1, '2') + + def test_divide_int(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.divide_int(Decimal(1), Decimal(2)) + self.assertEqual(c.divide_int(1, 2), d) + self.assertEqual(c.divide_int(Decimal(1), 2), d) + self.assertEqual(c.divide_int(1, Decimal(2)), d) + self.assertRaises(TypeError, c.divide_int, '1', 2) + self.assertRaises(TypeError, c.divide_int, 1, '2') + + def test_divmod(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.divmod(Decimal(1), Decimal(2)) + self.assertEqual(c.divmod(1, 2), d) + self.assertEqual(c.divmod(Decimal(1), 2), d) + self.assertEqual(c.divmod(1, Decimal(2)), d) + self.assertRaises(TypeError, c.divmod, '1', 2) + self.assertRaises(TypeError, c.divmod, 1, '2') + + def test_exp(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.exp(Decimal(10)) + self.assertEqual(c.exp(10), d) + self.assertRaises(TypeError, c.exp, '10') + + def test_fma(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.fma(Decimal(2), Decimal(3), Decimal(4)) + self.assertEqual(c.fma(2, 3, 4), d) + self.assertEqual(c.fma(Decimal(2), 3, 4), d) + self.assertEqual(c.fma(2, Decimal(3), 4), d) + self.assertEqual(c.fma(2, 3, Decimal(4)), d) + self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d) + self.assertRaises(TypeError, c.fma, '2', 3, 4) + self.assertRaises(TypeError, c.fma, 2, '3', 4) + self.assertRaises(TypeError, c.fma, 2, 3, '4') + + # Issue 12079 for Context.fma ... + self.assertRaises(TypeError, c.fma, + Decimal('Infinity'), Decimal(0), "not a decimal") + self.assertRaises(TypeError, c.fma, + Decimal(1), Decimal('snan'), 1.222) + # ... and for Decimal.fma. + self.assertRaises(TypeError, Decimal('Infinity').fma, + Decimal(0), "not a decimal") + self.assertRaises(TypeError, Decimal(1).fma, + Decimal('snan'), 1.222) + + def test_is_finite(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_finite(Decimal(10)) + self.assertEqual(c.is_finite(10), d) + self.assertRaises(TypeError, c.is_finite, '10') + + def test_is_infinite(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_infinite(Decimal(10)) + self.assertEqual(c.is_infinite(10), d) + self.assertRaises(TypeError, c.is_infinite, '10') + + def test_is_nan(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_nan(Decimal(10)) + self.assertEqual(c.is_nan(10), d) + self.assertRaises(TypeError, c.is_nan, '10') + + def test_is_normal(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_normal(Decimal(10)) + self.assertEqual(c.is_normal(10), d) + self.assertRaises(TypeError, c.is_normal, '10') + + def test_is_qnan(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_qnan(Decimal(10)) + self.assertEqual(c.is_qnan(10), d) + self.assertRaises(TypeError, c.is_qnan, '10') + + def test_is_signed(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_signed(Decimal(10)) + self.assertEqual(c.is_signed(10), d) + self.assertRaises(TypeError, c.is_signed, '10') + + def test_is_snan(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_snan(Decimal(10)) + self.assertEqual(c.is_snan(10), d) + self.assertRaises(TypeError, c.is_snan, '10') + + def test_is_subnormal(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_subnormal(Decimal(10)) + self.assertEqual(c.is_subnormal(10), d) + self.assertRaises(TypeError, c.is_subnormal, '10') + + def test_is_zero(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_zero(Decimal(10)) + self.assertEqual(c.is_zero(10), d) + self.assertRaises(TypeError, c.is_zero, '10') + + def test_ln(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.ln(Decimal(10)) + self.assertEqual(c.ln(10), d) + self.assertRaises(TypeError, c.ln, '10') + + def test_log10(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.log10(Decimal(10)) + self.assertEqual(c.log10(10), d) + self.assertRaises(TypeError, c.log10, '10') + + def test_logb(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logb(Decimal(10)) + self.assertEqual(c.logb(10), d) + self.assertRaises(TypeError, c.logb, '10') + + def test_logical_and(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logical_and(Decimal(1), Decimal(1)) + self.assertEqual(c.logical_and(1, 1), d) + self.assertEqual(c.logical_and(Decimal(1), 1), d) + self.assertEqual(c.logical_and(1, Decimal(1)), d) + self.assertRaises(TypeError, c.logical_and, '1', 1) + self.assertRaises(TypeError, c.logical_and, 1, '1') + + def test_logical_invert(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logical_invert(Decimal(1000)) + self.assertEqual(c.logical_invert(1000), d) + self.assertRaises(TypeError, c.logical_invert, '1000') + + def test_logical_or(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logical_or(Decimal(1), Decimal(1)) + self.assertEqual(c.logical_or(1, 1), d) + self.assertEqual(c.logical_or(Decimal(1), 1), d) + self.assertEqual(c.logical_or(1, Decimal(1)), d) + self.assertRaises(TypeError, c.logical_or, '1', 1) + self.assertRaises(TypeError, c.logical_or, 1, '1') + + def test_logical_xor(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logical_xor(Decimal(1), Decimal(1)) + self.assertEqual(c.logical_xor(1, 1), d) + self.assertEqual(c.logical_xor(Decimal(1), 1), d) + self.assertEqual(c.logical_xor(1, Decimal(1)), d) + self.assertRaises(TypeError, c.logical_xor, '1', 1) + self.assertRaises(TypeError, c.logical_xor, 1, '1') + + def test_max(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.max(Decimal(1), Decimal(2)) + self.assertEqual(c.max(1, 2), d) + self.assertEqual(c.max(Decimal(1), 2), d) + self.assertEqual(c.max(1, Decimal(2)), d) + self.assertRaises(TypeError, c.max, '1', 2) + self.assertRaises(TypeError, c.max, 1, '2') + + def test_max_mag(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.max_mag(Decimal(1), Decimal(2)) + self.assertEqual(c.max_mag(1, 2), d) + self.assertEqual(c.max_mag(Decimal(1), 2), d) + self.assertEqual(c.max_mag(1, Decimal(2)), d) + self.assertRaises(TypeError, c.max_mag, '1', 2) + self.assertRaises(TypeError, c.max_mag, 1, '2') + + def test_min(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.min(Decimal(1), Decimal(2)) + self.assertEqual(c.min(1, 2), d) + self.assertEqual(c.min(Decimal(1), 2), d) + self.assertEqual(c.min(1, Decimal(2)), d) + self.assertRaises(TypeError, c.min, '1', 2) + self.assertRaises(TypeError, c.min, 1, '2') + + def test_min_mag(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.min_mag(Decimal(1), Decimal(2)) + self.assertEqual(c.min_mag(1, 2), d) + self.assertEqual(c.min_mag(Decimal(1), 2), d) + self.assertEqual(c.min_mag(1, Decimal(2)), d) + self.assertRaises(TypeError, c.min_mag, '1', 2) + self.assertRaises(TypeError, c.min_mag, 1, '2') + + def test_minus(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.minus(Decimal(10)) + self.assertEqual(c.minus(10), d) + self.assertRaises(TypeError, c.minus, '10') + + def test_multiply(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.multiply(Decimal(1), Decimal(2)) + self.assertEqual(c.multiply(1, 2), d) + self.assertEqual(c.multiply(Decimal(1), 2), d) + self.assertEqual(c.multiply(1, Decimal(2)), d) + self.assertRaises(TypeError, c.multiply, '1', 2) + self.assertRaises(TypeError, c.multiply, 1, '2') + + def test_next_minus(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.next_minus(Decimal(10)) + self.assertEqual(c.next_minus(10), d) + self.assertRaises(TypeError, c.next_minus, '10') + + def test_next_plus(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.next_plus(Decimal(10)) + self.assertEqual(c.next_plus(10), d) + self.assertRaises(TypeError, c.next_plus, '10') + + def test_next_toward(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.next_toward(Decimal(1), Decimal(2)) + self.assertEqual(c.next_toward(1, 2), d) + self.assertEqual(c.next_toward(Decimal(1), 2), d) + self.assertEqual(c.next_toward(1, Decimal(2)), d) + self.assertRaises(TypeError, c.next_toward, '1', 2) + self.assertRaises(TypeError, c.next_toward, 1, '2') + + def test_normalize(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.normalize(Decimal(10)) + self.assertEqual(c.normalize(10), d) + self.assertRaises(TypeError, c.normalize, '10') + + def test_number_class(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + self.assertEqual(c.number_class(123), c.number_class(Decimal(123))) + self.assertEqual(c.number_class(0), c.number_class(Decimal(0))) + self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45))) + + def test_plus(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.plus(Decimal(10)) + self.assertEqual(c.plus(10), d) + self.assertRaises(TypeError, c.plus, '10') + + def test_power(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.power(Decimal(1), Decimal(4)) + self.assertEqual(c.power(1, 4), d) + self.assertEqual(c.power(Decimal(1), 4), d) + self.assertEqual(c.power(1, Decimal(4)), d) + self.assertEqual(c.power(Decimal(1), Decimal(4)), d) + self.assertRaises(TypeError, c.power, '1', 4) + self.assertRaises(TypeError, c.power, 1, '4') + self.assertEqual(c.power(modulo=5, b=8, a=2), 1) + + def test_quantize(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.quantize(Decimal(1), Decimal(2)) + self.assertEqual(c.quantize(1, 2), d) + self.assertEqual(c.quantize(Decimal(1), 2), d) + self.assertEqual(c.quantize(1, Decimal(2)), d) + self.assertRaises(TypeError, c.quantize, '1', 2) + self.assertRaises(TypeError, c.quantize, 1, '2') + + def test_remainder(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.remainder(Decimal(1), Decimal(2)) + self.assertEqual(c.remainder(1, 2), d) + self.assertEqual(c.remainder(Decimal(1), 2), d) + self.assertEqual(c.remainder(1, Decimal(2)), d) + self.assertRaises(TypeError, c.remainder, '1', 2) + self.assertRaises(TypeError, c.remainder, 1, '2') + + def test_remainder_near(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.remainder_near(Decimal(1), Decimal(2)) + self.assertEqual(c.remainder_near(1, 2), d) + self.assertEqual(c.remainder_near(Decimal(1), 2), d) + self.assertEqual(c.remainder_near(1, Decimal(2)), d) + self.assertRaises(TypeError, c.remainder_near, '1', 2) + self.assertRaises(TypeError, c.remainder_near, 1, '2') + + def test_rotate(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.rotate(Decimal(1), Decimal(2)) + self.assertEqual(c.rotate(1, 2), d) + self.assertEqual(c.rotate(Decimal(1), 2), d) + self.assertEqual(c.rotate(1, Decimal(2)), d) + self.assertRaises(TypeError, c.rotate, '1', 2) + self.assertRaises(TypeError, c.rotate, 1, '2') + + def test_sqrt(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.sqrt(Decimal(10)) + self.assertEqual(c.sqrt(10), d) + self.assertRaises(TypeError, c.sqrt, '10') + + def test_same_quantum(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.same_quantum(Decimal(1), Decimal(2)) + self.assertEqual(c.same_quantum(1, 2), d) + self.assertEqual(c.same_quantum(Decimal(1), 2), d) + self.assertEqual(c.same_quantum(1, Decimal(2)), d) + self.assertRaises(TypeError, c.same_quantum, '1', 2) + self.assertRaises(TypeError, c.same_quantum, 1, '2') + + def test_scaleb(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.scaleb(Decimal(1), Decimal(2)) + self.assertEqual(c.scaleb(1, 2), d) + self.assertEqual(c.scaleb(Decimal(1), 2), d) + self.assertEqual(c.scaleb(1, Decimal(2)), d) + self.assertRaises(TypeError, c.scaleb, '1', 2) + self.assertRaises(TypeError, c.scaleb, 1, '2') + + def test_shift(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.shift(Decimal(1), Decimal(2)) + self.assertEqual(c.shift(1, 2), d) + self.assertEqual(c.shift(Decimal(1), 2), d) + self.assertEqual(c.shift(1, Decimal(2)), d) + self.assertRaises(TypeError, c.shift, '1', 2) + self.assertRaises(TypeError, c.shift, 1, '2') + + def test_subtract(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.subtract(Decimal(1), Decimal(2)) + self.assertEqual(c.subtract(1, 2), d) + self.assertEqual(c.subtract(Decimal(1), 2), d) + self.assertEqual(c.subtract(1, Decimal(2)), d) + self.assertRaises(TypeError, c.subtract, '1', 2) + self.assertRaises(TypeError, c.subtract, 1, '2') + + def test_to_eng_string(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.to_eng_string(Decimal(10)) + self.assertEqual(c.to_eng_string(10), d) + self.assertRaises(TypeError, c.to_eng_string, '10') + + def test_to_sci_string(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.to_sci_string(Decimal(10)) + self.assertEqual(c.to_sci_string(10), d) + self.assertRaises(TypeError, c.to_sci_string, '10') + + def test_to_integral_exact(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.to_integral_exact(Decimal(10)) + self.assertEqual(c.to_integral_exact(10), d) + self.assertRaises(TypeError, c.to_integral_exact, '10') + + def test_to_integral_value(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.to_integral_value(Decimal(10)) + self.assertEqual(c.to_integral_value(10), d) + self.assertRaises(TypeError, c.to_integral_value, '10') + self.assertRaises(TypeError, c.to_integral_value, 10, 'x') + +class CContextAPItests(ContextAPItests): + decimal = C +class PyContextAPItests(ContextAPItests): + decimal = P + +class ContextWithStatement(unittest.TestCase): + # Can't do these as docstrings until Python 2.6 + # as doctest can't handle __future__ statements + + def test_localcontext(self): + # Use a copy of the current context in the block + getcontext = self.decimal.getcontext + localcontext = self.decimal.localcontext + + orig_ctx = getcontext() + with localcontext() as enter_ctx: + set_ctx = getcontext() + final_ctx = getcontext() + self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly') + self.assertIsNot(orig_ctx, set_ctx, 'did not copy the context') + self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context') + + def test_localcontextarg(self): + # Use a copy of the supplied context in the block + Context = self.decimal.Context + getcontext = self.decimal.getcontext + localcontext = self.decimal.localcontext + + localcontext = self.decimal.localcontext + orig_ctx = getcontext() + new_ctx = Context(prec=42) + with localcontext(new_ctx) as enter_ctx: + set_ctx = getcontext() + final_ctx = getcontext() + self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly') + self.assertEqual(set_ctx.prec, new_ctx.prec, 'did not set correct context') + self.assertIsNot(new_ctx, set_ctx, 'did not copy the context') + self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context') + + def test_nested_with_statements(self): + # Use a copy of the supplied context in the block + Decimal = self.decimal.Decimal + Context = self.decimal.Context + getcontext = self.decimal.getcontext + localcontext = self.decimal.localcontext + Clamped = self.decimal.Clamped + Overflow = self.decimal.Overflow + + orig_ctx = getcontext() + orig_ctx.clear_flags() + new_ctx = Context(Emax=384) + with localcontext() as c1: + self.assertEqual(c1.flags, orig_ctx.flags) + self.assertEqual(c1.traps, orig_ctx.traps) + c1.traps[Clamped] = True + c1.Emin = -383 + self.assertNotEqual(orig_ctx.Emin, -383) + self.assertRaises(Clamped, c1.create_decimal, '0e-999') + self.assertTrue(c1.flags[Clamped]) + with localcontext(new_ctx) as c2: + self.assertEqual(c2.flags, new_ctx.flags) + self.assertEqual(c2.traps, new_ctx.traps) + self.assertRaises(Overflow, c2.power, Decimal('3.4e200'), 2) + self.assertFalse(c2.flags[Clamped]) + self.assertTrue(c2.flags[Overflow]) + del c2 + self.assertFalse(c1.flags[Overflow]) + del c1 + self.assertNotEqual(orig_ctx.Emin, -383) + self.assertFalse(orig_ctx.flags[Clamped]) + self.assertFalse(orig_ctx.flags[Overflow]) + self.assertFalse(new_ctx.flags[Clamped]) + self.assertFalse(new_ctx.flags[Overflow]) + + def test_with_statements_gc1(self): + localcontext = self.decimal.localcontext + + with localcontext() as c1: + del c1 + with localcontext() as c2: + del c2 + with localcontext() as c3: + del c3 + with localcontext() as c4: + del c4 + + def test_with_statements_gc2(self): + localcontext = self.decimal.localcontext + + with localcontext() as c1: + with localcontext(c1) as c2: + del c1 + with localcontext(c2) as c3: + del c2 + with localcontext(c3) as c4: + del c3 + del c4 + + def test_with_statements_gc3(self): + Context = self.decimal.Context + localcontext = self.decimal.localcontext + getcontext = self.decimal.getcontext + setcontext = self.decimal.setcontext + + with localcontext() as c1: + del c1 + n1 = Context(prec=1) + setcontext(n1) + with localcontext(n1) as c2: + del n1 + self.assertEqual(c2.prec, 1) + del c2 + n2 = Context(prec=2) + setcontext(n2) + del n2 + self.assertEqual(getcontext().prec, 2) + n3 = Context(prec=3) + setcontext(n3) + self.assertEqual(getcontext().prec, 3) + with localcontext(n3) as c3: + del n3 + self.assertEqual(c3.prec, 3) + del c3 + n4 = Context(prec=4) + setcontext(n4) + del n4 + self.assertEqual(getcontext().prec, 4) + with localcontext() as c4: + self.assertEqual(c4.prec, 4) + del c4 + +class CContextWithStatement(ContextWithStatement): + decimal = C +class PyContextWithStatement(ContextWithStatement): + decimal = P + +class ContextFlags(unittest.TestCase): + + def test_flags_irrelevant(self): + # check that the result (numeric result + flags raised) of an + # arithmetic operation doesn't depend on the current flags + Decimal = self.decimal.Decimal + Context = self.decimal.Context + Inexact = self.decimal.Inexact + Rounded = self.decimal.Rounded + Underflow = self.decimal.Underflow + Clamped = self.decimal.Clamped + Subnormal = self.decimal.Subnormal + ROUND_HALF_EVEN = self.decimal.ROUND_HALF_EVEN + + def raise_error(context, flag): + if self.decimal == C: + context.flags[flag] = True + if context.traps[flag]: + raise flag + else: + context._raise_error(flag) + + context = Context(prec=9, Emin = -425000000, Emax = 425000000, + rounding=ROUND_HALF_EVEN, traps=[], flags=[]) + + # operations that raise various flags, in the form (function, arglist) + operations = [ + (context._apply, [Decimal("100E-425000010")]), + (context.sqrt, [Decimal(2)]), + (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]), + (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]), + (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]), + ] + + # try various flags individually, then a whole lot at once + flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal], + [Inexact, Rounded, Underflow, Clamped, Subnormal]] + + for fn, args in operations: + # find answer and flags raised using a clean context + context.clear_flags() + ans = fn(*args) + flags = [k for k, v in context.flags.items() if v] + + for extra_flags in flagsets: + # set flags, before calling operation + context.clear_flags() + for flag in extra_flags: + raise_error(context, flag) + new_ans = fn(*args) + + # flags that we expect to be set after the operation + expected_flags = list(flags) + for flag in extra_flags: + if flag not in expected_flags: + expected_flags.append(flag) + expected_flags.sort(key=id) + + # flags we actually got + new_flags = [k for k,v in context.flags.items() if v] + new_flags.sort(key=id) + + self.assertEqual(ans, new_ans, + "operation produces different answers depending on flags set: " + + "expected %s, got %s." % (ans, new_ans)) + self.assertEqual(new_flags, expected_flags, + "operation raises different flags depending on flags set: " + + "expected %s, got %s" % (expected_flags, new_flags)) + + def test_flag_comparisons(self): + Context = self.decimal.Context + Inexact = self.decimal.Inexact + Rounded = self.decimal.Rounded + + c = Context() + + # Valid SignalDict + self.assertNotEqual(c.flags, c.traps) + self.assertNotEqual(c.traps, c.flags) + + c.flags = c.traps + self.assertEqual(c.flags, c.traps) + self.assertEqual(c.traps, c.flags) + + c.flags[Rounded] = True + c.traps = c.flags + self.assertEqual(c.flags, c.traps) + self.assertEqual(c.traps, c.flags) + + d = {} + d.update(c.flags) + self.assertEqual(d, c.flags) + self.assertEqual(c.flags, d) + + d[Inexact] = True + self.assertNotEqual(d, c.flags) + self.assertNotEqual(c.flags, d) + + # Invalid SignalDict + d = {Inexact:False} + self.assertNotEqual(d, c.flags) + self.assertNotEqual(c.flags, d) + + d = ["xyz"] + self.assertNotEqual(d, c.flags) + self.assertNotEqual(c.flags, d) + + @requires_IEEE_754 + def test_float_operation(self): + Decimal = self.decimal.Decimal + FloatOperation = self.decimal.FloatOperation + localcontext = self.decimal.localcontext + + with localcontext() as c: + ##### trap is off by default + self.assertFalse(c.traps[FloatOperation]) + + # implicit conversion sets the flag + c.clear_flags() + self.assertEqual(Decimal(7.5), 7.5) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + self.assertEqual(c.create_decimal(7.5), 7.5) + self.assertTrue(c.flags[FloatOperation]) + + # explicit conversion does not set the flag + c.clear_flags() + x = Decimal.from_float(7.5) + self.assertFalse(c.flags[FloatOperation]) + # comparison sets the flag + self.assertEqual(x, 7.5) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + x = c.create_decimal_from_float(7.5) + self.assertFalse(c.flags[FloatOperation]) + self.assertEqual(x, 7.5) + self.assertTrue(c.flags[FloatOperation]) + + ##### set the trap + c.traps[FloatOperation] = True + + # implicit conversion raises + c.clear_flags() + self.assertRaises(FloatOperation, Decimal, 7.5) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + self.assertRaises(FloatOperation, c.create_decimal, 7.5) + self.assertTrue(c.flags[FloatOperation]) + + # explicit conversion is silent + c.clear_flags() + x = Decimal.from_float(7.5) + self.assertFalse(c.flags[FloatOperation]) + + c.clear_flags() + x = c.create_decimal_from_float(7.5) + self.assertFalse(c.flags[FloatOperation]) + + def test_float_comparison(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + FloatOperation = self.decimal.FloatOperation + localcontext = self.decimal.localcontext + + def assert_attr(a, b, attr, context, signal=None): + context.clear_flags() + f = getattr(a, attr) + if signal == FloatOperation: + self.assertRaises(signal, f, b) + else: + self.assertIs(f(b), True) + self.assertTrue(context.flags[FloatOperation]) + + small_d = Decimal('0.25') + big_d = Decimal('3.0') + small_f = 0.25 + big_f = 3.0 + + zero_d = Decimal('0.0') + neg_zero_d = Decimal('-0.0') + zero_f = 0.0 + neg_zero_f = -0.0 + + inf_d = Decimal('Infinity') + neg_inf_d = Decimal('-Infinity') + inf_f = float('inf') + neg_inf_f = float('-inf') + + def doit(c, signal=None): + # Order + for attr in '__lt__', '__le__': + assert_attr(small_d, big_f, attr, c, signal) + + for attr in '__gt__', '__ge__': + assert_attr(big_d, small_f, attr, c, signal) + + # Equality + assert_attr(small_d, small_f, '__eq__', c, None) + + assert_attr(neg_zero_d, neg_zero_f, '__eq__', c, None) + assert_attr(neg_zero_d, zero_f, '__eq__', c, None) + + assert_attr(zero_d, neg_zero_f, '__eq__', c, None) + assert_attr(zero_d, zero_f, '__eq__', c, None) + + assert_attr(neg_inf_d, neg_inf_f, '__eq__', c, None) + assert_attr(inf_d, inf_f, '__eq__', c, None) + + # Inequality + assert_attr(small_d, big_f, '__ne__', c, None) + + assert_attr(Decimal('0.1'), 0.1, '__ne__', c, None) + + assert_attr(neg_inf_d, inf_f, '__ne__', c, None) + assert_attr(inf_d, neg_inf_f, '__ne__', c, None) + + assert_attr(Decimal('NaN'), float('nan'), '__ne__', c, None) + + def test_containers(c, signal=None): + c.clear_flags() + s = set([100.0, Decimal('100.0')]) + self.assertEqual(len(s), 1) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + if signal: + self.assertRaises(signal, sorted, [1.0, Decimal('10.0')]) + else: + s = sorted([10.0, Decimal('10.0')]) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + b = 10.0 in [Decimal('10.0'), 1.0] + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + b = 10.0 in {Decimal('10.0'):'a', 1.0:'b'} + self.assertTrue(c.flags[FloatOperation]) + + nc = Context() + with localcontext(nc) as c: + self.assertFalse(c.traps[FloatOperation]) + doit(c, signal=None) + test_containers(c, signal=None) + + c.traps[FloatOperation] = True + doit(c, signal=FloatOperation) + test_containers(c, signal=FloatOperation) + + def test_float_operation_default(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + Inexact = self.decimal.Inexact + FloatOperation= self.decimal.FloatOperation + + context = Context() + self.assertFalse(context.flags[FloatOperation]) + self.assertFalse(context.traps[FloatOperation]) + + context.clear_traps() + context.traps[Inexact] = True + context.traps[FloatOperation] = True + self.assertTrue(context.traps[FloatOperation]) + self.assertTrue(context.traps[Inexact]) + +class CContextFlags(ContextFlags): + decimal = C +class PyContextFlags(ContextFlags): + decimal = P + +class SpecialContexts(unittest.TestCase): + """Test the context templates.""" + + def test_context_templates(self): + BasicContext = self.decimal.BasicContext + ExtendedContext = self.decimal.ExtendedContext + getcontext = self.decimal.getcontext + setcontext = self.decimal.setcontext + InvalidOperation = self.decimal.InvalidOperation + DivisionByZero = self.decimal.DivisionByZero + Overflow = self.decimal.Overflow + Underflow = self.decimal.Underflow + Clamped = self.decimal.Clamped + + assert_signals(self, BasicContext, 'traps', + [InvalidOperation, DivisionByZero, Overflow, Underflow, Clamped] + ) + + savecontext = getcontext().copy() + basic_context_prec = BasicContext.prec + extended_context_prec = ExtendedContext.prec + + ex = None + try: + BasicContext.prec = ExtendedContext.prec = 441 + for template in BasicContext, ExtendedContext: + setcontext(template) + c = getcontext() + self.assertIsNot(c, template) + self.assertEqual(c.prec, 441) + except Exception as e: + ex = e.__class__ + finally: + BasicContext.prec = basic_context_prec + ExtendedContext.prec = extended_context_prec + setcontext(savecontext) + if ex: + raise ex + + def test_default_context(self): + DefaultContext = self.decimal.DefaultContext + BasicContext = self.decimal.BasicContext + ExtendedContext = self.decimal.ExtendedContext + getcontext = self.decimal.getcontext + setcontext = self.decimal.setcontext + InvalidOperation = self.decimal.InvalidOperation + DivisionByZero = self.decimal.DivisionByZero + Overflow = self.decimal.Overflow + + self.assertEqual(BasicContext.prec, 9) + self.assertEqual(ExtendedContext.prec, 9) + + assert_signals(self, DefaultContext, 'traps', + [InvalidOperation, DivisionByZero, Overflow] + ) + + savecontext = getcontext().copy() + default_context_prec = DefaultContext.prec + + ex = None + try: + c = getcontext() + saveprec = c.prec + + DefaultContext.prec = 961 + c = getcontext() + self.assertEqual(c.prec, saveprec) + + setcontext(DefaultContext) + c = getcontext() + self.assertIsNot(c, DefaultContext) + self.assertEqual(c.prec, 961) + except Exception as e: + ex = e.__class__ + finally: + DefaultContext.prec = default_context_prec + setcontext(savecontext) + if ex: + raise ex + +class CSpecialContexts(SpecialContexts): + decimal = C +class PySpecialContexts(SpecialContexts): + decimal = P + +class ContextInputValidation(unittest.TestCase): + + def test_invalid_context(self): + Context = self.decimal.Context + DefaultContext = self.decimal.DefaultContext + + c = DefaultContext.copy() + + # prec, Emax + for attr in ['prec', 'Emax']: + setattr(c, attr, 999999) + self.assertEqual(getattr(c, attr), 999999) + self.assertRaises(ValueError, setattr, c, attr, -1) + self.assertRaises(TypeError, setattr, c, attr, 'xyz') + + # Emin + setattr(c, 'Emin', -999999) + self.assertEqual(getattr(c, 'Emin'), -999999) + self.assertRaises(ValueError, setattr, c, 'Emin', 1) + self.assertRaises(TypeError, setattr, c, 'Emin', (1,2,3)) + + # rounding: always raise TypeError in order to get consistent + # exceptions across implementations. In decimal, rounding + # modes are strings, in _decimal they are integers. The idea + # is to view rounding as an abstract type and not mind the + # implementation details. + # Hence, a user should view the rounding modes as if they + # had been defined in a language that supports abstract + # data types, e.g. ocaml: + # + # type rounding = ROUND_DOWN | ROUND_HALF_UP | ... ;; + # + self.assertRaises(TypeError, setattr, c, 'rounding', -1) + self.assertRaises(TypeError, setattr, c, 'rounding', 9) + self.assertRaises(TypeError, setattr, c, 'rounding', 1.0) + self.assertRaises(TypeError, setattr, c, 'rounding', 'xyz') + + # capitals, clamp + for attr in ['capitals', 'clamp']: + self.assertRaises(ValueError, setattr, c, attr, -1) + self.assertRaises(ValueError, setattr, c, attr, 2) + self.assertRaises(TypeError, setattr, c, attr, [1,2,3]) + + # Invalid attribute + self.assertRaises(AttributeError, setattr, c, 'emax', 100) + + # Invalid signal dict + self.assertRaises(TypeError, setattr, c, 'flags', []) + self.assertRaises(KeyError, setattr, c, 'flags', {}) + self.assertRaises(KeyError, setattr, c, 'traps', + {'InvalidOperation':0}) + + # Attributes cannot be deleted + for attr in ['prec', 'Emax', 'Emin', 'rounding', 'capitals', 'clamp', + 'flags', 'traps']: + self.assertRaises(AttributeError, c.__delattr__, attr) + + # Invalid attributes + self.assertRaises(TypeError, getattr, c, 9) + self.assertRaises(TypeError, setattr, c, 9) + + # Invalid values in constructor + self.assertRaises(TypeError, Context, rounding=999999) + self.assertRaises(TypeError, Context, rounding='xyz') + self.assertRaises(ValueError, Context, clamp=2) + self.assertRaises(ValueError, Context, capitals=-1) + self.assertRaises(KeyError, Context, flags=["P"]) + self.assertRaises(KeyError, Context, traps=["Q"]) + + # Type error in conversion + self.assertRaises(TypeError, Context, flags=(0,1)) + self.assertRaises(TypeError, Context, traps=(1,0)) + +class CContextInputValidation(ContextInputValidation): + decimal = C +class PyContextInputValidation(ContextInputValidation): + decimal = P + +class ContextSubclassing(unittest.TestCase): + + def test_context_subclassing(self): + decimal = self.decimal + Decimal = decimal.Decimal + Context = decimal.Context + ROUND_HALF_EVEN = decimal.ROUND_HALF_EVEN + ROUND_DOWN = decimal.ROUND_DOWN + Clamped = decimal.Clamped + DivisionByZero = decimal.DivisionByZero + Inexact = decimal.Inexact + Overflow = decimal.Overflow + Rounded = decimal.Rounded + Subnormal = decimal.Subnormal + Underflow = decimal.Underflow + InvalidOperation = decimal.InvalidOperation + + class MyContext(Context): + def __init__(self, prec=None, rounding=None, Emin=None, Emax=None, + capitals=None, clamp=None, flags=None, + traps=None): + Context.__init__(self) + if prec is not None: + self.prec = prec + if rounding is not None: + self.rounding = rounding + if Emin is not None: + self.Emin = Emin + if Emax is not None: + self.Emax = Emax + if capitals is not None: + self.capitals = capitals + if clamp is not None: + self.clamp = clamp + if flags is not None: + if isinstance(flags, list): + flags = {v:(v in flags) for v in OrderedSignals[decimal] + flags} + self.flags = flags + if traps is not None: + if isinstance(traps, list): + traps = {v:(v in traps) for v in OrderedSignals[decimal] + traps} + self.traps = traps + + c = Context() + d = MyContext() + for attr in ('prec', 'rounding', 'Emin', 'Emax', 'capitals', 'clamp', + 'flags', 'traps'): + self.assertEqual(getattr(c, attr), getattr(d, attr)) + + # prec + self.assertRaises(ValueError, MyContext, **{'prec':-1}) + c = MyContext(prec=1) + self.assertEqual(c.prec, 1) + self.assertRaises(InvalidOperation, c.quantize, Decimal('9e2'), 0) + + # rounding + self.assertRaises(TypeError, MyContext, **{'rounding':'XYZ'}) + c = MyContext(rounding=ROUND_DOWN, prec=1) + self.assertEqual(c.rounding, ROUND_DOWN) + self.assertEqual(c.plus(Decimal('9.9')), 9) + + # Emin + self.assertRaises(ValueError, MyContext, **{'Emin':5}) + c = MyContext(Emin=-1, prec=1) + self.assertEqual(c.Emin, -1) + x = c.add(Decimal('1e-99'), Decimal('2.234e-2000')) + self.assertEqual(x, Decimal('0.0')) + for signal in (Inexact, Underflow, Subnormal, Rounded, Clamped): + self.assertTrue(c.flags[signal]) + + # Emax + self.assertRaises(ValueError, MyContext, **{'Emax':-1}) + c = MyContext(Emax=1, prec=1) + self.assertEqual(c.Emax, 1) + self.assertRaises(Overflow, c.add, Decimal('1e99'), Decimal('2.234e2000')) + if self.decimal == C: + for signal in (Inexact, Overflow, Rounded): + self.assertTrue(c.flags[signal]) + + # capitals + self.assertRaises(ValueError, MyContext, **{'capitals':-1}) + c = MyContext(capitals=0) + self.assertEqual(c.capitals, 0) + x = c.create_decimal('1E222') + self.assertEqual(c.to_sci_string(x), '1e+222') + + # clamp + self.assertRaises(ValueError, MyContext, **{'clamp':2}) + c = MyContext(clamp=1, Emax=99) + self.assertEqual(c.clamp, 1) + x = c.plus(Decimal('1e99')) + self.assertEqual(str(x), '1.000000000000000000000000000E+99') + + # flags + self.assertRaises(TypeError, MyContext, **{'flags':'XYZ'}) + c = MyContext(flags=[Rounded, DivisionByZero]) + for signal in (Rounded, DivisionByZero): + self.assertTrue(c.flags[signal]) + c.clear_flags() + for signal in OrderedSignals[decimal]: + self.assertFalse(c.flags[signal]) + + # traps + self.assertRaises(TypeError, MyContext, **{'traps':'XYZ'}) + c = MyContext(traps=[Rounded, DivisionByZero]) + for signal in (Rounded, DivisionByZero): + self.assertTrue(c.traps[signal]) + c.clear_traps() + for signal in OrderedSignals[decimal]: + self.assertFalse(c.traps[signal]) + +class CContextSubclassing(ContextSubclassing): + decimal = C +class PyContextSubclassing(ContextSubclassing): + decimal = P + + at skip_if_extra_functionality +class CheckAttributes(unittest.TestCase): + + def test_module_attributes(self): + + # Architecture dependent context limits + self.assertEqual(C.MAX_PREC, P.MAX_PREC) + self.assertEqual(C.MAX_EMAX, P.MAX_EMAX) + self.assertEqual(C.MIN_EMIN, P.MIN_EMIN) + self.assertEqual(C.MIN_ETINY, P.MIN_ETINY) + + self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False) + self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False) + + self.assertEqual(C.__version__, P.__version__) + + x = dir(C) + y = [s for s in dir(P) if '__' in s or not s.startswith('_')] + self.assertEqual(set(x) - set(y), {'MallocError'}) + + def test_context_attributes(self): + + x = [s for s in dir(C.Context()) if '__' in s or not s.startswith('_')] + y = [s for s in dir(P.Context()) if '__' in s or not s.startswith('_')] + self.assertEqual(set(x) - set(y), set()) + + def test_decimal_attributes(self): + + x = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')] + y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')] + self.assertEqual(set(x) - set(y), set()) + +class Coverage(unittest.TestCase): + + def test_adjusted(self): + Decimal = self.decimal.Decimal + + self.assertEqual(Decimal('1234e9999').adjusted(), 10002) + # XXX raise? + self.assertEqual(Decimal('nan').adjusted(), 0) + self.assertEqual(Decimal('inf').adjusted(), 0) + + def test_canonical(self): + Decimal = self.decimal.Decimal + getcontext = self.decimal.getcontext + + x = Decimal(9).canonical() + self.assertEqual(x, 9) + + c = getcontext() + x = c.canonical(Decimal(9)) + self.assertEqual(x, 9) + + def test_context_repr(self): + c = self.decimal.DefaultContext.copy() + + c.prec = 425000000 + c.Emax = 425000000 + c.Emin = -425000000 + c.rounding = self.decimal.ROUND_HALF_DOWN + c.capitals = 0 + c.clamp = 1 + for sig in OrderedSignals[self.decimal]: + c.flags[sig] = False + c.traps[sig] = False + + s = c.__repr__() + t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \ + "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \ + "flags=[], traps=[])" + self.assertEqual(s, t) + + def test_implicit_context(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + + with localcontext() as c: + c.prec = 1 + c.Emax = 1 + c.Emin = -1 + + # abs + self.assertEqual(abs(Decimal("-10")), 10) + # add + self.assertEqual(Decimal("7") + 1, 8) + # divide + self.assertEqual(Decimal("10") / 5, 2) + # divide_int + self.assertEqual(Decimal("10") // 7, 1) + # fma + self.assertEqual(Decimal("1.2").fma(Decimal("0.01"), 1), 1) + self.assertIs(Decimal("NaN").fma(7, 1).is_nan(), True) + # three arg power + self.assertEqual(pow(Decimal(10), 2, 7), 2) + # exp + self.assertEqual(Decimal("1.01").exp(), 3) + # is_normal + self.assertIs(Decimal("0.01").is_normal(), False) + # is_subnormal + self.assertIs(Decimal("0.01").is_subnormal(), True) + # ln + self.assertEqual(Decimal("20").ln(), 3) + # log10 + self.assertEqual(Decimal("20").log10(), 1) + # logb + self.assertEqual(Decimal("580").logb(), 2) + # logical_invert + self.assertEqual(Decimal("10").logical_invert(), 1) + # minus + self.assertEqual(-Decimal("-10"), 10) + # multiply + self.assertEqual(Decimal("2") * 4, 8) + # next_minus + self.assertEqual(Decimal("10").next_minus(), 9) + # next_plus + self.assertEqual(Decimal("10").next_plus(), Decimal('2E+1')) + # normalize + self.assertEqual(Decimal("-10").normalize(), Decimal('-1E+1')) + # number_class + self.assertEqual(Decimal("10").number_class(), '+Normal') + # plus + self.assertEqual(+Decimal("-1"), -1) + # remainder + self.assertEqual(Decimal("10") % 7, 3) + # subtract + self.assertEqual(Decimal("10") - 7, 3) + # to_integral_exact + self.assertEqual(Decimal("1.12345").to_integral_exact(), 1) + + # Boolean functions + self.assertTrue(Decimal("1").is_canonical()) + self.assertTrue(Decimal("1").is_finite()) + self.assertTrue(Decimal("1").is_finite()) + self.assertTrue(Decimal("snan").is_snan()) + self.assertTrue(Decimal("-1").is_signed()) + self.assertTrue(Decimal("0").is_zero()) + self.assertTrue(Decimal("0").is_zero()) + + # Copy + with localcontext() as c: + c.prec = 10000 + x = 1228 ** 1523 + y = -Decimal(x) + + z = y.copy_abs() + self.assertEqual(z, x) + + z = y.copy_negate() + self.assertEqual(z, x) + + z = y.copy_sign(Decimal(1)) + self.assertEqual(z, x) + + def test_divmod(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + InvalidOperation = self.decimal.InvalidOperation + DivisionByZero = self.decimal.DivisionByZero + + with localcontext() as c: + q, r = divmod(Decimal("10912837129"), 1001) + self.assertEqual(q, Decimal('10901935')) + self.assertEqual(r, Decimal('194')) + + q, r = divmod(Decimal("NaN"), 7) + self.assertTrue(q.is_nan() and r.is_nan()) + + c.traps[InvalidOperation] = False + q, r = divmod(Decimal("NaN"), 7) + self.assertTrue(q.is_nan() and r.is_nan()) + + c.traps[InvalidOperation] = False + c.clear_flags() + q, r = divmod(Decimal("inf"), Decimal("inf")) + self.assertTrue(q.is_nan() and r.is_nan()) + self.assertTrue(c.flags[InvalidOperation]) + + c.clear_flags() + q, r = divmod(Decimal("inf"), 101) + self.assertTrue(q.is_infinite() and r.is_nan()) + self.assertTrue(c.flags[InvalidOperation]) + + c.clear_flags() + q, r = divmod(Decimal(0), 0) + self.assertTrue(q.is_nan() and r.is_nan()) + self.assertTrue(c.flags[InvalidOperation]) + + c.traps[DivisionByZero] = False + c.clear_flags() + q, r = divmod(Decimal(11), 0) + self.assertTrue(q.is_infinite() and r.is_nan()) + self.assertTrue(c.flags[InvalidOperation] and + c.flags[DivisionByZero]) + + def test_power(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + Overflow = self.decimal.Overflow + Rounded = self.decimal.Rounded + + with localcontext() as c: + c.prec = 3 + c.clear_flags() + self.assertEqual(Decimal("1.0") ** 100, Decimal('1.00')) + self.assertTrue(c.flags[Rounded]) + + c.prec = 1 + c.Emax = 1 + c.Emin = -1 + c.clear_flags() + c.traps[Overflow] = False + self.assertEqual(Decimal(10000) ** Decimal("0.5"), Decimal('inf')) + self.assertTrue(c.flags[Overflow]) + + def test_quantize(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + InvalidOperation = self.decimal.InvalidOperation + + with localcontext() as c: + c.prec = 1 + c.Emax = 1 + c.Emin = -1 + c.traps[InvalidOperation] = False + x = Decimal(99).quantize(Decimal("1e1")) + self.assertTrue(x.is_nan()) + + def test_radix(self): + Decimal = self.decimal.Decimal + getcontext = self.decimal.getcontext + + c = getcontext() + self.assertEqual(Decimal("1").radix(), 10) + self.assertEqual(c.radix(), 10) + + def test_rop(self): + Decimal = self.decimal.Decimal + + for attr in ('__radd__', '__rsub__', '__rmul__', '__rtruediv__', + '__rdivmod__', '__rmod__', '__rfloordiv__', '__rpow__'): + self.assertIs(getattr(Decimal("1"), attr)("xyz"), NotImplemented) + + def test_round(self): + # Python3 behavior: round() returns Decimal + Decimal = self.decimal.Decimal + getcontext = self.decimal.getcontext + + c = getcontext() + c.prec = 28 + + self.assertEqual(str(Decimal("9.99").__round__()), "10") + self.assertEqual(str(Decimal("9.99e-5").__round__()), "0") + self.assertEqual(str(Decimal("1.23456789").__round__(5)), "1.23457") + self.assertEqual(str(Decimal("1.2345").__round__(10)), "1.2345000000") + self.assertEqual(str(Decimal("1.2345").__round__(-10)), "0E+10") + + self.assertRaises(TypeError, Decimal("1.23").__round__, "5") + self.assertRaises(TypeError, Decimal("1.23").__round__, 5, 8) + + def test_create_decimal(self): + c = self.decimal.Context() + self.assertRaises(ValueError, c.create_decimal, ["%"]) + + def test_int(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + + with localcontext() as c: + c.prec = 9999 + x = Decimal(1221**1271) / 10**3923 + self.assertEqual(int(x), 1) + self.assertEqual(x.to_integral(), 2) + + def test_copy(self): + Context = self.decimal.Context + + c = Context() + c.prec = 10000 + x = -(1172 ** 1712) + + y = c.copy_abs(x) + self.assertEqual(y, -x) + + y = c.copy_negate(x) + self.assertEqual(y, -x) + + y = c.copy_sign(x, 1) + self.assertEqual(y, -x) + +class CCoverage(Coverage): + decimal = C +class PyCoverage(Coverage): + decimal = P + +class PyFunctionality(unittest.TestCase): + """Extra functionality in decimal.py""" + + def test_py_quantize_watchexp(self): + # watchexp functionality + Decimal = P.Decimal + localcontext = P.localcontext + + with localcontext() as c: + c.prec = 1 + c.Emax = 1 + c.Emin = -1 + x = Decimal(99999).quantize(Decimal("1e3"), watchexp=False) + self.assertEqual(x, Decimal('1.00E+5')) + + def test_py_alternate_formatting(self): + # triples giving a format, a Decimal, and the expected result + Decimal = P.Decimal + localcontext = P.localcontext + + test_values = [ + # Issue 7094: Alternate formatting (specified by #) + ('.0e', '1.0', '1e+0'), + ('#.0e', '1.0', '1.e+0'), + ('.0f', '1.0', '1'), + ('#.0f', '1.0', '1.'), + ('g', '1.1', '1.1'), + ('#g', '1.1', '1.1'), + ('.0g', '1', '1'), + ('#.0g', '1', '1.'), + ('.0%', '1.0', '100%'), + ('#.0%', '1.0', '100.%'), + ] + for fmt, d, result in test_values: + self.assertEqual(format(Decimal(d), fmt), result) + +class PyWhitebox(unittest.TestCase): + """White box testing for decimal.py""" + + def test_py_exact_power(self): + # Rarely exercised lines in _power_exact. + Decimal = P.Decimal + localcontext = P.localcontext + + with localcontext() as c: + c.prec = 8 + x = Decimal(2**16) ** Decimal("-0.5") + self.assertEqual(x, Decimal('0.00390625')) + + x = Decimal(2**16) ** Decimal("-0.6") + self.assertEqual(x, Decimal('0.0012885819')) + + x = Decimal("256e7") ** Decimal("-0.5") + + x = Decimal(152587890625) ** Decimal('-0.0625') + self.assertEqual(x, Decimal("0.2")) + + x = Decimal("152587890625e7") ** Decimal('-0.0625') + + x = Decimal(5**2659) ** Decimal('-0.0625') + + c.prec = 1 + x = Decimal("152587890625") ** Decimal('-0.5') + c.prec = 201 + x = Decimal(2**578) ** Decimal("-0.5") + + def test_py_immutability_operations(self): # Do operations and check that it didn't change change internal objects. + Decimal = P.Decimal + DefaultContext = P.DefaultContext + setcontext = P.setcontext + + c = DefaultContext.copy() + c.traps = dict((s, 0) for s in OrderedSignals[P]) + setcontext(c) d1 = Decimal('-25e55') b1 = Decimal('-25e55') @@ -1649,715 +4219,727 @@ checkSameDec("to_eng_string") checkSameDec("to_integral") - def test_subclassing(self): - # Different behaviours when subclassing Decimal - - class MyDecimal(Decimal): - pass - - d1 = MyDecimal(1) - d2 = MyDecimal(2) - d = d1 + d2 - self.assertIs(type(d), Decimal) - - d = d1.max(d2) - self.assertIs(type(d), Decimal) - - def test_implicit_context(self): - # Check results when context given implicitly. (Issue 2478) - c = getcontext() - self.assertEqual(str(Decimal(0).sqrt()), - str(c.sqrt(Decimal(0)))) - - def test_conversions_from_int(self): - # Check that methods taking a second Decimal argument will - # always accept an integer in place of a Decimal. - self.assertEqual(Decimal(4).compare(3), - Decimal(4).compare(Decimal(3))) - self.assertEqual(Decimal(4).compare_signal(3), - Decimal(4).compare_signal(Decimal(3))) - self.assertEqual(Decimal(4).compare_total(3), - Decimal(4).compare_total(Decimal(3))) - self.assertEqual(Decimal(4).compare_total_mag(3), - Decimal(4).compare_total_mag(Decimal(3))) - self.assertEqual(Decimal(10101).logical_and(1001), - Decimal(10101).logical_and(Decimal(1001))) - self.assertEqual(Decimal(10101).logical_or(1001), - Decimal(10101).logical_or(Decimal(1001))) - self.assertEqual(Decimal(10101).logical_xor(1001), - Decimal(10101).logical_xor(Decimal(1001))) - self.assertEqual(Decimal(567).max(123), - Decimal(567).max(Decimal(123))) - self.assertEqual(Decimal(567).max_mag(123), - Decimal(567).max_mag(Decimal(123))) - self.assertEqual(Decimal(567).min(123), - Decimal(567).min(Decimal(123))) - self.assertEqual(Decimal(567).min_mag(123), - Decimal(567).min_mag(Decimal(123))) - self.assertEqual(Decimal(567).next_toward(123), - Decimal(567).next_toward(Decimal(123))) - self.assertEqual(Decimal(1234).quantize(100), - Decimal(1234).quantize(Decimal(100))) - self.assertEqual(Decimal(768).remainder_near(1234), - Decimal(768).remainder_near(Decimal(1234))) - self.assertEqual(Decimal(123).rotate(1), - Decimal(123).rotate(Decimal(1))) - self.assertEqual(Decimal(1234).same_quantum(1000), - Decimal(1234).same_quantum(Decimal(1000))) - self.assertEqual(Decimal('9.123').scaleb(-100), - Decimal('9.123').scaleb(Decimal(-100))) - self.assertEqual(Decimal(456).shift(-1), - Decimal(456).shift(Decimal(-1))) - - self.assertEqual(Decimal(-12).fma(Decimal(45), 67), - Decimal(-12).fma(Decimal(45), Decimal(67))) - self.assertEqual(Decimal(-12).fma(45, 67), - Decimal(-12).fma(Decimal(45), Decimal(67))) - self.assertEqual(Decimal(-12).fma(45, Decimal(67)), - Decimal(-12).fma(Decimal(45), Decimal(67))) - - -class DecimalPythonAPItests(unittest.TestCase): - - def test_abc(self): - self.assertTrue(issubclass(Decimal, numbers.Number)) - self.assertFalse(issubclass(Decimal, numbers.Real)) - self.assertIsInstance(Decimal(0), numbers.Number) - self.assertNotIsInstance(Decimal(0), numbers.Real) - - def test_pickle(self): - d = Decimal('-3.141590000') - p = pickle.dumps(d) - e = pickle.loads(p) - self.assertEqual(d, e) - - def test_int(self): - for x in range(-250, 250): - s = '%0.2f' % (x / 100.0) - # should work the same as for floats - self.assertEqual(int(Decimal(s)), int(float(s))) - # should work the same as to_integral in the ROUND_DOWN mode - d = Decimal(s) - r = d.to_integral(ROUND_DOWN) - self.assertEqual(Decimal(int(d)), r) - - self.assertRaises(ValueError, int, Decimal('-nan')) - self.assertRaises(ValueError, int, Decimal('snan')) - self.assertRaises(OverflowError, int, Decimal('inf')) - self.assertRaises(OverflowError, int, Decimal('-inf')) - - def test_trunc(self): - for x in range(-250, 250): - s = '%0.2f' % (x / 100.0) - # should work the same as for floats - self.assertEqual(int(Decimal(s)), int(float(s))) - # should work the same as to_integral in the ROUND_DOWN mode - d = Decimal(s) - r = d.to_integral(ROUND_DOWN) - self.assertEqual(Decimal(math.trunc(d)), r) - - def test_from_float(self): - - class MyDecimal(Decimal): - pass - - r = MyDecimal.from_float(0.1) - self.assertEqual(type(r), MyDecimal) - self.assertEqual(str(r), - '0.1000000000000000055511151231257827021181583404541015625') - bigint = 12345678901234567890123456789 - self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint)) - self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan()) - self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite()) - self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite()) - self.assertEqual(str(MyDecimal.from_float(float('nan'))), - str(Decimal('NaN'))) - self.assertEqual(str(MyDecimal.from_float(float('inf'))), - str(Decimal('Infinity'))) - self.assertEqual(str(MyDecimal.from_float(float('-inf'))), - str(Decimal('-Infinity'))) - self.assertRaises(TypeError, MyDecimal.from_float, 'abc') - for i in range(200): - x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) - self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip - - def test_create_decimal_from_float(self): - context = Context(prec=5, rounding=ROUND_DOWN) + def test_py_decimal_id(self): + Decimal = P.Decimal + + d = Decimal(45) + e = Decimal(d) + self.assertEqual(str(e), '45') + self.assertNotEqual(id(d), id(e)) + + def test_py_rescale(self): + # Coverage + Decimal = P.Decimal + ROUND_UP = P.ROUND_UP + localcontext = P.localcontext + + with localcontext() as c: + x = Decimal("NaN")._rescale(3, ROUND_UP) + self.assertTrue(x.is_nan()) + + def test_py__round(self): + # Coverage + Decimal = P.Decimal + ROUND_UP = P.ROUND_UP + + self.assertRaises(ValueError, Decimal("3.1234")._round, 0, ROUND_UP) + +class CFunctionality(unittest.TestCase): + """Extra functionality in _decimal""" + + @requires_extra_functionality + def test_c_ieee_context(self): + # issue 8786: Add support for IEEE 754 contexts to decimal module. + IEEEContext = C.IEEEContext + DECIMAL32 = C.DECIMAL32 + DECIMAL64 = C.DECIMAL64 + DECIMAL128 = C.DECIMAL128 + + def assert_rest(self, context): + self.assertEqual(context.clamp, 1) + assert_signals(self, context, 'traps', []) + assert_signals(self, context, 'flags', []) + + c = IEEEContext(DECIMAL32) + self.assertEqual(c.prec, 7) + self.assertEqual(c.Emax, 96) + self.assertEqual(c.Emin, -95) + assert_rest(self, c) + + c = IEEEContext(DECIMAL64) + self.assertEqual(c.prec, 16) + self.assertEqual(c.Emax, 384) + self.assertEqual(c.Emin, -383) + assert_rest(self, c) + + c = IEEEContext(DECIMAL128) + self.assertEqual(c.prec, 34) + self.assertEqual(c.Emax, 6144) + self.assertEqual(c.Emin, -6143) + assert_rest(self, c) + + # Invalid values + self.assertRaises(OverflowError, IEEEContext, 2**63) + self.assertRaises(ValueError, IEEEContext, -1) + self.assertRaises(ValueError, IEEEContext, 1024) + + @requires_extra_functionality + def test_c_context(self): + Context = C.Context + + c = Context(flags=C.DecClamped, traps=C.DecRounded) + self.assertEqual(c._flags, C.DecClamped) + self.assertEqual(c._traps, C.DecRounded) + + @requires_extra_functionality + def test_constants(self): + # Condition flags + cond = ( + C.DecClamped, C.DecConversionSyntax, C.DecDivisionByZero, + C.DecDivisionImpossible, C.DecDivisionUndefined, + C.DecFpuError, C.DecInexact, C.DecInvalidContext, + C.DecInvalidOperation, C.DecMallocError, + C.DecFloatOperation, C.DecOverflow, C.DecRounded, + C.DecSubnormal, C.DecUnderflow + ) + + # IEEEContext + self.assertEqual(C.DECIMAL32, 32) + self.assertEqual(C.DECIMAL64, 64) + self.assertEqual(C.DECIMAL128, 128) + self.assertEqual(C.IEEE_CONTEXT_MAX_BITS, 512) + + # Rounding modes + for i, v in enumerate(RoundingModes[C]): + self.assertEqual(v, i) + self.assertEqual(C.ROUND_TRUNC, 8) + + # Conditions + for i, v in enumerate(cond): + self.assertEqual(v, 1< 425000000) + + c = Context() + + # SignalDict: input validation + self.assertRaises(KeyError, c.flags.__setitem__, 801, 0) + self.assertRaises(KeyError, c.traps.__setitem__, 801, 0) + self.assertRaises(ValueError, c.flags.__delitem__, Overflow) + self.assertRaises(ValueError, c.traps.__delitem__, InvalidOperation) + self.assertRaises(TypeError, setattr, c, 'flags', ['x']) + self.assertRaises(TypeError, setattr, c,'traps', ['y']) + self.assertRaises(KeyError, setattr, c, 'flags', {0:1}) + self.assertRaises(KeyError, setattr, c, 'traps', {0:1}) + + # Test assignment from a signal dict with the correct length but + # one invalid key. + d = c.flags.copy() + del d[FloatOperation] + d["XYZ"] = 91283719 + self.assertRaises(KeyError, setattr, c, 'flags', d) + self.assertRaises(KeyError, setattr, c, 'traps', d) + + # Input corner cases + int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1 + gt_max_emax = 10**18 if HAVE_CONFIG_64 else 10**9 + + # prec, Emax, Emin + for attr in ['prec', 'Emax']: + self.assertRaises(ValueError, setattr, c, attr, gt_max_emax) + self.assertRaises(ValueError, setattr, c, 'Emin', -gt_max_emax) + + # prec, Emax, Emin in context constructor + self.assertRaises(ValueError, Context, prec=gt_max_emax) + self.assertRaises(ValueError, Context, Emax=gt_max_emax) + self.assertRaises(ValueError, Context, Emin=-gt_max_emax) + + # Overflow in conversion + self.assertRaises(OverflowError, Context, prec=int_max+1) + self.assertRaises(OverflowError, Context, Emax=int_max+1) + self.assertRaises(OverflowError, Context, Emin=-int_max-2) + self.assertRaises(OverflowError, Context, rounding=int_max+1) + self.assertRaises(OverflowError, Context, clamp=int_max+1) + self.assertRaises(OverflowError, Context, capitals=int_max+1) + + # OverflowError, general ValueError + for attr in ('prec', 'Emin', 'Emax', 'capitals', 'clamp'): + self.assertRaises(OverflowError, setattr, c, attr, int_max+1) + self.assertRaises(OverflowError, setattr, c, attr, -int_max-2) + if sys.platform != 'win32': + self.assertRaises(ValueError, setattr, c, attr, int_max) + self.assertRaises(ValueError, setattr, c, attr, -int_max-1) + + # OverflowError, general TypeError + for attr in ('rounding',): + self.assertRaises(OverflowError, setattr, c, attr, int_max+1) + self.assertRaises(OverflowError, setattr, c, attr, -int_max-2) + if sys.platform != 'win32': + self.assertRaises(TypeError, setattr, c, attr, int_max) + self.assertRaises(TypeError, setattr, c, attr, -int_max-1) + + # OverflowError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax + if C.MAX_PREC == 425000000: + self.assertRaises(OverflowError, getattr(c, '_unsafe_setprec'), + int_max+1) + self.assertRaises(OverflowError, getattr(c, '_unsafe_setemax'), + int_max+1) + self.assertRaises(OverflowError, getattr(c, '_unsafe_setemin'), + -int_max-2) + + # ValueError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax + if C.MAX_PREC == 425000000: + self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'), 0) + self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'), + 1070000001) + self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'), -1) + self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'), + 1070000001) + self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'), + -1070000001) + self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'), 1) + + # capitals, clamp + for attr in ['capitals', 'clamp']: + self.assertRaises(ValueError, setattr, c, attr, -1) + self.assertRaises(ValueError, setattr, c, attr, 2) + self.assertRaises(TypeError, setattr, c, attr, [1,2,3]) + if HAVE_CONFIG_64: + self.assertRaises(ValueError, setattr, c, attr, 2**32) + self.assertRaises(ValueError, setattr, c, attr, 2**32+1) + + # Invalid local context + self.assertRaises(TypeError, exec, 'with localcontext("xyz"): pass', + locals()) + + # setcontext + saved_context = getcontext() + self.assertRaises(TypeError, setcontext, "xyz") + setcontext(saved_context) + + @requires_extra_functionality + def test_c_context_errors_extra(self): + Context = C.Context + InvalidOperation = C.InvalidOperation + Overflow = C.Overflow + localcontext = C.localcontext + getcontext = C.getcontext + setcontext = C.setcontext + HAVE_CONFIG_64 = (C.MAX_PREC > 425000000) + + c = Context() + + # Input corner cases + int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1 + + # OverflowError, general ValueError + self.assertRaises(OverflowError, setattr, c, '_allcr', int_max+1) + self.assertRaises(OverflowError, setattr, c, '_allcr', -int_max-2) + if sys.platform != 'win32': + self.assertRaises(ValueError, setattr, c, '_allcr', int_max) + self.assertRaises(ValueError, setattr, c, '_allcr', -int_max-1) + + # OverflowError, general TypeError + for attr in ('_flags', '_traps'): + self.assertRaises(OverflowError, setattr, c, attr, int_max+1) + self.assertRaises(OverflowError, setattr, c, attr, -int_max-2) + if sys.platform != 'win32': + self.assertRaises(TypeError, setattr, c, attr, int_max) + self.assertRaises(TypeError, setattr, c, attr, -int_max-1) + + # _allcr + self.assertRaises(ValueError, setattr, c, '_allcr', -1) + self.assertRaises(ValueError, setattr, c, '_allcr', 2) + self.assertRaises(TypeError, setattr, c, '_allcr', [1,2,3]) + if HAVE_CONFIG_64: + self.assertRaises(ValueError, setattr, c, '_allcr', 2**32) + self.assertRaises(ValueError, setattr, c, '_allcr', 2**32+1) + + # _flags, _traps + for attr in ['_flags', '_traps']: + self.assertRaises(TypeError, setattr, c, attr, 999999) + self.assertRaises(TypeError, setattr, c, attr, 'x') + + def test_c_valid_context(self): + # These tests are for code coverage in _decimal. + DefaultContext = C.DefaultContext + ROUND_HALF_UP = C.ROUND_HALF_UP + Clamped = C.Clamped + Underflow = C.Underflow + Inexact = C.Inexact + Rounded = C.Rounded + Subnormal = C.Subnormal + + c = DefaultContext.copy() + + # Exercise all getters and setters + c.prec = 34 + c.rounding = ROUND_HALF_UP + c.Emax = 3000 + c.Emin = -3000 + c.capitals = 1 + c.clamp = 0 + + self.assertEqual(c.prec, 34) + self.assertEqual(c.rounding, ROUND_HALF_UP) + self.assertEqual(c.Emin, -3000) + self.assertEqual(c.Emax, 3000) + self.assertEqual(c.capitals, 1) + self.assertEqual(c.clamp, 0) + + self.assertEqual(c.Etiny(), -3033) + self.assertEqual(c.Etop(), 2967) + + # Exercise all unsafe setters + if C.MAX_PREC == 425000000: + c._unsafe_setprec(999999999) + c._unsafe_setemax(999999999) + c._unsafe_setemin(-999999999) + self.assertEqual(c.prec, 999999999) + self.assertEqual(c.Emax, 999999999) + self.assertEqual(c.Emin, -999999999) + + @requires_extra_functionality + def test_c_valid_context_extra(self): + DefaultContext = C.DefaultContext + + c = DefaultContext.copy() + self.assertEqual(c._allcr, 1) + c._allcr = 0 + self.assertEqual(c._allcr, 0) + + def test_c_round(self): + # Restricted input. + Decimal = C.Decimal + InvalidOperation = C.InvalidOperation + localcontext = C.localcontext + MAX_EMAX = C.MAX_EMAX + MIN_ETINY = C.MIN_ETINY + int_max = 2**63-1 if C.MAX_PREC > 425000000 else 2**31-1 + + with localcontext() as c: + c.traps[InvalidOperation] = True + self.assertRaises(InvalidOperation, Decimal("1.23").__round__, + -int_max-1) + self.assertRaises(InvalidOperation, Decimal("1.23").__round__, + int_max) + self.assertRaises(InvalidOperation, Decimal("1").__round__, + int(MAX_EMAX+1)) + self.assertRaises(C.InvalidOperation, Decimal("1").__round__, + -int(MIN_ETINY-1)) + self.assertRaises(OverflowError, Decimal("1.23").__round__, + -int_max-2) + self.assertRaises(OverflowError, Decimal("1.23").__round__, + int_max+1) + + def test_c_format(self): + # Restricted input + Decimal = C.Decimal + InvalidOperation = C.InvalidOperation + Rounded = C.Rounded + localcontext = C.localcontext + HAVE_CONFIG_64 = (C.MAX_PREC > 425000000) + + self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", [], 9) + self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", 9) + self.assertRaises(TypeError, Decimal(1).__format__, []) + + with localcontext() as c: + c.traps[InvalidOperation] = True + c.traps[Rounded] = True + self.assertRaises(ValueError, Decimal(1).__format__, "<>=10.10") + maxsize = 2**63-1 if HAVE_CONFIG_64 else 2**31-1 + self.assertRaises(InvalidOperation, Decimal("1.23456789").__format__, + "=%d.1" % maxsize) + + def test_c_integral(self): + Decimal = C.Decimal + Inexact = C.Inexact + ROUND_UP = C.ROUND_UP + localcontext = C.localcontext + + x = Decimal(10) + self.assertEqual(x.to_integral(), 10) + self.assertRaises(TypeError, x.to_integral, '10') + self.assertRaises(TypeError, x.to_integral, 10, 'x') + self.assertRaises(TypeError, x.to_integral, 10) + + self.assertEqual(x.to_integral_value(), 10) + self.assertRaises(TypeError, x.to_integral_value, '10') + self.assertRaises(TypeError, x.to_integral_value, 10, 'x') + self.assertRaises(TypeError, x.to_integral_value, 10) + + self.assertEqual(x.to_integral_exact(), 10) + self.assertRaises(TypeError, x.to_integral_exact, '10') + self.assertRaises(TypeError, x.to_integral_exact, 10, 'x') + self.assertRaises(TypeError, x.to_integral_exact, 10) + + with localcontext() as c: + x = Decimal("99999999999999999999999999.9").to_integral_value(ROUND_UP) + self.assertEqual(x, Decimal('100000000000000000000000000')) + + x = Decimal("99999999999999999999999999.9").to_integral_exact(ROUND_UP) + self.assertEqual(x, Decimal('100000000000000000000000000')) + + c.traps[Inexact] = True + self.assertRaises(Inexact, Decimal("999.9").to_integral_exact, ROUND_UP) + + def test_c_funcs(self): + # Invalid arguments + Decimal = C.Decimal + InvalidOperation = C.InvalidOperation + DivisionByZero = C.DivisionByZero + ROUND_UP = C.ROUND_UP + getcontext = C.getcontext + localcontext = C.localcontext + + self.assertEqual(Decimal('9.99e10').to_eng_string(), '99.9E+9') + + self.assertRaises(TypeError, pow, Decimal(1), 2, "3") + self.assertRaises(TypeError, Decimal(9).number_class, "x", "y") + self.assertRaises(TypeError, Decimal(9).same_quantum, 3, "x", "y") + + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), [] + ) + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), getcontext() + ) + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), 10 + ) + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), ROUND_UP, 1000 + ) + + with localcontext() as c: + c.clear_traps() + + # Invalid arguments + self.assertRaises(TypeError, c.copy_sign, Decimal(1), "x", "y") + self.assertRaises(TypeError, c.canonical, 200) + self.assertRaises(TypeError, c.is_canonical, 200) + self.assertRaises(TypeError, c.divmod, 9, 8, "x", "y") + self.assertRaises(TypeError, c.same_quantum, 9, 3, "x", "y") + + self.assertEqual(str(c.canonical(Decimal(200))), '200') + self.assertEqual(c.radix(), 10) + + c.traps[DivisionByZero] = True + self.assertRaises(DivisionByZero, Decimal(9).__divmod__, 0) + self.assertRaises(DivisionByZero, c.divmod, 9, 0) + self.assertTrue(c.flags[InvalidOperation]) + + c.clear_flags() + c.traps[InvalidOperation] = True + self.assertRaises(InvalidOperation, Decimal(9).__divmod__, 0) + self.assertRaises(InvalidOperation, c.divmod, 9, 0) + self.assertTrue(c.flags[DivisionByZero]) + + c.traps[InvalidOperation] = True + c.prec = 2 + self.assertRaises(InvalidOperation, pow, Decimal(1000), 1, 501) + + @requires_extra_functionality + def test_c_context_templates(self): self.assertEqual( - context.create_decimal_from_float(math.pi), - Decimal('3.1415') + C.BasicContext._traps, + C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow| + C.DecUnderflow|C.DecClamped ) - context = Context(prec=5, rounding=ROUND_UP) self.assertEqual( - context.create_decimal_from_float(math.pi), - Decimal('3.1416') + C.DefaultContext._traps, + C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow ) - context = Context(prec=5, traps=[Inexact]) - self.assertRaises( - Inexact, - context.create_decimal_from_float, - math.pi - ) - self.assertEqual(repr(context.create_decimal_from_float(-0.0)), - "Decimal('-0')") - self.assertEqual(repr(context.create_decimal_from_float(1.0)), - "Decimal('1')") - self.assertEqual(repr(context.create_decimal_from_float(10)), - "Decimal('10')") - -class ContextAPItests(unittest.TestCase): - - def test_pickle(self): - c = Context() - e = pickle.loads(pickle.dumps(c)) - for k in vars(c): - v1 = vars(c)[k] - v2 = vars(e)[k] - self.assertEqual(v1, v2) - - def test_equality_with_other_types(self): - self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}]) - self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}]) - - def test_copy(self): - # All copies should be deep - c = Context() - d = c.copy() - self.assertNotEqual(id(c), id(d)) - self.assertNotEqual(id(c.flags), id(d.flags)) - self.assertNotEqual(id(c.traps), id(d.traps)) - - def test__clamp(self): - # In Python 3.2, the private attribute `_clamp` was made - # public (issue 8540), with the old `_clamp` becoming a - # property wrapping `clamp`. For the duration of Python 3.2 - # only, the attribute should be gettable/settable via both - # `clamp` and `_clamp`; in Python 3.3, `_clamp` should be - # removed. - c = Context() - with self.assertRaises(AttributeError): - clamp_value = c._clamp - - def test_abs(self): - c = Context() - d = c.abs(Decimal(-1)) - self.assertEqual(c.abs(-1), d) - self.assertRaises(TypeError, c.abs, '-1') - - def test_add(self): - c = Context() - d = c.add(Decimal(1), Decimal(1)) - self.assertEqual(c.add(1, 1), d) - self.assertEqual(c.add(Decimal(1), 1), d) - self.assertEqual(c.add(1, Decimal(1)), d) - self.assertRaises(TypeError, c.add, '1', 1) - self.assertRaises(TypeError, c.add, 1, '1') - - def test_compare(self): - c = Context() - d = c.compare(Decimal(1), Decimal(1)) - self.assertEqual(c.compare(1, 1), d) - self.assertEqual(c.compare(Decimal(1), 1), d) - self.assertEqual(c.compare(1, Decimal(1)), d) - self.assertRaises(TypeError, c.compare, '1', 1) - self.assertRaises(TypeError, c.compare, 1, '1') - - def test_compare_signal(self): - c = Context() - d = c.compare_signal(Decimal(1), Decimal(1)) - self.assertEqual(c.compare_signal(1, 1), d) - self.assertEqual(c.compare_signal(Decimal(1), 1), d) - self.assertEqual(c.compare_signal(1, Decimal(1)), d) - self.assertRaises(TypeError, c.compare_signal, '1', 1) - self.assertRaises(TypeError, c.compare_signal, 1, '1') - - def test_compare_total(self): - c = Context() - d = c.compare_total(Decimal(1), Decimal(1)) - self.assertEqual(c.compare_total(1, 1), d) - self.assertEqual(c.compare_total(Decimal(1), 1), d) - self.assertEqual(c.compare_total(1, Decimal(1)), d) - self.assertRaises(TypeError, c.compare_total, '1', 1) - self.assertRaises(TypeError, c.compare_total, 1, '1') - - def test_compare_total_mag(self): - c = Context() - d = c.compare_total_mag(Decimal(1), Decimal(1)) - self.assertEqual(c.compare_total_mag(1, 1), d) - self.assertEqual(c.compare_total_mag(Decimal(1), 1), d) - self.assertEqual(c.compare_total_mag(1, Decimal(1)), d) - self.assertRaises(TypeError, c.compare_total_mag, '1', 1) - self.assertRaises(TypeError, c.compare_total_mag, 1, '1') - - def test_copy_abs(self): - c = Context() - d = c.copy_abs(Decimal(-1)) - self.assertEqual(c.copy_abs(-1), d) - self.assertRaises(TypeError, c.copy_abs, '-1') - - def test_copy_decimal(self): - c = Context() - d = c.copy_decimal(Decimal(-1)) - self.assertEqual(c.copy_decimal(-1), d) - self.assertRaises(TypeError, c.copy_decimal, '-1') - - def test_copy_negate(self): - c = Context() - d = c.copy_negate(Decimal(-1)) - self.assertEqual(c.copy_negate(-1), d) - self.assertRaises(TypeError, c.copy_negate, '-1') - - def test_copy_sign(self): - c = Context() - d = c.copy_sign(Decimal(1), Decimal(-2)) - self.assertEqual(c.copy_sign(1, -2), d) - self.assertEqual(c.copy_sign(Decimal(1), -2), d) - self.assertEqual(c.copy_sign(1, Decimal(-2)), d) - self.assertRaises(TypeError, c.copy_sign, '1', -2) - self.assertRaises(TypeError, c.copy_sign, 1, '-2') - - def test_divide(self): - c = Context() - d = c.divide(Decimal(1), Decimal(2)) - self.assertEqual(c.divide(1, 2), d) - self.assertEqual(c.divide(Decimal(1), 2), d) - self.assertEqual(c.divide(1, Decimal(2)), d) - self.assertRaises(TypeError, c.divide, '1', 2) - self.assertRaises(TypeError, c.divide, 1, '2') - - def test_divide_int(self): - c = Context() - d = c.divide_int(Decimal(1), Decimal(2)) - self.assertEqual(c.divide_int(1, 2), d) - self.assertEqual(c.divide_int(Decimal(1), 2), d) - self.assertEqual(c.divide_int(1, Decimal(2)), d) - self.assertRaises(TypeError, c.divide_int, '1', 2) - self.assertRaises(TypeError, c.divide_int, 1, '2') - - def test_divmod(self): - c = Context() - d = c.divmod(Decimal(1), Decimal(2)) - self.assertEqual(c.divmod(1, 2), d) - self.assertEqual(c.divmod(Decimal(1), 2), d) - self.assertEqual(c.divmod(1, Decimal(2)), d) - self.assertRaises(TypeError, c.divmod, '1', 2) - self.assertRaises(TypeError, c.divmod, 1, '2') - - def test_exp(self): - c = Context() - d = c.exp(Decimal(10)) - self.assertEqual(c.exp(10), d) - self.assertRaises(TypeError, c.exp, '10') - - def test_fma(self): - c = Context() - d = c.fma(Decimal(2), Decimal(3), Decimal(4)) - self.assertEqual(c.fma(2, 3, 4), d) - self.assertEqual(c.fma(Decimal(2), 3, 4), d) - self.assertEqual(c.fma(2, Decimal(3), 4), d) - self.assertEqual(c.fma(2, 3, Decimal(4)), d) - self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d) - self.assertRaises(TypeError, c.fma, '2', 3, 4) - self.assertRaises(TypeError, c.fma, 2, '3', 4) - self.assertRaises(TypeError, c.fma, 2, 3, '4') - - # Issue 12079 for Context.fma ... - self.assertRaises(TypeError, c.fma, - Decimal('Infinity'), Decimal(0), "not a decimal") - self.assertRaises(TypeError, c.fma, - Decimal(1), Decimal('snan'), 1.222) - # ... and for Decimal.fma. - self.assertRaises(TypeError, Decimal('Infinity').fma, - Decimal(0), "not a decimal") - self.assertRaises(TypeError, Decimal(1).fma, - Decimal('snan'), 1.222) - - def test_is_finite(self): - c = Context() - d = c.is_finite(Decimal(10)) - self.assertEqual(c.is_finite(10), d) - self.assertRaises(TypeError, c.is_finite, '10') - - def test_is_infinite(self): - c = Context() - d = c.is_infinite(Decimal(10)) - self.assertEqual(c.is_infinite(10), d) - self.assertRaises(TypeError, c.is_infinite, '10') - - def test_is_nan(self): - c = Context() - d = c.is_nan(Decimal(10)) - self.assertEqual(c.is_nan(10), d) - self.assertRaises(TypeError, c.is_nan, '10') - - def test_is_normal(self): - c = Context() - d = c.is_normal(Decimal(10)) - self.assertEqual(c.is_normal(10), d) - self.assertRaises(TypeError, c.is_normal, '10') - - def test_is_qnan(self): - c = Context() - d = c.is_qnan(Decimal(10)) - self.assertEqual(c.is_qnan(10), d) - self.assertRaises(TypeError, c.is_qnan, '10') - - def test_is_signed(self): - c = Context() - d = c.is_signed(Decimal(10)) - self.assertEqual(c.is_signed(10), d) - self.assertRaises(TypeError, c.is_signed, '10') - - def test_is_snan(self): - c = Context() - d = c.is_snan(Decimal(10)) - self.assertEqual(c.is_snan(10), d) - self.assertRaises(TypeError, c.is_snan, '10') - - def test_is_subnormal(self): - c = Context() - d = c.is_subnormal(Decimal(10)) - self.assertEqual(c.is_subnormal(10), d) - self.assertRaises(TypeError, c.is_subnormal, '10') - - def test_is_zero(self): - c = Context() - d = c.is_zero(Decimal(10)) - self.assertEqual(c.is_zero(10), d) - self.assertRaises(TypeError, c.is_zero, '10') - - def test_ln(self): - c = Context() - d = c.ln(Decimal(10)) - self.assertEqual(c.ln(10), d) - self.assertRaises(TypeError, c.ln, '10') - - def test_log10(self): - c = Context() - d = c.log10(Decimal(10)) - self.assertEqual(c.log10(10), d) - self.assertRaises(TypeError, c.log10, '10') - - def test_logb(self): - c = Context() - d = c.logb(Decimal(10)) - self.assertEqual(c.logb(10), d) - self.assertRaises(TypeError, c.logb, '10') - - def test_logical_and(self): - c = Context() - d = c.logical_and(Decimal(1), Decimal(1)) - self.assertEqual(c.logical_and(1, 1), d) - self.assertEqual(c.logical_and(Decimal(1), 1), d) - self.assertEqual(c.logical_and(1, Decimal(1)), d) - self.assertRaises(TypeError, c.logical_and, '1', 1) - self.assertRaises(TypeError, c.logical_and, 1, '1') - - def test_logical_invert(self): - c = Context() - d = c.logical_invert(Decimal(1000)) - self.assertEqual(c.logical_invert(1000), d) - self.assertRaises(TypeError, c.logical_invert, '1000') - - def test_logical_or(self): - c = Context() - d = c.logical_or(Decimal(1), Decimal(1)) - self.assertEqual(c.logical_or(1, 1), d) - self.assertEqual(c.logical_or(Decimal(1), 1), d) - self.assertEqual(c.logical_or(1, Decimal(1)), d) - self.assertRaises(TypeError, c.logical_or, '1', 1) - self.assertRaises(TypeError, c.logical_or, 1, '1') - - def test_logical_xor(self): - c = Context() - d = c.logical_xor(Decimal(1), Decimal(1)) - self.assertEqual(c.logical_xor(1, 1), d) - self.assertEqual(c.logical_xor(Decimal(1), 1), d) - self.assertEqual(c.logical_xor(1, Decimal(1)), d) - self.assertRaises(TypeError, c.logical_xor, '1', 1) - self.assertRaises(TypeError, c.logical_xor, 1, '1') - - def test_max(self): - c = Context() - d = c.max(Decimal(1), Decimal(2)) - self.assertEqual(c.max(1, 2), d) - self.assertEqual(c.max(Decimal(1), 2), d) - self.assertEqual(c.max(1, Decimal(2)), d) - self.assertRaises(TypeError, c.max, '1', 2) - self.assertRaises(TypeError, c.max, 1, '2') - - def test_max_mag(self): - c = Context() - d = c.max_mag(Decimal(1), Decimal(2)) - self.assertEqual(c.max_mag(1, 2), d) - self.assertEqual(c.max_mag(Decimal(1), 2), d) - self.assertEqual(c.max_mag(1, Decimal(2)), d) - self.assertRaises(TypeError, c.max_mag, '1', 2) - self.assertRaises(TypeError, c.max_mag, 1, '2') - - def test_min(self): - c = Context() - d = c.min(Decimal(1), Decimal(2)) - self.assertEqual(c.min(1, 2), d) - self.assertEqual(c.min(Decimal(1), 2), d) - self.assertEqual(c.min(1, Decimal(2)), d) - self.assertRaises(TypeError, c.min, '1', 2) - self.assertRaises(TypeError, c.min, 1, '2') - - def test_min_mag(self): - c = Context() - d = c.min_mag(Decimal(1), Decimal(2)) - self.assertEqual(c.min_mag(1, 2), d) - self.assertEqual(c.min_mag(Decimal(1), 2), d) - self.assertEqual(c.min_mag(1, Decimal(2)), d) - self.assertRaises(TypeError, c.min_mag, '1', 2) - self.assertRaises(TypeError, c.min_mag, 1, '2') - - def test_minus(self): - c = Context() - d = c.minus(Decimal(10)) - self.assertEqual(c.minus(10), d) - self.assertRaises(TypeError, c.minus, '10') - - def test_multiply(self): - c = Context() - d = c.multiply(Decimal(1), Decimal(2)) - self.assertEqual(c.multiply(1, 2), d) - self.assertEqual(c.multiply(Decimal(1), 2), d) - self.assertEqual(c.multiply(1, Decimal(2)), d) - self.assertRaises(TypeError, c.multiply, '1', 2) - self.assertRaises(TypeError, c.multiply, 1, '2') - - def test_next_minus(self): - c = Context() - d = c.next_minus(Decimal(10)) - self.assertEqual(c.next_minus(10), d) - self.assertRaises(TypeError, c.next_minus, '10') - - def test_next_plus(self): - c = Context() - d = c.next_plus(Decimal(10)) - self.assertEqual(c.next_plus(10), d) - self.assertRaises(TypeError, c.next_plus, '10') - - def test_next_toward(self): - c = Context() - d = c.next_toward(Decimal(1), Decimal(2)) - self.assertEqual(c.next_toward(1, 2), d) - self.assertEqual(c.next_toward(Decimal(1), 2), d) - self.assertEqual(c.next_toward(1, Decimal(2)), d) - self.assertRaises(TypeError, c.next_toward, '1', 2) - self.assertRaises(TypeError, c.next_toward, 1, '2') - - def test_normalize(self): - c = Context() - d = c.normalize(Decimal(10)) - self.assertEqual(c.normalize(10), d) - self.assertRaises(TypeError, c.normalize, '10') - - def test_number_class(self): - c = Context() - self.assertEqual(c.number_class(123), c.number_class(Decimal(123))) - self.assertEqual(c.number_class(0), c.number_class(Decimal(0))) - self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45))) - - def test_power(self): - c = Context() - d = c.power(Decimal(1), Decimal(4), Decimal(2)) - self.assertEqual(c.power(1, 4, 2), d) - self.assertEqual(c.power(Decimal(1), 4, 2), d) - self.assertEqual(c.power(1, Decimal(4), 2), d) - self.assertEqual(c.power(1, 4, Decimal(2)), d) - self.assertEqual(c.power(Decimal(1), Decimal(4), 2), d) - self.assertRaises(TypeError, c.power, '1', 4, 2) - self.assertRaises(TypeError, c.power, 1, '4', 2) - self.assertRaises(TypeError, c.power, 1, 4, '2') - - def test_plus(self): - c = Context() - d = c.plus(Decimal(10)) - self.assertEqual(c.plus(10), d) - self.assertRaises(TypeError, c.plus, '10') - - def test_quantize(self): - c = Context() - d = c.quantize(Decimal(1), Decimal(2)) - self.assertEqual(c.quantize(1, 2), d) - self.assertEqual(c.quantize(Decimal(1), 2), d) - self.assertEqual(c.quantize(1, Decimal(2)), d) - self.assertRaises(TypeError, c.quantize, '1', 2) - self.assertRaises(TypeError, c.quantize, 1, '2') - - def test_remainder(self): - c = Context() - d = c.remainder(Decimal(1), Decimal(2)) - self.assertEqual(c.remainder(1, 2), d) - self.assertEqual(c.remainder(Decimal(1), 2), d) - self.assertEqual(c.remainder(1, Decimal(2)), d) - self.assertRaises(TypeError, c.remainder, '1', 2) - self.assertRaises(TypeError, c.remainder, 1, '2') - - def test_remainder_near(self): - c = Context() - d = c.remainder_near(Decimal(1), Decimal(2)) - self.assertEqual(c.remainder_near(1, 2), d) - self.assertEqual(c.remainder_near(Decimal(1), 2), d) - self.assertEqual(c.remainder_near(1, Decimal(2)), d) - self.assertRaises(TypeError, c.remainder_near, '1', 2) - self.assertRaises(TypeError, c.remainder_near, 1, '2') - - def test_rotate(self): - c = Context() - d = c.rotate(Decimal(1), Decimal(2)) - self.assertEqual(c.rotate(1, 2), d) - self.assertEqual(c.rotate(Decimal(1), 2), d) - self.assertEqual(c.rotate(1, Decimal(2)), d) - self.assertRaises(TypeError, c.rotate, '1', 2) - self.assertRaises(TypeError, c.rotate, 1, '2') - - def test_sqrt(self): - c = Context() - d = c.sqrt(Decimal(10)) - self.assertEqual(c.sqrt(10), d) - self.assertRaises(TypeError, c.sqrt, '10') - - def test_same_quantum(self): - c = Context() - d = c.same_quantum(Decimal(1), Decimal(2)) - self.assertEqual(c.same_quantum(1, 2), d) - self.assertEqual(c.same_quantum(Decimal(1), 2), d) - self.assertEqual(c.same_quantum(1, Decimal(2)), d) - self.assertRaises(TypeError, c.same_quantum, '1', 2) - self.assertRaises(TypeError, c.same_quantum, 1, '2') - - def test_scaleb(self): - c = Context() - d = c.scaleb(Decimal(1), Decimal(2)) - self.assertEqual(c.scaleb(1, 2), d) - self.assertEqual(c.scaleb(Decimal(1), 2), d) - self.assertEqual(c.scaleb(1, Decimal(2)), d) - self.assertRaises(TypeError, c.scaleb, '1', 2) - self.assertRaises(TypeError, c.scaleb, 1, '2') - - def test_shift(self): - c = Context() - d = c.shift(Decimal(1), Decimal(2)) - self.assertEqual(c.shift(1, 2), d) - self.assertEqual(c.shift(Decimal(1), 2), d) - self.assertEqual(c.shift(1, Decimal(2)), d) - self.assertRaises(TypeError, c.shift, '1', 2) - self.assertRaises(TypeError, c.shift, 1, '2') - - def test_subtract(self): - c = Context() - d = c.subtract(Decimal(1), Decimal(2)) - self.assertEqual(c.subtract(1, 2), d) - self.assertEqual(c.subtract(Decimal(1), 2), d) - self.assertEqual(c.subtract(1, Decimal(2)), d) - self.assertRaises(TypeError, c.subtract, '1', 2) - self.assertRaises(TypeError, c.subtract, 1, '2') - - def test_to_eng_string(self): - c = Context() - d = c.to_eng_string(Decimal(10)) - self.assertEqual(c.to_eng_string(10), d) - self.assertRaises(TypeError, c.to_eng_string, '10') - - def test_to_sci_string(self): - c = Context() - d = c.to_sci_string(Decimal(10)) - self.assertEqual(c.to_sci_string(10), d) - self.assertRaises(TypeError, c.to_sci_string, '10') - - def test_to_integral_exact(self): - c = Context() - d = c.to_integral_exact(Decimal(10)) - self.assertEqual(c.to_integral_exact(10), d) - self.assertRaises(TypeError, c.to_integral_exact, '10') - - def test_to_integral_value(self): - c = Context() - d = c.to_integral_value(Decimal(10)) - self.assertEqual(c.to_integral_value(10), d) - self.assertRaises(TypeError, c.to_integral_value, '10') - -class WithStatementTest(unittest.TestCase): - # Can't do these as docstrings until Python 2.6 - # as doctest can't handle __future__ statements - - def test_localcontext(self): - # Use a copy of the current context in the block - orig_ctx = getcontext() - with localcontext() as enter_ctx: - set_ctx = getcontext() - final_ctx = getcontext() - self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly') - self.assertIsNot(orig_ctx, set_ctx, 'did not copy the context') - self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context') - - def test_localcontextarg(self): - # Use a copy of the supplied context in the block - orig_ctx = getcontext() - new_ctx = Context(prec=42) - with localcontext(new_ctx) as enter_ctx: - set_ctx = getcontext() - final_ctx = getcontext() - self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly') - self.assertEqual(set_ctx.prec, new_ctx.prec, 'did not set correct context') - self.assertIsNot(new_ctx, set_ctx, 'did not copy the context') - self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context') - -class ContextFlags(unittest.TestCase): - def test_flags_irrelevant(self): - # check that the result (numeric result + flags raised) of an - # arithmetic operation doesn't depend on the current flags - - context = Context(prec=9, Emin = -999999999, Emax = 999999999, - rounding=ROUND_HALF_EVEN, traps=[], flags=[]) - - # operations that raise various flags, in the form (function, arglist) - operations = [ - (context._apply, [Decimal("100E-1000000009")]), - (context.sqrt, [Decimal(2)]), - (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]), - (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]), - (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]), - ] - - # try various flags individually, then a whole lot at once - flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal], - [Inexact, Rounded, Underflow, Clamped, Subnormal]] - - for fn, args in operations: - # find answer and flags raised using a clean context - context.clear_flags() - ans = fn(*args) - flags = [k for k, v in context.flags.items() if v] - - for extra_flags in flagsets: - # set flags, before calling operation - context.clear_flags() - for flag in extra_flags: - context._raise_error(flag) - new_ans = fn(*args) - - # flags that we expect to be set after the operation - expected_flags = list(flags) - for flag in extra_flags: - if flag not in expected_flags: - expected_flags.append(flag) - expected_flags.sort(key=id) - - # flags we actually got - new_flags = [k for k,v in context.flags.items() if v] - new_flags.sort(key=id) - - self.assertEqual(ans, new_ans, - "operation produces different answers depending on flags set: " + - "expected %s, got %s." % (ans, new_ans)) - self.assertEqual(new_flags, expected_flags, - "operation raises different flags depending on flags set: " + - "expected %s, got %s" % (expected_flags, new_flags)) + + @requires_extra_functionality + def test_c_signal_dict(self): + + # SignalDict coverage + Context = C.Context + DefaultContext = C.DefaultContext + + InvalidOperation = C.InvalidOperation + DivisionByZero = C.DivisionByZero + Overflow = C.Overflow + Subnormal = C.Subnormal + Underflow = C.Underflow + Rounded = C.Rounded + Inexact = C.Inexact + Clamped = C.Clamped + + DecClamped = C.DecClamped + DecInvalidOperation = C.DecInvalidOperation + DecIEEEInvalidOperation = C.DecIEEEInvalidOperation + + def assertIsExclusivelySet(signal, signal_dict): + for sig in signal_dict: + if sig == signal: + self.assertTrue(signal_dict[sig]) + else: + self.assertFalse(signal_dict[sig]) + + c = DefaultContext.copy() + + # Signal dict methods + self.assertTrue(Overflow in c.traps) + c.clear_traps() + for k in c.traps.keys(): + c.traps[k] = True + for v in c.traps.values(): + self.assertTrue(v) + c.clear_traps() + for k, v in c.traps.items(): + self.assertFalse(v) + + self.assertFalse(c.flags.get(Overflow)) + self.assertIs(c.flags.get("x"), None) + self.assertEqual(c.flags.get("x", "y"), "y") + self.assertRaises(TypeError, c.flags.get, "x", "y", "z") + + self.assertEqual(len(c.flags), len(c.traps)) + s = sys.getsizeof(c.flags) + s = sys.getsizeof(c.traps) + s = c.flags.__repr__() + + # Set flags/traps. + c.clear_flags() + c._flags = DecClamped + self.assertTrue(c.flags[Clamped]) + + c.clear_traps() + c._traps = DecInvalidOperation + self.assertTrue(c.traps[InvalidOperation]) + + # Set flags/traps from dictionary. + c.clear_flags() + d = c.flags.copy() + d[DivisionByZero] = True + c.flags = d + assertIsExclusivelySet(DivisionByZero, c.flags) + + c.clear_traps() + d = c.traps.copy() + d[Underflow] = True + c.traps = d + assertIsExclusivelySet(Underflow, c.traps) + + # Random constructors + IntSignals = { + Clamped: C.DecClamped, + Rounded: C.DecRounded, + Inexact: C.DecInexact, + Subnormal: C.DecSubnormal, + Underflow: C.DecUnderflow, + Overflow: C.DecOverflow, + DivisionByZero: C.DecDivisionByZero, + InvalidOperation: C.DecIEEEInvalidOperation + } + IntCond = [ + C.DecDivisionImpossible, C.DecDivisionUndefined, C.DecFpuError, + C.DecInvalidContext, C.DecInvalidOperation, C.DecMallocError, + C.DecConversionSyntax, + ] + + lim = len(OrderedSignals[C]) + for r in range(lim): + for t in range(lim): + for round in RoundingModes[C]: + flags = random.sample(OrderedSignals[C], r) + traps = random.sample(OrderedSignals[C], t) + prec = random.randrange(1, 10000) + emin = random.randrange(-10000, 0) + emax = random.randrange(0, 10000) + clamp = random.randrange(0, 2) + caps = random.randrange(0, 2) + cr = random.randrange(0, 2) + c = Context(prec=prec, rounding=round, Emin=emin, Emax=emax, + capitals=caps, clamp=clamp, flags=list(flags), + traps=list(traps)) + + self.assertEqual(c.prec, prec) + self.assertEqual(c.rounding, round) + self.assertEqual(c.Emin, emin) + self.assertEqual(c.Emax, emax) + self.assertEqual(c.capitals, caps) + self.assertEqual(c.clamp, clamp) + + f = 0 + for x in flags: + f |= IntSignals[x] + self.assertEqual(c._flags, f) + + f = 0 + for x in traps: + f |= IntSignals[x] + self.assertEqual(c._traps, f) + + for cond in IntCond: + c._flags = cond + self.assertTrue(c._flags&DecIEEEInvalidOperation) + assertIsExclusivelySet(InvalidOperation, c.flags) + + for cond in IntCond: + c._traps = cond + self.assertTrue(c._traps&DecIEEEInvalidOperation) + assertIsExclusivelySet(InvalidOperation, c.traps) + + def test_invalid_override(self): + Decimal = C.Decimal + + try: + from locale import CHAR_MAX + except ImportError: + return + + def make_grouping(lst): + return ''.join([chr(x) for x in lst]) + + def get_fmt(x, override=None, fmt='n'): + return Decimal(x).__format__(fmt, override) + + invalid_grouping = { + 'decimal_point' : ',', + 'grouping' : make_grouping([255, 255, 0]), + 'thousands_sep' : ',' + } + invalid_dot = { + 'decimal_point' : 'xxxxx', + 'grouping' : make_grouping([3, 3, 0]), + 'thousands_sep' : ',' + } + invalid_sep = { + 'decimal_point' : '.', + 'grouping' : make_grouping([3, 3, 0]), + 'thousands_sep' : 'yyyyy' + } + + if CHAR_MAX == 127: # negative grouping in override + self.assertRaises(ValueError, get_fmt, 12345, + invalid_grouping, 'g') + + self.assertRaises(ValueError, get_fmt, 12345, invalid_dot, 'g') + self.assertRaises(ValueError, get_fmt, 12345, invalid_sep, 'g') + + +all_tests = [ + CExplicitConstructionTest, PyExplicitConstructionTest, + CImplicitConstructionTest, PyImplicitConstructionTest, + CFormatTest, PyFormatTest, + CArithmeticOperatorsTest, PyArithmeticOperatorsTest, + CThreadingTest, PyThreadingTest, + CUsabilityTest, PyUsabilityTest, + CPythonAPItests, PyPythonAPItests, + CContextAPItests, PyContextAPItests, + CContextWithStatement, PyContextWithStatement, + CContextFlags, PyContextFlags, + CSpecialContexts, PySpecialContexts, + CContextInputValidation, PyContextInputValidation, + CContextSubclassing, PyContextSubclassing, + CCoverage, PyCoverage, + CFunctionality, PyFunctionality, + CWhitebox, PyWhitebox, + CIBMTestCases, PyIBMTestCases, +] + +# Delete C tests if _decimal.so is not present. +if not C: + all_tests = all_tests[1::2] +else: + all_tests.insert(0, CheckAttributes) + def test_main(arith=False, verbose=None, todo_tests=None, debug=None): """ Execute the tests. @@ -2366,27 +4948,16 @@ is enabled in regrtest.py """ - init() + init(C) + init(P) global TEST_ALL, DEBUG TEST_ALL = arith or is_resource_enabled('decimal') DEBUG = debug if todo_tests is None: - test_classes = [ - DecimalExplicitConstructionTest, - DecimalImplicitConstructionTest, - DecimalArithmeticOperatorsTest, - DecimalFormatTest, - DecimalUseOfContextTest, - DecimalUsabilityTest, - DecimalPythonAPItests, - ContextAPItests, - DecimalTest, - WithStatementTest, - ContextFlags - ] + test_classes = all_tests else: - test_classes = [DecimalTest] + test_classes = [CIBMTestCases, PyIBMTestCases] # Dynamically build custom test definition for each file in the test # directory and add the definitions to the DecimalTest class. This @@ -2398,17 +4969,32 @@ if todo_tests is not None and head not in todo_tests: continue tester = lambda self, f=filename: self.eval_file(directory + f) - setattr(DecimalTest, 'test_' + head, tester) + setattr(CIBMTestCases, 'test_' + head, tester) + setattr(PyIBMTestCases, 'test_' + head, tester) del filename, head, tail, tester try: run_unittest(*test_classes) if todo_tests is None: - import decimal as DecimalModule - run_doctest(DecimalModule, verbose) + from doctest import IGNORE_EXCEPTION_DETAIL + savedecimal = sys.modules['decimal'] + if C: + sys.modules['decimal'] = C + run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL) + sys.modules['decimal'] = P + run_doctest(P, verbose) + sys.modules['decimal'] = savedecimal finally: - setcontext(ORIGINAL_CONTEXT) + if C: C.setcontext(ORIGINAL_CONTEXT[C]) + P.setcontext(ORIGINAL_CONTEXT[P]) + if not C: + warnings.warn('C tests skipped: no module named _decimal.', + UserWarning) + if not orig_sys_decimal is sys.modules['decimal']: + raise TestFailed("Internal error: unbalanced number of changes to " + "sys.modules['decimal'].") + if __name__ == '__main__': import optparse diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -401,14 +401,10 @@ def testMixingWithDecimal(self): # Decimal refuses mixed arithmetic (but not mixed comparisons) - self.assertRaisesMessage( - TypeError, - "unsupported operand type(s) for +: 'Fraction' and 'Decimal'", - operator.add, F(3,11), Decimal('3.1415926')) - self.assertRaisesMessage( - TypeError, - "unsupported operand type(s) for +: 'Decimal' and 'Fraction'", - operator.add, Decimal('3.1415926'), F(3,11)) + self.assertRaises(TypeError, operator.add, + F(3,11), Decimal('3.1415926')) + self.assertRaises(TypeError, operator.add, + Decimal('3.1415926'), F(3,11)) def testComparisons(self): self.assertTrue(F(1, 2) < F(2, 3)) diff --git a/Lib/test/test_numeric_tower.py b/Lib/test/test_numeric_tower.py --- a/Lib/test/test_numeric_tower.py +++ b/Lib/test/test_numeric_tower.py @@ -150,7 +150,7 @@ # int, float, Fraction, Decimal test_values = [ float('-inf'), - D('-1e999999999'), + D('-1e425000000'), -1e308, F(-22, 7), -3.14, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,10 @@ Library ------- +- Issue #7652: Integrate the decimal floating point libmpdec library to speed + up the decimal module. Performance gains of the new C implementation are + between 12x and 80x, depending on the application. + - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)) (Patch by Guilherme Polo) diff --git a/Misc/valgrind-python.supp b/Misc/valgrind-python.supp --- a/Misc/valgrind-python.supp +++ b/Misc/valgrind-python.supp @@ -456,3 +456,16 @@ fun:PyUnicode_FSConverter } +# Additional suppressions for the unified decimal tests: +{ + test_decimal + Memcheck:Addr4 + fun:PyUnicodeUCS2_FSConverter +} + +{ + test_decimal2 + Memcheck:Addr4 + fun:PyUnicode_FSConverter +} + diff --git a/Modules/_decimal/ISSUES.txt b/Modules/_decimal/ISSUES.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/ISSUES.txt @@ -0,0 +1,56 @@ + + +Normal priority: +---------------- + +1) Add C-API importable as capsule. + +2) Add --with-system-libmpdec to ./configure. + +3) Use same default emin/emax on 32-bit (MAX_EMAX=425000000) and 64-bit + (MAX_EMAX=10**18-1). + +4) Order of arguments in Context(). + +5) Documentation. + +6) quantize() + - exp argument is misleading: + Decimal('0.321000e+2').quantize(exp=9) -> user might expect + that the result will have exp=9. + - watchexp + +7) Match the exception hierarchy of decimal.py: + + exceptions.ArithmeticError(exceptions.Exception) + DecimalException + Clamped + DivisionByZero(DecimalException, exceptions.ZeroDivisionError) + Inexact + Overflow(Inexact, Rounded) + Underflow(Inexact, Rounded, Subnormal) + InvalidOperation + Rounded + Subnormal + FloatOperation + + +Low priority: +------------- + +1) Convert tabs (wait until commit). + +2) Pre-ANSI compilers require '#' in the first column (should be done + for the whole Python source tree if we support such compilers). (?) + +3) FETCH_CURRENT_CONTEXT vs. CURRENT_CONTEXT? + +4) Justify remaining uses of exit on overflow in bignum arith. Short + answer: with correct context values the coefficients never get big + enough for that to happen. + +5) Justify remaining uses of abort() in mpdecimal: These uses are + for debug purposes and can't be reached when the library is used + correctly. + + diff --git a/Modules/_decimal/README.txt b/Modules/_decimal/README.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/README.txt @@ -0,0 +1,46 @@ + + +About +===== + +_decimal.c is a wrapper for the libmpdec library. libmpdec is a fast C +library for correctly-rounded arbitrary precision decimal floating point +arithmetic. It is a complete implementation of Mike Cowlishaw/IBM's +General Decimal Arithmetic Specification. + + +Build process for the module +============================ + +As usual, the build process for _decimal.so is driven by setup.py in the top +level directory. setup.py autodetects the following build configurations: + + 1) x64 - 64-bit Python, x86_64 processor (AMD, Intel) + + 2) uint128 - 64-bit Python, compiler provides __uint128_t (gcc) + + 3) ansi64 - 64-bit Python, ANSI C + + 4) ppro - 32-bit Python, x86 CPU, PentiumPro or later + + 5) ansi32 - 32-bit Python, ANSI C + + 6) ansi-legacy - 32-bit Python, compiler without uint64_t + + 7) universal - Mac OS only (multi-arch) + + +It is possible to override autodetection by exporting: + + PYTHON_DECIMAL_WITH_MACHINE=value, where value is one of the above options. + + +NOTE +==== + +decimal.so is not built from a static libmpdec.a since doing so led to +failures on AIX (user report) and Windows (mixing static and dynamic CRTs +causes locale problems and more). + + + diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/_decimal.c @@ -0,0 +1,5512 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include +#include "longintrepr.h" +#include "pythread.h" +#include "structmember.h" +#include "complexobject.h" +#include "mpdecimal.h" + +#include + +#include "docstrings.h" +#include "memory.h" + + +/* + * Type sizes with assertions in mpdecimal.h and pyport.h: + * sizeof(size_t) == sizeof(Py_ssize_t) + * sizeof(size_t) == sizeof(mpd_uint_t) == sizeof(mpd_ssize_t) + */ + +#ifdef TEST_COVERAGE + #undef Py_LOCAL_INLINE + #define Py_LOCAL_INLINE Py_LOCAL +#endif + +#define MPD_Float_operation MPD_Not_implemented + +#define BOUNDS_CHECK(x, MIN, MAX) x = (x < MIN || MAX < x) ? MAX : x + + +typedef struct { + PyObject_HEAD + mpd_t *dec; +} PyDecObject; + +typedef struct { + PyObject_HEAD + uint32_t *flags; +} PyDecSignalDictObject; + +typedef struct { + PyObject_HEAD + mpd_context_t ctx; + PyObject *traps; + PyObject *flags; + int capitals; +} PyDecContextObject; + +typedef struct { + PyObject_HEAD + PyObject *local; + PyObject *global; +} PyDecContextManagerObject; + + +#undef MPD +#undef CTX +static PyTypeObject PyDec_Type; +static PyTypeObject *PyDecSignalDict_Type; +static PyTypeObject PyDecContext_Type; +static PyTypeObject PyDecContextManager_Type; +#define PyDec_CheckExact(v) (Py_TYPE(v) == &PyDec_Type) +#define PyDec_Check(v) PyObject_TypeCheck(v, &PyDec_Type) +#define PyDecSignalDict_Check(v) (Py_TYPE(v) == PyDecSignalDict_Type) +#define PyDecContext_Check(v) PyObject_TypeCheck(v, &PyDecContext_Type) +#define MPD(v) (((PyDecObject *)v)->dec) +#define SdFlagAddr(v) (((PyDecSignalDictObject *)v)->flags) +#define SdFlags(v) (*((PyDecSignalDictObject *)v)->flags) +#define CTX(v) (&((PyDecContextObject *)v)->ctx) +#define CtxCaps(v) (((PyDecContextObject *)v)->capitals) + + +Py_LOCAL_INLINE(PyObject *) +incr_true(void) +{ + Py_INCREF(Py_True); + return Py_True; +} + +Py_LOCAL_INLINE(PyObject *) +incr_false(void) +{ + Py_INCREF(Py_False); + return Py_False; +} + + +#ifdef WITHOUT_THREADS +/* Default module context */ +static PyObject *module_context = NULL; +#else +/* Key for thread state dictionary */ +static PyObject *tls_context_key = NULL; +#endif + +/* Template for creating new thread contexts, calling Context() without + * arguments and initializing the module_context on first access. */ +static PyObject *default_context_template = NULL; +/* Basic and extended context templates */ +static PyObject *basic_context_template = NULL; +static PyObject *extended_context_template = NULL; + + +/* Error codes for functions that return signals or conditions */ +#define DEC_INVALID_SIGNALS (MPD_Max_status+1U) +#define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1) +#define DEC_ERRORS (DEC_INVALID_SIGNALS|DEC_ERR_OCCURRED) + +typedef struct { + const char *name; /* condition or signal name */ + const char *fqname; /* fully qualified name */ + uint32_t flag; /* libmpdec flag */ + PyObject *ex; /* corresponding exception */ +} DecCondMap; + +/* Top level Exception; inherits from ArithmeticError */ +static PyObject *DecimalException = NULL; + +/* Exceptions that correspond to IEEE signals; inherit from DecimalException */ +#define SIGNAL_MAP_LEN 9 +static DecCondMap signal_map[] = { + {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, + {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL}, + {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL}, + {"Overflow", "decimal.Overflow", MPD_Overflow, NULL}, + {"Underflow", "decimal.Underflow", MPD_Underflow, NULL}, + {"Subnormal", "decimal.Subnormal", MPD_Subnormal, NULL}, + {"Inexact", "decimal.Inexact", MPD_Inexact, NULL}, + {"Rounded", "decimal.Rounded", MPD_Rounded, NULL}, + {"Clamped", "decimal.Clamped", MPD_Clamped, NULL}, + {NULL} +}; + +/* Exceptions that inherit from InvalidOperation */ +static DecCondMap cond_map[] = { + {"InvalidOperation", "decimal.InvalidOperation", MPD_Invalid_operation, NULL}, + {"ConversionSyntax", "decimal.ConversionSyntax", MPD_Conversion_syntax, NULL}, + {"DivisionImpossible", "decimal.DivisionImpossible", MPD_Division_impossible, NULL}, + {"DivisionUndefined", "decimal.DivisionUndefined", MPD_Division_undefined, NULL}, + {"InvalidContext", "decimal.InvalidContext", MPD_Invalid_context, NULL}, + {"MallocError", "decimal.MallocError", MPD_Malloc_error, NULL}, + {NULL} +}; + +static const char *dec_signal_string[MPD_NUM_FLAGS] = { + "Clamped", + "InvalidOperation", + "DivisionByZero", + "InvalidOperation", + "InvalidOperation", + "InvalidOperation", + "Inexact", + "InvalidOperation", + "InvalidOperation", + "InvalidOperation", + "FloatOperation", + "Overflow", + "Rounded", + "Subnormal", + "Underflow", +}; + +static const char *invalid_rounding_err = +"valid values for rounding are:\n\ + [ROUND_CEILING, ROUND_FLOOR, ROUND_UP, ROUND_DOWN,\n\ + ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN,\n\ + ROUND_05UP]"; + +static const char *invalid_signals_err = +"valid values for signals are:\n\ + [InvalidOperation, FloatOperation, DivisionByZero,\n\ + Overflow, Underflow, Subnormal, Inexact, Rounded,\n\ + Clamped]"; + +#ifdef EXTRA_FUNCTIONALITY +static const char *invalid_flags_err = +"valid values for _flags or _traps are:\n\ + signals:\n\ + [DecIEEEInvalidOperation, DecFloatOperation, DecDivisionByZero,\n\ + DecOverflow, DecUnderflow, DecSubnormal, DecInexact, DecRounded,\n\ + DecClamped]\n\ + conditions which trigger DecIEEEInvalidOperation:\n\ + [DecInvalidOperation, DecConversionSyntax, DecDivisionImpossible,\n\ + DecDivisionUndefined, DecFpuError, DecInvalidContext, DecMallocError]"; +#endif + +static int +value_error_int(const char *mesg) +{ + PyErr_SetString(PyExc_ValueError, mesg); + return -1; +} + +#ifdef CONFIG_32 +static PyObject * +value_error_ptr(const char *mesg) +{ + PyErr_SetString(PyExc_ValueError, mesg); + return NULL; +} +#endif + +static int +type_error_int(const char *mesg) +{ + PyErr_SetString(PyExc_TypeError, mesg); + return -1; +} + +static PyObject * +type_error_ptr(const char *mesg) +{ + PyErr_SetString(PyExc_TypeError, mesg); + return NULL; +} + +static int +runtime_error_int(const char *mesg) +{ + PyErr_SetString(PyExc_RuntimeError, mesg); + return -1; +} +#define INTERNAL_ERROR_INT(funcname) \ + return runtime_error_int("internal error in " funcname) + +static PyObject * +runtime_error_ptr(const char *mesg) +{ + PyErr_SetString(PyExc_RuntimeError, mesg); + return NULL; +} +#define INTERNAL_ERROR_PTR(funcname) \ + return runtime_error_ptr("internal error in " funcname) + +static void +dec_traphandler(mpd_context_t *ctx UNUSED) /* GCOV_NOT_REACHED */ +{ /* GCOV_NOT_REACHED */ + return; /* GCOV_NOT_REACHED */ +} + +static PyObject * +flags_as_exception(uint32_t flags) +{ + DecCondMap *cm; + + for (cm = signal_map; cm->name != NULL; cm++) { + if (flags&cm->flag) { + return cm->ex; + } + } + + INTERNAL_ERROR_PTR("flags_as_exception"); /* GCOV_NOT_REACHED */ +} + +Py_LOCAL_INLINE(uint32_t) +exception_as_flag(PyObject *ex) +{ + DecCondMap *cm; + + for (cm = signal_map; cm->name != NULL; cm++) { + if (cm->ex == ex) { + return cm->flag; + } + } + + PyErr_SetString(PyExc_KeyError, invalid_signals_err); + return DEC_INVALID_SIGNALS; +} + +static PyObject * +flags_as_list(uint32_t flags) +{ + PyObject *list; + DecCondMap *cm; + + list = PyList_New(0); + if (list == NULL) { + return NULL; + } + + for (cm = cond_map; cm->name != NULL; cm++) { + if (flags&cm->flag) { + if (PyList_Append(list, cm->ex) < 0) { + goto error; + } + } + } + for (cm = signal_map+1; cm->name != NULL; cm++) { + if (flags&cm->flag) { + if (PyList_Append(list, cm->ex) < 0) { + goto error; + } + } + } + + return list; + +error: + Py_DECREF(list); + return NULL; +} + +static PyObject * +signals_as_list(uint32_t flags) +{ + PyObject *list; + DecCondMap *cm; + + list = PyList_New(0); + if (list == NULL) { + return NULL; + } + + for (cm = signal_map; cm->name != NULL; cm++) { + if (flags&cm->flag) { + if (PyList_Append(list, cm->ex) < 0) { + Py_DECREF(list); + return NULL; + } + } + } + + return list; +} + +static uint32_t +list_as_flags(PyObject *list) +{ + PyObject *item; + uint32_t flags, x; + Py_ssize_t n, j; + + assert(PyList_Check(list)); + + n = PyList_Size(list); + flags = 0; + for (j = 0; j < n; j++) { + item = PyList_GetItem(list, j); + x = exception_as_flag(item); + if (x & DEC_ERRORS) { + return x; + } + flags |= x; + } + + return flags; +} + +static PyObject * +flags_as_dict(uint32_t flags) +{ + DecCondMap *cm; + PyObject *dict; + + dict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + + for (cm = signal_map; cm->name != NULL; cm++) { + PyObject *b = flags&cm->flag ? Py_True : Py_False; + if (PyDict_SetItem(dict, cm->ex, b) < 0) { + Py_DECREF(dict); + return NULL; + } + } + + return dict; +} + +static uint32_t +dict_as_flags(PyObject *val) +{ + PyObject *b; + DecCondMap *cm; + uint32_t flags = 0; + int x; + + if (!PyDict_Check(val)) { + PyErr_SetString(PyExc_TypeError, + "argument must be a signal dict"); + return DEC_INVALID_SIGNALS; + } + + if (PyDict_Size(val) != SIGNAL_MAP_LEN) { + PyErr_SetString(PyExc_KeyError, + "invalid signal dict"); + return DEC_INVALID_SIGNALS; + } + + for (cm = signal_map; cm->name != NULL; cm++) { + b = PyDict_GetItemWithError(val, cm->ex); + if (b == NULL) { + if (PyErr_Occurred()) { + return DEC_ERR_OCCURRED; + } + PyErr_SetString(PyExc_KeyError, + "invalid signal dict"); + return DEC_INVALID_SIGNALS; + } + + x = PyObject_IsTrue(b); + if (x < 0) { + return DEC_ERR_OCCURRED; + } + if (x == 1) { + flags |= cm->flag; + } + } + + return flags; +} + +#ifdef EXTRA_FUNCTIONALITY +static uint32_t +long_as_flags(PyObject *v) +{ + long x; + + x = PyLong_AsLong(v); + if (x == -1 && PyErr_Occurred()) { + return DEC_ERR_OCCURRED; + } + if (x < 0 || x > (long)MPD_Max_status) { + PyErr_SetString(PyExc_TypeError, invalid_flags_err); + return DEC_INVALID_SIGNALS; + } + + return x; +} +#endif + +static int +dec_addstatus(PyObject *context, uint32_t status) +{ + mpd_context_t *ctx = CTX(context); + + ctx->status |= status; + if (ctx->traps&status) { + PyObject *ex, *siglist; + + ex = flags_as_exception(ctx->traps&status); + if (ex == NULL) { + return 1; /* GCOV_NOT_REACHED */ + } + siglist = flags_as_list(ctx->traps&status); + if (siglist == NULL) { + return 1; + } + + PyErr_SetObject(ex, siglist); + Py_DECREF(siglist); + return 1; + } + return 0; +} + + +/******************************************************************************/ +/* SignalDict Object */ +/******************************************************************************/ + +/* The SignalDict is a MutableMapping that provides access to the + mpd_context_t flags, which reside in the context object. When a + new context is created, context.traps and context.flags are + initialized to new SignalDicts. Once a SignalDict is tied to + a context, it cannot be deleted. */ + +static int +signaldict_init(PyObject *self, PyObject *args UNUSED, PyObject *kwds UNUSED) +{ + SdFlagAddr(self) = NULL; + return 0; +} + +static Py_ssize_t +signaldict_len(PyObject *self UNUSED) +{ + return SIGNAL_MAP_LEN; +} + +static PyObject *SignalTuple; +static PyObject * +signaldict_iter(PyObject *self UNUSED) +{ + return PyTuple_Type.tp_iter(SignalTuple); +} + +static PyObject * +signaldict_getitem(PyObject *self, PyObject *key) +{ + uint32_t flag; + + flag = exception_as_flag(key); + if (flag & DEC_ERRORS) { + return NULL; + } + + return SdFlags(self)&flag ? incr_true() : incr_false(); +} + +static int +signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) +{ + uint32_t flag; + int x; + + if (value == NULL) { + return value_error_int("signal keys cannot be deleted"); + } + + flag = exception_as_flag(key); + if (flag & DEC_ERRORS) { + return -1; + } + + x = PyObject_IsTrue(value); + if (x < 0) { + return -1; + } + + if (x == 1) { + SdFlags(self) |= flag; + } + else { + SdFlags(self) &= ~flag; + } + + return 0; +} + +static PyObject * +signaldict_repr(PyObject *self) +{ + DecCondMap *cm; + const char *n[SIGNAL_MAP_LEN]; /* name */ + const char *b[SIGNAL_MAP_LEN]; /* bool */ + int i; + + assert(SIGNAL_MAP_LEN == 9); + + for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { + n[i] = cm->fqname; + b[i] = SdFlags(self)&cm->flag ? "True" : "False"; + } + return PyUnicode_FromFormat( + "{:%s, :%s, :%s, " + ":%s, :%s, :%s, " + ":%s, :%s, :%s}", + n[0], b[0], n[1], b[1], n[2], b[2], + n[3], b[3], n[4], b[4], n[5], b[5], + n[6], b[6], n[7], b[7], n[8], b[8]); +} + +static PyObject * +signaldict_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *res = Py_NotImplemented; + + assert(PyDecSignalDict_Check(v)); + + if (op == Py_EQ || op == Py_NE) { + if (PyDecSignalDict_Check(w)) { + res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False; + } + else if (PyDict_Check(w)) { + uint32_t flags = dict_as_flags(w); + if (flags & DEC_ERRORS) { + if (flags & DEC_INVALID_SIGNALS) { + /* non-comparable: Py_NotImplemented */ + PyErr_Clear(); + } + else { + return NULL; + } + } + else { + res = (SdFlags(v)==flags) ^ (op==Py_NE) ? Py_True : Py_False; + } + } + } + + Py_INCREF(res); + return res; +} + +static PyObject * +signaldict_copy(PyObject *self) +{ + return flags_as_dict(SdFlags(self)); +} + + +static PyMappingMethods signaldict_as_mapping = { + (lenfunc)signaldict_len, /* mp_length */ + (binaryfunc)signaldict_getitem, /* mp_subscript */ + (objobjargproc)signaldict_setitem /* mp_ass_subscript */ +}; + +static PyMethodDef signaldict_methods[] = { + { "copy", (PyCFunction)signaldict_copy, METH_NOARGS, NULL}, + {NULL, NULL} +}; + + +static PyTypeObject PyDecSignalDictMixin_Type = +{ + PyVarObject_HEAD_INIT(0, 0) + "decimal.SignalDictMixin", /* tp_name */ + sizeof(PyDecSignalDictObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc) signaldict_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &signaldict_as_mapping, /* tp_as_mapping */ + PyObject_HashNotImplemented, /* tp_hash */ + 0, /* tp_call */ + (reprfunc) 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + (PyBufferProcs *) 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE| + Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + signaldict_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)signaldict_iter, /* tp_iter */ + 0, /* tp_iternext */ + signaldict_methods, /* 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 */ + (initproc)signaldict_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ +}; + + +/******************************************************************************/ +/* Context Object, Part 1 */ +/******************************************************************************/ + +#define Dec_CONTEXT_GET_SSIZE(mem) \ +static PyObject * \ +context_get##mem(PyObject *self, void *closure UNUSED) \ +{ \ + return PyLong_FromSsize_t(mpd_get##mem(CTX(self))); \ +} + +#define Dec_CONTEXT_GET_ULONG(mem) \ +static PyObject * \ +context_get##mem(PyObject *self, void *closure UNUSED) \ +{ \ + return PyLong_FromUnsignedLong(mpd_get##mem(CTX(self))); \ +} + +Dec_CONTEXT_GET_SSIZE(prec) +Dec_CONTEXT_GET_SSIZE(emax) +Dec_CONTEXT_GET_SSIZE(emin) +Dec_CONTEXT_GET_SSIZE(round) +Dec_CONTEXT_GET_SSIZE(clamp) + +#ifdef EXTRA_FUNCTIONALITY +Dec_CONTEXT_GET_ULONG(traps) +Dec_CONTEXT_GET_ULONG(status) +#endif + +static PyObject * +context_getcapitals(PyObject *self, void *closure UNUSED) +{ + return PyLong_FromLong(CtxCaps(self)); +} + +#ifdef EXTRA_FUNCTIONALITY +static PyObject * +context_getallcr(PyObject *self, void *closure UNUSED) +{ + return PyLong_FromLong(mpd_getcr(CTX(self))); +} +#endif + +static PyObject * +context_getetiny(PyObject *self, PyObject *dummy UNUSED) +{ + return PyLong_FromSsize_t(mpd_etiny(CTX(self))); +} + +static PyObject * +context_getetop(PyObject *self, PyObject *dummy UNUSED) +{ + return PyLong_FromSsize_t(mpd_etop(CTX(self))); +} + +static int +context_setprec(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetprec(ctx, x)) { + return value_error_int( + "valid range for prec is [1, MAX_PREC]"); + } + + return 0; +} + +static int +context_setemin(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetemin(ctx, x)) { + return value_error_int( + "valid range for Emin is [MIN_EMIN, 0]"); + } + + return 0; +} + +static int +context_setemax(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetemax(ctx, x)) { + return value_error_int( + "valid range for Emax is [0, MAX_EMAX]"); + } + + return 0; +} + +#ifdef CONFIG_32 +static PyObject * +context_unsafe_setprec(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx = CTX(self); + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return NULL; + } + + if (x < 1 || x > 1070000000L) { + return value_error_ptr( + "valid range for unsafe prec is [1, 1070000000]"); + } + + ctx->prec = x; + Py_RETURN_NONE; +} + +static PyObject * +context_unsafe_setemin(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx = CTX(self); + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return NULL; + } + + if (x < -1070000000L || x > 0) { + return value_error_ptr( + "valid range for unsafe emin is [-1070000000, 0]"); + } + + ctx->emin = x; + Py_RETURN_NONE; +} + +static PyObject * +context_unsafe_setemax(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx = CTX(self); + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return NULL; + } + + if (x < 0 || x > 1070000000L) { + return value_error_ptr( + "valid range for unsafe emax is [0, 1070000000]"); + } + + ctx->emax = x; + Py_RETURN_NONE; +} +#endif + +static int +context_setround(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + BOUNDS_CHECK(x, INT_MIN, INT_MAX); + + ctx = CTX(self); + if (!mpd_qsetround(ctx, (int)x)) { + return type_error_int(invalid_rounding_err); + } + + return 0; +} + +static int +context_setcapitals(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + + if (x != 0 && x != 1) { + return value_error_int( + "valid values for capitals are 0 or 1"); + } + CtxCaps(self) = (int)x; + + return 0; +} + +#ifdef EXTRA_FUNCTIONALITY +static int +context_settraps(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + uint32_t flags; + + flags = long_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsettraps(ctx, flags)) { + INTERNAL_ERROR_INT("context_settraps"); + } + + return 0; +} +#endif + +static int +context_settraps_list(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx; + uint32_t flags; + + flags = list_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsettraps(ctx, flags)) { + INTERNAL_ERROR_INT("context_settraps_list"); + } + + return 0; +} + +static int +context_settraps_dict(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx; + uint32_t flags; + + if (PyDecSignalDict_Check(value)) { + flags = SdFlags(value); + } + else { + flags = dict_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + } + + ctx = CTX(self); + if (!mpd_qsettraps(ctx, flags)) { + INTERNAL_ERROR_INT("context_settraps_dict"); + } + + return 0; +} + +#ifdef EXTRA_FUNCTIONALITY +static int +context_setstatus(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + uint32_t flags; + + flags = long_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetstatus(ctx, flags)) { + INTERNAL_ERROR_INT("context_setstatus"); + } + + return 0; +} +#endif + +static int +context_setstatus_list(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx; + uint32_t flags; + + flags = list_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetstatus(ctx, flags)) { + INTERNAL_ERROR_INT("context_setstatus_list"); + } + + return 0; +} + +static int +context_setstatus_dict(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx; + uint32_t flags; + + if (PyDecSignalDict_Check(value)) { + flags = SdFlags(value); + } + else { + flags = dict_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + } + + ctx = CTX(self); + if (!mpd_qsetstatus(ctx, flags)) { + INTERNAL_ERROR_INT("context_setstatus_dict"); + } + + return 0; +} + +static int +context_setclamp(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + BOUNDS_CHECK(x, INT_MIN, INT_MAX); + + ctx = CTX(self); + if (!mpd_qsetclamp(ctx, (int)x)) { + return value_error_int("valid values for clamp are 0 or 1"); + } + + return 0; +} + +#ifdef EXTRA_FUNCTIONALITY +static int +context_setallcr(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + BOUNDS_CHECK(x, INT_MIN, INT_MAX); + + ctx = CTX(self); + if (!mpd_qsetcr(ctx, (int)x)) { + return value_error_int("valid values for _allcr are 0 or 1"); + } + + return 0; +} +#endif + +static PyObject * +context_getattr(PyObject *self, PyObject *name) +{ + PyObject *retval; + + if (PyUnicode_Check(name)) { + if (PyUnicode_CompareWithASCIIString(name, "traps") == 0) { + retval = ((PyDecContextObject *)self)->traps; + Py_INCREF(retval); + return retval; + } + if (PyUnicode_CompareWithASCIIString(name, "flags") == 0) { + retval = ((PyDecContextObject *)self)->flags; + Py_INCREF(retval); + return retval; + } + } + + return PyObject_GenericGetAttr(self, name); +} + +static int +context_setattr(PyObject *self, PyObject *name, PyObject *value) +{ + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, + "context attributes cannot be deleted"); + return -1; + } + + if (PyUnicode_Check(name)) { + if (PyUnicode_CompareWithASCIIString(name, "traps") == 0) { + return context_settraps_dict(self, value); + } + if (PyUnicode_CompareWithASCIIString(name, "flags") == 0) { + return context_setstatus_dict(self, value); + } + } + + return PyObject_GenericSetAttr(self, name, value); +} + +static PyObject * +context_clear_traps(PyObject *self, PyObject *dummy UNUSED) +{ + CTX(self)->traps = 0; + Py_RETURN_NONE; +} + +static PyObject * +context_clear_flags(PyObject *self, PyObject *dummy UNUSED) +{ + CTX(self)->status = 0; + Py_RETURN_NONE; +} + +#define DEC_DFLT_EMAX 999999 +#define DEC_DFLT_EMIN -999999 + +static mpd_context_t dflt_ctx = { + 28, DEC_DFLT_EMAX, DEC_DFLT_EMIN, + MPD_IEEE_Invalid_operation|MPD_Division_by_zero|MPD_Overflow, + 0, 0, MPD_ROUND_HALF_EVEN, 0, 1 +}; + +static PyObject * +context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) +{ + PyDecContextObject *self = NULL; + mpd_context_t *ctx; + + if (type == &PyDecContext_Type) { + self = PyObject_New(PyDecContextObject, &PyDecContext_Type); + } + else { + self = (PyDecContextObject *)type->tp_alloc(type, 0); + } + + if (self == NULL) { + return NULL; + } + + self->traps = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + if (self->traps == NULL) { + self->flags = NULL; + Py_DECREF(self); + return NULL; + } + self->flags = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + if (self->flags == NULL) { + Py_DECREF(self); + return NULL; + } + + ctx = CTX(self); + + if (default_context_template) { + *ctx = *CTX(default_context_template); + } + else { + *ctx = dflt_ctx; + } + + SdFlagAddr(self->traps) = &ctx->traps; + SdFlagAddr(self->flags) = &ctx->status; + + CtxCaps(self) = 1; + + return (PyObject *)self; +} + +static void +context_dealloc(PyDecContextObject *self) +{ + Py_XDECREF(self->traps); + Py_XDECREF(self->flags); + Py_TYPE(self)->tp_free(self); +} + +static int +getround(PyObject *v) +{ + const char *s; + long x; + int i; + + if (PyLong_Check(v)) { + x = PyLong_AsLong(v); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + BOUNDS_CHECK(x, 0, INT_MAX); + return (int)x; + } + else if (PyUnicode_Check(v)) { + for (i = 0; i < MPD_ROUND_GUARD; i++) { + s = mpd_round_string[i]; + if (PyUnicode_CompareWithASCIIString(v, s) == 0) { + return i; + } + } + } + + return type_error_int("invalid rounding mode"); +} + +static int +context_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = { + "prec", "rounding", "Emin", "Emax", "capitals", "clamp", + "flags", "traps", NULL + }; + PyObject *rounding = NULL; + PyObject *traps = NULL; + PyObject *status = NULL; + mpd_context_t *ctx, t; + int capitals = 1; + int ret; + + assert(PyTuple_Check(args)); + ctx = CTX(self); + + t = *ctx; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, + "|nOnniiOO", kwlist, + &t.prec, &rounding, &t.emin, &t.emax, &capitals, &t.clamp, + &status, &traps + )) { + return -1; + } + if (rounding != NULL) { + t.round = getround(rounding); + if (t.round < 0) { + return -1; + } + } + + if (!mpd_qsetprec(ctx, t.prec) || + !mpd_qsetemin(ctx, t.emin) || + !mpd_qsetemax(ctx, t.emax) || + !mpd_qsetclamp(ctx, t.clamp)) { + return value_error_int("invalid context"); + } + if (!mpd_qsetround(ctx, t.round) || + !mpd_qsettraps(ctx, t.traps) || + !mpd_qsetstatus(ctx, t.status)) { + return type_error_int("invalid context"); + } + + if (capitals != 0 && capitals != 1) { + return value_error_int("invalid context"); + } + CtxCaps(self) = capitals; + + if (traps != NULL) { + if (PyList_Check(traps)) { + ret = context_settraps_list(self, traps); + } +#ifdef EXTRA_FUNCTIONALITY + else if (PyLong_Check(traps)) { + ret = context_settraps(self, traps, NULL); + } +#endif + else { + ret = context_settraps_dict(self, traps); + } + if (ret < 0) { + return ret; + } + } + if (status != NULL) { + if (PyList_Check(status)) { + ret = context_setstatus_list(self, status); + } +#ifdef EXTRA_FUNCTIONALITY + else if (PyLong_Check(status)) { + ret = context_setstatus(self, status, NULL); + } +#endif + else { + ret = context_setstatus_dict(self, status); + } + if (ret < 0) { + return ret; + } + } + + return 0; +} + +static PyObject * +context_repr(PyDecContextObject *self) +{ + mpd_context_t *ctx; + char flags[MPD_MAX_SIGNAL_LIST]; + char traps[MPD_MAX_SIGNAL_LIST]; + int n, mem; + + assert(PyDecContext_Check(self)); + ctx = CTX(self); + + mem = MPD_MAX_SIGNAL_LIST; + n = mpd_lsnprint_signals(flags, mem, ctx->status, dec_signal_string); + if (n < 0 || n >= mem) { + INTERNAL_ERROR_PTR("context_repr"); + } + + n = mpd_lsnprint_signals(traps, mem, ctx->traps, dec_signal_string); + if (n < 0 || n >= mem) { + INTERNAL_ERROR_PTR("context_repr"); + } + + return PyUnicode_FromFormat( + "Context(prec=%zd, rounding=%s, Emin=%zd, Emax=%zd, " + "capitals=%d, clamp=%d, flags=%s, traps=%s)", + ctx->prec, mpd_round_string[ctx->round], ctx->emin, ctx->emax, + self->capitals, ctx->clamp, flags, traps); +} + +static void +init_basic_context(PyObject *v) +{ + mpd_context_t ctx = dflt_ctx; + + ctx.prec = 9; + ctx.traps |= (MPD_Underflow|MPD_Clamped); + ctx.round = MPD_ROUND_HALF_UP; + + *CTX(v) = ctx; + CtxCaps(v) = 1; +} + +static void +init_extended_context(PyObject *v) +{ + mpd_context_t ctx = dflt_ctx; + + ctx.prec = 9; + ctx.traps = 0; + + *CTX(v) = ctx; + CtxCaps(v) = 1; +} + +#ifdef EXTRA_FUNCTIONALITY +/* Factory function for creating IEEE interchange format contexts */ +static PyObject * +ieee_context(PyObject *dummy UNUSED, PyObject *v) +{ + PyObject *context; + mpd_ssize_t bits; + mpd_context_t ctx; + + bits = PyLong_AsSsize_t(v); + if (bits == -1 && PyErr_Occurred()) { + return NULL; + } + if (bits <= 0 || bits > INT_MAX) { + goto error; + } + if (mpd_ieee_context(&ctx, (int)bits) < 0) { + goto error; + } + + context = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + if (context == NULL) { + return NULL; + } + *CTX(context) = ctx; + + return context; + +error: + PyErr_Format(PyExc_ValueError, + "argument must be a multiple of 32, with a maximum of %d", + MPD_IEEE_CONTEXT_MAX_BITS); + + return NULL; +} +#endif + +static PyObject * +context_copy(PyObject *self) +{ + PyObject *copy; + + copy = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + if (copy == NULL) { + return NULL; + } + + *CTX(copy) = *CTX(self); + CTX(copy)->newtrap = 0; + CtxCaps(copy) = CtxCaps(self); + + return copy; +} + +static PyObject * +context_reduce(PyObject *self, PyObject *args UNUSED) +{ + PyObject *flags; + PyObject *traps; + PyObject *ret; + mpd_context_t *ctx; + + ctx = CTX(self); + + flags = signals_as_list(ctx->status); + if (flags == NULL) { + return NULL; + } + traps = signals_as_list(ctx->traps); + if (traps == NULL) { + Py_DECREF(flags); + return NULL; + } + + ret = Py_BuildValue( + "O(nsnniiOO)", + Py_TYPE(self), + ctx->prec, mpd_round_string[ctx->round], ctx->emin, ctx->emax, + CtxCaps(self), ctx->clamp, flags, traps + ); + + Py_DECREF(flags); + Py_DECREF(traps); + return ret; +} + + +static PyGetSetDef context_getsets [] = +{ + { "prec", (getter)context_getprec, (setter)context_setprec, NULL, NULL}, + { "Emax", (getter)context_getemax, (setter)context_setemax, NULL, NULL}, + { "Emin", (getter)context_getemin, (setter)context_setemin, NULL, NULL}, + { "rounding", (getter)context_getround, (setter)context_setround, NULL, NULL}, + { "capitals", (getter)context_getcapitals, (setter)context_setcapitals, NULL, NULL}, + { "clamp", (getter)context_getclamp, (setter)context_setclamp, NULL, NULL}, +#ifdef EXTRA_FUNCTIONALITY + { "_allcr", (getter)context_getallcr, (setter)context_setallcr, NULL, NULL}, + { "_traps", (getter)context_gettraps, (setter)context_settraps, NULL, NULL}, + { "_flags", (getter)context_getstatus, (setter)context_setstatus, NULL, NULL}, +#endif + {NULL} +}; + + +#define CONTEXT_CHECK(obj) \ + if (!PyDecContext_Check(obj)) { \ + PyErr_SetString(PyExc_TypeError, \ + "argument must be a context"); \ + return NULL; \ + } + +#define CONTEXT_CHECK_VA(obj) \ + if (!PyDecContext_Check(obj)) { \ + PyErr_SetString(PyExc_TypeError, \ + "optional argument must be a context"); \ + return NULL; \ + } + + +/******************************************************************************/ +/* Global, thread local and temporary contexts */ +/******************************************************************************/ + +#ifdef WITHOUT_THREADS +/* Return borrowed reference to the current context. When compiled + * without threads, this is always the module context. */ +static int module_context_set = 0; +static PyObject * +current_context(void) +{ + /* In decimal.py, the module context is automatically initialized + * from the DefaultContext when it is first accessed. This + * complicates the code and has a speed penalty of 1-2%. */ + if (module_context_set) { + return module_context; + } + + *CTX(module_context) = *CTX(default_context_template); + module_context_set = 1; + return module_context; +} + +/* ctxobj := borrowed reference to the current context */ +#define CURRENT_CONTEXT(ctxobj) \ + ctxobj = current_context() + +/* ctx := pointer to the mpd_context_t struct of the current context */ +#define CURRENT_CONTEXT_ADDR(ctx) \ + ctx = CTX(current_context()) + +/* Return current context, increment reference */ +static PyObject * +PyDec_GetCurrentContext(void) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + + Py_INCREF(context); + return context; +} + +/* Set the module context to a new context, decrement old reference */ +static PyObject * +PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) +{ + CONTEXT_CHECK(v); + + /* If the new context is one of the templates, make a copy. + * This is the current behavior of decimal.py. */ + if (v == default_context_template || + v == basic_context_template || + v == extended_context_template) { + v = context_copy(v); + if (v == NULL) { + return NULL; + } + } + else { + Py_INCREF(v); + } + + Py_XDECREF(module_context); + module_context = v; + module_context_set = 1; + Py_RETURN_NONE; +} +#else +/* + * Thread local storage currently has a speed penalty of about 16%. + * All functions that map Python's arithmetic operators to mpdecimal + * functions have to look up the current context for each and every + * operation. + */ + +/* Return borrowed reference to thread local context. */ +static PyObject * +current_context(void) +{ + PyObject *dict = NULL; + PyObject *tl_context = NULL; + + dict = PyThreadState_GetDict(); + if (dict == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "cannot get thread state"); + return NULL; + } + + tl_context = PyDict_GetItemWithError(dict, tls_context_key); + if (tl_context != NULL) { + /* We already have a thread local context and + * return a borrowed reference. */ + CONTEXT_CHECK(tl_context); + return tl_context; + } + if (PyErr_Occurred()) { + return NULL; + } + + /* Otherwise, set up a new thread local context. */ + tl_context = context_copy(default_context_template); + if (tl_context == NULL) { + return NULL; + } + if (PyDict_SetItem(dict, tls_context_key, tl_context) < 0) { + Py_DECREF(tl_context); + return NULL; + } + Py_DECREF(tl_context); + + /* refcount is 1 */ + return tl_context; +} + +/* ctxobj := borrowed reference to the current context */ +#define CURRENT_CONTEXT(ctxobj) \ + ctxobj = current_context(); \ + if (ctxobj == NULL) { \ + return NULL; \ + } + +/* ctx := pointer to the mpd_context_t struct of the current context */ +#define CURRENT_CONTEXT_ADDR(ctx) { \ + PyObject *_c_t_x_o_b_j = current_context(); \ + if (_c_t_x_o_b_j == NULL) { \ + return NULL; \ + } \ + ctx = CTX(_c_t_x_o_b_j); \ +} + +/* Return current context, increment reference */ +static PyObject * +PyDec_GetCurrentContext(void) +{ + PyObject *context; + + context = current_context(); + if (context == NULL) { + return NULL; + } + + Py_INCREF(context); + return context; +} + +/* Set the thread local context to a new context, decrement old reference */ +static PyObject * +PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) +{ + PyObject *dict; + + CONTEXT_CHECK(v); + + dict = PyThreadState_GetDict(); + if (dict == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "cannot get thread state"); + return NULL; + } + + /* If the new context is one of the templates, make a copy. + * This is the current behavior of decimal.py. */ + if (v == default_context_template || + v == basic_context_template || + v == extended_context_template) { + v = context_copy(v); + if (v == NULL) { + return NULL; + } + } + else { + Py_INCREF(v); + } + + if (PyDict_SetItem(dict, tls_context_key, v) < 0) { + Py_DECREF(v); + return NULL; + } + + Py_DECREF(v); + Py_RETURN_NONE; +} +#endif + +/* Context manager object for the 'with' statement. The manager + * owns one reference to the global (outer) context and one + * to the local (inner) context. */ +static PyObject * +ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args) +{ + PyDecContextManagerObject *self; + PyObject *local; + PyObject *global; + + CURRENT_CONTEXT(global); + local = global; + if (!PyArg_ParseTuple(args, "|O", &local)) { + return NULL; + } + CONTEXT_CHECK_VA(local); + + self = PyObject_New(PyDecContextManagerObject, + &PyDecContextManager_Type); + if (self == NULL) { + return NULL; + } + + self->local = context_copy(local); + if (self->local == NULL) { + self->global = NULL; + Py_DECREF(self); + return NULL; + } + self->global = global; + Py_INCREF(self->global); + + return (PyObject *)self; +} + +static void +ctxmanager_dealloc(PyDecContextManagerObject *self) +{ + Py_XDECREF(self->local); + Py_XDECREF(self->global); + PyObject_Del(self); +} + +static PyObject * +ctxmanager_set_local(PyDecContextManagerObject *self, PyObject *args UNUSED) +{ + PyObject *ret; + + ret = PyDec_SetCurrentContext(NULL, self->local); + if (ret == NULL) { + return NULL; + } + Py_DECREF(ret); + + Py_INCREF(self->local); + return self->local; +} + +static PyObject * +ctxmanager_restore_global(PyDecContextManagerObject *self, + PyObject *args UNUSED) +{ + PyObject *ret; + + ret = PyDec_SetCurrentContext(NULL, self->global); + if (ret == NULL) { + return NULL; + } + Py_DECREF(ret); + + Py_RETURN_NONE; +} + + +static PyMethodDef ctxmanager_methods[] = { + {"__enter__", (PyCFunction)ctxmanager_set_local, METH_NOARGS, NULL}, + {"__exit__", (PyCFunction)ctxmanager_restore_global, METH_VARARGS, NULL}, + {NULL, NULL} +}; + +static PyTypeObject PyDecContextManager_Type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "decimal.ContextManager", /* tp_name */ + sizeof(PyDecContextManagerObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) ctxmanager_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc) 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + (PyBufferProcs *) 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + ctxmanager_methods, /* tp_methods */ +}; + + +/******************************************************************************/ +/* New Decimal Object */ +/******************************************************************************/ + +static PyObject * +PyDecType_New(PyTypeObject *type) +{ + PyObject *dec; + + if (type == &PyDec_Type) { + dec = (PyObject *)PyObject_New(PyDecObject, &PyDec_Type); + } + else { + dec = type->tp_alloc(type, 0); + } + if (dec == NULL) { + return NULL; + } + + MPD(dec) = mpd_qnew(); + if (MPD(dec) == NULL) { + Py_DECREF(dec); + PyErr_NoMemory(); + return NULL; + } + + return dec; +} +#define dec_alloc() PyDecType_New(&PyDec_Type) + +static void +dec_dealloc(PyObject *dec) +{ + if (MPD(dec)) { + mpd_del(MPD(dec)); + } + Py_TYPE(dec)->tp_free(dec); +} + + +/******************************************************************************/ +/* Conversions to Decimal */ +/******************************************************************************/ + +Py_LOCAL_INLINE(int) +is_space(enum PyUnicode_Kind kind, void *data, Py_ssize_t pos) +{ + Py_UCS4 ch = PyUnicode_READ(kind, data, pos); + return Py_UNICODE_ISSPACE(ch); +} + +/* Return the ASCII representation of a numeric Unicode string. The numeric + string may contain ascii characters in the range [1, 127], any Unicode + space and any unicode digit. If strip_ws is true, leading and trailing + whitespace is stripped. + + Return NULL if malloc fails and an empty string if invalid characters + are found. */ +static char * +numeric_as_ascii(const PyObject *u, int strip_ws) +{ + enum PyUnicode_Kind kind; + void *data; + Py_UCS4 ch; + char *res, *cp; + Py_ssize_t j, len; + int d; + + assert(PyUnicode_IS_READY(u)); + + kind = PyUnicode_KIND(u); + data = PyUnicode_DATA(u); + len = PyUnicode_GET_LENGTH(u); + + cp = res = PyMem_Malloc(len+1); + if (res == NULL) { + PyErr_NoMemory(); + return NULL; + } + + j = 0; + if (strip_ws) { + while (len > 0 && is_space(kind, data, len-1)) { + len--; + } + while (j < len && is_space(kind, data, j)) { + j++; + } + } + + for (; j < len; j++) { + ch = PyUnicode_READ(kind, data, j); + if (0 < ch && ch <= 127) { + *cp++ = ch; + continue; + } + if (Py_UNICODE_ISSPACE(ch)) { + *cp++ = ' '; + continue; + } + d = Py_UNICODE_TODECIMAL(ch); + if (d < 0) { + /* empty string triggers ConversionSyntax */ + *res = '\0'; + return res; + } + *cp++ = '0' + d; + } + *cp = '\0'; + return res; +} + +/* Return a new PyDecObject or a subtype from a C string. Use the context + during conversion. */ +static PyObject * +PyDecType_FromCString(PyTypeObject *type, const char *s, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + mpd_qset_string(MPD(dec), s, CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + return dec; +} + +/* Return a new PyDecObject or a subtype from a C string. Attempt exact + conversion. If the operand cannot be converted exactly, set + InvalidOperation. */ +static PyObject * +PyDecType_FromCStringExact(PyTypeObject *type, const char *s, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + mpd_context_t maxctx; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + mpd_maxcontext(&maxctx); + + mpd_qset_string(MPD(dec), s, &maxctx, &status); + if (status & (MPD_Inexact|MPD_Rounded)) { + /* we want exact results */ + mpd_seterror(MPD(dec), MPD_Invalid_operation, &status); + } + status &= MPD_Errors; + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + + return dec; +} + +/* Return a new PyDecObject or a subtype from a PyUnicodeObject. */ +static PyObject * +PyDecType_FromUnicode(PyTypeObject *type, const PyObject *u, + PyObject *context) +{ + PyObject *dec; + char *s; + + s = numeric_as_ascii(u, 0); + if (s == NULL) { + return NULL; + } + + dec = PyDecType_FromCString(type, s, context); + PyMem_Free(s); + return dec; +} + +/* Return a new PyDecObject or a subtype from a PyUnicodeObject. Attempt exact + * conversion. If the conversion is not exact, fail with InvalidOperation. + * Allow leading and trailing whitespace in the input operand. */ +static PyObject * +PyDecType_FromUnicodeExactWS(PyTypeObject *type, const PyObject *u, + PyObject *context) +{ + PyObject *dec; + char *s; + + s = numeric_as_ascii(u, 1); + if (s == NULL) { + return NULL; + } + + dec = PyDecType_FromCStringExact(type, s, context); + PyMem_Free(s); + return dec; +} + +/* Set PyDecObject from triple without any error checking. */ +Py_LOCAL_INLINE(void) +_dec_settriple(PyObject *dec, uint8_t sign, uint32_t v, mpd_ssize_t exp) +{ + +#ifdef CONFIG_64 + MPD(dec)->data[0] = v; + MPD(dec)->len = 1; +#else + uint32_t q, r; + q = v / MPD_RADIX; + r = v - q * MPD_RADIX; + MPD(dec)->data[1] = q; + MPD(dec)->data[0] = r; + MPD(dec)->len = q ? 2 : 1; +#endif + mpd_set_flags(MPD(dec), sign); + MPD(dec)->exp = exp; + mpd_setdigits(MPD(dec)); +} + +/* Return a new PyDecObject from an mpd_ssize_t. */ +static PyObject * +PyDecType_FromSsize(PyTypeObject *type, mpd_ssize_t v, PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + mpd_qset_ssize(MPD(dec), v, CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + return dec; +} + +/* Return a new PyDecObject from an mpd_ssize_t. Conversion is exact. */ +static PyObject * +PyDecType_FromSsizeExact(PyTypeObject *type, mpd_ssize_t v, PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + mpd_context_t maxctx; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + mpd_maxcontext(&maxctx); + + mpd_qset_ssize(MPD(dec), v, &maxctx, &status); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + return dec; +} + +/* Convert from a PyLongObject. The context is not modified; flags set + during conversion are accumulated in the status parameter. */ +static PyObject * +dec_from_long(PyTypeObject *type, const PyObject *v, + const mpd_context_t *ctx, uint32_t *status) +{ + PyObject *dec; + PyLongObject *l = (PyLongObject *)v; + Py_ssize_t ob_size; + size_t len; + uint8_t sign; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + ob_size = Py_SIZE(l); + if (ob_size == 0) { + _dec_settriple(dec, MPD_POS, 0, 0); + return dec; + } + + if (ob_size < 0) { + len = -ob_size; + sign = MPD_NEG; + } + else { + len = ob_size; + sign = MPD_POS; + } + + if (len == 1) { + _dec_settriple(dec, sign, *l->ob_digit, 0); + mpd_qfinalize(MPD(dec), ctx, status); + return dec; + } + +#if PYLONG_BITS_IN_DIGIT == 30 + mpd_qimport_u32(MPD(dec), l->ob_digit, len, sign, PyLong_BASE, + ctx, status); +#elif PYLONG_BITS_IN_DIGIT == 15 + mpd_qimport_u16(MPD(dec), l->ob_digit, len, sign, PyLong_BASE, + ctx, status); +#else + #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" +#endif + + return dec; +} + +/* Return a new PyDecObject from a PyLongObject. Use the context for + conversion. */ +static PyObject * +PyDecType_FromLong(PyTypeObject *type, const PyObject *pylong, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + + dec = dec_from_long(type, pylong, CTX(context), &status); + if (dec == NULL) { + return NULL; + } + + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + + return dec; +} + +/* Return a new PyDecObject from a PyLongObject. Use a maximum context + for conversion. If the conversion is not exact, set InvalidOperation. */ +static PyObject * +PyDecType_FromLongExact(PyTypeObject *type, const PyObject *pylong, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + mpd_context_t maxctx; + + mpd_maxcontext(&maxctx); + dec = dec_from_long(type, pylong, &maxctx, &status); + if (dec == NULL) { + return NULL; + } + + if (status & (MPD_Inexact|MPD_Rounded)) { + /* we want exact results */ + mpd_seterror(MPD(dec), MPD_Invalid_operation, &status); + } + status &= MPD_Errors; + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + + return dec; +} + +/* Return a PyDecObject or a subtype from a PyFloatObject. + Conversion is exact. */ +static PyObject * +PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, + PyObject *context) +{ + PyObject *dec, *tmp; + PyObject *n, *d, *n_d; + mpd_ssize_t k; + double x; + int sign; + mpd_t *d1, *d2; + uint32_t status = 0; + mpd_context_t maxctx; + + + assert(PyType_IsSubtype(type, &PyDec_Type)); + + if (PyLong_Check(v)) { + return PyDecType_FromLongExact(type, v, context); + } + if (!PyFloat_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "argument must be int of float"); + return NULL; + } + + x = PyFloat_AsDouble(v); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + sign = (copysign(1.0, x) == 1.0) ? 0 : 1; + + if (Py_IS_NAN(x) || Py_IS_INFINITY(x)) { + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + if (Py_IS_NAN(x)) { + /* decimal.py calls repr(float(+-nan)), + * which always gives a positive result. */ + mpd_setspecial(MPD(dec), MPD_POS, MPD_NAN); + } + else { + mpd_setspecial(MPD(dec), sign, MPD_INF); + } + return dec; + } + + /* absolute value of the float */ + tmp = PyObject_CallMethod(v, "__abs__", NULL); + if (tmp == NULL) { + return NULL; + } + + /* float as integer ratio: numerator/denominator */ + n_d = PyObject_CallMethod(tmp, "as_integer_ratio", NULL); + Py_DECREF(tmp); + if (n_d == NULL) { + return NULL; + } + n = PyTuple_GET_ITEM(n_d, 0); + d = PyTuple_GET_ITEM(n_d, 1); + + tmp = PyObject_CallMethod(d, "bit_length", NULL); + if (tmp == NULL) { + Py_DECREF(n_d); + return NULL; + } + k = PyLong_AsSsize_t(tmp); + Py_DECREF(tmp); + if (k == -1 && PyErr_Occurred()) { + Py_DECREF(n_d); + return NULL; + } + k--; + + dec = PyDecType_FromLongExact(type, n, context); + Py_DECREF(n_d); + if (dec == NULL) { + return NULL; + } + + d1 = mpd_qnew(); + if (d1 == NULL) { + Py_DECREF(dec); + PyErr_NoMemory(); + return NULL; + } + d2 = mpd_qnew(); + if (d2 == NULL) { + mpd_del(d1); + Py_DECREF(dec); + PyErr_NoMemory(); + return NULL; + } + + mpd_maxcontext(&maxctx); + mpd_qset_uint(d1, 5, &maxctx, &status); + mpd_qset_ssize(d2, k, &maxctx, &status); + mpd_qpow(d1, d1, d2, &maxctx, &status); + if (dec_addstatus(context, status)) { + mpd_del(d1); + mpd_del(d2); + Py_DECREF(dec); + return NULL; + } + + /* result = n * 5**k */ + mpd_qmul(MPD(dec), MPD(dec), d1, &maxctx, &status); + mpd_del(d1); + mpd_del(d2); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + /* result = +- n * 5**k * 10**-k */ + mpd_set_sign(MPD(dec), sign); + MPD(dec)->exp = -k; + + return dec; +} + +static PyObject * +PyDecType_FromFloat(PyTypeObject *type, PyObject *v, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + + dec = PyDecType_FromFloatExact(type, v, context); + if (dec == NULL) { + return NULL; + } + + mpd_qfinalize(MPD(dec), CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + + return dec; +} + +static PyObject * +sequence_as_tuple(PyObject *v, PyObject *ex, const char *mesg) +{ + if (PyTuple_Check(v)) { + Py_INCREF(v); + return v; + } + if (PyList_Check(v)) { + return PyList_AsTuple(v); + } + + PyErr_SetString(ex, mesg); + return NULL; +} + +/* Return a new C string representation of a DecimalTuple. */ +static char * +dectuple_as_str(PyObject *dectuple) +{ + PyObject *digits = NULL, *tmp; + char *decstring = NULL; + char sign_special[6]; + char *cp; + long sign, l; + mpd_ssize_t exp = 0; + Py_ssize_t i, mem, tsize; + int n; + + assert(PyTuple_Check(dectuple)); + + if (PyTuple_Size(dectuple) != 3) { + PyErr_SetString(PyExc_ValueError, + "argument must be a sequence of length 3"); + goto error; + } + + /* sign */ + tmp = PyTuple_GET_ITEM(dectuple, 0); + if (!PyLong_Check(tmp)) { + PyErr_SetString(PyExc_ValueError, + "sign must be an integer with the value 0 or 1"); + goto error; + } + sign = PyLong_AsLong(tmp); + if (sign == -1 && PyErr_Occurred()) { + goto error; + } + if (sign != 0 && sign != 1) { + PyErr_SetString(PyExc_ValueError, + "sign must be an integer with the value 0 or 1"); + goto error; + } + sign_special[0] = sign ? '-' : '+'; + sign_special[1] = '\0'; + + /* exponent or encoding for a special number */ + tmp = PyTuple_GET_ITEM(dectuple, 2); + if (PyUnicode_Check(tmp)) { + /* special */ + if (PyUnicode_CompareWithASCIIString(tmp, "F") == 0) { + strcat(sign_special, "Inf"); + } + else if (PyUnicode_CompareWithASCIIString(tmp, "n") == 0) { + strcat(sign_special, "NaN"); + } + else if (PyUnicode_CompareWithASCIIString(tmp, "N") == 0) { + strcat(sign_special, "sNaN"); + } + else { + PyErr_SetString(PyExc_ValueError, + "string argument in the third position " + "must be 'F', 'n' or 'N'"); + goto error; + } + } + else { + /* exponent */ + if (!PyLong_Check(tmp)) { + PyErr_SetString(PyExc_ValueError, + "exponent must be an integer"); + goto error; + } + exp = PyLong_AsSsize_t(tmp); + if (exp == -1 && PyErr_Occurred()) { + goto error; + } + } + + /* coefficient */ + digits = sequence_as_tuple(PyTuple_GET_ITEM(dectuple, 1), + PyExc_ValueError, "coefficient must be a tuple of digits"); + if (digits == NULL) { + goto error; + } + + tsize = PyTuple_Size(digits); + /* [sign][coeffdigits+1][E][-][expdigits+1]['\0'] */ + mem = 1 + tsize + 3 + MPD_EXPDIGITS + 2; + cp = decstring = PyMem_Malloc(mem); + if (decstring == NULL) { + PyErr_NoMemory(); + goto error; + } + + n = snprintf(cp, mem, "%s", sign_special); + if (n < 0 || n >= mem) { + PyErr_SetString(PyExc_RuntimeError, + "internal error in dec_sequence_as_str"); + goto error; + } + cp += n; + + if (tsize == 0 && sign_special[1] == '\0') { + /* empty tuple: zero coefficient, except for special numbers */ + *cp++ = '0'; + } + for (i = 0; i < tsize; i++) { + tmp = PyTuple_GET_ITEM(digits, i); + if (!PyLong_Check(tmp)) { + PyErr_SetString(PyExc_ValueError, + "coefficient must be a tuple of digits"); + goto error; + } + l = PyLong_AsLong(tmp); + if (l == -1 && PyErr_Occurred()) { + goto error; + } + if (l < 0 || l > 9) { + PyErr_SetString(PyExc_ValueError, + "coefficient must be a tuple of digits"); + goto error; + } + *cp++ = (char)l + '0'; + } + *cp = '\0'; + + if (sign_special[1] == '\0') { + /* not a special number */ + *cp++ = 'E'; + n = snprintf(cp, MPD_EXPDIGITS+1, "%" PRI_mpd_ssize_t, exp); + if (n < 0 || n >= MPD_EXPDIGITS+1) { + PyErr_SetString(PyExc_RuntimeError, + "internal error in dec_sequence_as_str"); + goto error; + } + } + + Py_XDECREF(digits); + return decstring; + + +error: + Py_XDECREF(digits); + if (decstring) PyMem_Free(decstring); + return NULL; +} + +/* Currently accepts tuples and lists. */ +static PyObject * +PyDecType_FromSequence(PyTypeObject *type, PyObject *v, + PyObject *context) +{ + PyObject *dectuple; + PyObject *dec; + char *s; + + dectuple = sequence_as_tuple(v, PyExc_TypeError, + "argument must be a tuple or list"); + if (dectuple == NULL) { + return NULL; + } + + s = dectuple_as_str(dectuple); + Py_DECREF(dectuple); + if (s == NULL) { + return NULL; + } + + dec = PyDecType_FromCString(type, s, context); + + PyMem_Free(s); + return dec; +} + +/* Currently accepts tuples and lists. */ +static PyObject * +PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v, + PyObject *context) +{ + PyObject *dectuple; + PyObject *dec; + char *s; + + dectuple = sequence_as_tuple(v, PyExc_TypeError, + "argument must be a tuple or list"); + if (dectuple == NULL) { + return NULL; + } + + s = dectuple_as_str(dectuple); + Py_DECREF(dectuple); + if (s == NULL) { + return NULL; + } + + dec = PyDecType_FromCStringExact(type, s, context); + + PyMem_Free(s); + return dec; +} + +#define PyDec_FromCString(str, context) \ + PyDecType_FromCString(&PyDec_Type, str, context) +#define PyDec_FromCStringExact(str, context) \ + PyDecType_FromCStringExact(&PyDec_Type, str, context) + +#define PyDec_FromUnicode(unicode, context) \ + PyDecType_FromUnicode(&PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExact(unicode, context) \ + PyDecType_FromUnicodeExact(&PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExactWS(unicode, context) \ + PyDecType_FromUnicodeExactWS(&PyDec_Type, unicode, context) + +#define PyDec_FromSsize(v, context) \ + PyDecType_FromSsize(&PyDec_Type, v, context) +#define PyDec_FromSsizeExact(v, context) \ + PyDecType_FromSsizeExact(&PyDec_Type, v, context) + +#define PyDec_FromLong(pylong, context) \ + PyDecType_FromLong(&PyDec_Type, pylong, context) +#define PyDec_FromLongExact(pylong, context) \ + PyDecType_FromLongExact(&PyDec_Type, pylong, context) + +#define PyDec_FromFloat(pyfloat, context) \ + PyDecType_FromFloat(&PyDec_Type, pyfloat, context) +#define PyDec_FromFloatExact(pyfloat, context) \ + PyDecType_FromFloatExact(&PyDec_Type, pyfloat, context) + +#define PyDec_FromSequence(sequence, context) \ + PyDecType_FromSequence(&PyDec_Type, sequence, context) +#define PyDec_FromSequenceExact(sequence, context) \ + PyDecType_FromSequenceExact(&PyDec_Type, sequence, context) + +/* class method */ +static PyObject * +dec_from_float(PyObject *dec, PyObject *pyfloat) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return PyDecType_FromFloatExact((PyTypeObject *)dec, pyfloat, context); +} + +/* create_decimal_from_float */ +static PyObject * +ctx_from_float(PyObject *context, PyObject *v) +{ + return PyDec_FromFloat(v, context); +} + +/* Apply the context to the input operand. Return a new PyDecObject. */ +static PyObject * +dec_apply(PyObject *v, PyObject *context) +{ + PyObject *result; + uint32_t status = 0; + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + mpd_qcopy(MPD(result), MPD(v), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + mpd_qfinalize(MPD(result), CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +/* 'v' can have any type accepted by the Decimal constructor. Attempt + an exact conversion. If the result does not meet the restrictions + for an mpd_t, fail with InvalidOperation. */ +static PyObject * +PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) +{ + if (v == NULL) { + return PyDecType_FromSsizeExact(type, 0, context); + } + else if (PyDec_Check(v)) { + Py_INCREF(v); + return v; + } + else if (PyUnicode_Check(v)) { + return PyDecType_FromUnicodeExactWS(type, v, context); + } + else if (PyLong_Check(v)) { + return PyDecType_FromLongExact(type, v, context); + } + else if (PyTuple_Check(v) || PyList_Check(v)) { + return PyDecType_FromSequenceExact(type, v, context); + } + else if (PyFloat_Check(v)) { + if (dec_addstatus(context, MPD_Float_operation)) { + return NULL; + } + return PyDecType_FromFloatExact(type, v, context); + } + else { + PyErr_Format(PyExc_TypeError, + "conversion from %s to Decimal is not supported", + v->ob_type->tp_name); + return NULL; + } +} + +/* The context is used during conversion. This function is the + equivalent of context.create_decimal(). */ +static PyObject * +PyDec_FromObject(PyObject *v, PyObject *context) +{ + if (v == NULL) { + return PyDec_FromSsize(0, context); + } + else if (PyDec_Check(v)) { + mpd_context_t *ctx = CTX(context); + if (mpd_isnan(MPD(v)) && + MPD(v)->digits > ctx->prec - ctx->clamp) { + /* Special case: too many NaN payload digits */ + PyObject *result; + if (dec_addstatus(context, MPD_Conversion_syntax)) { + return NULL; + } + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + mpd_setspecial(MPD(result), MPD_POS, MPD_NAN); + return result; + } + return dec_apply(v, context); + } + else if (PyUnicode_Check(v)) { + return PyDec_FromUnicode(v, context); + } + else if (PyLong_Check(v)) { + return PyDec_FromLong(v, context); + } + else if (PyTuple_Check(v) || PyList_Check(v)) { + return PyDec_FromSequence(v, context); + } + else if (PyFloat_Check(v)) { + if (dec_addstatus(context, MPD_Float_operation)) { + return NULL; + } + return PyDec_FromFloat(v, context); + } + else { + PyErr_Format(PyExc_TypeError, + "conversion from %s to Decimal is not supported", + v->ob_type->tp_name); + return NULL; + } +} + +static PyObject * +dec_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"value", "context", NULL}; + PyObject *v = NULL; + PyObject *context; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, + &v, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + return PyDecType_FromObjectExact(type, v, context); +} + +static PyObject * +ctx_create_decimal(PyObject *context, PyObject *args) +{ + PyObject *v = NULL; + + if (!PyArg_ParseTuple(args, "|O", &v)) { + return NULL; + } + + return PyDec_FromObject(v, context); +} + + +/******************************************************************************/ +/* Implicit conversions to Decimal */ +/******************************************************************************/ + +/* Try to convert PyObject v to a new PyDecObject conv. If the conversion + fails, set conv to NULL (exception is set). If the conversion is not + implemented, set conv to Py_NotImplemented. */ +#define NOT_IMPL 0 +#define TYPE_ERR 1 +Py_LOCAL_INLINE(int) +convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context) +{ + + if (PyDec_Check(v)) { + *conv = v; + Py_INCREF(v); + return 1; + } + if (PyLong_Check(v)) { + *conv = PyDec_FromLongExact(v, context); + if (*conv == NULL) { + return 0; + } + return 1; + } + + if (type_err) { + PyErr_Format(PyExc_TypeError, + "conversion from %s to Decimal is not supported", + v->ob_type->tp_name); + } + else { + Py_INCREF(Py_NotImplemented); + *conv = Py_NotImplemented; + } + return 0; +} + +/* Return NotImplemented for unsupported types. */ +#define CONVERT_OP(a, v, context) \ + if (!convert_op(NOT_IMPL, a, v, context)) { \ + return *(a); \ + } + +#define CONVERT_BINOP(a, b, v, w, context) \ + if (!convert_op(NOT_IMPL, a, v, context)) { \ + return *(a); \ + } \ + if (!convert_op(NOT_IMPL, b, w, context)) { \ + Py_DECREF(*(a)); \ + return *(b); \ + } + +#define CONVERT_TERNOP(a, b, c, v, w, x, context) \ + if (!convert_op(NOT_IMPL, a, v, context)) { \ + return *(a); \ + } \ + if (!convert_op(NOT_IMPL, b, w, context)) { \ + Py_DECREF(*(a)); \ + return *(b); \ + } \ + if (!convert_op(NOT_IMPL, c, x, context)) { \ + Py_DECREF(*(a)); \ + Py_DECREF(*(b)); \ + return *(c); \ + } + +/* Raise TypeError for unsupported types. */ +#define CONVERT_OP_RAISE(a, v, context) \ + if (!convert_op(TYPE_ERR, a, v, context)) { \ + return NULL; \ + } + +#define CONVERT_BINOP_RAISE(a, b, v, w, context) \ + if (!convert_op(TYPE_ERR, a, v, context)) { \ + return NULL; \ + } \ + if (!convert_op(TYPE_ERR, b, w, context)) { \ + Py_DECREF(*(a)); \ + return NULL; \ + } + +#define CONVERT_TERNOP_RAISE(a, b, c, v, w, x, context) \ + if (!convert_op(TYPE_ERR, a, v, context)) { \ + return NULL; \ + } \ + if (!convert_op(TYPE_ERR, b, w, context)) { \ + Py_DECREF(*(a)); \ + return NULL; \ + } \ + if (!convert_op(TYPE_ERR, c, x, context)) { \ + Py_DECREF(*(a)); \ + Py_DECREF(*(b)); \ + return NULL; \ + } + + +/******************************************************************************/ +/* Implicit conversions to Decimal for comparison */ +/******************************************************************************/ + +/* Convert rationals for comparison */ +static PyObject *Rational = NULL; +static PyObject * +multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) +{ + PyObject *result; + PyObject *tmp = NULL; + PyObject *denom = NULL; + uint32_t status = 0; + mpd_context_t maxctx; + mpd_ssize_t exp; + mpd_t *vv; + + /* v is not special, r is a rational */ + tmp = PyObject_GetAttrString(r, "denominator"); + if (tmp == NULL) { + return NULL; + } + denom = PyDec_FromLongExact(tmp, context); + Py_DECREF(tmp); + if (denom == NULL) { + return NULL; + } + + vv = mpd_qncopy(MPD(v)); + if (vv == NULL) { + Py_DECREF(denom); + PyErr_NoMemory(); + return NULL; + } + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(denom); + mpd_del(vv); + return NULL; + } + + mpd_maxcontext(&maxctx); + /* Prevent Overflow in the following multiplication. The result of + the multiplication is only used in mpd_qcmp, which can handle + values that are technically out of bounds, like (for 32-bit) + 99999999999999999999...99999999e+425000000. */ + exp = vv->exp; + vv->exp = 0; + mpd_qmul(MPD(result), vv, MPD(denom), &maxctx, &status); + MPD(result)->exp = exp; + + Py_DECREF(denom); + mpd_del(vv); + /* If any status has been accumulated during the multiplication, + the result is invalid. This is very unlikely, since even the + 32-bit version supports 425000000 digits. */ + if (status) { + PyErr_SetString(PyExc_ValueError, + "exact conversion for comparison failed"); + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +numerator_as_decimal(PyObject *r, PyObject *context) +{ + PyObject *tmp, *num; + + tmp = PyObject_GetAttrString(r, "numerator"); + if (tmp == NULL) { + return NULL; + } + + num = PyDec_FromLongExact(tmp, context); + Py_DECREF(tmp); + return num; +} + +/* Convert v and w for comparison. v is a Decimal. If w is a Rational, both + v and w have to be transformed. Return 1 for success, with new references + to the converted objects in vcmp and wcmp. Return 0 for failure. In that + case wcmp is either NULL or Py_NotImplemented (new reference) and vcmp + is undefined. */ +static int +convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, + int op, PyObject *context) +{ + mpd_context_t *ctx = CTX(context); + + *vcmp = v; + + if (PyDec_Check(w)) { + Py_INCREF(w); + *wcmp = w; + } + else if (PyLong_Check(w)) { + *wcmp = PyDec_FromLongExact(w, context); + } + else if (PyFloat_Check(w)) { + if (op != Py_EQ && op != Py_NE && + dec_addstatus(context, MPD_Float_operation)) { + *wcmp = NULL; + } + else { + ctx->status |= MPD_Float_operation; + *wcmp = PyDec_FromFloatExact(w, context); + } + } + else if (PyComplex_Check(w) && (op == Py_EQ || op == Py_NE)) { + Py_complex c = PyComplex_AsCComplex(w); + if (c.real == -1.0 && PyErr_Occurred()) { + *wcmp = NULL; + } + else if (c.imag == 0.0) { + PyObject *tmp = PyFloat_FromDouble(c.real); + if (tmp == NULL) { + *wcmp = NULL; + } + else { + ctx->status |= MPD_Float_operation; + *wcmp = PyDec_FromFloatExact(tmp, context); + Py_DECREF(tmp); + } + } + else { + Py_INCREF(Py_NotImplemented); + *wcmp = Py_NotImplemented; + } + } + else if (PyObject_IsInstance(w, Rational)) { + *wcmp = numerator_as_decimal(w, context); + if (*wcmp && !mpd_isspecial(MPD(v))) { + *vcmp = multiply_by_denominator(v, w, context); + if (*vcmp == NULL) { + Py_CLEAR(*wcmp); + } + } + } + else { + Py_INCREF(Py_NotImplemented); + *wcmp = Py_NotImplemented; + } + + if (*wcmp == NULL || *wcmp == Py_NotImplemented) { + return 0; + } + if (*vcmp == v) { + Py_INCREF(v); + } + return 1; +} + +#define CONVERT_BINOP_CMP(vcmp, wcmp, v, w, op, ctx) \ + if (!convert_op_cmp(vcmp, wcmp, v, w, op, ctx)) { \ + return *(wcmp); \ + } \ + + +/******************************************************************************/ +/* Conversions from decimal */ +/******************************************************************************/ + +static PyObject * +unicode_fromascii(const char *s, Py_ssize_t size) +{ + PyObject *res; + + res = PyUnicode_New(size, 127); + if (res == NULL) { + return NULL; + } + + memcpy(PyUnicode_1BYTE_DATA(res), s, size); + return res; +} + +/* PyDecObject as a string. The default module context is only used for + the value of 'capitals'. */ +static PyObject * +dec_str(PyObject *dec) +{ + PyObject *res, *context; + mpd_ssize_t size; + char *cp; + + CURRENT_CONTEXT(context); + size = mpd_to_sci_size(&cp, MPD(dec), CtxCaps(context)); + if (size < 0) { + PyErr_NoMemory(); + return NULL; + } + + res = unicode_fromascii(cp, size); + mpd_free(cp); + return res; +} + +/* Representation of a PyDecObject. */ +static PyObject * +dec_repr(PyObject *dec) +{ + PyObject *res, *context; + char *cp; + + CURRENT_CONTEXT(context); + cp = mpd_to_sci(MPD(dec), CtxCaps(context)); + if (cp == NULL) { + PyErr_NoMemory(); + return NULL; + } + + res = PyUnicode_FromFormat("Decimal('%s')", cp); + mpd_free(cp); + return res; +} + +/* Convert decimal_point or thousands_sep, which may be multibyte or in + the range [128, 255], to a UTF8 string. */ +static PyObject * +dotsep_as_utf8(const char *s) +{ + PyObject *utf8; + PyObject *tmp; + wchar_t buf[2]; + size_t n; + + n = mbstowcs(buf, s, 2); + if (n != 1) { /* Issue #7442 */ + PyErr_SetString(PyExc_ValueError, + "invalid decimal point or unsupported " + "combination of LC_CTYPE and LC_NUMERIC"); + return NULL; + } + tmp = PyUnicode_FromWideChar(buf, n); + if (tmp == NULL) { + return NULL; + } + utf8 = PyUnicode_AsUTF8String(tmp); + Py_DECREF(tmp); + return utf8; +} + +/* Formatted representation of a PyDecObject. */ +static PyObject * +dec_format(PyObject *dec, PyObject *args) +{ + PyObject *result = NULL; + PyObject *override = NULL; + PyObject *dot = NULL; + PyObject *sep = NULL; + PyObject *grouping = NULL; + PyObject *fmt = NULL; + PyObject *fmtarg; + PyObject *context; + mpd_spec_t spec; + char *decstring= NULL; + uint32_t status = 0; + size_t n; + + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTuple(args, "O|O", &fmtarg, &override)) { + return NULL; + } + + if (PyUnicode_Check(fmtarg)) { + fmt = PyUnicode_AsUTF8String(fmtarg); + if (fmt == NULL) { + return NULL; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "format arg must be str"); + return NULL; + } + + if (!mpd_parse_fmt_str(&spec, PyBytes_AS_STRING(fmt), + CtxCaps(context))) { + PyErr_SetString(PyExc_ValueError, + "invalid format string"); + goto finish; + } + if (override) { + /* Values for decimal_point, thousands_sep and grouping can + be explicitly specified in the override dict. These values + take precedence over the values obtained from localeconv() + in mpd_parse_fmt_str(). The feature is not documented and + is only used in test_decimal. */ + if (!PyDict_Check(override)) { + PyErr_SetString(PyExc_TypeError, + "optional argument must be a dict"); + goto finish; + } + if ((dot = PyDict_GetItemString(override, "decimal_point"))) { + if ((dot = PyUnicode_AsUTF8String(dot)) == NULL) { + goto finish; + } + spec.dot = PyBytes_AS_STRING(dot); + } + if ((sep = PyDict_GetItemString(override, "thousands_sep"))) { + if ((sep = PyUnicode_AsUTF8String(sep)) == NULL) { + goto finish; + } + spec.sep = PyBytes_AS_STRING(sep); + } + if ((grouping = PyDict_GetItemString(override, "grouping"))) { + if ((grouping = PyUnicode_AsUTF8String(grouping)) == NULL) { + goto finish; + } + spec.grouping = PyBytes_AS_STRING(grouping); + } + if (mpd_validate_lconv(&spec) < 0) { + PyErr_SetString(PyExc_ValueError, + "invalid override dict"); + goto finish; + } + } + else { + n = strlen(spec.dot); + if (n > 1 || (n == 1 && !isascii((uchar)spec.dot[0]))) { + /* fix locale dependent non-ascii characters */ + dot = dotsep_as_utf8(spec.dot); + if (dot == NULL) { + goto finish; + } + spec.dot = PyBytes_AS_STRING(dot); + } + n = strlen(spec.sep); + if (n > 1 || (n == 1 && !isascii((uchar)spec.sep[0]))) { + /* fix locale dependent non-ascii characters */ + sep = dotsep_as_utf8(spec.sep); + if (sep == NULL) { + goto finish; + } + spec.sep = PyBytes_AS_STRING(sep); + } + } + + + decstring = mpd_qformat_spec(MPD(dec), &spec, CTX(context), &status); + if (decstring == NULL) { + dec_addstatus(context, status); + goto finish; + } + result = PyUnicode_DecodeUTF8(decstring, strlen(decstring), NULL); + + +finish: + Py_XDECREF(grouping); + Py_XDECREF(sep); + Py_XDECREF(dot); + Py_XDECREF(fmt); + if (decstring) mpd_free(decstring); + return result; +} + +/* Return a PyLongObject from a PyDecObject, using the specified rounding + * mode. The context precision is not observed. */ +static PyObject * +dec_as_long(PyObject *dec, PyObject *context, int round) +{ + PyLongObject *pylong; + size_t maxsize, n; + Py_ssize_t i; + mpd_t *x; + mpd_context_t workctx; + uint32_t status = 0; + + if (mpd_isspecial(MPD(dec))) { + if (mpd_isnan(MPD(dec))) { + PyErr_SetString(PyExc_ValueError, + "cannot convert NaN to integer"); + } + else { + PyErr_SetString(PyExc_OverflowError, + "cannot convert Infinity to integer"); + } + return NULL; + } + + x = mpd_qnew(); + if (x == NULL) { + PyErr_NoMemory(); + return NULL; + } + workctx = *CTX(context); + workctx.round = round; + mpd_qround_to_int(x, MPD(dec), &workctx, &status); + if (dec_addstatus(context, status)) { + mpd_del(x); + return NULL; + } + + maxsize = mpd_sizeinbase(x, PyLong_BASE); + if (maxsize > PY_SSIZE_T_MAX) { + mpd_del(x); + PyErr_NoMemory(); + return NULL; + } + pylong = _PyLong_New(maxsize); + if (pylong == NULL) { + mpd_del(x); + return NULL; + } + + status = 0; +#if PYLONG_BITS_IN_DIGIT == 30 + n = mpd_qexport_u32(pylong->ob_digit, maxsize, PyLong_BASE, x, &status); +#elif PYLONG_BITS_IN_DIGIT == 15 + n = mpd_qexport_u16(pylong->ob_digit, maxsize, PyLong_BASE, x, &status); +#else + #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" +#endif + if (dec_addstatus(context, status)) { + Py_DECREF((PyObject *) pylong); + mpd_del(x); + return NULL; + } + + i = n; + while ((i > 0) && (pylong->ob_digit[i-1] == 0)) { + i--; + } + + Py_SIZE(pylong) = i; + if (mpd_isnegative(x) && !mpd_iszero(x)) { + Py_SIZE(pylong) = -i; + } + + mpd_del(x); + return (PyObject *) pylong; +} + +static PyObject * +PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"rounding", "context", NULL}; + PyObject *result; + PyObject *context; + uint32_t status = 0; + mpd_context_t workctx; + int round = -1; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, + &round, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + workctx = *CTX(context); + if (round >= 0) { + if (!mpd_qsetround(&workctx, round)) { + return type_error_ptr(invalid_rounding_err); + } + } + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + mpd_qround_to_int(MPD(result), MPD(dec), &workctx, &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"rounding", "context", NULL}; + PyObject *result; + PyObject *context; + uint32_t status = 0; + mpd_context_t workctx; + int round = -1; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, + &round, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + workctx = *CTX(context); + if (round >= 0) { + if (!mpd_qsetround(&workctx, round)) { + return type_error_ptr(invalid_rounding_err); + } + } + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + mpd_qround_to_intx(MPD(result), MPD(dec), &workctx, &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +PyDec_AsFloat(PyObject *dec) +{ + PyObject *f, *s; + + s = dec_str(dec); + if (s == NULL) { + return NULL; + } + + f = PyFloat_FromString(s); + Py_DECREF(s); + + return f; +} + +static PyObject * +PyDec_Round(PyObject *dec, PyObject *args) +{ + PyObject *result; + PyObject *x = NULL; + uint32_t status = 0; + PyObject *context; + + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTuple(args, "|O", &x)) { + return NULL; + } + + if (x) { + mpd_uint_t dq[1] = {1}; + mpd_t q = {MPD_STATIC|MPD_CONST_DATA,0,1,1,1,dq}; + mpd_ssize_t y; + + if (!PyLong_Check(x)) { + PyErr_SetString(PyExc_TypeError, + "optional arg must be an integer"); + return NULL; + } + + y = PyLong_AsSsize_t(x); + if (y == -1 && PyErr_Occurred()) { + return NULL; + } + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + q.exp = (y == MPD_SSIZE_MIN) ? MPD_SSIZE_MAX : -y; + mpd_qquantize(MPD(result), MPD(dec), &q, CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; + } + else { + return dec_as_long(dec, context, MPD_ROUND_HALF_EVEN); + } +} + +PyObject *DecimalTuple = NULL; +/* Return the DecimalTuple representation of a PyDecObject. */ +static PyObject * +PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED) +{ + PyObject *result = NULL; + PyObject *sign = NULL; + PyObject *coeff = NULL; + PyObject *expt = NULL; + PyObject *tmp = NULL; + mpd_t *x = NULL; + char *intstring = NULL; + Py_ssize_t intlen, i; + + + x = mpd_qncopy(MPD(dec)); + if (x == NULL) { + PyErr_NoMemory(); + goto out; + } + + sign = PyLong_FromUnsignedLong(mpd_sign(MPD(dec))); + if (sign == NULL) { + goto out; + } + + if (mpd_isinfinite(x)) { + expt = PyUnicode_FromString("F"); + if (expt == NULL) { + goto out; + } + /* decimal.py has non-compliant infinity payloads. */ + coeff = Py_BuildValue("(i)", 0); + if (coeff == NULL) { + goto out; + } + } + else { + if (mpd_isnan(x)) { + expt = PyUnicode_FromString(mpd_isqnan(x)?"n":"N"); + } + else { + expt = PyLong_FromSsize_t(MPD(dec)->exp); + } + if (expt == NULL) { + goto out; + } + + /* coefficient is defined */ + if (x->len > 0) { + + /* make an integer */ + x->exp = 0; + /* clear NaN and sign */ + mpd_clear_flags(x); + intstring = mpd_to_sci(x, 1); + if (intstring == NULL) { + PyErr_NoMemory(); + goto out; + } + + intlen = strlen(intstring); + coeff = PyTuple_New(intlen); + if (coeff == NULL) { + goto out; + } + + for (i = 0; i < intlen; i++) { + tmp = PyLong_FromLong(intstring[i]-'0'); + if (tmp == NULL) { + goto out; + } + PyTuple_SET_ITEM(coeff, i, tmp); + } + } + else { + coeff = PyTuple_New(0); + if (coeff == NULL) { + goto out; + } + } + } + + result = PyObject_CallFunctionObjArgs(DecimalTuple, + sign, coeff, expt, NULL); + +out: + if (x) mpd_del(x); + if (intstring) mpd_free(intstring); + Py_XDECREF(sign); + Py_XDECREF(coeff); + Py_XDECREF(expt); + return result; +} + + +/******************************************************************************/ +/* Macros for converting mpdecimal functions to Decimal methods */ +/******************************************************************************/ + +/* Unary number method that uses the default module context. */ +#define Dec_UnaryNumberMethod(MPDFUNC) \ +static PyObject * \ +nm_##MPDFUNC(PyObject *self) \ +{ \ + PyObject *result; \ + PyObject *context; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if ((result = dec_alloc()) == NULL) { \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(self), CTX(context), &status); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Binary number method that uses default module context. */ +#define Dec_BinaryNumberMethod(MPDFUNC) \ +static PyObject * \ +nm_##MPDFUNC(PyObject *self, PyObject *other) \ +{ \ + PyObject *a, *b; \ + PyObject *result; \ + PyObject *context; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context) ; \ + CONVERT_BINOP(&a, &b, self, other, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Boolean function without a context arg. */ +#define Dec_BoolFunc(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *dummy UNUSED) \ +{ \ + return MPDFUNC(MPD(self)) ? incr_true() : incr_false(); \ +} + +/* Boolean function with an optional context arg. */ +#define Dec_BoolFuncVA(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"context", NULL}; \ + PyObject *context; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ + &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + \ + return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \ +} + +/* Unary function with an optional context arg. */ +#define Dec_UnaryFuncVA(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"context", NULL}; \ + PyObject *result; \ + PyObject *context; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ + &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(self), CTX(context), &status); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Unary function with an optional context arg. The actual MPDFUNC + only takes a status parameter. */ +#define Dec_UnaryFuncVA_NO_CTX(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"context", NULL}; \ + PyObject *result; \ + PyObject *context; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ + &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(self), &status); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Binary function with an optional context arg. */ +#define Dec_BinaryFuncVA(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"other", "context", NULL}; \ + PyObject *other, *context; \ + PyObject *a, *b; \ + PyObject *result; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ + &other, &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Binary function with an optional context arg. Actual MPDFUNC does + NOT take a context. The context is used to record InvalidOperation + if the second operand cannot be converted exactly. */ +#define Dec_BinaryFuncVA_NO_CTX(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"other", "context", NULL}; \ + PyObject *other, *context; \ + PyObject *a, *b; \ + PyObject *result; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ + &other, &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b)); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + \ + return result; \ +} + +/* Ternary function with an optional context arg. */ +#define Dec_TernaryFuncVA(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"other", "third", "context", NULL}; \ + PyObject *other, *third, *context; \ + PyObject *a, *b, *c; \ + PyObject *result; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist, \ + &other, &third, &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + Py_DECREF(c); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), MPD(c), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + Py_DECREF(c); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + + +/**********************************************/ +/* Number methods */ +/**********************************************/ + +Dec_UnaryNumberMethod(mpd_qminus) +Dec_UnaryNumberMethod(mpd_qplus) +Dec_UnaryNumberMethod(mpd_qabs) + +Dec_BinaryNumberMethod(mpd_qadd) +Dec_BinaryNumberMethod(mpd_qsub) +Dec_BinaryNumberMethod(mpd_qmul) +Dec_BinaryNumberMethod(mpd_qdiv) +Dec_BinaryNumberMethod(mpd_qrem) +Dec_BinaryNumberMethod(mpd_qdivint) + +static PyObject * +nm_dec_as_long(PyObject *dec) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return dec_as_long(dec, context, MPD_ROUND_DOWN); +} + +static int +nm_nonzero(PyDecObject *v) +{ + return !mpd_iszero(v->dec); +} + +static PyObject * +nm_mpd_qdivmod(PyObject *v, PyObject *w) +{ + PyObject *a, *b; + PyObject *q, *r; + PyObject *context; + uint32_t status = 0; + PyObject *ret; + + CURRENT_CONTEXT(context); + CONVERT_BINOP(&a, &b, v, w, context); + + q = dec_alloc(); + if (q == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + r = dec_alloc(); + if (r == NULL) { + Py_DECREF(a); + Py_DECREF(b); + Py_DECREF(q); + return NULL; + } + + mpd_qdivmod(MPD(q), MPD(r), MPD(a), MPD(b), CTX(context), &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(r); + Py_DECREF(q); + return NULL; + } + + ret = Py_BuildValue("(OO)", q, r); + Py_DECREF(r); + Py_DECREF(q); + return ret; +} + +static mpd_uint_t data_zero[1] = {0}; +static const mpd_t zero = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_zero}; + +static PyObject * +nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod) +{ + PyObject *a, *b, *c = NULL; + PyObject *result; + PyObject *context; + uint32_t status = 0; + + CURRENT_CONTEXT(context); + CONVERT_BINOP(&a, &b, base, exp, context); + + if (mod != Py_None) { + if (!convert_op(NOT_IMPL, &c, mod, context)) { + Py_DECREF(a); + Py_DECREF(b); + return c; + } + } + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + Py_XDECREF(c); + return NULL; + } + + if (c == NULL) { + mpd_qpow(MPD(result), MPD(a), MPD(b), + CTX(context), &status); + } + else { + mpd_qpowmod(MPD(result), MPD(a), MPD(b), MPD(c), + CTX(context), &status); + status = (status == MPD_Clamped) ? 0 : status; + /* remove ideal exponent for compatibility with decimal.py */ + mpd_qquantize(MPD(result), MPD(result), &zero, + CTX(context), &status); + Py_DECREF(c); + } + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + + +/******************************************************************************/ +/* Decimal Methods */ +/******************************************************************************/ + +/* Unary arithmetic functions, optional context arg */ +Dec_UnaryFuncVA(mpd_qexp) +Dec_UnaryFuncVA(mpd_qln) +Dec_UnaryFuncVA(mpd_qlog10) +Dec_UnaryFuncVA(mpd_qnext_minus) +Dec_UnaryFuncVA(mpd_qnext_plus) +Dec_UnaryFuncVA(mpd_qreduce) +Dec_UnaryFuncVA(mpd_qsqrt) + +/* Binary arithmetic functions, optional context arg */ +Dec_BinaryFuncVA(mpd_qcompare) +Dec_BinaryFuncVA(mpd_qcompare_signal) +Dec_BinaryFuncVA(mpd_qmax) +Dec_BinaryFuncVA(mpd_qmax_mag) +Dec_BinaryFuncVA(mpd_qmin) +Dec_BinaryFuncVA(mpd_qmin_mag) +Dec_BinaryFuncVA(mpd_qnext_toward) +Dec_BinaryFuncVA(mpd_qrem_near) + +/* Ternary arithmetic functions, optional context arg */ +Dec_TernaryFuncVA(mpd_qfma) + +/* Boolean functions, no context arg */ +Dec_BoolFunc(mpd_iscanonical) +Dec_BoolFunc(mpd_isfinite) +Dec_BoolFunc(mpd_isinfinite) +Dec_BoolFunc(mpd_isnan) +Dec_BoolFunc(mpd_isqnan) +Dec_BoolFunc(mpd_issnan) +Dec_BoolFunc(mpd_issigned) +Dec_BoolFunc(mpd_iszero) + +/* Boolean functions, optional context arg */ +Dec_BoolFuncVA(mpd_isnormal) +Dec_BoolFuncVA(mpd_issubnormal) + +/* Unary functions, no context arg */ +static PyObject * +dec_mpd_adjexp(PyObject *self, PyObject *dummy UNUSED) +{ + mpd_ssize_t retval; + + if (mpd_isspecial(MPD(self))) { + retval = 0; + } + else { + retval = mpd_adjexp(MPD(self)); + } + + return PyLong_FromSsize_t(retval); +} + +static PyObject * +dec_canonical(PyObject *self, PyObject *dummy UNUSED) +{ + Py_INCREF(self); + return self; +} + +static PyObject * +dec_conjugate(PyObject *self, PyObject *dummy UNUSED) +{ + Py_INCREF(self); + return self; +} + +static PyObject * +dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED) +{ + PyObject *result; + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + _dec_settriple(result, MPD_POS, 10, 0); + return result; +} + +/* Unary functions, optional context arg for conversion errors */ +Dec_UnaryFuncVA_NO_CTX(mpd_qcopy_abs) +Dec_UnaryFuncVA_NO_CTX(mpd_qcopy_negate) + +/* Unary functions, optional context arg */ +Dec_UnaryFuncVA(mpd_qinvert) +Dec_UnaryFuncVA(mpd_qlogb) + +static PyObject * +dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"context", NULL}; + PyObject *context; + const char *cp; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, + &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + cp = mpd_class(MPD(self), CTX(context)); + return PyUnicode_FromString(cp); +} + +static PyObject * +dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"context", NULL}; + PyObject *result; + PyObject *context; + mpd_ssize_t size; + char *s; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, + &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + size = mpd_to_eng_size(&s, MPD(self), CtxCaps(context)); + if (size < 0) { + PyErr_NoMemory(); + return NULL; + } + + result = unicode_fromascii(s, size); + mpd_free(s); + + return result; +} + +/* Binary functions, optional context arg for conversion errors */ +Dec_BinaryFuncVA_NO_CTX(mpd_compare_total) +Dec_BinaryFuncVA_NO_CTX(mpd_compare_total_mag) + +static PyObject * +dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"other", "context", NULL}; + PyObject *other, *context; + PyObject *a, *b; + PyObject *result; + uint32_t status = 0; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, + &other, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + CONVERT_BINOP_RAISE(&a, &b, self, other, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + + mpd_qcopy_sign(MPD(result), MPD(a), MPD(b), &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"other", "context", NULL}; + PyObject *other, *context; + PyObject *a, *b; + PyObject *result; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, + &other, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + CONVERT_BINOP_RAISE(&a, &b, self, other, context); + + result = mpd_same_quantum(MPD(a), MPD(b)) ? incr_true() : incr_false(); + Py_DECREF(a); + Py_DECREF(b); + + return result; +} + +/* Binary functions, optional context arg */ +Dec_BinaryFuncVA(mpd_qand) +Dec_BinaryFuncVA(mpd_qor) +Dec_BinaryFuncVA(mpd_qxor) + +Dec_BinaryFuncVA(mpd_qrotate) +Dec_BinaryFuncVA(mpd_qscaleb) +Dec_BinaryFuncVA(mpd_qshift) + +static PyObject * +dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"exp", "rounding", "context", NULL}; + PyObject *w, *context; + PyObject *a, *b; + PyObject *result; + uint32_t status = 0; + mpd_context_t workctx; + int round = -1; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO", kwlist, + &w, &round, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + workctx = *CTX(context); + if (round >= 0) { + if (!mpd_qsetround(&workctx, round)) { + return type_error_ptr(invalid_rounding_err); + } + } + + CONVERT_BINOP_RAISE(&a, &b, v, w, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + + mpd_qquantize(MPD(result), MPD(a), MPD(b), &workctx, &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +/* Special methods */ +static PyObject * +dec_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *a; + PyObject *b; + PyObject *context; + uint32_t status = 0; + int a_issnan, b_issnan; + int r; + + assert(PyDec_Check(v)); + + CURRENT_CONTEXT(context); + CONVERT_BINOP_CMP(&a, &b, v, w, op, context); + + a_issnan = mpd_issnan(MPD(a)); + b_issnan = mpd_issnan(MPD(b)); + + r = mpd_qcmp(MPD(a), MPD(b), &status); + Py_DECREF(a); + Py_DECREF(b); + if (r == INT_MAX) { + /* sNaNs or op={le,ge,lt,gt} always signal. */ + if (a_issnan || b_issnan || (op != Py_EQ && op != Py_NE)) { + if (dec_addstatus(context, status)) { + return NULL; + } + } + /* qNaN comparison with op={eq,ne} or comparison + * with InvalidOperation disabled. */ + return (op == Py_NE) ? incr_true() : incr_false(); + } + + switch (op) { + case Py_EQ: + r = (r == 0); + break; + case Py_NE: + r = (r != 0); + break; + case Py_LE: + r = (r <= 0); + break; + case Py_GE: + r = (r >= 0); + break; + case Py_LT: + r = (r == -1); + break; + case Py_GT: + r = (r == 1); + break; + } + + return PyBool_FromLong(r); +} + +/* __ceil__ */ +static PyObject * +dec_ceil(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return dec_as_long(self, context, MPD_ROUND_CEILING); +} + +/* __complex__ */ +static PyObject * +dec_complex(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *f; + double x; + + f = PyDec_AsFloat(self); + if (f == NULL) { + return NULL; + } + + x = PyFloat_AsDouble(f); + Py_DECREF(f); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + + return PyComplex_FromDoubles(x, 0); +} + +/* __copy__ and __deepcopy__ */ +static PyObject * +dec_copy(PyObject *self, PyObject *dummy UNUSED) +{ + Py_INCREF(self); + return self; +} + +/* __floor__ */ +static PyObject * +dec_floor(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return dec_as_long(self, context, MPD_ROUND_FLOOR); +} + +/* Always uses the module context */ +static Py_hash_t +dec_hash(PyObject *v) +{ +#if defined(CONFIG_64) && _PyHASH_BITS == 61 + /* 2**61 - 1 */ + mpd_uint_t p_data[1] = {2305843009213693951ULL}; + mpd_t p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 19, 1, 1, p_data}; + /* Inverse of 10 modulo p */ + mpd_uint_t inv10_p_data[2] = {2075258708292324556ULL}; + mpd_t inv10_p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, + 0, 19, 1, 1, inv10_p_data}; +#elif defined(CONFIG_32) && _PyHASH_BITS == 31 + /* 2**31 - 1 */ + mpd_uint_t p_data[2] = {147483647UL, 2}; + mpd_t p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 10, 2, 2, p_data}; + /* Inverse of 10 modulo p */ + mpd_uint_t inv10_p_data[2] = {503238553UL, 1}; + mpd_t inv10_p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, + 0, 10, 2, 2, inv10_p_data}; +#else + #error "No valid combination of CONFIG_64, CONFIG_32 and _PyHASH_BITS" +#endif + const Py_hash_t py_hash_inf = 314159; + const Py_hash_t py_hash_nan = 0; + mpd_uint_t ten_data[1] = {10}; + mpd_t ten = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, + 0, 2, 1, 1, ten_data}; + Py_hash_t result; + mpd_t *exp_hash = NULL; + mpd_t *tmp = NULL; + mpd_ssize_t exp; + uint32_t status = 0; + mpd_context_t maxctx; + PyObject *context; + + + context = current_context(); + if (context == NULL) { + return -1; + } + + if (mpd_isspecial(MPD(v))) { + if (mpd_issnan(MPD(v))) { + PyErr_SetString(PyExc_TypeError, + "Cannot hash a signaling NaN value"); + return -1; + } + else if (mpd_isnan(MPD(v))) { + return py_hash_nan; + } + else { + return py_hash_inf * mpd_arith_sign(MPD(v)); + } + } + + mpd_maxcontext(&maxctx); + exp_hash = mpd_qnew(); + if (exp_hash == NULL) { + goto malloc_error; + } + tmp = mpd_qnew(); + if (tmp == NULL) { + goto malloc_error; + } + + /* + * exp(v): exponent of v + * int(v): coefficient of v + */ + exp = MPD(v)->exp; + if (exp >= 0) { + /* 10**exp(v) % p */ + mpd_qsset_ssize(tmp, exp, &maxctx, &status); + mpd_qpowmod(exp_hash, &ten, tmp, &p, &maxctx, &status); + } + else { + /* inv10_p**(-exp(v)) % p */ + mpd_qsset_ssize(tmp, -exp, &maxctx, &status); + mpd_qpowmod(exp_hash, &inv10_p, tmp, &p, &maxctx, &status); + } + + /* hash = (int(v) * exp_hash) % p */ + if (!mpd_qcopy(tmp, MPD(v), &status)) { + goto malloc_error; + } + tmp->exp = 0; + mpd_set_positive(tmp); + mpd_qmul(tmp, tmp, exp_hash, &maxctx, &status); + mpd_qrem(tmp, tmp, &p, &maxctx, &status); + + result = mpd_qget_ssize(tmp, &status); + result = mpd_ispositive(MPD(v)) ? result : -result; + result = (result == -1) ? -2 : result; + + if (status != 0) { + status |= MPD_Invalid_operation; + if (dec_addstatus(context, status)) { + result = -1; + goto finish; + } + } + + +finish: + if (exp_hash) mpd_del(exp_hash); + if (tmp) mpd_del(tmp); + return result; + +malloc_error: + PyErr_NoMemory(); + result = -1; + goto finish; +} + +/* __reduce__ */ +static PyObject * +dec_reduce(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *result, *str; + + str = dec_str(self); + if (str == NULL) { + return NULL; + } + + result = Py_BuildValue("O(O)", Py_TYPE(self), str); + Py_DECREF(str); + + return result; +} + +/* __trunc__ */ +static PyObject * +dec_trunc(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return dec_as_long(self, context, MPD_ROUND_DOWN); +} + +/* real and imag */ +static PyObject * +dec_real(PyObject *self, void *closure UNUSED) +{ + Py_INCREF(self); + return self; +} + +static PyObject * +dec_imag(PyObject *self UNUSED, void *closure UNUSED) +{ + PyObject *result; + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + _dec_settriple(result, MPD_POS, 0, 0); + return result; +} + + +static PyGetSetDef dec_getsets [] = +{ + { "real", (getter)dec_real, NULL, NULL, NULL}, + { "imag", (getter)dec_imag, NULL, NULL, NULL}, + {NULL} +}; + +static PyNumberMethods dec_number_methods = +{ + (binaryfunc) nm_mpd_qadd, + (binaryfunc) nm_mpd_qsub, + (binaryfunc) nm_mpd_qmul, + (binaryfunc) nm_mpd_qrem, + (binaryfunc) nm_mpd_qdivmod, + (ternaryfunc) nm_mpd_qpow, + (unaryfunc) nm_mpd_qminus, + (unaryfunc) nm_mpd_qplus, + (unaryfunc) nm_mpd_qabs, + (inquiry) nm_nonzero, + (unaryfunc) 0, /* no bit-complement */ + (binaryfunc) 0, /* no shiftl */ + (binaryfunc) 0, /* no shiftr */ + (binaryfunc) 0, /* no bit-and */ + (binaryfunc) 0, /* no bit-xor */ + (binaryfunc) 0, /* no bit-ior */ + (unaryfunc) nm_dec_as_long, + 0, /* nb_reserved */ + (unaryfunc) PyDec_AsFloat, + 0, /* binaryfunc nb_inplace_add; */ + 0, /* binaryfunc nb_inplace_subtract; */ + 0, /* binaryfunc nb_inplace_multiply; */ + 0, /* binaryfunc nb_inplace_remainder; */ + 0, /* ternaryfunc nb_inplace_power; */ + 0, /* binaryfunc nb_inplace_lshift; */ + 0, /* binaryfunc nb_inplace_rshift; */ + 0, /* binaryfunc nb_inplace_and; */ + 0, /* binaryfunc nb_inplace_xor; */ + 0, /* binaryfunc nb_inplace_or; */ + (binaryfunc) nm_mpd_qdivint, /* binaryfunc nb_floor_divide; */ + (binaryfunc) nm_mpd_qdiv, /* binaryfunc nb_true_divide; */ + 0, /* binaryfunc nb_inplace_floor_divide; */ + 0, /* binaryfunc nb_inplace_true_divide; */ +}; + +static PyMethodDef dec_methods [] = +{ + /* Unary arithmetic functions, optional context arg */ + { "exp", (PyCFunction)dec_mpd_qexp, METH_VARARGS|METH_KEYWORDS, doc_exp }, + { "ln", (PyCFunction)dec_mpd_qln, METH_VARARGS|METH_KEYWORDS, doc_ln }, + { "log10", (PyCFunction)dec_mpd_qlog10, METH_VARARGS|METH_KEYWORDS, doc_log10 }, + { "next_minus", (PyCFunction)dec_mpd_qnext_minus, METH_VARARGS|METH_KEYWORDS, doc_next_minus }, + { "next_plus", (PyCFunction)dec_mpd_qnext_plus, METH_VARARGS|METH_KEYWORDS, doc_next_plus }, + { "normalize", (PyCFunction)dec_mpd_qreduce, METH_VARARGS|METH_KEYWORDS, doc_normalize }, + { "to_integral", (PyCFunction)PyDec_ToIntegralValue, METH_VARARGS|METH_KEYWORDS, doc_to_integral }, + { "to_integral_exact", (PyCFunction)PyDec_ToIntegralExact, METH_VARARGS|METH_KEYWORDS, doc_to_integral_exact }, + { "to_integral_value", (PyCFunction)PyDec_ToIntegralValue, METH_VARARGS|METH_KEYWORDS, doc_to_integral_value }, + { "sqrt", (PyCFunction)dec_mpd_qsqrt, METH_VARARGS|METH_KEYWORDS, doc_sqrt }, + + /* Binary arithmetic functions, optional context arg */ + { "compare", (PyCFunction)dec_mpd_qcompare, METH_VARARGS|METH_KEYWORDS, doc_compare }, + { "compare_signal", (PyCFunction)dec_mpd_qcompare_signal, METH_VARARGS|METH_KEYWORDS, doc_compare_signal }, + { "max", (PyCFunction)dec_mpd_qmax, METH_VARARGS|METH_KEYWORDS, doc_max }, + { "max_mag", (PyCFunction)dec_mpd_qmax_mag, METH_VARARGS|METH_KEYWORDS, doc_max_mag }, + { "min", (PyCFunction)dec_mpd_qmin, METH_VARARGS|METH_KEYWORDS, doc_min }, + { "min_mag", (PyCFunction)dec_mpd_qmin_mag, METH_VARARGS|METH_KEYWORDS, doc_min_mag }, + { "next_toward", (PyCFunction)dec_mpd_qnext_toward, METH_VARARGS|METH_KEYWORDS, doc_next_toward }, + { "quantize", (PyCFunction)dec_mpd_qquantize, METH_VARARGS|METH_KEYWORDS, doc_quantize }, + { "remainder_near", (PyCFunction)dec_mpd_qrem_near, METH_VARARGS|METH_KEYWORDS, doc_remainder_near }, + + /* Ternary arithmetic functions, optional context arg */ + { "fma", (PyCFunction)dec_mpd_qfma, METH_VARARGS|METH_KEYWORDS, doc_fma }, + + /* Boolean functions, no context arg */ + { "is_canonical", dec_mpd_iscanonical, METH_NOARGS, doc_is_canonical }, + { "is_finite", dec_mpd_isfinite, METH_NOARGS, doc_is_finite }, + { "is_infinite", dec_mpd_isinfinite, METH_NOARGS, doc_is_infinite }, + { "is_nan", dec_mpd_isnan, METH_NOARGS, doc_is_nan }, + { "is_qnan", dec_mpd_isqnan, METH_NOARGS, doc_is_qnan }, + { "is_snan", dec_mpd_issnan, METH_NOARGS, doc_is_snan }, + { "is_signed", dec_mpd_issigned, METH_NOARGS, doc_is_signed }, + { "is_zero", dec_mpd_iszero, METH_NOARGS, doc_is_zero }, + + /* Boolean functions, optional context arg */ + { "is_normal", (PyCFunction)dec_mpd_isnormal, METH_VARARGS|METH_KEYWORDS, doc_is_normal }, + { "is_subnormal", (PyCFunction)dec_mpd_issubnormal, METH_VARARGS|METH_KEYWORDS, doc_is_subnormal }, + + /* Unary functions, no context arg */ + { "adjusted", dec_mpd_adjexp, METH_NOARGS, doc_adjusted }, + { "canonical", dec_canonical, METH_NOARGS, doc_canonical }, + { "conjugate", dec_conjugate, METH_NOARGS, doc_conjugate }, + { "radix", dec_mpd_radix, METH_NOARGS, doc_radix }, + + /* Unary functions, optional context arg for conversion errors */ + { "copy_abs", (PyCFunction)dec_mpd_qcopy_abs, METH_VARARGS|METH_KEYWORDS, doc_copy_abs }, + { "copy_negate", (PyCFunction)dec_mpd_qcopy_negate, METH_VARARGS|METH_KEYWORDS, doc_copy_negate }, + + /* Unary functions, optional context arg */ + { "logb", (PyCFunction)dec_mpd_qlogb, METH_VARARGS|METH_KEYWORDS, doc_logb }, + { "logical_invert", (PyCFunction)dec_mpd_qinvert, METH_VARARGS|METH_KEYWORDS, doc_logical_invert }, + { "number_class", (PyCFunction)dec_mpd_class, METH_VARARGS|METH_KEYWORDS, doc_number_class }, + { "to_eng_string", (PyCFunction)dec_mpd_to_eng, METH_VARARGS|METH_KEYWORDS, doc_to_eng_string }, + + /* Binary functions, optional context arg for conversion errors */ + { "compare_total", (PyCFunction)dec_mpd_compare_total, METH_VARARGS|METH_KEYWORDS, doc_compare_total }, + { "compare_total_mag", (PyCFunction)dec_mpd_compare_total_mag, METH_VARARGS|METH_KEYWORDS, doc_compare_total_mag }, + { "copy_sign", (PyCFunction)dec_mpd_qcopy_sign, METH_VARARGS|METH_KEYWORDS, doc_copy_sign }, + { "same_quantum", (PyCFunction)dec_mpd_same_quantum, METH_VARARGS|METH_KEYWORDS, doc_same_quantum }, + + /* Binary functions, optional context arg */ + { "logical_and", (PyCFunction)dec_mpd_qand, METH_VARARGS|METH_KEYWORDS, doc_logical_and }, + { "logical_or", (PyCFunction)dec_mpd_qor, METH_VARARGS|METH_KEYWORDS, doc_logical_or }, + { "logical_xor", (PyCFunction)dec_mpd_qxor, METH_VARARGS|METH_KEYWORDS, doc_logical_xor }, + { "rotate", (PyCFunction)dec_mpd_qrotate, METH_VARARGS|METH_KEYWORDS, doc_rotate }, + { "scaleb", (PyCFunction)dec_mpd_qscaleb, METH_VARARGS|METH_KEYWORDS, doc_scaleb }, + { "shift", (PyCFunction)dec_mpd_qshift, METH_VARARGS|METH_KEYWORDS, doc_shift }, + + /* Miscellaneous */ + { "from_float", dec_from_float, METH_O|METH_CLASS, doc_from_float }, + { "as_tuple", PyDec_AsTuple, METH_NOARGS, doc_as_tuple }, + + /* Special methods */ + { "__copy__", dec_copy, METH_NOARGS, NULL }, + { "__deepcopy__", dec_copy, METH_O, NULL }, + { "__format__", dec_format, METH_VARARGS, NULL }, + { "__reduce__", dec_reduce, METH_NOARGS, NULL }, + { "__round__", PyDec_Round, METH_VARARGS, NULL }, + { "__ceil__", dec_ceil, METH_NOARGS, NULL }, + { "__floor__", dec_floor, METH_NOARGS, NULL }, + { "__trunc__", dec_trunc, METH_NOARGS, NULL }, + { "__complex__", dec_complex, METH_NOARGS, NULL }, + + { NULL, NULL, 1 } +}; + +static PyTypeObject PyDec_Type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "decimal.Decimal", /* tp_name */ + sizeof(PyDecObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) dec_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc) dec_repr, /* tp_repr */ + &dec_number_methods, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc) dec_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc) dec_str, /* tp_str */ + (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + (PyBufferProcs *) 0, /* tp_as_buffer */ + (Py_TPFLAGS_DEFAULT| + Py_TPFLAGS_BASETYPE), /* tp_flags */ + doc_decimal, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + dec_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + dec_methods, /* tp_methods */ + 0, /* tp_members */ + dec_getsets, /* 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 */ + dec_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + +/******************************************************************************/ +/* Context Object, Part 2 */ +/******************************************************************************/ + + +/************************************************************************/ +/* Macros for converting mpdecimal functions to Context methods */ +/************************************************************************/ + +/* Boolean context method. */ +#define DecCtx_BoolFunc(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *v) \ +{ \ + PyObject *ret; \ + PyObject *a; \ + \ + CONVERT_OP_RAISE(&a, v, context); \ + \ + ret = MPDFUNC(MPD(a), CTX(context)) ? incr_true() : incr_false(); \ + Py_DECREF(a); \ + return ret; \ +} + +/* Boolean context method. MPDFUNC does NOT use a context. */ +#define DecCtx_BoolFunc_NO_CTX(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *v) \ +{ \ + PyObject *ret; \ + PyObject *a; \ + \ + CONVERT_OP_RAISE(&a, v, context); \ + \ + ret = MPDFUNC(MPD(a)) ? incr_true() : incr_false(); \ + Py_DECREF(a); \ + return ret; \ +} + +/* Unary context method. */ +#define DecCtx_UnaryFunc(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *v) \ +{ \ + PyObject *result, *a; \ + uint32_t status = 0; \ + \ + CONVERT_OP_RAISE(&a, v, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), CTX(context), &status); \ + Py_DECREF(a); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Binary context method. */ +#define DecCtx_BinaryFunc(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *args) \ +{ \ + PyObject *v, *w; \ + PyObject *a, *b; \ + PyObject *result; \ + uint32_t status = 0; \ + \ + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { \ + return NULL; \ + } \ + \ + CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* + * Binary context method. The context is only used for conversion. + * The actual MPDFUNC does NOT take a context arg. + */ +#define DecCtx_BinaryFunc_NO_CTX(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *args) \ +{ \ + PyObject *v, *w; \ + PyObject *a, *b; \ + PyObject *result; \ + \ + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { \ + return NULL; \ + } \ + \ + CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b)); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + \ + return result; \ +} + +/* Ternary context method. */ +#define DecCtx_TernaryFunc(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *args) \ +{ \ + PyObject *v, *w, *x; \ + PyObject *a, *b, *c; \ + PyObject *result; \ + uint32_t status = 0; \ + \ + if (!PyArg_ParseTuple(args, "OOO", &v, &w, &x)) { \ + return NULL; \ + } \ + \ + CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + Py_DECREF(c); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), MPD(c), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + Py_DECREF(c); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + + +/* Unary arithmetic functions */ +DecCtx_UnaryFunc(mpd_qabs) +DecCtx_UnaryFunc(mpd_qexp) +DecCtx_UnaryFunc(mpd_qln) +DecCtx_UnaryFunc(mpd_qlog10) +DecCtx_UnaryFunc(mpd_qminus) +DecCtx_UnaryFunc(mpd_qnext_minus) +DecCtx_UnaryFunc(mpd_qnext_plus) +DecCtx_UnaryFunc(mpd_qplus) +DecCtx_UnaryFunc(mpd_qreduce) +DecCtx_UnaryFunc(mpd_qround_to_int) +DecCtx_UnaryFunc(mpd_qround_to_intx) +DecCtx_UnaryFunc(mpd_qsqrt) + +/* Binary arithmetic functions */ +DecCtx_BinaryFunc(mpd_qadd) +DecCtx_BinaryFunc(mpd_qcompare) +DecCtx_BinaryFunc(mpd_qcompare_signal) +DecCtx_BinaryFunc(mpd_qdiv) +DecCtx_BinaryFunc(mpd_qdivint) +DecCtx_BinaryFunc(mpd_qmax) +DecCtx_BinaryFunc(mpd_qmax_mag) +DecCtx_BinaryFunc(mpd_qmin) +DecCtx_BinaryFunc(mpd_qmin_mag) +DecCtx_BinaryFunc(mpd_qmul) +DecCtx_BinaryFunc(mpd_qnext_toward) +DecCtx_BinaryFunc(mpd_qquantize) +DecCtx_BinaryFunc(mpd_qrem) +DecCtx_BinaryFunc(mpd_qrem_near) +DecCtx_BinaryFunc(mpd_qsub) + +static PyObject * +ctx_mpd_qdivmod(PyObject *context, PyObject *args) +{ + PyObject *v, *w; + PyObject *a, *b; + PyObject *q, *r; + uint32_t status = 0; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { + return NULL; + } + + CONVERT_BINOP_RAISE(&a, &b, v, w, context); + + q = dec_alloc(); + if (q == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + r = dec_alloc(); + if (r == NULL) { + Py_DECREF(a); + Py_DECREF(b); + Py_DECREF(q); + return NULL; + } + + mpd_qdivmod(MPD(q), MPD(r), MPD(a), MPD(b), CTX(context), &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(r); + Py_DECREF(q); + return NULL; + } + + ret = Py_BuildValue("(OO)", q, r); + Py_DECREF(r); + Py_DECREF(q); + return ret; +} + +/* Binary or ternary arithmetic functions */ +static PyObject * +ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"a", "b", "modulo", NULL}; + PyObject *base, *exp, *mod = NULL; + PyObject *a, *b, *c = NULL; + PyObject *result; + uint32_t status = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist, + &base, &exp, &mod)) { + return NULL; + } + + CONVERT_BINOP_RAISE(&a, &b, base, exp, context); + + if (mod != NULL) { + if (!convert_op(TYPE_ERR, &c, mod, context)) { + Py_DECREF(a); + Py_DECREF(b); + return c; + } + } + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + Py_XDECREF(c); + return NULL; + } + + if (c == NULL) { + mpd_qpow(MPD(result), MPD(a), MPD(b), + CTX(context), &status); + } + else { + mpd_qpowmod(MPD(result), MPD(a), MPD(b), MPD(c), + CTX(context), &status); + status = (status == MPD_Clamped) ? 0 : status; + /* remove ideal exponent for compatibility with decimal.py */ + mpd_qquantize(MPD(result), MPD(result), &zero, + CTX(context), &status); + Py_DECREF(c); + } + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +/* Ternary arithmetic functions */ +DecCtx_TernaryFunc(mpd_qfma) + +/* No argument */ +static PyObject * +ctx_mpd_radix(PyObject *context, PyObject *dummy) +{ + return dec_mpd_radix(context, dummy); +} + +/* Boolean functions: single decimal argument */ +DecCtx_BoolFunc(mpd_isnormal) +DecCtx_BoolFunc(mpd_issubnormal) +DecCtx_BoolFunc_NO_CTX(mpd_isfinite) +DecCtx_BoolFunc_NO_CTX(mpd_isinfinite) +DecCtx_BoolFunc_NO_CTX(mpd_isnan) +DecCtx_BoolFunc_NO_CTX(mpd_isqnan) +DecCtx_BoolFunc_NO_CTX(mpd_issigned) +DecCtx_BoolFunc_NO_CTX(mpd_issnan) +DecCtx_BoolFunc_NO_CTX(mpd_iszero) + +static PyObject * +ctx_iscanonical(PyObject *context UNUSED, PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "argument must be a Decimal"); + return NULL; + } + + return mpd_iscanonical(MPD(v)) ? incr_true() : incr_false(); +} + +/* Functions with a single decimal argument */ +static PyObject * +PyDecContext_Apply(PyObject *context, PyObject *v) +{ + PyObject *result, *a; + + CONVERT_OP_RAISE(&a, v, context); + + result = dec_apply(a, context); + Py_DECREF(a); + return result; +} + +static PyObject * +ctx_canonical(PyObject *context UNUSED, PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "argument must be a Decimal"); + return NULL; + } + + Py_INCREF(v); + return v; +} + +static PyObject * +ctx_mpd_qcopy_abs(PyObject *context, PyObject *v) +{ + PyObject *result, *a; + uint32_t status = 0; + + CONVERT_OP_RAISE(&a, v, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + return NULL; + } + + mpd_qcopy_abs(MPD(result), MPD(a), &status); + Py_DECREF(a); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +ctx_copy_decimal(PyObject *context, PyObject *v) +{ + PyObject *result; + + CONVERT_OP_RAISE(&result, v, context); + return result; +} + +static PyObject * +ctx_mpd_qcopy_negate(PyObject *context, PyObject *v) +{ + PyObject *result, *a; + uint32_t status = 0; + + CONVERT_OP_RAISE(&a, v, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + return NULL; + } + + mpd_qcopy_negate(MPD(result), MPD(a), &status); + Py_DECREF(a); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +DecCtx_UnaryFunc(mpd_qlogb) +DecCtx_UnaryFunc(mpd_qinvert) + +static PyObject * +ctx_mpd_class(PyObject *context, PyObject *v) +{ + PyObject *a; + const char *cp; + + CONVERT_OP_RAISE(&a, v, context); + + cp = mpd_class(MPD(a), CTX(context)); + Py_DECREF(a); + + return PyUnicode_FromString(cp); +} + +static PyObject * +ctx_mpd_to_sci(PyObject *context, PyObject *v) +{ + PyObject *result; + PyObject *a; + mpd_ssize_t size; + char *s; + + CONVERT_OP_RAISE(&a, v, context); + + size = mpd_to_sci_size(&s, MPD(a), CtxCaps(context)); + Py_DECREF(a); + if (size < 0) { + PyErr_NoMemory(); + return NULL; + } + + result = unicode_fromascii(s, size); + mpd_free(s); + + return result; +} + +static PyObject * +ctx_mpd_to_eng(PyObject *context, PyObject *v) +{ + PyObject *result; + PyObject *a; + mpd_ssize_t size; + char *s; + + CONVERT_OP_RAISE(&a, v, context); + + size = mpd_to_eng_size(&s, MPD(a), CtxCaps(context)); + Py_DECREF(a); + if (size < 0) { + PyErr_NoMemory(); + return NULL; + } + + result = unicode_fromascii(s, size); + mpd_free(s); + + return result; +} + +/* Functions with two decimal arguments */ +DecCtx_BinaryFunc_NO_CTX(mpd_compare_total) +DecCtx_BinaryFunc_NO_CTX(mpd_compare_total_mag) + +static PyObject * +ctx_mpd_qcopy_sign(PyObject *context, PyObject *args) +{ + PyObject *v, *w; + PyObject *a, *b; + PyObject *result; + uint32_t status = 0; + + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { + return NULL; + } + + CONVERT_BINOP_RAISE(&a, &b, v, w, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + + mpd_qcopy_sign(MPD(result), MPD(a), MPD(b), &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +DecCtx_BinaryFunc(mpd_qand) +DecCtx_BinaryFunc(mpd_qor) +DecCtx_BinaryFunc(mpd_qxor) + +DecCtx_BinaryFunc(mpd_qrotate) +DecCtx_BinaryFunc(mpd_qscaleb) +DecCtx_BinaryFunc(mpd_qshift) + +static PyObject * +ctx_mpd_same_quantum(PyObject *context, PyObject *args) +{ + PyObject *v, *w; + PyObject *a, *b; + PyObject *result; + + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { + return NULL; + } + + CONVERT_BINOP_RAISE(&a, &b, v, w, context); + + result = mpd_same_quantum(MPD(a), MPD(b)) ? incr_true() : incr_false(); + Py_DECREF(a); + Py_DECREF(b); + + return result; +} + + +static PyMethodDef context_methods [] = +{ + /* Unary arithmetic functions */ + { "abs", ctx_mpd_qabs, METH_O, doc_ctx_abs }, + { "exp", ctx_mpd_qexp, METH_O, doc_ctx_exp }, + { "ln", ctx_mpd_qln, METH_O, doc_ctx_ln }, + { "log10", ctx_mpd_qlog10, METH_O, doc_ctx_log10 }, + { "minus", ctx_mpd_qminus, METH_O, doc_ctx_minus }, + { "next_minus", ctx_mpd_qnext_minus, METH_O, doc_ctx_next_minus }, + { "next_plus", ctx_mpd_qnext_plus, METH_O, doc_ctx_next_plus }, + { "normalize", ctx_mpd_qreduce, METH_O, doc_ctx_normalize }, + { "plus", ctx_mpd_qplus, METH_O, doc_ctx_plus }, + { "to_integral", ctx_mpd_qround_to_int, METH_O, doc_ctx_to_integral }, + { "to_integral_exact", ctx_mpd_qround_to_intx, METH_O, doc_ctx_to_integral_exact }, + { "to_integral_value", ctx_mpd_qround_to_int, METH_O, doc_ctx_to_integral_value }, + { "sqrt", ctx_mpd_qsqrt, METH_O, doc_ctx_sqrt }, + + /* Binary arithmetic functions */ + { "add", ctx_mpd_qadd, METH_VARARGS, doc_ctx_add }, + { "compare", ctx_mpd_qcompare, METH_VARARGS, doc_ctx_compare }, + { "compare_signal", ctx_mpd_qcompare_signal, METH_VARARGS, doc_ctx_compare_signal }, + { "divide", ctx_mpd_qdiv, METH_VARARGS, doc_ctx_divide }, + { "divide_int", ctx_mpd_qdivint, METH_VARARGS, doc_ctx_divide_int }, + { "divmod", ctx_mpd_qdivmod, METH_VARARGS, doc_ctx_divmod }, + { "max", ctx_mpd_qmax, METH_VARARGS, doc_ctx_max }, + { "max_mag", ctx_mpd_qmax_mag, METH_VARARGS, doc_ctx_max_mag }, + { "min", ctx_mpd_qmin, METH_VARARGS, doc_ctx_min }, + { "min_mag", ctx_mpd_qmin_mag, METH_VARARGS, doc_ctx_min_mag }, + { "multiply", ctx_mpd_qmul, METH_VARARGS, doc_ctx_multiply }, + { "next_toward", ctx_mpd_qnext_toward, METH_VARARGS, doc_ctx_next_toward }, + { "quantize", ctx_mpd_qquantize, METH_VARARGS, doc_ctx_quantize }, + { "remainder", ctx_mpd_qrem, METH_VARARGS, doc_ctx_remainder }, + { "remainder_near", ctx_mpd_qrem_near, METH_VARARGS, doc_ctx_remainder_near }, + { "subtract", ctx_mpd_qsub, METH_VARARGS, doc_ctx_subtract }, + + /* Binary or ternary arithmetic functions */ + { "power", (PyCFunction)ctx_mpd_qpow, METH_VARARGS|METH_KEYWORDS, doc_ctx_power }, + + /* Ternary arithmetic functions */ + { "fma", ctx_mpd_qfma, METH_VARARGS, doc_ctx_fma }, + + /* No argument */ + { "Etiny", context_getetiny, METH_NOARGS, doc_ctx_Etiny }, + { "Etop", context_getetop, METH_NOARGS, doc_ctx_Etop }, + { "radix", ctx_mpd_radix, METH_NOARGS, doc_ctx_radix }, + + /* Boolean functions */ + { "is_canonical", ctx_iscanonical, METH_O, doc_ctx_is_canonical }, + { "is_finite", ctx_mpd_isfinite, METH_O, doc_ctx_is_finite }, + { "is_infinite", ctx_mpd_isinfinite, METH_O, doc_ctx_is_infinite }, + { "is_nan", ctx_mpd_isnan, METH_O, doc_ctx_is_nan }, + { "is_normal", ctx_mpd_isnormal, METH_O, doc_ctx_is_normal }, + { "is_qnan", ctx_mpd_isqnan, METH_O, doc_ctx_is_qnan }, + { "is_signed", ctx_mpd_issigned, METH_O, doc_ctx_is_signed }, + { "is_snan", ctx_mpd_issnan, METH_O, doc_ctx_is_snan }, + { "is_subnormal", ctx_mpd_issubnormal, METH_O, doc_ctx_is_subnormal }, + { "is_zero", ctx_mpd_iszero, METH_O, doc_ctx_is_zero }, + + /* Functions with a single decimal argument */ + { "_apply", PyDecContext_Apply, METH_O, NULL }, /* alias for apply */ +#ifdef EXTRA_FUNCTIONALITY + { "apply", PyDecContext_Apply, METH_O, doc_ctx_apply }, +#endif + { "canonical", ctx_canonical, METH_O, doc_ctx_canonical }, + { "copy_abs", ctx_mpd_qcopy_abs, METH_O, doc_ctx_copy_abs }, + { "copy_decimal", ctx_copy_decimal, METH_O, doc_ctx_copy_decimal }, + { "copy_negate", ctx_mpd_qcopy_negate, METH_O, doc_ctx_copy_negate }, + { "logb", ctx_mpd_qlogb, METH_O, doc_ctx_logb }, + { "logical_invert", ctx_mpd_qinvert, METH_O, doc_ctx_logical_invert }, + { "number_class", ctx_mpd_class, METH_O, doc_ctx_number_class }, + { "to_sci_string", ctx_mpd_to_sci, METH_O, doc_ctx_to_sci_string }, + { "to_eng_string", ctx_mpd_to_eng, METH_O, doc_ctx_to_eng_string }, + + /* Functions with two decimal arguments */ + { "compare_total", ctx_mpd_compare_total, METH_VARARGS, doc_ctx_compare_total }, + { "compare_total_mag", ctx_mpd_compare_total_mag, METH_VARARGS, doc_ctx_compare_total_mag }, + { "copy_sign", ctx_mpd_qcopy_sign, METH_VARARGS, doc_ctx_copy_sign }, + { "logical_and", ctx_mpd_qand, METH_VARARGS, doc_ctx_logical_and }, + { "logical_or", ctx_mpd_qor, METH_VARARGS, doc_ctx_logical_or }, + { "logical_xor", ctx_mpd_qxor, METH_VARARGS, doc_ctx_logical_xor }, + { "rotate", ctx_mpd_qrotate, METH_VARARGS, doc_ctx_rotate }, + { "same_quantum", ctx_mpd_same_quantum, METH_VARARGS, doc_ctx_same_quantum }, + { "scaleb", ctx_mpd_qscaleb, METH_VARARGS, doc_ctx_scaleb }, + { "shift", ctx_mpd_qshift, METH_VARARGS, doc_ctx_shift }, + + /* Set context values */ + { "clear_flags", context_clear_flags, METH_NOARGS, doc_ctx_clear_flags }, + { "clear_traps", context_clear_traps, METH_NOARGS, doc_ctx_clear_traps }, + +#ifdef CONFIG_32 + /* Unsafe set functions with relaxed range checks */ + { "_unsafe_setprec", context_unsafe_setprec, METH_O, NULL }, + { "_unsafe_setemin", context_unsafe_setemin, METH_O, NULL }, + { "_unsafe_setemax", context_unsafe_setemax, METH_O, NULL }, +#endif + + /* Miscellaneous */ + { "__copy__", (PyCFunction)context_copy, METH_NOARGS, NULL }, + { "__reduce__", context_reduce, METH_NOARGS, NULL }, + { "copy", (PyCFunction)context_copy, METH_NOARGS, doc_ctx_copy }, + { "create_decimal", ctx_create_decimal, METH_VARARGS, doc_ctx_create_decimal }, + { "create_decimal_from_float", ctx_from_float, METH_O, doc_ctx_create_decimal_from_float }, + + { NULL, NULL, 1 } +}; + +static PyTypeObject PyDecContext_Type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "decimal.Context", /* tp_name */ + sizeof(PyDecContextObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) context_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc) context_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc) 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc) context_repr, /* tp_str */ + (getattrofunc) context_getattr, /* tp_getattro */ + (setattrofunc) context_setattr, /* tp_setattro */ + (PyBufferProcs *) 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + doc_context, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + context_methods, /* tp_methods */ + 0, /* tp_members */ + context_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + context_init, /* tp_init */ + 0, /* tp_alloc */ + context_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + +static PyMethodDef _decimal_methods [] = +{ + { "getcontext", (PyCFunction)PyDec_GetCurrentContext, METH_NOARGS, doc_getcontext}, + { "setcontext", (PyCFunction)PyDec_SetCurrentContext, METH_O, doc_setcontext}, + { "localcontext", (PyCFunction)ctxmanager_new, METH_VARARGS, doc_localcontext}, +#ifdef EXTRA_FUNCTIONALITY + { "IEEEContext", (PyCFunction)ieee_context, METH_O, doc_ieee_context}, +#endif + { NULL, NULL, 1, NULL } +}; + +static struct PyModuleDef _decimal_module = { + PyModuleDef_HEAD_INIT, + "decimal", + doc__decimal, + -1, + _decimal_methods, + NULL, + NULL, + NULL, + NULL +}; + +struct ssize_constmap { const char *name; mpd_ssize_t val; }; +static struct ssize_constmap ssize_constants [] = { + {"MAX_PREC", MPD_MAX_PREC}, + {"MAX_EMAX", MPD_MAX_EMAX}, + {"MIN_EMIN", MPD_MIN_EMIN}, + {"MIN_ETINY", MPD_MIN_ETINY}, + {NULL} +}; + +struct int_constmap { const char *name; int val; }; +static struct int_constmap int_constants [] = { + /* int constants */ +#ifdef EXTRA_FUNCTIONALITY + {"DECIMAL32", MPD_DECIMAL32}, + {"DECIMAL64", MPD_DECIMAL64}, + {"DECIMAL128", MPD_DECIMAL128}, + {"IEEE_CONTEXT_MAX_BITS", MPD_IEEE_CONTEXT_MAX_BITS}, +#endif + {"ROUND_CEILING", MPD_ROUND_CEILING}, + {"ROUND_FLOOR", MPD_ROUND_FLOOR}, + {"ROUND_UP", MPD_ROUND_UP}, + {"ROUND_DOWN", MPD_ROUND_DOWN}, + {"ROUND_HALF_UP", MPD_ROUND_HALF_UP}, + {"ROUND_HALF_DOWN", MPD_ROUND_HALF_DOWN}, + {"ROUND_HALF_EVEN", MPD_ROUND_HALF_EVEN}, + {"ROUND_05UP", MPD_ROUND_05UP}, +#ifdef EXTRA_FUNCTIONALITY + {"ROUND_TRUNC", MPD_ROUND_TRUNC}, + /* int condition flags */ + {"DecClamped", MPD_Clamped}, + {"DecConversionSyntax", MPD_Conversion_syntax}, + {"DecDivisionByZero", MPD_Division_by_zero}, + {"DecDivisionImpossible", MPD_Division_impossible}, + {"DecDivisionUndefined", MPD_Division_undefined}, + {"DecFpuError", MPD_Fpu_error}, + {"DecInexact", MPD_Inexact}, + {"DecInvalidContext", MPD_Invalid_context}, + {"DecInvalidOperation", MPD_Invalid_operation}, + {"DecIEEEInvalidOperation", MPD_IEEE_Invalid_operation}, + {"DecMallocError", MPD_Malloc_error}, + {"DecFloatOperation", MPD_Float_operation}, + {"DecOverflow", MPD_Overflow}, + {"DecRounded", MPD_Rounded}, + {"DecSubnormal", MPD_Subnormal}, + {"DecUnderflow", MPD_Underflow}, + {"DecErrors", MPD_Errors}, + {"DecTraps", MPD_Traps}, +#endif + {NULL} +}; + + +#define CHECK_INT(expr) \ + do { if ((expr) < 0) goto error; } while (0) +#define ASSIGN_PTR(result, expr) \ + do { result = (expr); if (result == NULL) goto error; } while (0) +#define CHECK_PTR(expr) \ + do { if ((expr) == NULL) goto error; } while (0) + +PyMODINIT_FUNC +PyInit__decimal(void) +{ + PyObject *m = NULL; + PyObject *numbers = NULL; + PyObject *Number = NULL; + PyObject *collections = NULL; + PyObject *MutableMapping = NULL; + PyObject *obj = NULL; + DecCondMap *cm; + struct ssize_constmap *ssize_cm; + struct int_constmap *int_cm; + int i; + + + /* Init libmpdec */ + mpd_traphandler = dec_traphandler; + mpd_mallocfunc = PyMem_Malloc; + mpd_reallocfunc = PyMem_Realloc; + mpd_callocfunc = mpd_callocfunc_em; + mpd_free = PyMem_Free; + mpd_setminalloc(4); + + + /* Init types */ + PyDec_Type.tp_base = &PyBaseObject_Type; + PyDecContext_Type.tp_base = &PyBaseObject_Type; + PyDecContextManager_Type.tp_base = &PyBaseObject_Type; + PyDecSignalDictMixin_Type.tp_base = &PyBaseObject_Type; + + CHECK_INT(PyType_Ready(&PyDec_Type)); + CHECK_INT(PyType_Ready(&PyDecContext_Type)); + CHECK_INT(PyType_Ready(&PyDecSignalDictMixin_Type)); + CHECK_INT(PyType_Ready(&PyDecContextManager_Type)); + + ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); + CHECK_INT(PyDict_SetItemString(PyDec_Type.tp_dict, "__module__", obj)); + CHECK_INT(PyDict_SetItemString(PyDecContext_Type.tp_dict, + "__module__", obj)); + Py_CLEAR(obj); + + + /* Numeric abstract base classes */ + ASSIGN_PTR(numbers, PyImport_ImportModule("numbers")); + ASSIGN_PTR(Number, PyObject_GetAttrString(numbers, "Number")); + /* Register Decimal with the Number abstract base class */ + ASSIGN_PTR(obj, PyObject_CallMethod(Number, "register", "(O)", + (PyObject *)&PyDec_Type)); + Py_CLEAR(obj); + /* Rational is a global variable used for fraction comparisons. */ + ASSIGN_PTR(Rational, PyObject_GetAttrString(numbers, "Rational")); + /* Done with numbers, Number */ + Py_CLEAR(numbers); + Py_CLEAR(Number); + + /* DecimalTuple */ + ASSIGN_PTR(collections, PyImport_ImportModule("collections")); + ASSIGN_PTR(DecimalTuple, PyObject_CallMethod(collections, + "namedtuple", "(ss)", "DecimalTuple", + "sign digits exponent")); + /* MutableMapping */ + ASSIGN_PTR(MutableMapping, PyObject_GetAttrString(collections, + "MutableMapping")); + /* Create SignalDict type */ + ASSIGN_PTR(PyDecSignalDict_Type, + (PyTypeObject *)PyObject_CallFunction( + (PyObject *)&PyType_Type, "s(OO){}", + "SignalDict", &PyDecSignalDictMixin_Type, + MutableMapping)); + + /* Done with collections, MutableMapping */ + Py_CLEAR(collections); + Py_CLEAR(MutableMapping); + + + /* Create the module */ + ASSIGN_PTR(m, PyModule_Create(&_decimal_module)); + + + /* Add types to the module */ + Py_INCREF(&PyDec_Type); + CHECK_INT(PyModule_AddObject(m, "Decimal", (PyObject *)&PyDec_Type)); + Py_INCREF(&PyDecContext_Type); + CHECK_INT(PyModule_AddObject(m, "Context", + (PyObject *)&PyDecContext_Type)); + Py_INCREF(DecimalTuple); + CHECK_INT(PyModule_AddObject(m, "DecimalTuple", DecimalTuple)); + + + /* Create top level exception */ + ASSIGN_PTR(DecimalException, PyErr_NewException( + "decimal.DecimalException", + PyExc_ArithmeticError, NULL)); + Py_INCREF(DecimalException); + CHECK_INT(PyModule_AddObject(m, "DecimalException", DecimalException)); + + /* Create signal tuple */ + ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); + + /* Add exceptions that correspond to IEEE signals */ + for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { + ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, + DecimalException, NULL)); + + /* add to module */ + Py_INCREF(cm->ex); + CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex)); + + /* add to signal tuple */ + Py_INCREF(cm->ex); + PyTuple_SET_ITEM(SignalTuple, i, cm->ex); + } + + /* + * Unfortunately, InvalidOperation is a signal that comprises + * several conditions, including InvalidOperation! Naming the + * signal IEEEInvalidOperation would prevent the confusion. + */ + cond_map[0].ex = signal_map[0].ex; + + /* Add remaining exceptions, inherit from InvalidOperation */ + for (cm = cond_map+1; cm->name != NULL; cm++) { + ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, + signal_map[0].ex, NULL)); + Py_INCREF(cm->ex); + CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex)); + } + + + /* Init default context template first */ + ASSIGN_PTR(default_context_template, + PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + Py_INCREF(default_context_template); + CHECK_INT(PyModule_AddObject(m, "DefaultContext", + default_context_template)); + +#ifdef WITHOUT_THREADS + /* Init module context */ + ASSIGN_PTR(module_context, + PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + Py_INCREF(Py_False); + CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_False)); +#else + ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); + Py_INCREF(Py_True); + CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_True)); +#endif + + /* Init basic context template */ + ASSIGN_PTR(basic_context_template, + PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + init_basic_context(basic_context_template); + Py_INCREF(basic_context_template); + CHECK_INT(PyModule_AddObject(m, "BasicContext", + basic_context_template)); + + /* Init extended context template */ + ASSIGN_PTR(extended_context_template, + PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + init_extended_context(extended_context_template); + Py_INCREF(extended_context_template); + CHECK_INT(PyModule_AddObject(m, "ExtendedContext", + extended_context_template)); + + + /* Init mpd_ssize_t constants */ + for (ssize_cm = ssize_constants; ssize_cm->name != NULL; ssize_cm++) { + ASSIGN_PTR(obj, PyLong_FromSsize_t(ssize_cm->val)); + CHECK_INT(PyModule_AddObject(m, ssize_cm->name, obj)); + } + + /* Init int constants */ + for (int_cm = int_constants; int_cm->name != NULL; int_cm++) { + CHECK_INT(PyModule_AddIntConstant(m, int_cm->name, + int_cm->val)); + } + + /* Add specification version number */ + CHECK_INT(PyModule_AddStringConstant(m, "__version__", " 1.70")); + + + return m; + + +error: + Py_XDECREF(obj); /* GCOV_NOT_REACHED */ + Py_XDECREF(numbers); /* GCOV_NOT_REACHED */ + Py_XDECREF(Number); /* GCOV_NOT_REACHED */ + Py_XDECREF(Rational); /* GCOV_NOT_REACHED */ + Py_XDECREF(collections); /* GCOV_NOT_REACHED */ + Py_XDECREF(MutableMapping); /* GCOV_NOT_REACHED */ + Py_XDECREF(SignalTuple); /* GCOV_NOT_REACHED */ + Py_XDECREF(DecimalTuple); /* GCOV_NOT_REACHED */ +#ifdef WITHOUT_THREADS + Py_XDECREF(module_context); /* GCOV_NOT_REACHED */ +#else + Py_XDECREF(default_context_template); /* GCOV_NOT_REACHED */ + Py_XDECREF(tls_context_key); /* GCOV_NOT_REACHED */ +#endif + Py_XDECREF(basic_context_template); /* GCOV_NOT_REACHED */ + Py_XDECREF(extended_context_template); /* GCOV_NOT_REACHED */ + Py_XDECREF(m); /* GCOV_NOT_REACHED */ + + return NULL; /* GCOV_NOT_REACHED */ +} + + diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/docstrings.h @@ -0,0 +1,753 @@ +/* + * Copyright (c) 2001-2012 Python Software Foundation. All Rights Reserved. + * Modified and extended by Stefan Krah. + */ + + +#ifndef DOCSTRINGS_H +#define DOCSTRINGS_H + + +#include "pymacro.h" + + +/******************************************************************************/ +/* Module */ +/******************************************************************************/ + + +PyDoc_STRVAR(doc__decimal, +"C decimal arithmetic module"); + +PyDoc_STRVAR(doc_getcontext,"\n\ +getcontext() - Get the current default context.\n\ +\n"); + +PyDoc_STRVAR(doc_setcontext,"\n\ +setcontext(c) - Set a new default context.\n\ +\n"); + +PyDoc_STRVAR(doc_localcontext,"\n\ +localcontext(c) - Return a context manager that will set the default context\n\ +to a copy of c on entry to the with-statement and restore the previous default\n\ +context when exiting the with-statement. If no context is specified, a copy of\n\ +the current default context is used.\n\ +\n"); + +#ifdef EXTRA_FUNCTIONALITY +PyDoc_STRVAR(doc_ieee_context,"\n\ +IEEEContext(bits) - Return a context object initialized to the proper values for\n\ +one of the IEEE interchange formats. The argument must be a multiple of 32 and\n\ +less than IEEE_CONTEXT_MAX_BITS. For the most common values, the constants\n\ +DECIMAL32, DECIMAL64 and DECIMAL128 are provided.\n\ +\n"); +#endif + + +/******************************************************************************/ +/* Decimal Object and Methods */ +/******************************************************************************/ + +PyDoc_STRVAR(doc_decimal,"\n\ +Decimal([value[, context]]): Construct a new Decimal object from value.\n\ +\n\ +value can be an integer, string, tuple, or another Decimal object.\n\ +If no value is given, return Decimal('0'). The context does not affect\n\ +the conversion and is only passed to determine if the InvalidOperation\n\ +trap is active.\n\ +\n"); + +PyDoc_STRVAR(doc_adjusted,"\n\ +adjusted() - Return the adjusted exponent of the number.\n\ +\n\ +Defined as exp + digits - 1.\n\ +\n"); + +PyDoc_STRVAR(doc_as_tuple,"\n\ +as_tuple() - Return a tuple representation of the number.\n\ +\n"); + +PyDoc_STRVAR(doc_canonical,"\n\ +canonical() - Return the canonical encoding of the argument. Currently,\n\ +the encoding of a Decimal instance is always canonical, so this operation\n\ +returns its argument unchanged.\n\ +\n"); + +PyDoc_STRVAR(doc_compare,"\n\ +compare(other[, context]) - Compare self to other. Return a decimal value:\n\ +\n\ + a or b is a NaN ==> Decimal('NaN')\n\ + a < b ==> Decimal('-1')\n\ + a == b ==> Decimal('0')\n\ + a > b ==> Decimal('1')\n\ +\n"); + +PyDoc_STRVAR(doc_compare_signal,"\n\ +compare_signal(other[, context]) - Identical to compare, except that\n\ +all NaNs signal.\n\ +\n"); + +PyDoc_STRVAR(doc_compare_total,"\n\ +compare_total(other) - Compare two operands using their abstract representation\n\ +rather than their numerical value. Similar to the compare() method, but the\n\ +result gives a total ordering on Decimal instances. Two Decimal instances with\n\ +the same numeric value but different representations compare unequal in this\n\ +ordering:\n\ +\n\ + >>> Decimal('12.0').compare_total(Decimal('12'))\n\ + Decimal('-1')\n\ +\n\ +Quiet and signaling NaNs are also included in the total ordering. The result\n\ +of this function is Decimal('0') if both operands have the same representation,\n\ +Decimal('-1') if the first operand is lower in the total order than the second,\n\ +and Decimal('1') if the first operand is higher in the total order than the\n\ +second operand. See the specification for details of the total order.\n\ +\n"); + +PyDoc_STRVAR(doc_compare_total_mag,"\n\ +compare_total_mag(other) - Compare two operands using their abstract\n\ +representation rather than their value as in compare_total(), but\n\ +ignoring the sign of each operand. x.compare_total_mag(y) is\n\ +equivalent to x.copy_abs().compare_total(y.copy_abs()).\n\ +\n"); + +PyDoc_STRVAR(doc_conjugate,"\n\ +conjugate() - Return self.\n\ +\n"); + +PyDoc_STRVAR(doc_copy_abs,"\n\ +copy_abs() - Return the absolute value of the argument. This operation\n\ +is unaffected by the context and is quiet: no flags are changed and no\n\ +rounding is performed.\n\ +\n"); + +PyDoc_STRVAR(doc_copy_negate,"\n\ +copy_negate() - Return the negation of the argument. This operation is\n\ +unaffected by the context and is quiet: no flags are changed and no\n\ +rounding is performed.\n\ +\n"); + +PyDoc_STRVAR(doc_copy_sign,"\n\ +copy_sign(other) - Return a copy of the first operand with the sign set\n\ +to be the same as the sign of the second operand. For example:\n\ +\n\ + >>> Decimal('2.3').copy_sign(Decimal('-1.5'))\n\ + Decimal('-2.3')\n\ +\n\ +This operation is unaffected by the context and is quiet: no flags are\n\ +changed and no rounding is performed.\n\ +\n"); + +PyDoc_STRVAR(doc_exp,"\n\ +exp([context]) - Return the value of the (natural) exponential function e**x\n\ +at the given number. The function always uses the ROUND_HALF_EVEN mode and\n\ +the result is correctly rounded.\n\ +\n"); + +PyDoc_STRVAR(doc_from_float,"\n\ +from_float(f) - Class method that converts a float to a decimal number, exactly.\n\ +Since 0.1 is not exactly representable in binary floating point,\n\ +Decimal.from_float(0.1) is not the same as Decimal('0.1').\n\ +\n\ + >>> Decimal.from_float(0.1)\n\ + Decimal('0.1000000000000000055511151231257827021181583404541015625')\n\ + >>> Decimal.from_float(float('nan'))\n\ + Decimal('NaN')\n\ + >>> Decimal.from_float(float('inf'))\n\ + Decimal('Infinity')\n\ + >>> Decimal.from_float(float('-inf'))\n\ + Decimal('-Infinity')\n\ +\n\ +\n"); + +PyDoc_STRVAR(doc_fma,"\n\ +fma(other, third[, context]) - Fused multiply-add. Return self*other+third\n\ +with no rounding of the intermediate product self*other.\n\ +\n\ + >>> Decimal(2).fma(3, 5)\n\ + Decimal('11')\n\ +\n\ +\n"); + +PyDoc_STRVAR(doc_is_canonical,"\n\ +is_canonical() - Return True if the argument is canonical and False otherwise.\n\ +Currently, a Decimal instance is always canonical, so this operation always\n\ +returns True.\n\ +\n"); + +PyDoc_STRVAR(doc_is_finite,"\n\ +is_finite() - Return True if the argument is a finite number, and False if the\n\ +argument is infinite or a NaN.\n\ +\n"); + +PyDoc_STRVAR(doc_is_infinite,"\n\ +is_infinite() - Return True if the argument is either positive or negative\n\ +infinity and False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_is_nan,"\n\ +is_nan() - Return True if the argument is a (quiet or signaling) NaN and\n\ +False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_is_normal,"\n\ +is_normal([context]) - Return True if the argument is a normal finite non-zero\n\ +number with an adjusted exponent greater than or equal to Emin. Return False\n\ +if the argument is zero, subnormal, infinite or a NaN.\n\ +\n"); + +PyDoc_STRVAR(doc_is_qnan,"\n\ +is_qnan() - Return True if the argument is a quiet NaN, and False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_is_signed,"\n\ +is_signed() - Return True if the argument has a negative sign and\n\ +False otherwise. Note that both zeros and NaNs can carry signs.\n\ +\n"); + +PyDoc_STRVAR(doc_is_snan,"\n\ +is_snan() - Return True if the argument is a signaling NaN and False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_is_subnormal,"\n\ +is_subnormal([context]) - Return True if the argument is subnormal, and False\n\ +otherwise. A number is subnormal if it is non-zero, finite, and has an\n\ +adjusted exponent less than Emin.\n\ +\n"); + +PyDoc_STRVAR(doc_is_zero,"\n\ +is_zero() - Return True if the argument is a (positive or negative) zero and\n\ +False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ln,"\n\ +ln([context]) - Return the natural (base e) logarithm of the operand.\n\ +The function always uses the ROUND_HALF_EVEN mode and the result is\n\ +correctly rounded.\n\ +\n"); + +PyDoc_STRVAR(doc_log10,"\n\ +log10([context]) - Return the base ten logarithm of the operand.\n\ +The function always uses the ROUND_HALF_EVEN mode and the result is\n\ +correctly rounded.\n\ +\n"); + +PyDoc_STRVAR(doc_logb,"\n\ +logb([context]) - For a non-zero number, return the adjusted exponent\n\ +of the operand as a Decimal instance. If the operand is a zero, then\n\ +Decimal('-Infinity') is returned and the DivisionByZero condition is\n\ +raised. If the operand is an infinity then Decimal('Infinity') is returned.\n\ +\n"); + +PyDoc_STRVAR(doc_logical_and,"\n\ +logical_and(other[, context]) - Return the digit-wise and of the two\n\ +(logical) operands.\n\ +\n"); + +PyDoc_STRVAR(doc_logical_invert,"\n\ +logical_invert([context]) - Return the digit-wise inversion of the\n\ +(logical) operand.\n\ +\n"); + +PyDoc_STRVAR(doc_logical_or,"\n\ +logical_or(other[, context]) - Return the digit-wise or of the two\n\ +(logical) operands.\n\ +\n"); + +PyDoc_STRVAR(doc_logical_xor,"\n\ +logical_xor(other[, context]) - Return the digit-wise exclusive or of the\n\ +two (logical) operands.\n\ +\n"); + +PyDoc_STRVAR(doc_max,"\n\ +max(other[, context]) - Maximum of self and other. If one operand is a quiet\n\ +NaN and the other is numeric, the numeric operand is returned.\n\ +\n"); + +PyDoc_STRVAR(doc_max_mag,"\n\ +max_mag(other[, context]) - Similar to the max() method, but the comparison is\n\ +done using the absolute values of the operands.\n\ +\n"); + +PyDoc_STRVAR(doc_min,"\n\ +min(other[, context]) - Minimum of self and other. If one operand is a quiet\n\ +NaN and the other is numeric, the numeric operand is returned.\n\ +\n"); + +PyDoc_STRVAR(doc_min_mag,"\n\ +min_mag(other[, context]) - Similar to the min() method, but the comparison is\n\ +done using the absolute values of the operands.\n\ +\n"); + +PyDoc_STRVAR(doc_next_minus,"\n\ +next_minus([context]) - Return the largest number representable in the given\n\ +context (or in the current default context if no context is given) that is\n\ +smaller than the given operand.\n\ +\n"); + +PyDoc_STRVAR(doc_next_plus,"\n\ +next_plus([context]) - Return the smallest number representable in the given\n\ +context (or in the current default context if no context is given) that is\n\ +larger than the given operand.\n\ +\n"); + +PyDoc_STRVAR(doc_next_toward,"\n\ +next_toward(other[, context]) - If the two operands are unequal, return the\n\ +number closest to the first operand in the direction of the second operand.\n\ +If both operands are numerically equal, return a copy of the first operand\n\ +with the sign set to be the same as the sign of the second operand.\n\ +\n"); + +PyDoc_STRVAR(doc_normalize,"\n\ +normalize([context]) - Normalize the number by stripping the rightmost trailing\n\ +zeros and converting any result equal to Decimal('0') to Decimal('0e0'). Used\n\ +for producing canonical values for members of an equivalence class. For example,\n\ +Decimal('32.100') and Decimal('0.321000e+2') both normalize to the equivalent\n\ +value Decimal('32.1').\n\ +\n"); + +PyDoc_STRVAR(doc_number_class,"\n\ +number_class([context]) - Return a string describing the class of the operand.\n\ +The returned value is one of the following ten strings:\n\ +\n\ + * '-Infinity', indicating that the operand is negative infinity.\n\ + * '-Normal', indicating that the operand is a negative normal number.\n\ + * '-Subnormal', indicating that the operand is negative and subnormal.\n\ + * '-Zero', indicating that the operand is a negative zero.\n\ + * '+Zero', indicating that the operand is a positive zero.\n\ + * '+Subnormal', indicating that the operand is positive and subnormal.\n\ + * '+Normal', indicating that the operand is a positive normal number.\n\ + * '+Infinity', indicating that the operand is positive infinity.\n\ + * 'NaN', indicating that the operand is a quiet NaN (Not a Number).\n\ + * 'sNaN', indicating that the operand is a signaling NaN.\n\ +\n\ +\n"); + +PyDoc_STRVAR(doc_quantize,"\n\ +quantize(exp[, rounding[, context]]) - Return a value equal to the first\n\ +operand after rounding and having the exponent of the second operand.\n\ +\n\ + >>> Decimal('1.41421356').quantize(Decimal('1.000'))\n\ + Decimal('1.414')\n\ +\n\ +Unlike other operations, if the length of the coefficient after the quantize\n\ +operation would be greater than precision, then an InvalidOperation is signaled.\n\ +This guarantees that, unless there is an error condition, the quantized exponent\n\ +is always equal to that of the right-hand operand.\n\ +\n\ +Also unlike other operations, quantize never signals Underflow, even if the\n\ +result is subnormal and inexact.\n\ +\n\ +If the exponent of the second operand is larger than that of the first, then\n\ +rounding may be necessary. In this case, the rounding mode is determined by the\n\ +rounding argument if given, else by the given context argument; if neither\n\ +argument is given, the rounding mode of the current thread's context is used.\n\ +\n"); + +PyDoc_STRVAR(doc_radix,"\n\ +radix() - Return Decimal(10), the radix (base) in which the Decimal class does\n\ +all its arithmetic. Included for compatibility with the specification.\n\ +\n"); + +PyDoc_STRVAR(doc_remainder_near,"\n\ +remainder_near(other[, context]) - Compute the modulo as either a positive\n\ +or negative value depending on which is closest to zero. For instance,\n\ +Decimal(10).remainder_near(6) returns Decimal('-2'), which is closer to zero\n\ +than Decimal('4').\n\ +\n\ +If both are equally close, the one chosen will have the same sign as self.\n\ +\n"); + +PyDoc_STRVAR(doc_rotate,"\n\ +rotate(other[, context]) - Return the result of rotating the digits of the\n\ +first operand by an amount specified by the second operand. The second operand\n\ +must be an integer in the range -precision through precision. The absolute\n\ +value of the second operand gives the number of places to rotate. If the second\n\ +operand is positive then rotation is to the left; otherwise rotation is to the\n\ +right. The coefficient of the first operand is padded on the left with zeros to\n\ +length precision if necessary. The sign and exponent of the first operand are\n\ +unchanged.\n\ +\n"); + +PyDoc_STRVAR(doc_same_quantum,"\n\ +same_quantum(other[, context]) - Test whether self and other have the\n\ +same exponent or whether both are NaN.\n\ +\n"); + +PyDoc_STRVAR(doc_scaleb,"\n\ +scaleb(other[, context]) - Return the first operand with the exponent adjusted\n\ +the second. Equivalently, return the first operand multiplied by 10**other.\n\ +The second operand must be an integer.\n\ +\n"); + +PyDoc_STRVAR(doc_shift,"\n\ +shift(other[, context]) - Return the result of shifting the digits of\n\ +the first operand by an amount specified by the second operand. The second\n\ +operand must be an integer in the range -precision through precision. The\n\ +absolute value of the second operand gives the number of places to shift.\n\ +If the second operand is positive, then the shift is to the left; otherwise\n\ +the shift is to the right. Digits shifted into the coefficient are zeros.\n\ +The sign and exponent of the first operand are unchanged.\n\ +\n"); + +PyDoc_STRVAR(doc_sqrt,"\n\ +sqrt([context]) - Return the square root of the argument to full precision.\n\ +The result is correctly rounded using the ROUND_HALF_EVEN rounding mode.\n\ +\n"); + +PyDoc_STRVAR(doc_to_eng_string,"\n\ +to_eng_string([context]) - Convert to an engineering-type string.\n\ +Engineering notation has an exponent which is a multiple of 3, so\n\ +there are up to 3 digits left of the decimal place. For example,\n\ +Decimal('123E+1') is converted to Decimal('1.23E+3')\n\ +\n"); + +PyDoc_STRVAR(doc_to_integral,"\n\ +to_integral([rounding[, context]]) - Identical to the to_integral_value()\n\ +method. The to_integral name has been kept for compatibility with older\n\ +versions.\n\ +\n"); + +PyDoc_STRVAR(doc_to_integral_exact,"\n\ +to_integral_exact([rounding[, context]]) - Round to the nearest integer,\n\ +signaling Inexact or Rounded as appropriate if rounding occurs. The rounding\n\ +mode is determined by the rounding parameter if given, else by the given\n\ +context. If neither parameter is given, then the rounding mode of the current\n\ +default context is used.\n\ +\n"); + +PyDoc_STRVAR(doc_to_integral_value,"\n\ +to_integral_value([rounding[, context]]) - Round to the nearest integer without\n\ +signaling Inexact or Rounded. The rounding mode is determined by the rounding\n\ +parameter if given, else by the given context. If neither parameter is given,\n\ +then the rounding mode of the current default context is used.\n\ +\n"); + + +/******************************************************************************/ +/* Context Object and Methods */ +/******************************************************************************/ + +PyDoc_STRVAR(doc_context,"\n\ +The context affects almost all operations and controls rounding,\n\ +Over/Underflow, raising of exceptions and much more. A new context\n\ +can be constructed as follows:\n\ +\n\ + >>> c = Context(prec=28, Emin=-425000000, Emax=425000000,\n\ + ... rounding=ROUND_HALF_EVEN, capitals=1, clamp=1,\n\ + ... traps=[InvalidOperation, DivisionByZero, Overflow],\n\ + ... flags=[])\n\ + >>>\n\ +\n\ +\n"); + +#ifdef EXTRA_FUNCTIONALITY +PyDoc_STRVAR(doc_ctx_apply,"\n\ +apply(x) - Apply self to Decimal x.\n\ +\n"); +#endif + +PyDoc_STRVAR(doc_ctx_clear_flags,"\n\ +clear_flags() - Reset all flags to False.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_clear_traps,"\n\ +clear_traps() - Set all traps to False.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy,"\n\ +copy() - Return a duplicate of the context with all flags cleared.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy_decimal,"\n\ +copy_decimal(x) - Return a copy of Decimal x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_create_decimal,"\n\ +create_decimal(x) - Create a new Decimal instance from x, using self as the\n\ +context. Unlike the Decimal constructor, this function observes the context\n\ +limits.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_create_decimal_from_float,"\n\ +create_decimal_from_float(f) - Create a new Decimal instance from float f.\n\ +Unlike the Decimal.from_float() class method, this function observes the\n\ +context limits.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_Etiny,"\n\ +Etiny() - Return a value equal to Emin - prec + 1, which is the minimum\n\ +exponent value for subnormal results. When underflow occurs, the exponent\n\ +is set to Etiny.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_Etop,"\n\ +Etop() - Return a value equal to Emax - prec + 1. This is the maximum exponent\n\ +if the _clamp field of the context is set to 1 (IEEE clamp mode). Etop() must\n\ +not be negative.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_abs,"\n\ +abs(x) - Return the absolute value of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_add,"\n\ +add(x, y) - Return the sum of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_canonical,"\n\ +canonical(x) - Return a new instance of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_compare,"\n\ +compare(x, y) - Compare x and y numerically.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_compare_signal,"\n\ +compare_signal(x, y) - Compare x and y numerically. All NaNs signal.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_compare_total,"\n\ +compare_total(x, y) - Compare x and y using their abstract representation.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_compare_total_mag,"\n\ +compare_total_mag(x, y) - Compare x and y using their abstract representation,\n\ +ignoring sign.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy_abs,"\n\ +copy_abs(x) - Return a copy of x with the sign set to 0.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy_negate,"\n\ +copy_negate(x) - Return a copy of x with the sign inverted.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy_sign,"\n\ +copy_sign(x, y) - Copy the sign from y to x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_divide,"\n\ +divide(x, y) - Return x divided by y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_divide_int,"\n\ +divide_int(x, y) - Return x divided by y, truncated to an integer.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_divmod,"\n\ +divmod(x, y) - Return quotient and remainder of the division x / y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_exp,"\n\ +exp(x) - Return e ** x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_fma,"\n\ +fma(x, y, z) - Return x multiplied by y, plus z.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_canonical,"\n\ +is_canonical(x) - Return True if x is canonical, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_finite,"\n\ +is_finite(x) - Return True if x is finite, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_infinite,"\n\ +is_infinite(x) - Return True if x is infinite, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_nan,"\n\ +is_nan(x) - Return True if x is a qNaN or sNaN, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_normal,"\n\ +is_normal(x) - Return True if x is a normal number, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_qnan,"\n\ +is_qnan(x) - Return True if x is a quiet NaN, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_signed,"\n\ +is_signed(x) - Return True if x is negative, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_snan,"\n\ +is_snan() - Return True if x is a signaling NaN, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_subnormal,"\n\ +is_subnormal(x) - Return True if x is subnormal, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_zero,"\n\ +is_zero(x) - Return True if x is a zero, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_ln,"\n\ +ln(x) - Return the natural (base e) logarithm of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_log10,"\n\ +log10(x) - Return the base 10 logarithm of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logb,"\n\ +logb(x) - Return the exponent of the magnitude of the operand's MSD.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logical_and,"\n\ +logical_and(x, y) - Digit-wise and of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logical_invert,"\n\ +logical_invert(x) - Invert all digits of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logical_or,"\n\ +logical_or(x, y) - Digit-wise or of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logical_xor,"\n\ +logical_xor(x, y) - Digit-wise xor of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_max,"\n\ +max(x, y) - Compare the values numerically and return the maximum.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_max_mag,"\n\ +max_mag(x, y) - Compare the values numerically with their sign ignored.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_min,"\n\ +min(x, y) - Compare the values numerically and return the minimum.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_min_mag,"\n\ +min_mag(x, y) - Compare the values numerically with their sign ignored.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_minus,"\n\ +minus(x) - Minus corresponds to the unary prefix minus operator in Python,\n\ +but applies the context to the result.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_multiply,"\n\ +multiply(x, y) - Return the product of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_next_minus,"\n\ +next_minus(x) - Return the largest representable number smaller than x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_next_plus,"\n\ +next_plus(x) - Return the smallest representable number larger than x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_next_toward,"\n\ +next_toward(x) - Return the number closest to x, in the direction towards y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_normalize,"\n\ +normalize(x) - Reduce x to its simplest form. Alias for reduce(x).\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_number_class,"\n\ +number_class(x) - Return an indication of the class of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_plus,"\n\ +plus(x) - Plus corresponds to the unary prefix plus operator in Python,\n\ +but applies the context to the result.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_power,"\n\ +power(x, y) - Compute x**y. If x is negative, then y must be integral.\n\ +The result will be inexact unless y is integral and the result is finite\n\ +and can be expressed exactly in 'precision' digits. In the Python version\n\ +the result is always correctly rounded, in the C version the result is\n\ +almost always correctly rounded.\n\ +\n\ +power(x, y, m) - Compute (x**y) % m. The following restrictions hold:\n\ +\n\ + * all three arguments must be integral\n\ + * y must be nonnegative\n\ + * at least one of x or y must be nonzero\n\ + * m must be nonzero and less than 10**prec in absolute value\n\ +\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_quantize,"\n\ +quantize(x, y) - Return a value equal to x (rounded), having the exponent of y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_radix,"\n\ +radix() - Return 10.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_remainder,"\n\ +remainder(x, y) - Return the remainder from integer division. The sign of\n\ +the result, if non-zero, is the same as that of the original dividend.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_remainder_near,"\n\ +remainder_near(x, y) - Return x - y * n, where n is the integer nearest the\n\ +exact value of x / y (if the result is 0 then its sign will be the sign of x).\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_rotate,"\n\ +rotate(x, y) - Return a copy of x, rotated by y places.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_same_quantum,"\n\ +same_quantum(x, y) - Return True if the two operands have the same exponent.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_scaleb,"\n\ +scaleb(x, y) - Return the first operand after adding the second value\n\ +to its exp.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_shift,"\n\ +shift(x, y) - Return a copy of x, shifted by y places.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_sqrt,"\n\ +sqrt(x) - Square root of a non-negative number to context precision.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_subtract,"\n\ +subtract(x, y) - Return the difference between x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_eng_string,"\n\ +to_eng_string(x) - Convert a number to a string, using engineering notation.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_integral,"\n\ +to_integral(x) - Identical to to_integral_value(x).\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_integral_exact,"\n\ +to_integral_exact(x) - Round to an integer. Signal if the result is\n\ +rounded or inexact.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_integral_value,"\n\ +to_integral_value(x) - Round to an integer.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_sci_string,"\n\ +to_sci_string(x) - Convert a number to a string using scientific notation.\n\ +\n"); + + +#endif /* DOCSTRINGS_H */ + + + diff --git a/Modules/_decimal/libmpdec/README.txt b/Modules/_decimal/libmpdec/README.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/README.txt @@ -0,0 +1,90 @@ + + +libmpdec +======== + +libmpdec is a fast C/C++ library for correctly-rounded arbitrary precision +decimal floating point arithmetic. It is a complete implementation of +Mike Cowlishaw/IBM's General Decimal Arithmetic Specification. + + +Files required for the Python _decimal module +============================================= + + Core files for small and medium precision arithmetic + ---------------------------------------------------- + + basearith.{c,h} -> Core arithmetic in base 10**9 or 10**19. + bits.h -> Portable detection of least/most significant one-bit. + constants.{c,h} -> Constants that are used in multiple files. + context.c -> Context functions. + io.{c,h} -> Conversions between mpd_t and ASCII strings, + mpd_t formatting (allows UTF-8 fill character). + memory.{c,h} -> Allocation handlers with overflow detection + and functions for switching between static + and dynamic mpd_t. + mpdecimal.{c,h} -> All (quiet) functions of the specification. + typearith.h -> Fast primitives for double word multiplication, + division etc. + + Visual Studio only: + ~~~~~~~~~~~~~~~~~~~ + vccompat.h -> snprintf <==> sprintf_s and similar things. + vcstdint.h -> stdint.h (included in VS 2010 but not in VS 2008). + vcdiv64.asm -> Double word division used in typearith.h. VS 2008 does + not allow inline asm for x64. Also, it does not provide + an intrinsic for double word division. + + Files for bignum arithmetic: + ---------------------------- + + The following files implement the Fast Number Theoretic Transform + used for multiplying coefficients with more than 1024 words (see + mpdecimal.c: _mpd_fntmul()). + + umodarith.h -> Fast low level routines for unsigned modular arithmetic. + numbertheory.{c,h} -> Routines for setting up the Number Theoretic Transform. + difradix2.{c,h} -> Decimation in frequency transform, used as the + "base case" by the following three files: + + fnt.{c,h} -> Transform arrays up to 4096 words. + sixstep.{c,h} -> Transform larger arrays of length 2**n. + fourstep.{c,h} -> Transform larger arrays of length 3 * 2**n. + + convolute.{c,h} -> Fast convolution using one of the three transform + functions. + transpose.{c,h} -> Transpositions needed for the sixstep algorithm. + crt.{c,h} -> Chinese Remainder Theorem: use information from three + transforms modulo three different primes to get the + final result. + + +Pointers to literature, proofs and more +======================================= + + literature/ + ----------- + + REFERENCES.txt -> List of relevant papers. + bignum.txt -> Explanation of the Fast Number Theoretic Transform (FNT). + fnt.py -> Verify constants used in the FNT; Python demo for the + O(N**2) discrete transform. + + matrix-transform.txt -> Proof for the Matrix Fourier Transform used in + fourstep.c. + six-step.txt -> Show that the algorithm used in sixstep.c is + a variant of the Matrix Fourier Transform. + mulmod-64.txt -> Proof for the mulmod64 algorithm from + umodarith.h. + mulmod-ppro.txt -> Proof for the x87 FPU modular multiplication + from umodarith.h. + umodarith.lisp -> ACL2 proofs for many functions from umodarith.h. + + +Library Author +============== + + Stefan Krah + + + diff --git a/Modules/_decimal/libmpdec/basearith.c b/Modules/_decimal/libmpdec/basearith.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/basearith.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include +#include "constants.h" +#include "memory.h" +#include "typearith.h" +#include "basearith.h" + + +/*********************************************************************/ +/* Calculations in base MPD_RADIX */ +/*********************************************************************/ + + +/* + * Knuth, TAOCP, Volume 2, 4.3.1: + * w := sum of u (len m) and v (len n) + * n > 0 and m >= n + * The calling function has to handle a possible final carry. + */ +mpd_uint_t +_mpd_baseadd(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n) +{ + mpd_uint_t s; + mpd_uint_t carry = 0; + mpd_size_t i; + + assert(n > 0 && m >= n); + + /* add n members of u and v */ + for (i = 0; i < n; i++) { + s = u[i] + (v[i] + carry); + carry = (s < u[i]) | (s >= MPD_RADIX); + w[i] = carry ? s-MPD_RADIX : s; + } + /* if there is a carry, propagate it */ + for (; carry && i < m; i++) { + s = u[i] + carry; + carry = (s == MPD_RADIX); + w[i] = carry ? 0 : s; + } + /* copy the rest of u */ + for (; i < m; i++) { + w[i] = u[i]; + } + + return carry; +} + +/* + * Add the contents of u to w. Carries are propagated further. The caller + * has to make sure that w is big enough. + */ +void +_mpd_baseaddto(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n) +{ + mpd_uint_t s; + mpd_uint_t carry = 0; + mpd_size_t i; + + if (n == 0) return; + + /* add n members of u to w */ + for (i = 0; i < n; i++) { + s = w[i] + (u[i] + carry); + carry = (s < w[i]) | (s >= MPD_RADIX); + w[i] = carry ? s-MPD_RADIX : s; + } + /* if there is a carry, propagate it */ + for (; carry; i++) { + s = w[i] + carry; + carry = (s == MPD_RADIX); + w[i] = carry ? 0 : s; + } +} + +/* + * Add v to w (len m). The calling function has to handle a possible + * final carry. Assumption: m > 0. + */ +mpd_uint_t +_mpd_shortadd(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v) +{ + mpd_uint_t s; + mpd_uint_t carry; + mpd_size_t i; + + assert(m > 0); + + /* add v to w */ + s = w[0] + v; + carry = (s < v) | (s >= MPD_RADIX); + w[0] = carry ? s-MPD_RADIX : s; + + /* if there is a carry, propagate it */ + for (i = 1; carry && i < m; i++) { + s = w[i] + carry; + carry = (s == MPD_RADIX); + w[i] = carry ? 0 : s; + } + + return carry; +} + +/* Increment u. The calling function has to handle a possible carry. */ +mpd_uint_t +_mpd_baseincr(mpd_uint_t *u, mpd_size_t n) +{ + mpd_uint_t s; + mpd_uint_t carry = 1; + mpd_size_t i; + + assert(n > 0); + + /* if there is a carry, propagate it */ + for (i = 0; carry && i < n; i++) { + s = u[i] + carry; + carry = (s == MPD_RADIX); + u[i] = carry ? 0 : s; + } + + return carry; +} + +/* + * Knuth, TAOCP, Volume 2, 4.3.1: + * w := difference of u (len m) and v (len n). + * number in u >= number in v; + */ +void +_mpd_basesub(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n) +{ + mpd_uint_t d; + mpd_uint_t borrow = 0; + mpd_size_t i; + + assert(m > 0 && n > 0); + + /* subtract n members of v from u */ + for (i = 0; i < n; i++) { + d = u[i] - (v[i] + borrow); + borrow = (u[i] < d); + w[i] = borrow ? d + MPD_RADIX : d; + } + /* if there is a borrow, propagate it */ + for (; borrow && i < m; i++) { + d = u[i] - borrow; + borrow = (u[i] == 0); + w[i] = borrow ? MPD_RADIX-1 : d; + } + /* copy the rest of u */ + for (; i < m; i++) { + w[i] = u[i]; + } +} + +/* + * Subtract the contents of u from w. w is larger than u. Borrows are + * propagated further, but eventually w can absorb the final borrow. + */ +void +_mpd_basesubfrom(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n) +{ + mpd_uint_t d; + mpd_uint_t borrow = 0; + mpd_size_t i; + + if (n == 0) return; + + /* subtract n members of u from w */ + for (i = 0; i < n; i++) { + d = w[i] - (u[i] + borrow); + borrow = (w[i] < d); + w[i] = borrow ? d + MPD_RADIX : d; + } + /* if there is a borrow, propagate it */ + for (; borrow; i++) { + d = w[i] - borrow; + borrow = (w[i] == 0); + w[i] = borrow ? MPD_RADIX-1 : d; + } +} + +/* w := product of u (len n) and v (single word) */ +void +_mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v) +{ + mpd_uint_t hi, lo; + mpd_uint_t carry = 0; + mpd_size_t i; + + assert(n > 0); + + for (i=0; i < n; i++) { + + _mpd_mul_words(&hi, &lo, u[i], v); + lo = carry + lo; + if (lo < carry) hi++; + + _mpd_div_words_r(&carry, &w[i], hi, lo); + } + w[i] = carry; +} + +/* + * Knuth, TAOCP, Volume 2, 4.3.1: + * w := product of u (len m) and v (len n) + * w must be initialized to zero + */ +void +_mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n) +{ + mpd_uint_t hi, lo; + mpd_uint_t carry; + mpd_size_t i, j; + + assert(m > 0 && n > 0); + + for (j=0; j < n; j++) { + carry = 0; + for (i=0; i < m; i++) { + + _mpd_mul_words(&hi, &lo, u[i], v[j]); + lo = w[i+j] + lo; + if (lo < w[i+j]) hi++; + lo = carry + lo; + if (lo < carry) hi++; + + _mpd_div_words_r(&carry, &w[i+j], hi, lo); + } + w[j+m] = carry; + } +} + +/* + * Knuth, TAOCP Volume 2, 4.3.1, exercise 16: + * w := quotient of u (len n) divided by a single word v + */ +mpd_uint_t +_mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v) +{ + mpd_uint_t hi, lo; + mpd_uint_t rem = 0; + mpd_size_t i; + + assert(n > 0); + + for (i=n-1; i != MPD_SIZE_MAX; i--) { + + _mpd_mul_words(&hi, &lo, rem, MPD_RADIX); + lo = u[i] + lo; + if (lo < u[i]) hi++; + + _mpd_div_words(&w[i], &rem, hi, lo, v); + } + + return rem; +} + +/* + * Knuth, TAOCP Volume 2, 4.3.1: + * q, r := quotient and remainder of uconst (len nplusm) + * divided by vconst (len n) + * nplusm >= n + * + * If r is not NULL, r will contain the remainder. If r is NULL, the + * return value indicates if there is a remainder: 1 for true, 0 for + * false. A return value of -1 indicates an error. + */ +int +_mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r, + const mpd_uint_t *uconst, const mpd_uint_t *vconst, + mpd_size_t nplusm, mpd_size_t n) +{ + mpd_uint_t ustatic[MPD_MINALLOC_MAX]; + mpd_uint_t vstatic[MPD_MINALLOC_MAX]; + mpd_uint_t *u = ustatic; + mpd_uint_t *v = vstatic; + mpd_uint_t d, qhat, rhat, w2[2]; + mpd_uint_t hi, lo, x; + mpd_uint_t carry; + mpd_size_t i, j, m; + int retval = 0; + + assert(n > 1 && nplusm >= n); + m = sub_size_t(nplusm, n); + + /* D1: normalize */ + d = MPD_RADIX / (vconst[n-1] + 1); + + if (nplusm >= MPD_MINALLOC_MAX) { + if ((u = mpd_alloc(nplusm+1, sizeof *u)) == NULL) { + return -1; + } + } + if (n >= MPD_MINALLOC_MAX) { + if ((v = mpd_alloc(n+1, sizeof *v)) == NULL) { + mpd_free(u); + return -1; + } + } + + _mpd_shortmul(u, uconst, nplusm, d); + _mpd_shortmul(v, vconst, n, d); + + /* D2: loop */ + for (j=m; j != MPD_SIZE_MAX; j--) { + + /* D3: calculate qhat and rhat */ + rhat = _mpd_shortdiv(w2, u+j+n-1, 2, v[n-1]); + qhat = w2[1] * MPD_RADIX + w2[0]; + + while (1) { + if (qhat < MPD_RADIX) { + _mpd_singlemul(w2, qhat, v[n-2]); + if (w2[1] <= rhat) { + if (w2[1] != rhat || w2[0] <= u[j+n-2]) { + break; + } + } + } + qhat -= 1; + rhat += v[n-1]; + if (rhat < v[n-1] || rhat >= MPD_RADIX) { + break; + } + } + /* D4: multiply and subtract */ + carry = 0; + for (i=0; i <= n; i++) { + + _mpd_mul_words(&hi, &lo, qhat, v[i]); + + lo = carry + lo; + if (lo < carry) hi++; + + _mpd_div_words_r(&hi, &lo, hi, lo); + + x = u[i+j] - lo; + carry = (u[i+j] < x); + u[i+j] = carry ? x+MPD_RADIX : x; + carry += hi; + } + q[j] = qhat; + /* D5: test remainder */ + if (carry) { + q[j] -= 1; + /* D6: add back */ + (void)_mpd_baseadd(u+j, u+j, v, n+1, n); + } + } + + /* D8: unnormalize */ + if (r != NULL) { + _mpd_shortdiv(r, u, n, d); + /* we are not interested in the return value here */ + retval = 0; + } + else { + retval = !_mpd_isallzero(u, n); + } + + +if (u != ustatic) mpd_free(u); +if (v != vstatic) mpd_free(v); +return retval; +} + +/* + * Left shift of src by 'shift' digits; src may equal dest. + * + * dest := area of n mpd_uint_t with space for srcdigits+shift digits. + * src := coefficient with length m. + * + * The case splits in the function are non-obvious. The following + * equations might help: + * + * Let msdigits denote the number of digits in the most significant + * word of src. Then 1 <= msdigits <= rdigits. + * + * 1) shift = q * rdigits + r + * 2) srcdigits = qsrc * rdigits + msdigits + * 3) destdigits = shift + srcdigits + * = q * rdigits + r + qsrc * rdigits + msdigits + * = q * rdigits + (qsrc * rdigits + (r + msdigits)) + * + * The result has q zero words, followed by the coefficient that + * is left-shifted by r. The case r == 0 is trivial. For r > 0, it + * is important to keep in mind that we always read m source words, + * but write m+1 destination words if r + msdigits > rdigits, m words + * otherwise. + */ +void +_mpd_baseshiftl(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t n, mpd_size_t m, + mpd_size_t shift) +{ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) + /* spurious uninitialized warnings */ + mpd_uint_t l=l, lprev=lprev, h=h; +#else + mpd_uint_t l, lprev, h; +#endif + mpd_uint_t q, r; + mpd_uint_t ph; + + assert(m > 0 && n >= m); + + _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS); + + if (r != 0) { + + ph = mpd_pow10[r]; + + --m; --n; + _mpd_divmod_pow10(&h, &lprev, src[m--], MPD_RDIGITS-r); + if (h != 0) { /* r + msdigits > rdigits <==> h != 0 */ + dest[n--] = h; + } + /* write m-1 shifted words */ + for (; m != MPD_SIZE_MAX; m--,n--) { + _mpd_divmod_pow10(&h, &l, src[m], MPD_RDIGITS-r); + dest[n] = ph * lprev + h; + lprev = l; + } + /* write least significant word */ + dest[q] = ph * lprev; + } + else { + while (--m != MPD_SIZE_MAX) { + dest[m+q] = src[m]; + } + } + + mpd_uint_zero(dest, q); +} + +/* + * Right shift of src by 'shift' digits; src may equal dest. + * Assumption: srcdigits-shift > 0. + * + * dest := area with space for srcdigits-shift digits. + * src := coefficient with length 'slen'. + * + * The case splits in the function rely on the following equations: + * + * Let msdigits denote the number of digits in the most significant + * word of src. Then 1 <= msdigits <= rdigits. + * + * 1) shift = q * rdigits + r + * 2) srcdigits = qsrc * rdigits + msdigits + * 3) destdigits = srcdigits - shift + * = qsrc * rdigits + msdigits - (q * rdigits + r) + * = (qsrc - q) * rdigits + msdigits - r + * + * Since destdigits > 0 and 1 <= msdigits <= rdigits: + * + * 4) qsrc >= q + * 5) qsrc == q ==> msdigits > r + * + * The result has slen-q words if msdigits > r, slen-q-1 words otherwise. + */ +mpd_uint_t +_mpd_baseshiftr(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t slen, + mpd_size_t shift) +{ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) + /* spurious uninitialized warnings */ + mpd_uint_t l=l, h=h, hprev=hprev; /* low, high, previous high */ +#else + mpd_uint_t l, h, hprev; /* low, high, previous high */ +#endif + mpd_uint_t rnd, rest; /* rounding digit, rest */ + mpd_uint_t q, r; + mpd_size_t i, j; + mpd_uint_t ph; + + assert(slen > 0); + + _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS); + + rnd = rest = 0; + if (r != 0) { + + ph = mpd_pow10[MPD_RDIGITS-r]; + + _mpd_divmod_pow10(&hprev, &rest, src[q], r); + _mpd_divmod_pow10(&rnd, &rest, rest, r-1); + + if (rest == 0 && q > 0) { + rest = !_mpd_isallzero(src, q); + } + /* write slen-q-1 words */ + for (j=0,i=q+1; i 0) { + _mpd_divmod_pow10(&rnd, &rest, src[q-1], MPD_RDIGITS-1); + /* is there any non-zero digit below rnd? */ + if (rest == 0) rest = !_mpd_isallzero(src, q-1); + } + for (j = 0; j < slen-q; j++) { + dest[j] = src[q+j]; + } + } + + /* 0-4 ==> rnd+rest < 0.5 */ + /* 5 ==> rnd+rest == 0.5 */ + /* 6-9 ==> rnd+rest > 0.5 */ + return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd; +} + + +/*********************************************************************/ +/* Calculations in base b */ +/*********************************************************************/ + +/* + * Add v to w (len m). The calling function has to handle a possible + * final carry. Assumption: m > 0. + */ +mpd_uint_t +_mpd_shortadd_b(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v, mpd_uint_t b) +{ + mpd_uint_t s; + mpd_uint_t carry; + mpd_size_t i; + + assert(m > 0); + + /* add v to w */ + s = w[0] + v; + carry = (s < v) | (s >= b); + w[0] = carry ? s-b : s; + + /* if there is a carry, propagate it */ + for (i = 1; carry && i < m; i++) { + s = w[i] + carry; + carry = (s == b); + w[i] = carry ? 0 : s; + } + + return carry; +} + +/* w := product of u (len n) and v (single word) */ +void +_mpd_shortmul_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v, mpd_uint_t b) +{ + mpd_uint_t hi, lo; + mpd_uint_t carry = 0; + mpd_size_t i; + + assert(n > 0); + + for (i=0; i < n; i++) { + + _mpd_mul_words(&hi, &lo, u[i], v); + lo = carry + lo; + if (lo < carry) hi++; + + _mpd_div_words(&carry, &w[i], hi, lo, b); + } + w[i] = carry; +} + +/* + * Knuth, TAOCP Volume 2, 4.3.1, exercise 16: + * w := quotient of u (len n) divided by a single word v + */ +mpd_uint_t +_mpd_shortdiv_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v, mpd_uint_t b) +{ + mpd_uint_t hi, lo; + mpd_uint_t rem = 0; + mpd_size_t i; + + assert(n > 0); + + for (i=n-1; i != MPD_SIZE_MAX; i--) { + + _mpd_mul_words(&hi, &lo, rem, b); + lo = u[i] + lo; + if (lo < u[i]) hi++; + + _mpd_div_words(&w[i], &rem, hi, lo, v); + } + + return rem; +} + + + diff --git a/Modules/_decimal/libmpdec/basearith.h b/Modules/_decimal/libmpdec/basearith.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/basearith.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef BASEARITH_H +#define BASEARITH_H + + +#include "mpdecimal.h" +#include +#include "typearith.h" + + +mpd_uint_t _mpd_baseadd(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n); +void _mpd_baseaddto(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n); +mpd_uint_t _mpd_shortadd(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v); +mpd_uint_t _mpd_shortadd_b(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v, + mpd_uint_t b); +mpd_uint_t _mpd_baseincr(mpd_uint_t *u, mpd_size_t n); +void _mpd_basesub(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n); +void _mpd_basesubfrom(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n); +void _mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n); +void _mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v); +void _mpd_shortmul_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v, mpd_uint_t b); +mpd_uint_t _mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v); +mpd_uint_t _mpd_shortdiv_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v, mpd_uint_t b); +int _mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r, const mpd_uint_t *uconst, + const mpd_uint_t *vconst, mpd_size_t nplusm, mpd_size_t n); +void _mpd_baseshiftl(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t n, + mpd_size_t m, mpd_size_t shift); +mpd_uint_t _mpd_baseshiftr(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t slen, + mpd_size_t shift); + + + +#ifdef CONFIG_64 +extern const mpd_uint_t mprime_rdx; + +/* + * Algorithm from: Division by Invariant Integers using Multiplication, + * T. Granlund and P. L. Montgomery, Proceedings of the SIGPLAN '94 + * Conference on Programming Language Design and Implementation. + * + * http://gmplib.org/~tege/divcnst-pldi94.pdf + * + * Variables from the paper and their translations (See section 8): + * + * N := 64 + * d := MPD_RADIX + * l := 64 + * m' := floor((2**(64+64) - 1)/MPD_RADIX) - 2**64 + * + * Since N-l == 0: + * + * dnorm := d + * n2 := hi + * n10 := lo + * + * ACL2 proof: mpd-div-words-r-correct + */ +static inline void +_mpd_div_words_r(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo) +{ + mpd_uint_t n_adj, h, l, t; + mpd_uint_t n1_neg; + + /* n1_neg = if lo >= 2**63 then MPD_UINT_MAX else 0 */ + n1_neg = (lo & (1ULL<<63)) ? MPD_UINT_MAX : 0; + /* n_adj = if lo >= 2**63 then lo+MPD_RADIX else lo */ + n_adj = lo + (n1_neg & MPD_RADIX); + + /* (h, l) = if lo >= 2**63 then m'*(hi+1) else m'*hi */ + _mpd_mul_words(&h, &l, mprime_rdx, hi-n1_neg); + l = l + n_adj; + if (l < n_adj) h++; + t = h + hi; + /* At this point t == qest, with q == qest or q == qest+1: + * 1) 0 <= 2**64*hi + lo - qest*MPD_RADIX < 2*MPD_RADIX + */ + + /* t = 2**64-1 - qest = 2**64 - (qest+1) */ + t = MPD_UINT_MAX - t; + + /* (h, l) = 2**64*MPD_RADIX - (qest+1)*MPD_RADIX */ + _mpd_mul_words(&h, &l, t, MPD_RADIX); + l = l + lo; + if (l < lo) h++; + h += hi; + h -= MPD_RADIX; + /* (h, l) = 2**64*hi + lo - (qest+1)*MPD_RADIX (mod 2**128) + * Case q == qest+1: + * a) h == 0, l == r + * b) q := h - t == qest+1 + * c) r := l + * Case q == qest: + * a) h == MPD_UINT_MAX, l == 2**64-(MPD_RADIX-r) + * b) q := h - t == qest + * c) r := l + MPD_RADIX = r + */ + + *q = (h - t); + *r = l + (MPD_RADIX & h); +} +#else +static inline void +_mpd_div_words_r(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo) +{ + _mpd_div_words(q, r, hi, lo, MPD_RADIX); +} +#endif + + +/* Multiply two single base MPD_RADIX words, store result in array w[2]. */ +static inline void +_mpd_singlemul(mpd_uint_t w[2], mpd_uint_t u, mpd_uint_t v) +{ + mpd_uint_t hi, lo; + + _mpd_mul_words(&hi, &lo, u, v); + _mpd_div_words_r(&w[1], &w[0], hi, lo); +} + +/* Multiply u (len 2) and v (len m, 1 <= m <= 2). */ +static inline void +_mpd_mul_2_le2(mpd_uint_t w[4], mpd_uint_t u[2], mpd_uint_t v[2], mpd_ssize_t m) +{ + mpd_uint_t hi, lo; + + _mpd_mul_words(&hi, &lo, u[0], v[0]); + _mpd_div_words_r(&w[1], &w[0], hi, lo); + + _mpd_mul_words(&hi, &lo, u[1], v[0]); + lo = w[1] + lo; + if (lo < w[1]) hi++; + _mpd_div_words_r(&w[2], &w[1], hi, lo); + if (m == 1) return; + + _mpd_mul_words(&hi, &lo, u[0], v[1]); + lo = w[1] + lo; + if (lo < w[1]) hi++; + _mpd_div_words_r(&w[3], &w[1], hi, lo); + + _mpd_mul_words(&hi, &lo, u[1], v[1]); + lo = w[2] + lo; + if (lo < w[2]) hi++; + lo = w[3] + lo; + if (lo < w[3]) hi++; + _mpd_div_words_r(&w[3], &w[2], hi, lo); +} + + +/* + * Test if all words from data[len-1] to data[0] are zero. If len is 0, nothing + * is tested and the coefficient is regarded as "all zero". + */ +static inline int +_mpd_isallzero(const mpd_uint_t *data, mpd_ssize_t len) +{ + while (--len >= 0) { + if (data[len] != 0) return 0; + } + return 1; +} + +/* + * Test if all full words from data[len-1] to data[0] are MPD_RADIX-1 + * (all nines). Return true if len == 0. + */ +static inline int +_mpd_isallnine(const mpd_uint_t *data, mpd_ssize_t len) +{ + while (--len >= 0) { + if (data[len] != MPD_RADIX-1) return 0; + } + return 1; +} + + +#endif /* BASEARITH_H */ + + + diff --git a/Modules/_decimal/libmpdec/bits.h b/Modules/_decimal/libmpdec/bits.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/bits.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef BITS_H +#define BITS_H + + +#include "mpdecimal.h" +#include + + +/* Check if n is a power of 2. */ +static inline int +ispower2(mpd_size_t n) +{ + return n != 0 && (n & (n-1)) == 0; +} + +#if defined(ANSI) +/* + * Return the most significant bit position of n from 0 to 31 (63). + * Assumptions: n != 0. + */ +static inline int +mpd_bsr(mpd_size_t n) +{ + int pos = 0; + mpd_size_t tmp; + +#ifdef CONFIG_64 + tmp = n >> 32; + if (tmp != 0) { n = tmp; pos += 32; } +#endif + tmp = n >> 16; + if (tmp != 0) { n = tmp; pos += 16; } + tmp = n >> 8; + if (tmp != 0) { n = tmp; pos += 8; } + tmp = n >> 4; + if (tmp != 0) { n = tmp; pos += 4; } + tmp = n >> 2; + if (tmp != 0) { n = tmp; pos += 2; } + tmp = n >> 1; + if (tmp != 0) { n = tmp; pos += 1; } + + return pos + (int)n - 1; +} + +/* + * Return the least significant bit position of n from 0 to 31 (63). + * Assumptions: n != 0. + */ +static inline int +mpd_bsf(mpd_size_t n) +{ + int pos; + +#ifdef CONFIG_64 + pos = 63; + if (n & 0x00000000FFFFFFFFULL) { pos -= 32; } else { n >>= 32; } + if (n & 0x000000000000FFFFULL) { pos -= 16; } else { n >>= 16; } + if (n & 0x00000000000000FFULL) { pos -= 8; } else { n >>= 8; } + if (n & 0x000000000000000FULL) { pos -= 4; } else { n >>= 4; } + if (n & 0x0000000000000003ULL) { pos -= 2; } else { n >>= 2; } + if (n & 0x0000000000000001ULL) { pos -= 1; } +#else + pos = 31; + if (n & 0x000000000000FFFFUL) { pos -= 16; } else { n >>= 16; } + if (n & 0x00000000000000FFUL) { pos -= 8; } else { n >>= 8; } + if (n & 0x000000000000000FUL) { pos -= 4; } else { n >>= 4; } + if (n & 0x0000000000000003UL) { pos -= 2; } else { n >>= 2; } + if (n & 0x0000000000000001UL) { pos -= 1; } +#endif + return pos; +} +/* END ANSI */ + +#elif defined(ASM) +/* + * Bit scan reverse. Assumptions: a != 0. + */ +static inline int +mpd_bsr(mpd_size_t a) +{ + mpd_size_t retval; + + __asm__ ( +#ifdef CONFIG_64 + "bsrq %1, %0\n\t" +#else + "bsr %1, %0\n\t" +#endif + :"=r" (retval) + :"r" (a) + :"cc" + ); + + return (int)retval; +} + +/* + * Bit scan forward. Assumptions: a != 0. + */ +static inline int +mpd_bsf(mpd_size_t a) +{ + mpd_size_t retval; + + __asm__ ( +#ifdef CONFIG_64 + "bsfq %1, %0\n\t" +#else + "bsf %1, %0\n\t" +#endif + :"=r" (retval) + :"r" (a) + :"cc" + ); + + return (int)retval; +} +/* END ASM */ + +#elif defined(MASM) +#include +/* + * Bit scan reverse. Assumptions: a != 0. + */ +static inline int __cdecl +mpd_bsr(mpd_size_t a) +{ + unsigned long retval; + +#ifdef CONFIG_64 + _BitScanReverse64(&retval, a); +#else + _BitScanReverse(&retval, a); +#endif + + return (int)retval; +} + +/* + * Bit scan forward. Assumptions: a != 0. + */ +static inline int __cdecl +mpd_bsf(mpd_size_t a) +{ + unsigned long retval; + +#ifdef CONFIG_64 + _BitScanForward64(&retval, a); +#else + _BitScanForward(&retval, a); +#endif + + return (int)retval; +} +/* END MASM (_MSC_VER) */ +#else + #error "missing preprocessor definitions" +#endif /* BSR/BSF */ + + +#endif /* BITS_H */ + + + diff --git a/Modules/_decimal/libmpdec/constants.c b/Modules/_decimal/libmpdec/constants.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/constants.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include "constants.h" + + +#if defined(CONFIG_64) + + /* number-theory.c */ + const mpd_uint_t mpd_moduli[3] = { + 18446744069414584321ULL, 18446744056529682433ULL, 18446742974197923841ULL + }; + const mpd_uint_t mpd_roots[3] = {7ULL, 10ULL, 19ULL}; + + /* crt.c */ + const mpd_uint_t INV_P1_MOD_P2 = 18446744055098026669ULL; + const mpd_uint_t INV_P1P2_MOD_P3 = 287064143708160ULL; + const mpd_uint_t LH_P1P2 = 18446744052234715137ULL; /* (P1*P2) % 2^64 */ + const mpd_uint_t UH_P1P2 = 18446744052234715141ULL; /* (P1*P2) / 2^64 */ + + /* transpose.c */ + const mpd_size_t mpd_bits[64] = { + 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, + 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, + 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, + 2147483648ULL, 4294967296ULL, 8589934592ULL, 17179869184ULL, 34359738368ULL, + 68719476736ULL, 137438953472ULL, 274877906944ULL, 549755813888ULL, + 1099511627776ULL, 2199023255552ULL, 4398046511104, 8796093022208ULL, + 17592186044416ULL, 35184372088832ULL, 70368744177664ULL, 140737488355328ULL, + 281474976710656ULL, 562949953421312ULL, 1125899906842624ULL, + 2251799813685248ULL, 4503599627370496ULL, 9007199254740992ULL, + 18014398509481984ULL, 36028797018963968ULL, 72057594037927936ULL, + 144115188075855872ULL, 288230376151711744ULL, 576460752303423488ULL, + 1152921504606846976ULL, 2305843009213693952ULL, 4611686018427387904ULL, + 9223372036854775808ULL + }; + + /* mpdecimal.c */ + const mpd_uint_t mpd_pow10[MPD_RDIGITS+1] = { + 1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000, + 10000000000ULL,100000000000ULL,1000000000000ULL,10000000000000ULL, + 100000000000000ULL,1000000000000000ULL,10000000000000000ULL, + 100000000000000000ULL,1000000000000000000ULL,10000000000000000000ULL + }; + + /* magic number for constant division by MPD_RADIX */ + const mpd_uint_t mprime_rdx = 15581492618384294730ULL; + +#elif defined(CONFIG_32) + + /* number-theory.c */ + const mpd_uint_t mpd_moduli[3] = {2113929217UL, 2013265921UL, 1811939329UL}; + const mpd_uint_t mpd_roots[3] = {5UL, 31UL, 13UL}; + + /* PentiumPro modular multiplication: These constants have to be loaded as + * 80 bit long doubles, which are not supported by certain compilers. */ + const uint32_t mpd_invmoduli[3][3] = { + {4293885170U, 2181570688U, 16352U}, /* ((long double) 1 / 2113929217UL) */ + {1698898177U, 2290649223U, 16352U}, /* ((long double) 1 / 2013265921UL) */ + {2716021846U, 2545165803U, 16352U} /* ((long double) 1 / 1811939329UL) */ + }; + + const float MPD_TWO63 = 9223372036854775808.0; /* 2^63 */ + + /* crt.c */ + const mpd_uint_t INV_P1_MOD_P2 = 2013265901UL; + const mpd_uint_t INV_P1P2_MOD_P3 = 54UL; + const mpd_uint_t LH_P1P2 = 4127195137UL; /* (P1*P2) % 2^32 */ + const mpd_uint_t UH_P1P2 = 990904320UL; /* (P1*P2) / 2^32 */ + + /* transpose.c */ + const mpd_size_t mpd_bits[32] = { + 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, + 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, + 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, + 2147483648UL + }; + + /* mpdecimal.c */ + const mpd_uint_t mpd_pow10[MPD_RDIGITS+1] = { + 1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000 + }; + +#else + #error "CONFIG_64 or CONFIG_32 must be defined." +#endif + +const char *mpd_round_string[MPD_ROUND_GUARD] = { + "ROUND_UP", /* round away from 0 */ + "ROUND_DOWN", /* round toward 0 (truncate) */ + "ROUND_CEILING", /* round toward +infinity */ + "ROUND_FLOOR", /* round toward -infinity */ + "ROUND_HALF_UP", /* 0.5 is rounded up */ + "ROUND_HALF_DOWN", /* 0.5 is rounded down */ + "ROUND_HALF_EVEN", /* 0.5 is rounded to even */ + "ROUND_05UP", /* round zero or five away from 0 */ + "ROUND_TRUNC", /* truncate, but set infinity */ +}; + +const char *mpd_clamp_string[MPD_CLAMP_GUARD] = { + "CLAMP_DEFAULT", + "CLAMP_IEEE_754" +}; + + diff --git a/Modules/_decimal/libmpdec/constants.h b/Modules/_decimal/libmpdec/constants.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/constants.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef CONSTANTS_H +#define CONSTANTS_H + + +#include "mpdecimal.h" + + +/* choice of optimized functions */ +#if defined(CONFIG_64) +/* x64 */ + #define MULMOD(a, b) x64_mulmod(a, b, umod) + #define MULMOD2C(a0, a1, w) x64_mulmod2c(a0, a1, w, umod) + #define MULMOD2(a0, b0, a1, b1) x64_mulmod2(a0, b0, a1, b1, umod) + #define POWMOD(base, exp) x64_powmod(base, exp, umod) + #define SETMODULUS(modnum) std_setmodulus(modnum, &umod) + #define SIZE3_NTT(x0, x1, x2, w3table) std_size3_ntt(x0, x1, x2, w3table, umod) +#elif defined(PPRO) +/* PentiumPro (or later) gcc inline asm */ + #define MULMOD(a, b) ppro_mulmod(a, b, &dmod, dinvmod) + #define MULMOD2C(a0, a1, w) ppro_mulmod2c(a0, a1, w, &dmod, dinvmod) + #define MULMOD2(a0, b0, a1, b1) ppro_mulmod2(a0, b0, a1, b1, &dmod, dinvmod) + #define POWMOD(base, exp) ppro_powmod(base, exp, &dmod, dinvmod) + #define SETMODULUS(modnum) ppro_setmodulus(modnum, &umod, &dmod, dinvmod) + #define SIZE3_NTT(x0, x1, x2, w3table) ppro_size3_ntt(x0, x1, x2, w3table, umod, &dmod, dinvmod) +#else + /* ANSI C99 */ + #define MULMOD(a, b) std_mulmod(a, b, umod) + #define MULMOD2C(a0, a1, w) std_mulmod2c(a0, a1, w, umod) + #define MULMOD2(a0, b0, a1, b1) std_mulmod2(a0, b0, a1, b1, umod) + #define POWMOD(base, exp) std_powmod(base, exp, umod) + #define SETMODULUS(modnum) std_setmodulus(modnum, &umod) + #define SIZE3_NTT(x0, x1, x2, w3table) std_size3_ntt(x0, x1, x2, w3table, umod) +#endif + +/* PentiumPro (or later) gcc inline asm */ +extern const float MPD_TWO63; +extern const uint32_t mpd_invmoduli[3][3]; + +enum {P1, P2, P3}; + +extern const mpd_uint_t mpd_moduli[]; +extern const mpd_uint_t mpd_roots[]; +extern const mpd_size_t mpd_bits[]; +extern const mpd_uint_t mpd_pow10[]; + +extern const mpd_uint_t INV_P1_MOD_P2; +extern const mpd_uint_t INV_P1P2_MOD_P3; +extern const mpd_uint_t LH_P1P2; +extern const mpd_uint_t UH_P1P2; + + +#endif /* CONSTANTS_H */ + + + diff --git a/Modules/_decimal/libmpdec/context.c b/Modules/_decimal/libmpdec/context.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/context.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include + + +void +mpd_dflt_traphandler(mpd_context_t *ctx UNUSED) +{ + raise(SIGFPE); +} + +void (* mpd_traphandler)(mpd_context_t *) = mpd_dflt_traphandler; + + +/* Set guaranteed minimum number of coefficient words. The function may + be used once at program start. Setting MPD_MINALLOC to out-of-bounds + values is a catastrophic error, so in that case the function exits rather + than relying on the user to check a return value. */ +void +mpd_setminalloc(mpd_ssize_t n) +{ + static int minalloc_is_set = 0; + + if (minalloc_is_set) { + mpd_err_warn("mpd_setminalloc: ignoring request to set " + "MPD_MINALLOC a second time\n"); + return; + } + if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) { + mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */ + } + MPD_MINALLOC = n; + minalloc_is_set = 1; +} + +void +mpd_init(mpd_context_t *ctx, mpd_ssize_t prec) +{ + mpd_ssize_t ideal_minalloc; + + mpd_defaultcontext(ctx); + + if (!mpd_qsetprec(ctx, prec)) { + mpd_addstatus_raise(ctx, MPD_Invalid_context); + return; + } + + ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS); + if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN; + if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX; + + mpd_setminalloc(ideal_minalloc); +} + +void +mpd_maxcontext(mpd_context_t *ctx) +{ + ctx->prec=MPD_MAX_PREC; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_EVEN; + ctx->traps=MPD_Traps; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; +} + +void +mpd_defaultcontext(mpd_context_t *ctx) +{ + ctx->prec=2*MPD_RDIGITS; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_UP; + ctx->traps=MPD_Traps; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; +} + +void +mpd_basiccontext(mpd_context_t *ctx) +{ + ctx->prec=9; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_UP; + ctx->traps=MPD_Traps|MPD_Clamped; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; +} + +int +mpd_ieee_context(mpd_context_t *ctx, int bits) +{ + if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) { + return -1; + } + + ctx->prec = 9 * (bits/32) - 2; + ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3)); + ctx->emin = 1 - ctx->emax; + ctx->round=MPD_ROUND_HALF_EVEN; + ctx->traps=0; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=1; + ctx->allcr=1; + + return 0; +} + +mpd_ssize_t +mpd_getprec(const mpd_context_t *ctx) +{ + return ctx->prec; +} + +mpd_ssize_t +mpd_getemax(const mpd_context_t *ctx) +{ + return ctx->emax; +} + +mpd_ssize_t +mpd_getemin(const mpd_context_t *ctx) +{ + return ctx->emin; +} + +int +mpd_getround(const mpd_context_t *ctx) +{ + return ctx->round; +} + +uint32_t +mpd_gettraps(const mpd_context_t *ctx) +{ + return ctx->traps; +} + +uint32_t +mpd_getstatus(const mpd_context_t *ctx) +{ + return ctx->status; +} + +int +mpd_getclamp(const mpd_context_t *ctx) +{ + return ctx->clamp; +} + +int +mpd_getcr(const mpd_context_t *ctx) +{ + return ctx->allcr; +} + + +int +mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec) +{ + if (prec <= 0 || prec > MPD_MAX_PREC) { + return 0; + } + ctx->prec = prec; + return 1; +} + +int +mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax) +{ + if (emax < 0 || emax > MPD_MAX_EMAX) { + return 0; + } + ctx->emax = emax; + return 1; +} + +int +mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin) +{ + if (emin > 0 || emin < MPD_MIN_EMIN) { + return 0; + } + ctx->emin = emin; + return 1; +} + +int +mpd_qsetround(mpd_context_t *ctx, int round) +{ + if (!(0 <= round && round < MPD_ROUND_GUARD)) { + return 0; + } + ctx->round = round; + return 1; +} + +int +mpd_qsettraps(mpd_context_t *ctx, uint32_t traps) +{ + if (traps > MPD_Max_status) { + return 0; + } + ctx->traps = traps; + return 1; +} + +int +mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags) +{ + if (flags > MPD_Max_status) { + return 0; + } + ctx->status = flags; + return 1; +} + +int +mpd_qsetclamp(mpd_context_t *ctx, int c) +{ + if (c != 0 && c != 1) { + return 0; + } + ctx->clamp = c; + return 1; +} + +int +mpd_qsetcr(mpd_context_t *ctx, int c) +{ + if (c != 0 && c != 1) { + return 0; + } + ctx->allcr = c; + return 1; +} + + +void +mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags) +{ + ctx->status |= flags; + if (flags&ctx->traps) { + ctx->newtrap = (flags&ctx->traps); + mpd_traphandler(ctx); + } +} + + diff --git a/Modules/_decimal/libmpdec/convolute.c b/Modules/_decimal/libmpdec/convolute.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/convolute.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include "bits.h" +#include "constants.h" +#include "fnt.h" +#include "fourstep.h" +#include "numbertheory.h" +#include "sixstep.h" +#include "umodarith.h" +#include "convolute.h" + + +/* Bignum: Fast convolution using the Number Theoretic Transform. Used for + the multiplication of very large coefficients. */ + + +/* Convolute the data in c1 and c2. Result is in c1. */ +int +fnt_convolute(mpd_uint_t *c1, mpd_uint_t *c2, mpd_size_t n, int modnum) +{ + int (*fnt)(mpd_uint_t *, mpd_size_t, int); + int (*inv_fnt)(mpd_uint_t *, mpd_size_t, int); +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t n_inv, umod; + mpd_size_t i; + + + SETMODULUS(modnum); + n_inv = POWMOD(n, (umod-2)); + + if (ispower2(n)) { + if (n > SIX_STEP_THRESHOLD) { + fnt = six_step_fnt; + inv_fnt = inv_six_step_fnt; + } + else { + fnt = std_fnt; + inv_fnt = std_inv_fnt; + } + } + else { + fnt = four_step_fnt; + inv_fnt = inv_four_step_fnt; + } + + if (!fnt(c1, n, modnum)) { + return 0; + } + if (!fnt(c2, n, modnum)) { + return 0; + } + for (i = 0; i < n-1; i += 2) { + mpd_uint_t x0 = c1[i]; + mpd_uint_t y0 = c2[i]; + mpd_uint_t x1 = c1[i+1]; + mpd_uint_t y1 = c2[i+1]; + MULMOD2(&x0, y0, &x1, y1); + c1[i] = x0; + c1[i+1] = x1; + } + + if (!inv_fnt(c1, n, modnum)) { + return 0; + } + for (i = 0; i < n-3; i += 4) { + mpd_uint_t x0 = c1[i]; + mpd_uint_t x1 = c1[i+1]; + mpd_uint_t x2 = c1[i+2]; + mpd_uint_t x3 = c1[i+3]; + MULMOD2C(&x0, &x1, n_inv); + MULMOD2C(&x2, &x3, n_inv); + c1[i] = x0; + c1[i+1] = x1; + c1[i+2] = x2; + c1[i+3] = x3; + } + + return 1; +} + +/* Autoconvolute the data in c1. Result is in c1. */ +int +fnt_autoconvolute(mpd_uint_t *c1, mpd_size_t n, int modnum) +{ + int (*fnt)(mpd_uint_t *, mpd_size_t, int); + int (*inv_fnt)(mpd_uint_t *, mpd_size_t, int); +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t n_inv, umod; + mpd_size_t i; + + + SETMODULUS(modnum); + n_inv = POWMOD(n, (umod-2)); + + if (ispower2(n)) { + if (n > SIX_STEP_THRESHOLD) { + fnt = six_step_fnt; + inv_fnt = inv_six_step_fnt; + } + else { + fnt = std_fnt; + inv_fnt = std_inv_fnt; + } + } + else { + fnt = four_step_fnt; + inv_fnt = inv_four_step_fnt; + } + + if (!fnt(c1, n, modnum)) { + return 0; + } + for (i = 0; i < n-1; i += 2) { + mpd_uint_t x0 = c1[i]; + mpd_uint_t x1 = c1[i+1]; + MULMOD2(&x0, x0, &x1, x1); + c1[i] = x0; + c1[i+1] = x1; + } + + if (!inv_fnt(c1, n, modnum)) { + return 0; + } + for (i = 0; i < n-3; i += 4) { + mpd_uint_t x0 = c1[i]; + mpd_uint_t x1 = c1[i+1]; + mpd_uint_t x2 = c1[i+2]; + mpd_uint_t x3 = c1[i+3]; + MULMOD2C(&x0, &x1, n_inv); + MULMOD2C(&x2, &x3, n_inv); + c1[i] = x0; + c1[i+1] = x1; + c1[i+2] = x2; + c1[i+3] = x3; + } + + return 1; +} + + diff --git a/Modules/_decimal/libmpdec/convolute.h b/Modules/_decimal/libmpdec/convolute.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/convolute.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef CONVOLUTE_H +#define CONVOLUTE_H + + +#include "mpdecimal.h" +#include + +#define SIX_STEP_THRESHOLD 4096 + + +int fnt_convolute(mpd_uint_t *c1, mpd_uint_t *c2, mpd_size_t n, int modnum); +int fnt_autoconvolute(mpd_uint_t *c1, mpd_size_t n, int modnum); + + +#endif diff --git a/Modules/_decimal/libmpdec/crt.c b/Modules/_decimal/libmpdec/crt.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/crt.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include "numbertheory.h" +#include "umodarith.h" +#include "crt.h" + + +/* Bignum: Chinese Remainder Theorem, extends the maximum transform length. */ + + +/* Multiply P1P2 by v, store result in w. */ +static inline void +_crt_mulP1P2_3(mpd_uint_t w[3], mpd_uint_t v) +{ + mpd_uint_t hi1, hi2, lo; + + _mpd_mul_words(&hi1, &lo, LH_P1P2, v); + w[0] = lo; + + _mpd_mul_words(&hi2, &lo, UH_P1P2, v); + lo = hi1 + lo; + if (lo < hi1) hi2++; + + w[1] = lo; + w[2] = hi2; +} + +/* Add 3 words from v to w. The result is known to fit in w. */ +static inline void +_crt_add3(mpd_uint_t w[3], mpd_uint_t v[3]) +{ + mpd_uint_t carry; + mpd_uint_t s; + + s = w[0] + v[0]; + carry = (s < w[0]); + w[0] = s; + + s = w[1] + (v[1] + carry); + carry = (s < w[1]); + w[1] = s; + + w[2] = w[2] + (v[2] + carry); +} + +/* Divide 3 words in u by v, store result in w, return remainder. */ +static inline mpd_uint_t +_crt_div3(mpd_uint_t *w, const mpd_uint_t *u, mpd_uint_t v) +{ + mpd_uint_t r1 = u[2]; + mpd_uint_t r2; + + if (r1 < v) { + w[2] = 0; + } + else { + _mpd_div_word(&w[2], &r1, u[2], v); /* GCOV_NOT_REACHED */ + } + + _mpd_div_words(&w[1], &r2, r1, u[1], v); + _mpd_div_words(&w[0], &r1, r2, u[0], v); + + return r1; +} + + +/* + * Chinese Remainder Theorem: + * Algorithm from Joerg Arndt, "Matters Computational", + * Chapter 37.4.1 [http://www.jjj.de/fxt/] + * + * See also Knuth, TAOCP, Volume 2, 4.3.2, exercise 7. + */ + +/* + * CRT with carry: x1, x2, x3 contain numbers modulo p1, p2, p3. For each + * triple of members of the arrays, find the unique z modulo p1*p2*p3, with + * zmax = p1*p2*p3 - 1. + * + * In each iteration of the loop, split z into result[i] = z % MPD_RADIX + * and carry = z / MPD_RADIX. Let N be the size of carry[] and cmax the + * maximum carry. + * + * Limits for the 32-bit build: + * + * N = 2**96 + * cmax = 7711435591312380274 + * + * Limits for the 64 bit build: + * + * N = 2**192 + * cmax = 627710135393475385904124401220046371710 + * + * The following statements hold for both versions: + * + * 1) cmax + zmax < N, so the addition does not overflow. + * + * 2) (cmax + zmax) / MPD_RADIX == cmax. + * + * 3) If c <= cmax, then c_next = (c + zmax) / MPD_RADIX <= cmax. + */ +void +crt3(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_size_t rsize) +{ + mpd_uint_t p1 = mpd_moduli[P1]; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t a1, a2, a3; + mpd_uint_t s; + mpd_uint_t z[3], t[3]; + mpd_uint_t carry[3] = {0,0,0}; + mpd_uint_t hi, lo; + mpd_size_t i; + + for (i = 0; i < rsize; i++) { + + a1 = x1[i]; + a2 = x2[i]; + a3 = x3[i]; + + SETMODULUS(P2); + s = ext_submod(a2, a1, umod); + s = MULMOD(s, INV_P1_MOD_P2); + + _mpd_mul_words(&hi, &lo, s, p1); + lo = lo + a1; + if (lo < a1) hi++; + + SETMODULUS(P3); + s = dw_submod(a3, hi, lo, umod); + s = MULMOD(s, INV_P1P2_MOD_P3); + + z[0] = lo; + z[1] = hi; + z[2] = 0; + + _crt_mulP1P2_3(t, s); + _crt_add3(z, t); + _crt_add3(carry, z); + + x1[i] = _crt_div3(carry, carry, MPD_RADIX); + } + + assert(carry[0] == 0 && carry[1] == 0 && carry[2] == 0); +} + + diff --git a/Modules/_decimal/libmpdec/crt.h b/Modules/_decimal/libmpdec/crt.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/crt.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef CRT_H +#define CRT_H + + +#include "mpdecimal.h" +#include + + +void crt3(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_size_t nmemb); + + +#endif diff --git a/Modules/_decimal/libmpdec/difradix2.c b/Modules/_decimal/libmpdec/difradix2.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/difradix2.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include "bits.h" +#include "numbertheory.h" +#include "umodarith.h" +#include "difradix2.h" + + +/* Bignum: The actual transform routine (decimation in frequency). */ + + +/* + * Generate index pairs (x, bitreverse(x)) and carry out the permutation. + * n must be a power of two. + * Algorithm due to Brent/Lehmann, see Joerg Arndt, "Matters Computational", + * Chapter 1.14.4. [http://www.jjj.de/fxt/] + */ +static inline void +bitreverse_permute(mpd_uint_t a[], mpd_size_t n) +{ + mpd_size_t x = 0; + mpd_size_t r = 0; + mpd_uint_t t; + + do { /* Invariant: r = bitreverse(x) */ + if (r > x) { + t = a[x]; + a[x] = a[r]; + a[r] = t; + } + /* Flip trailing consecutive 1 bits and the first zero bit + * that absorbs a possible carry. */ + x += 1; + /* Mirror the operation on r: Flip n_trailing_zeros(x)+1 + high bits of r. */ + r ^= (n - (n >> (mpd_bsf(x)+1))); + /* The loop invariant is preserved. */ + } while (x < n); +} + + +/* Fast Number Theoretic Transform, decimation in frequency. */ +void +fnt_dif2(mpd_uint_t a[], mpd_size_t n, struct fnt_params *tparams) +{ + mpd_uint_t *wtable = tparams->wtable; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t u0, u1, v0, v1; + mpd_uint_t w, w0, w1, wstep; + mpd_size_t m, mhalf; + mpd_size_t j, r; + + + assert(ispower2(n)); + assert(n >= 4); + + SETMODULUS(tparams->modnum); + + /* m == n */ + mhalf = n / 2; + for (j = 0; j < mhalf; j += 2) { + + w0 = wtable[j]; + w1 = wtable[j+1]; + + u0 = a[j]; + v0 = a[j+mhalf]; + + u1 = a[j+1]; + v1 = a[j+1+mhalf]; + + a[j] = addmod(u0, v0, umod); + v0 = submod(u0, v0, umod); + + a[j+1] = addmod(u1, v1, umod); + v1 = submod(u1, v1, umod); + + MULMOD2(&v0, w0, &v1, w1); + + a[j+mhalf] = v0; + a[j+1+mhalf] = v1; + + } + + wstep = 2; + for (m = n/2; m >= 2; m>>=1, wstep<<=1) { + + mhalf = m / 2; + + /* j == 0 */ + for (r = 0; r < n; r += 2*m) { + + u0 = a[r]; + v0 = a[r+mhalf]; + + u1 = a[m+r]; + v1 = a[m+r+mhalf]; + + a[r] = addmod(u0, v0, umod); + v0 = submod(u0, v0, umod); + + a[m+r] = addmod(u1, v1, umod); + v1 = submod(u1, v1, umod); + + a[r+mhalf] = v0; + a[m+r+mhalf] = v1; + } + + for (j = 1; j < mhalf; j++) { + + w = wtable[j*wstep]; + + for (r = 0; r < n; r += 2*m) { + + u0 = a[r+j]; + v0 = a[r+j+mhalf]; + + u1 = a[m+r+j]; + v1 = a[m+r+j+mhalf]; + + a[r+j] = addmod(u0, v0, umod); + v0 = submod(u0, v0, umod); + + a[m+r+j] = addmod(u1, v1, umod); + v1 = submod(u1, v1, umod); + + MULMOD2C(&v0, &v1, w); + + a[r+j+mhalf] = v0; + a[m+r+j+mhalf] = v1; + } + + } + + } + + bitreverse_permute(a, n); +} + + diff --git a/Modules/_decimal/libmpdec/difradix2.h b/Modules/_decimal/libmpdec/difradix2.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/difradix2.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef DIF_RADIX2_H +#define DIF_RADIX2_H + + +#include "mpdecimal.h" +#include +#include "numbertheory.h" + + +void fnt_dif2(mpd_uint_t a[], mpd_size_t n, struct fnt_params *tparams); + + +#endif diff --git a/Modules/_decimal/libmpdec/fnt.c b/Modules/_decimal/libmpdec/fnt.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/fnt.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include "bits.h" +#include "difradix2.h" +#include "numbertheory.h" +#include "fnt.h" + + +/* Bignum: Fast transform for medium-sized coefficients. */ + + +/* forward transform, sign = -1 */ +int +std_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + struct fnt_params *tparams; + + assert(ispower2(n)); + assert(n >= 4); + assert(n <= 3*MPD_MAXTRANSFORM_2N); + + if ((tparams = _mpd_init_fnt_params(n, -1, modnum)) == NULL) { + return 0; + } + fnt_dif2(a, n, tparams); + + mpd_free(tparams); + return 1; +} + +/* reverse transform, sign = 1 */ +int +std_inv_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + struct fnt_params *tparams; + + assert(ispower2(n)); + assert(n >= 4); + assert(n <= 3*MPD_MAXTRANSFORM_2N); + + if ((tparams = _mpd_init_fnt_params(n, 1, modnum)) == NULL) { + return 0; + } + fnt_dif2(a, n, tparams); + + mpd_free(tparams); + return 1; +} + + + diff --git a/Modules/_decimal/libmpdec/fnt.h b/Modules/_decimal/libmpdec/fnt.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/fnt.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef FNT_H +#define FNT_H + + +#include "mpdecimal.h" +#include + + +int std_fnt(mpd_uint_t a[], mpd_size_t n, int modnum); +int std_inv_fnt(mpd_uint_t a[], mpd_size_t n, int modnum); + + +#endif + diff --git a/Modules/_decimal/libmpdec/fourstep.c b/Modules/_decimal/libmpdec/fourstep.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/fourstep.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include "numbertheory.h" +#include "sixstep.h" +#include "transpose.h" +#include "umodarith.h" +#include "fourstep.h" + + +/* Bignum: Cache efficient Matrix Fourier Transform for arrays of the + form 3 * 2**n (See literature/matrix-transform.txt). */ + + +#ifndef PPRO +static inline void +std_size3_ntt(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, + mpd_uint_t w3table[3], mpd_uint_t umod) +{ + mpd_uint_t r1, r2; + mpd_uint_t w; + mpd_uint_t s, tmp; + + + /* k = 0 -> w = 1 */ + s = *x1; + s = addmod(s, *x2, umod); + s = addmod(s, *x3, umod); + + r1 = s; + + /* k = 1 */ + s = *x1; + + w = w3table[1]; + tmp = MULMOD(*x2, w); + s = addmod(s, tmp, umod); + + w = w3table[2]; + tmp = MULMOD(*x3, w); + s = addmod(s, tmp, umod); + + r2 = s; + + /* k = 2 */ + s = *x1; + + w = w3table[2]; + tmp = MULMOD(*x2, w); + s = addmod(s, tmp, umod); + + w = w3table[1]; + tmp = MULMOD(*x3, w); + s = addmod(s, tmp, umod); + + *x3 = s; + *x2 = r2; + *x1 = r1; +} +#else /* PPRO */ +static inline void +ppro_size3_ntt(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_uint_t w3table[3], + mpd_uint_t umod, double *dmod, uint32_t dinvmod[3]) +{ + mpd_uint_t r1, r2; + mpd_uint_t w; + mpd_uint_t s, tmp; + + + /* k = 0 -> w = 1 */ + s = *x1; + s = addmod(s, *x2, umod); + s = addmod(s, *x3, umod); + + r1 = s; + + /* k = 1 */ + s = *x1; + + w = w3table[1]; + tmp = ppro_mulmod(*x2, w, dmod, dinvmod); + s = addmod(s, tmp, umod); + + w = w3table[2]; + tmp = ppro_mulmod(*x3, w, dmod, dinvmod); + s = addmod(s, tmp, umod); + + r2 = s; + + /* k = 2 */ + s = *x1; + + w = w3table[2]; + tmp = ppro_mulmod(*x2, w, dmod, dinvmod); + s = addmod(s, tmp, umod); + + w = w3table[1]; + tmp = ppro_mulmod(*x3, w, dmod, dinvmod); + s = addmod(s, tmp, umod); + + *x3 = s; + *x2 = r2; + *x1 = r1; +} +#endif + + +/* forward transform, sign = -1; transform length = 3 * 2**n */ +int +four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + mpd_size_t R = 3; /* number of rows */ + mpd_size_t C = n / 3; /* number of columns */ + mpd_uint_t w3table[3]; + mpd_uint_t kernel, w0, w1, wstep; + mpd_uint_t *s, *p0, *p1, *p2; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_size_t i, k; + + + assert(n >= 48); + assert(n <= 3*MPD_MAXTRANSFORM_2N); + + + /* Length R transform on the columns. */ + SETMODULUS(modnum); + _mpd_init_w3table(w3table, -1, modnum); + for (p0=a, p1=p0+C, p2=p0+2*C; p0= 48); + assert(n <= 3*MPD_MAXTRANSFORM_2N); + + +#if 0 /* An unordered transform is sufficient for convolution. */ + /* Transpose the matrix, producing an R*C matrix. */ + transpose_3xpow2(a, C, R); +#endif + + /* Length C transform on the rows. */ + for (s = a; s < a+n; s += C) { + if (!inv_six_step_fnt(s, C, modnum)) { + return 0; + } + } + + /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */ + SETMODULUS(modnum); + kernel = _mpd_getkernel(n, 1, modnum); + for (i = 1; i < R; i++) { + w0 = 1; + w1 = POWMOD(kernel, i); + wstep = MULMOD(w1, w1); + for (k = 0; k < C; k += 2) { + mpd_uint_t x0 = a[i*C+k]; + mpd_uint_t x1 = a[i*C+k+1]; + MULMOD2(&x0, w0, &x1, w1); + MULMOD2C(&w0, &w1, wstep); + a[i*C+k] = x0; + a[i*C+k+1] = x1; + } + } + + /* Length R transform on the columns. */ + _mpd_init_w3table(w3table, 1, modnum); + for (p0=a, p1=p0+C, p2=p0+2*C; p0 + + +int four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); +int inv_four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); + + +#endif diff --git a/Modules/_decimal/libmpdec/io.c b/Modules/_decimal/libmpdec/io.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/io.c @@ -0,0 +1,1575 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "bits.h" +#include "constants.h" +#include "memory.h" +#include "typearith.h" +#include "io.h" + + +/* This file contains functions for decimal <-> string conversions, including + PEP-3101 formatting for numeric types. */ + + +/* + * Work around the behavior of tolower() and strcasecmp() in certain + * locales. For example, in tr_TR.utf8: + * + * tolower((unsigned char)'I') == 'I' + * + * u is the exact uppercase version of l; n is strlen(l) or strlen(l)+1 + */ +static inline int +_mpd_strneq(const char *s, const char *l, const char *u, size_t n) +{ + while (--n != SIZE_MAX) { + if (*s != *l && *s != *u) { + return 0; + } + s++; u++; l++; + } + + return 1; +} + +static mpd_ssize_t +strtoexp(const char *s) +{ + char *end; + mpd_ssize_t retval; + + errno = 0; + retval = mpd_strtossize(s, &end, 10); + if (errno == 0 && !(*s != '\0' && *end == '\0')) + errno = EINVAL; + + return retval; +} + +/* + * Scan 'len' words. The most significant word contains 'r' digits, + * the remaining words are full words. Skip dpoint. The string 's' must + * consist of digits and an optional single decimal point at 'dpoint'. + */ +static void +string_to_coeff(mpd_uint_t *data, const char *s, const char *dpoint, int r, + size_t len) +{ + int j; + + if (r > 0) { + data[--len] = 0; + for (j = 0; j < r; j++, s++) { + if (s == dpoint) s++; + data[len] = 10 * data[len] + (*s - '0'); + } + } + + while (--len != SIZE_MAX) { + data[len] = 0; + for (j = 0; j < MPD_RDIGITS; j++, s++) { + if (s == dpoint) s++; + data[len] = 10 * data[len] + (*s - '0'); + } + } +} + +/* + * Partially verify a numeric string of the form: + * + * [cdigits][.][cdigits][eE][+-][edigits] + * + * If successful, return a pointer to the location of the first + * relevant coefficient digit. This digit is either non-zero or + * part of one of the following patterns: + * + * ["0\x00", "0.\x00", "0.E", "0.e", "0E", "0e"] + * + * The locations of a single optional dot or indicator are stored + * in 'dpoint' and 'exp'. + * + * The end of the string is stored in 'end'. If an indicator [eE] + * occurs without trailing [edigits], the condition is caught + * later by strtoexp(). + */ +static const char * +scan_dpoint_exp(const char *s, const char **dpoint, const char **exp, + const char **end) +{ + const char *coeff = NULL; + + *dpoint = NULL; + *exp = NULL; + for (; *s != '\0'; s++) { + switch (*s) { + case '.': + if (*dpoint != NULL || *exp != NULL) + return NULL; + *dpoint = s; + break; + case 'E': case 'e': + if (*exp != NULL) + return NULL; + *exp = s; + if (*(s+1) == '+' || *(s+1) == '-') + s++; + break; + default: + if (!isdigit((uchar)*s)) + return NULL; + if (coeff == NULL && *exp == NULL) { + if (*s == '0') { + if (!isdigit((uchar)*(s+1))) + if (!(*(s+1) == '.' && + isdigit((uchar)*(s+2)))) + coeff = s; + } + else { + coeff = s; + } + } + break; + + } + } + + *end = s; + return coeff; +} + +/* scan the payload of a NaN */ +static const char * +scan_payload(const char *s, const char **end) +{ + const char *coeff; + + while (*s == '0') + s++; + coeff = s; + + while (isdigit((uchar)*s)) + s++; + *end = s; + + return (*s == '\0') ? coeff : NULL; +} + +/* convert a character string to a decimal */ +void +mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_ssize_t q, r, len; + const char *coeff, *end; + const char *dpoint = NULL, *exp = NULL; + size_t digits; + uint8_t sign = MPD_POS; + + mpd_set_flags(dec, 0); + dec->len = 0; + dec->exp = 0; + + /* sign */ + if (*s == '+') { + s++; + } + else if (*s == '-') { + mpd_set_negative(dec); + sign = MPD_NEG; + s++; + } + + if (_mpd_strneq(s, "nan", "NAN", 3)) { /* NaN */ + s += 3; + mpd_setspecial(dec, sign, MPD_NAN); + if (*s == '\0') + return; + /* validate payload: digits only */ + if ((coeff = scan_payload(s, &end)) == NULL) + goto conversion_error; + /* payload consists entirely of zeros */ + if (*coeff == '\0') + return; + digits = end - coeff; + /* prec >= 1, clamp is 0 or 1 */ + if (digits > (size_t)(ctx->prec-ctx->clamp)) + goto conversion_error; + } /* sNaN */ + else if (_mpd_strneq(s, "snan", "SNAN", 4)) { + s += 4; + mpd_setspecial(dec, sign, MPD_SNAN); + if (*s == '\0') + return; + /* validate payload: digits only */ + if ((coeff = scan_payload(s, &end)) == NULL) + goto conversion_error; + /* payload consists entirely of zeros */ + if (*coeff == '\0') + return; + digits = end - coeff; + if (digits > (size_t)(ctx->prec-ctx->clamp)) + goto conversion_error; + } + else if (_mpd_strneq(s, "inf", "INF", 3)) { + s += 3; + if (*s == '\0' || _mpd_strneq(s, "inity", "INITY", 6)) { + /* numeric-value: infinity */ + mpd_setspecial(dec, sign, MPD_INF); + return; + } + goto conversion_error; + } + else { + /* scan for start of coefficient, decimal point, indicator, end */ + if ((coeff = scan_dpoint_exp(s, &dpoint, &exp, &end)) == NULL) + goto conversion_error; + + /* numeric-value: [exponent-part] */ + if (exp) { + /* exponent-part */ + end = exp; exp++; + dec->exp = strtoexp(exp); + if (errno) { + if (!(errno == ERANGE && + (dec->exp == MPD_SSIZE_MAX || + dec->exp == MPD_SSIZE_MIN))) + goto conversion_error; + } + } + + digits = end - coeff; + if (dpoint) { + size_t fracdigits = end-dpoint-1; + if (dpoint > coeff) digits--; + + if (fracdigits > MPD_MAX_PREC) { + goto conversion_error; + } + if (dec->exp < MPD_SSIZE_MIN+(mpd_ssize_t)fracdigits) { + dec->exp = MPD_SSIZE_MIN; + } + else { + dec->exp -= (mpd_ssize_t)fracdigits; + } + } + if (digits > MPD_MAX_PREC) { + goto conversion_error; + } + if (dec->exp > MPD_EXP_INF) { + dec->exp = MPD_EXP_INF; + } + if (dec->exp == MPD_SSIZE_MIN) { + dec->exp = MPD_SSIZE_MIN+1; + } + } + + _mpd_idiv_word(&q, &r, (mpd_ssize_t)digits, MPD_RDIGITS); + + len = (r == 0) ? q : q+1; + if (len == 0) { + goto conversion_error; /* GCOV_NOT_REACHED */ + } + if (!mpd_qresize(dec, len, status)) { + mpd_seterror(dec, MPD_Malloc_error, status); + return; + } + dec->len = len; + + string_to_coeff(dec->data, coeff, dpoint, (int)r, len); + + mpd_setdigits(dec); + mpd_qfinalize(dec, ctx, status); + return; + +conversion_error: + /* standard wants a positive NaN */ + mpd_seterror(dec, MPD_Conversion_syntax, status); +} + +/* Print word x with n decimal digits to string s. dot is either NULL + or the location of a decimal point. */ +#define EXTRACT_DIGIT(s, x, d, dot) \ + if (s == dot) *s++ = '.'; *s++ = '0' + (char)(x / d); x %= d +static inline char * +word_to_string(char *s, mpd_uint_t x, int n, char *dot) +{ + switch(n) { +#ifdef CONFIG_64 + case 20: EXTRACT_DIGIT(s, x, 10000000000000000000ULL, dot); /* GCOV_NOT_REACHED */ + case 19: EXTRACT_DIGIT(s, x, 1000000000000000000ULL, dot); + case 18: EXTRACT_DIGIT(s, x, 100000000000000000ULL, dot); + case 17: EXTRACT_DIGIT(s, x, 10000000000000000ULL, dot); + case 16: EXTRACT_DIGIT(s, x, 1000000000000000ULL, dot); + case 15: EXTRACT_DIGIT(s, x, 100000000000000ULL, dot); + case 14: EXTRACT_DIGIT(s, x, 10000000000000ULL, dot); + case 13: EXTRACT_DIGIT(s, x, 1000000000000ULL, dot); + case 12: EXTRACT_DIGIT(s, x, 100000000000ULL, dot); + case 11: EXTRACT_DIGIT(s, x, 10000000000ULL, dot); +#endif + case 10: EXTRACT_DIGIT(s, x, 1000000000UL, dot); + case 9: EXTRACT_DIGIT(s, x, 100000000UL, dot); + case 8: EXTRACT_DIGIT(s, x, 10000000UL, dot); + case 7: EXTRACT_DIGIT(s, x, 1000000UL, dot); + case 6: EXTRACT_DIGIT(s, x, 100000UL, dot); + case 5: EXTRACT_DIGIT(s, x, 10000UL, dot); + case 4: EXTRACT_DIGIT(s, x, 1000UL, dot); + case 3: EXTRACT_DIGIT(s, x, 100UL, dot); + case 2: EXTRACT_DIGIT(s, x, 10UL, dot); + default: if (s == dot) *s++ = '.'; *s++ = '0' + (char)x; + } + + *s = '\0'; + return s; +} + +/* Print exponent x to string s. Undefined for MPD_SSIZE_MIN. */ +static inline char * +exp_to_string(char *s, mpd_ssize_t x) +{ + char sign = '+'; + + if (x < 0) { + sign = '-'; + x = -x; + } + *s++ = sign; + + return word_to_string(s, x, mpd_word_digits(x), NULL); +} + +/* Print the coefficient of dec to string s. len(dec) > 0. */ +static inline char * +coeff_to_string(char *s, const mpd_t *dec) +{ + mpd_uint_t x; + mpd_ssize_t i; + + /* most significant word */ + x = mpd_msword(dec); + s = word_to_string(s, x, mpd_word_digits(x), NULL); + + /* remaining full words */ + for (i=dec->len-2; i >= 0; --i) { + x = dec->data[i]; + s = word_to_string(s, x, MPD_RDIGITS, NULL); + } + + return s; +} + +/* Print the coefficient of dec to string s. len(dec) > 0. dot is either + NULL or a pointer to the location of a decimal point. */ +static inline char * +coeff_to_string_dot(char *s, char *dot, const mpd_t *dec) +{ + mpd_uint_t x; + mpd_ssize_t i; + + /* most significant word */ + x = mpd_msword(dec); + s = word_to_string(s, x, mpd_word_digits(x), dot); + + /* remaining full words */ + for (i=dec->len-2; i >= 0; --i) { + x = dec->data[i]; + s = word_to_string(s, x, MPD_RDIGITS, dot); + } + + return s; +} + +/* Format type */ +#define MPD_FMT_LOWER 0x00000000 +#define MPD_FMT_UPPER 0x00000001 +#define MPD_FMT_TOSCI 0x00000002 +#define MPD_FMT_TOENG 0x00000004 +#define MPD_FMT_EXP 0x00000008 +#define MPD_FMT_FIXED 0x00000010 +#define MPD_FMT_PERCENT 0x00000020 +#define MPD_FMT_SIGN_SPACE 0x00000040 +#define MPD_FMT_SIGN_PLUS 0x00000080 + +/* Default place of the decimal point for MPD_FMT_TOSCI, MPD_FMT_EXP */ +#define MPD_DEFAULT_DOTPLACE 1 + +/* + * Set *result to the string representation of a decimal. Return the length + * of *result, not including the terminating '\0' character. + * + * Formatting is done according to 'flags'. A return value of -1 with *result + * set to NULL indicates MPD_Malloc_error. + * + * 'dplace' is the default place of the decimal point. It is always set to + * MPD_DEFAULT_DOTPLACE except for zeros in combination with MPD_FMT_EXP. + */ +static mpd_ssize_t +_mpd_to_string(char **result, const mpd_t *dec, int flags, mpd_ssize_t dplace) +{ + char *decstring = NULL, *cp = NULL; + mpd_ssize_t ldigits; + mpd_ssize_t mem = 0, k; + + if (mpd_isspecial(dec)) { + + mem = sizeof "-Infinity"; + if (mpd_isnan(dec) && dec->len > 0) { + /* diagnostic code */ + mem += dec->digits; + } + cp = decstring = mpd_alloc(mem, sizeof *decstring); + if (cp == NULL) { + *result = NULL; + return -1; + } + + if (mpd_isnegative(dec)) { + *cp++ = '-'; + } + else if (flags&MPD_FMT_SIGN_SPACE) { + *cp++ = ' '; + } + else if (flags&MPD_FMT_SIGN_PLUS) { + *cp++ = '+'; + } + + if (mpd_isnan(dec)) { + if (mpd_isqnan(dec)) { + strcpy(cp, "NaN"); + cp += 3; + } + else { + strcpy(cp, "sNaN"); + cp += 4; + } + if (dec->len > 0) { /* diagnostic code */ + cp = coeff_to_string(cp, dec); + } + } + else if (mpd_isinfinite(dec)) { + strcpy(cp, "Infinity"); + cp += 8; + } + else { /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + } + else { + assert(dec->len > 0); + + /* + * For easier manipulation of the decimal point's location + * and the exponent that is finally printed, the number is + * rescaled to a virtual representation with exp = 0. Here + * ldigits denotes the number of decimal digits to the left + * of the decimal point and remains constant once initialized. + * + * dplace is the location of the decimal point relative to + * the start of the coefficient. Note that 3) always holds + * when dplace is shifted. + * + * 1) ldigits := dec->digits - dec->exp + * 2) dplace := ldigits (initially) + * 3) exp := ldigits - dplace (initially exp = 0) + * + * 0.00000_.____._____000000. + * ^ ^ ^ ^ + * | | | | + * | | | `- dplace >= digits + * | | `- dplace in the middle of the coefficient + * | ` dplace = 1 (after the first coefficient digit) + * `- dplace <= 0 + */ + + ldigits = dec->digits + dec->exp; + + if (flags&MPD_FMT_EXP) { + ; + } + else if (flags&MPD_FMT_FIXED || (dec->exp <= 0 && ldigits > -6)) { + /* MPD_FMT_FIXED: always use fixed point notation. + * MPD_FMT_TOSCI, MPD_FMT_TOENG: for a certain range, + * override exponent notation. */ + dplace = ldigits; + } + else if (flags&MPD_FMT_TOENG) { + if (mpd_iszero(dec)) { + /* If the exponent is divisible by three, + * dplace = 1. Otherwise, move dplace one + * or two places to the left. */ + dplace = -1 + mod_mpd_ssize_t(dec->exp+2, 3); + } + else { /* ldigits-1 is the adjusted exponent, which + * should be divisible by three. If not, move + * dplace one or two places to the right. */ + dplace += mod_mpd_ssize_t(ldigits-1, 3); + } + } + + /* + * Basic space requirements: + * + * [-][.][coeffdigits][E][-][expdigits+1][%]['\0'] + * + * If the decimal point lies outside of the coefficient digits, + * space is adjusted accordingly. + */ + if (dplace <= 0) { + mem = -dplace + dec->digits + 2; + } + else if (dplace >= dec->digits) { + mem = dplace; + } + else { + mem = dec->digits; + } + mem += (MPD_EXPDIGITS+1+6); + + cp = decstring = mpd_alloc(mem, sizeof *decstring); + if (cp == NULL) { + *result = NULL; + return -1; + } + + + if (mpd_isnegative(dec)) { + *cp++ = '-'; + } + else if (flags&MPD_FMT_SIGN_SPACE) { + *cp++ = ' '; + } + else if (flags&MPD_FMT_SIGN_PLUS) { + *cp++ = '+'; + } + + if (dplace <= 0) { + /* space: -dplace+dec->digits+2 */ + *cp++ = '0'; + *cp++ = '.'; + for (k = 0; k < -dplace; k++) { + *cp++ = '0'; + } + cp = coeff_to_string(cp, dec); + } + else if (dplace >= dec->digits) { + /* space: dplace */ + cp = coeff_to_string(cp, dec); + for (k = 0; k < dplace-dec->digits; k++) { + *cp++ = '0'; + } + } + else { + /* space: dec->digits+1 */ + cp = coeff_to_string_dot(cp, cp+dplace, dec); + } + + /* + * Conditions for printing an exponent: + * + * MPD_FMT_TOSCI, MPD_FMT_TOENG: only if ldigits != dplace + * MPD_FMT_FIXED: never (ldigits == dplace) + * MPD_FMT_EXP: always + */ + if (ldigits != dplace || flags&MPD_FMT_EXP) { + /* space: expdigits+2 */ + *cp++ = (flags&MPD_FMT_UPPER) ? 'E' : 'e'; + cp = exp_to_string(cp, ldigits-dplace); + } + + if (flags&MPD_FMT_PERCENT) { + *cp++ = '%'; + } + } + + assert(cp < decstring+mem); + assert(cp-decstring < MPD_SSIZE_MAX); + + *cp = '\0'; + *result = decstring; + return (mpd_ssize_t)(cp-decstring); +} + +char * +mpd_to_sci(const mpd_t *dec, int fmt) +{ + char *res; + int flags = MPD_FMT_TOSCI; + + flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; + (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE); + return res; +} + +char * +mpd_to_eng(const mpd_t *dec, int fmt) +{ + char *res; + int flags = MPD_FMT_TOENG; + + flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; + (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE); + return res; +} + +mpd_ssize_t +mpd_to_sci_size(char **res, const mpd_t *dec, int fmt) +{ + int flags = MPD_FMT_TOSCI; + + flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; + return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE); +} + +mpd_ssize_t +mpd_to_eng_size(char **res, const mpd_t *dec, int fmt) +{ + int flags = MPD_FMT_TOENG; + + flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; + return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE); +} + +/* Copy a single UTF-8 char to dest. See: The Unicode Standard, version 5.2, + chapter 3.9: Well-formed UTF-8 byte sequences. */ +static int +_mpd_copy_utf8(char dest[5], const char *s) +{ + const uchar *cp = (const uchar *)s; + uchar lb, ub; + int count, i; + + + if (*cp == 0) { + /* empty string */ + dest[0] = '\0'; + return 0; + } + else if (*cp <= 0x7f) { + /* ascii */ + dest[0] = *cp; + dest[1] = '\0'; + return 1; + } + else if (0xc2 <= *cp && *cp <= 0xdf) { + lb = 0x80; ub = 0xbf; + count = 2; + } + else if (*cp == 0xe0) { + lb = 0xa0; ub = 0xbf; + count = 3; + } + else if (*cp <= 0xec) { + lb = 0x80; ub = 0xbf; + count = 3; + } + else if (*cp == 0xed) { + lb = 0x80; ub = 0x9f; + count = 3; + } + else if (*cp <= 0xef) { + lb = 0x80; ub = 0xbf; + count = 3; + } + else if (*cp == 0xf0) { + lb = 0x90; ub = 0xbf; + count = 4; + } + else if (*cp <= 0xf3) { + lb = 0x80; ub = 0xbf; + count = 4; + } + else if (*cp == 0xf4) { + lb = 0x80; ub = 0x8f; + count = 4; + } + else { + /* invalid */ + goto error; + } + + dest[0] = *cp++; + if (*cp < lb || ub < *cp) { + goto error; + } + dest[1] = *cp++; + for (i = 2; i < count; i++) { + if (*cp < 0x80 || 0xbf < *cp) { + goto error; + } + dest[i] = *cp++; + } + dest[i] = '\0'; + + return count; + +error: + dest[0] = '\0'; + return -1; +} + +int +mpd_validate_lconv(mpd_spec_t *spec) +{ + size_t n; +#if CHAR_MAX == SCHAR_MAX + const char *cp = spec->grouping; + while (*cp != '\0') { + if (*cp++ < 0) { + return -1; + } + } +#endif + n = strlen(spec->dot); + if (n == 0 || n > 4) { + return -1; + } + if (strlen(spec->sep) > 4) { + return -1; + } + + return 0; +} + +int +mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps) +{ + char *cp = (char *)fmt; + int have_align = 0, n; + + /* defaults */ + spec->min_width = 0; + spec->prec = -1; + spec->type = caps ? 'G' : 'g'; + spec->align = '>'; + spec->sign = '-'; + spec->dot = ""; + spec->sep = ""; + spec->grouping = ""; + + + /* presume that the first character is a UTF-8 fill character */ + if ((n = _mpd_copy_utf8(spec->fill, cp)) < 0) { + return 0; + } + + /* alignment directive, prefixed by a fill character */ + if (*cp && (*(cp+n) == '<' || *(cp+n) == '>' || + *(cp+n) == '=' || *(cp+n) == '^')) { + cp += n; + spec->align = *cp++; + have_align = 1; + } /* alignment directive */ + else { + /* default fill character */ + spec->fill[0] = ' '; + spec->fill[1] = '\0'; + if (*cp == '<' || *cp == '>' || + *cp == '=' || *cp == '^') { + spec->align = *cp++; + have_align = 1; + } + } + + /* sign formatting */ + if (*cp == '+' || *cp == '-' || *cp == ' ') { + spec->sign = *cp++; + } + + /* zero padding */ + if (*cp == '0') { + /* zero padding implies alignment, which should not be + * specified twice. */ + if (have_align) { + return 0; + } + spec->align = 'z'; + spec->fill[0] = *cp++; + spec->fill[1] = '\0'; + } + + /* minimum width */ + if (isdigit((uchar)*cp)) { + if (*cp == '0') { + return 0; + } + errno = 0; + spec->min_width = mpd_strtossize(cp, &cp, 10); + if (errno == ERANGE || errno == EINVAL) { + return 0; + } + } + + /* thousands separator */ + if (*cp == ',') { + spec->dot = "."; + spec->sep = ","; + spec->grouping = "\003\003"; + cp++; + } + + /* fraction digits or significant digits */ + if (*cp == '.') { + cp++; + if (!isdigit((uchar)*cp)) { + return 0; + } + errno = 0; + spec->prec = mpd_strtossize(cp, &cp, 10); + if (errno == ERANGE || errno == EINVAL) { + return 0; + } + } + + /* type */ + if (*cp == 'E' || *cp == 'e' || *cp == 'F' || *cp == 'f' || + *cp == 'G' || *cp == 'g' || *cp == '%') { + spec->type = *cp++; + } + else if (*cp == 'N' || *cp == 'n') { + /* locale specific conversion */ + struct lconv *lc; + /* separator has already been specified */ + if (*spec->sep) { + return 0; + } + spec->type = *cp++; + spec->type = (spec->type == 'N') ? 'G' : 'g'; + lc = localeconv(); + spec->dot = lc->decimal_point; + spec->sep = lc->thousands_sep; + spec->grouping = lc->grouping; + if (mpd_validate_lconv(spec) < 0) { + return 0; /* GCOV_NOT_REACHED */ + } + } + + /* check correctness */ + if (*cp != '\0') { + return 0; + } + + return 1; +} + +/* + * The following functions assume that spec->min_width <= MPD_MAX_PREC, which + * is made sure in mpd_qformat_spec. Then, even with a spec that inserts a + * four-byte separator after each digit, nbytes in the following struct + * cannot overflow. + */ + +/* Multibyte string */ +typedef struct { + mpd_ssize_t nbytes; /* length in bytes */ + mpd_ssize_t nchars; /* length in chars */ + mpd_ssize_t cur; /* current write index */ + char *data; +} mpd_mbstr_t; + +static inline void +_mpd_bcopy(char *dest, const char *src, mpd_ssize_t n) +{ + while (--n >= 0) { + dest[n] = src[n]; + } +} + +static inline void +_mbstr_copy_char(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n) +{ + dest->nbytes += n; + dest->nchars += (n > 0 ? 1 : 0); + dest->cur -= n; + + if (dest->data != NULL) { + _mpd_bcopy(dest->data+dest->cur, src, n); + } +} + +static inline void +_mbstr_copy_ascii(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n) +{ + dest->nbytes += n; + dest->nchars += n; + dest->cur -= n; + + if (dest->data != NULL) { + _mpd_bcopy(dest->data+dest->cur, src, n); + } +} + +static inline void +_mbstr_copy_pad(mpd_mbstr_t *dest, mpd_ssize_t n) +{ + dest->nbytes += n; + dest->nchars += n; + dest->cur -= n; + + if (dest->data != NULL) { + char *cp = dest->data + dest->cur; + while (--n >= 0) { + cp[n] = '0'; + } + } +} + +/* + * Copy a numeric string to dest->data, adding separators in the integer + * part according to spec->grouping. If leading zero padding is enabled + * and the result is smaller than spec->min_width, continue adding zeros + * and separators until the minimum width is reached. + * + * The final length of dest->data is stored in dest->nbytes. The number + * of UTF-8 characters is stored in dest->nchars. + * + * First run (dest->data == NULL): determine the length of the result + * string and store it in dest->nbytes. + * + * Second run (write to dest->data): data is written in chunks and in + * reverse order, starting with the rest of the numeric string. + */ +static void +_mpd_add_sep_dot(mpd_mbstr_t *dest, + const char *sign, /* location of optional sign */ + const char *src, mpd_ssize_t n_src, /* integer part and length */ + const char *dot, /* location of optional decimal point */ + const char *rest, mpd_ssize_t n_rest, /* remaining part and length */ + const mpd_spec_t *spec) +{ + mpd_ssize_t n_sep, n_sign, consume; + const char *g; + int pad = 0; + + n_sign = sign ? 1 : 0; + n_sep = (mpd_ssize_t)strlen(spec->sep); + /* Initial write index: set to location of '\0' in the output string. + * Irrelevant for the first run. */ + dest->cur = dest->nbytes; + dest->nbytes = dest->nchars = 0; + + _mbstr_copy_ascii(dest, rest, n_rest); + + if (dot) { + _mbstr_copy_char(dest, dot, (mpd_ssize_t)strlen(dot)); + } + + g = spec->grouping; + consume = *g; + while (1) { + /* If the group length is 0 or CHAR_MAX or greater than the + * number of source bytes, consume all remaining bytes. */ + if (*g == 0 || *g == CHAR_MAX || consume > n_src) { + consume = n_src; + } + n_src -= consume; + if (pad) { + _mbstr_copy_pad(dest, consume); + } + else { + _mbstr_copy_ascii(dest, src+n_src, consume); + } + + if (n_src == 0) { + /* Either the real source of intpart digits or the virtual + * source of padding zeros is exhausted. */ + if (spec->align == 'z' && + dest->nchars + n_sign < spec->min_width) { + /* Zero padding is set and length < min_width: + * Generate n_src additional characters. */ + n_src = spec->min_width - (dest->nchars + n_sign); + /* Next iteration: + * case *g == 0 || *g == CHAR_MAX: + * consume all padding characters + * case consume < g*: + * fill remainder of current group + * case consume == g* + * copying is a no-op */ + consume = *g - consume; + /* Switch on virtual source of zeros. */ + pad = 1; + continue; + } + break; + } + + if (n_sep > 0) { + /* If padding is switched on, separators are counted + * as padding characters. This rule does not apply if + * the separator would be the first character of the + * result string. */ + if (pad && n_src > 1) n_src -= 1; + _mbstr_copy_char(dest, spec->sep, n_sep); + } + + /* If non-NUL, use the next value for grouping. */ + if (*g && *(g+1)) g++; + consume = *g; + } + + if (sign) { + _mbstr_copy_ascii(dest, sign, 1); + } + + if (dest->data) { + dest->data[dest->nbytes] = '\0'; + } +} + +/* + * Convert a numeric-string to its locale-specific appearance. + * The string must have one of these forms: + * + * 1) [sign] digits [exponent-part] + * 2) [sign] digits '.' [digits] [exponent-part] + * + * Not allowed, since _mpd_to_string() never returns this form: + * + * 3) [sign] '.' digits [exponent-part] + * + * Input: result->data := original numeric string (ASCII) + * result->bytes := strlen(result->data) + * result->nchars := strlen(result->data) + * + * Output: result->data := modified or original string + * result->bytes := strlen(result->data) + * result->nchars := number of characters (possibly UTF-8) + */ +static int +_mpd_apply_lconv(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status) +{ + const char *sign = NULL, *intpart = NULL, *dot = NULL; + const char *rest, *dp; + char *decstring; + mpd_ssize_t n_int, n_rest; + + /* original numeric string */ + dp = result->data; + + /* sign */ + if (*dp == '+' || *dp == '-' || *dp == ' ') { + sign = dp++; + } + /* integer part */ + assert(isdigit((uchar)*dp)); + intpart = dp++; + while (isdigit((uchar)*dp)) { + dp++; + } + n_int = (mpd_ssize_t)(dp-intpart); + /* decimal point */ + if (*dp == '.') { + dp++; dot = spec->dot; + } + /* rest */ + rest = dp; + n_rest = result->nbytes - (mpd_ssize_t)(dp-result->data); + + if (dot == NULL && (*spec->sep == '\0' || *spec->grouping == '\0')) { + /* _mpd_add_sep_dot() would not change anything */ + return 1; + } + + /* Determine the size of the new decimal string after inserting the + * decimal point, optional separators and optional padding. */ + decstring = result->data; + result->data = NULL; + _mpd_add_sep_dot(result, sign, intpart, n_int, dot, + rest, n_rest, spec); + + result->data = mpd_alloc(result->nbytes+1, 1); + if (result->data == NULL) { + *status |= MPD_Malloc_error; + mpd_free(decstring); + return 0; + } + + /* Perform actual writes. */ + _mpd_add_sep_dot(result, sign, intpart, n_int, dot, + rest, n_rest, spec); + + mpd_free(decstring); + return 1; +} + +/* Add padding to the formatted string if necessary. */ +static int +_mpd_add_pad(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status) +{ + if (result->nchars < spec->min_width) { + mpd_ssize_t add_chars, add_bytes; + size_t lpad = 0, rpad = 0; + size_t n_fill, len, i, j; + char align = spec->align; + uint8_t err = 0; + char *cp; + + n_fill = strlen(spec->fill); + add_chars = (spec->min_width - result->nchars); + /* max value: MPD_MAX_PREC * 4 */ + add_bytes = add_chars * (mpd_ssize_t)n_fill; + + cp = result->data = mpd_realloc(result->data, + result->nbytes+add_bytes+1, + sizeof *result->data, &err); + if (err) { + *status |= MPD_Malloc_error; + mpd_free(result->data); + return 0; + } + + if (align == 'z') { + align = '='; + } + + if (align == '<') { + rpad = add_chars; + } + else if (align == '>' || align == '=') { + lpad = add_chars; + } + else { /* align == '^' */ + lpad = add_chars/2; + rpad = add_chars-lpad; + } + + len = result->nbytes; + if (align == '=' && (*cp == '-' || *cp == '+' || *cp == ' ')) { + /* leave sign in the leading position */ + cp++; len--; + } + + memmove(cp+n_fill*lpad, cp, len); + for (i = 0; i < lpad; i++) { + for (j = 0; j < n_fill; j++) { + cp[i*n_fill+j] = spec->fill[j]; + } + } + cp += (n_fill*lpad + len); + for (i = 0; i < rpad; i++) { + for (j = 0; j < n_fill; j++) { + cp[i*n_fill+j] = spec->fill[j]; + } + } + + result->nbytes += add_bytes; + result->nchars += add_chars; + result->data[result->nbytes] = '\0'; + } + + return 1; +} + +/* Round a number to prec digits. The adjusted exponent stays the same + or increases by one if rounding up crosses a power of ten boundary. + If result->digits would exceed MPD_MAX_PREC+1, MPD_Invalid_operation + is set and the result is NaN. */ +static inline void +_mpd_round(mpd_t *result, const mpd_t *a, mpd_ssize_t prec, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t exp = a->exp + a->digits - prec; + + if (prec <= 0) { + mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_NOT_REACHED */ + return; /* GCOV_NOT_REACHED */ + } + if (mpd_isspecial(a) || mpd_iszero(a)) { + mpd_qcopy(result, a, status); /* GCOV_NOT_REACHED */ + return; /* GCOV_NOT_REACHED */ + } + + mpd_qrescale_fmt(result, a, exp, ctx, status); + if (result->digits > prec) { + mpd_qrescale_fmt(result, result, exp+1, ctx, status); + } +} + +/* + * Return the string representation of an mpd_t, formatted according to 'spec'. + * The format specification is assumed to be valid. Memory errors are indicated + * as usual. This function is quiet. + */ +char * +mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t dt[MPD_MINALLOC_MAX]; + mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt}; + mpd_ssize_t dplace = MPD_DEFAULT_DOTPLACE; + mpd_mbstr_t result; + mpd_spec_t stackspec; + char type = spec->type; + int flags = 0; + + + if (spec->min_width > MPD_MAX_PREC) { + *status |= MPD_Invalid_operation; + return NULL; + } + + if (isupper((uchar)type)) { + type = tolower((uchar)type); + flags |= MPD_FMT_UPPER; + } + if (spec->sign == ' ') { + flags |= MPD_FMT_SIGN_SPACE; + } + else if (spec->sign == '+') { + flags |= MPD_FMT_SIGN_PLUS; + } + + if (mpd_isspecial(dec)) { + if (spec->align == 'z') { + stackspec = *spec; + stackspec.fill[0] = ' '; + stackspec.fill[1] = '\0'; + stackspec.align = '>'; + spec = &stackspec; + } + } + else { + uint32_t workstatus = 0; + mpd_ssize_t prec; + + switch (type) { + case 'g': flags |= MPD_FMT_TOSCI; break; + case 'e': flags |= MPD_FMT_EXP; break; + case '%': flags |= MPD_FMT_PERCENT; + if (!mpd_qcopy(&tmp, dec, status)) { + return NULL; + } + tmp.exp += 2; + dec = &tmp; + type = 'f'; /* fall through */ + case 'f': flags |= MPD_FMT_FIXED; break; + default: abort(); /* debug: GCOV_NOT_REACHED */ + } + + if (spec->prec >= 0) { + if (spec->prec > MPD_MAX_PREC) { + *status |= MPD_Invalid_operation; + goto error; + } + + switch (type) { + case 'g': + prec = (spec->prec == 0) ? 1 : spec->prec; + if (dec->digits > prec) { + _mpd_round(&tmp, dec, prec, ctx, + &workstatus); + dec = &tmp; + } + break; + case 'e': + if (mpd_iszero(dec)) { + dplace = 1-spec->prec; + } + else { + _mpd_round(&tmp, dec, spec->prec+1, ctx, + &workstatus); + dec = &tmp; + } + break; + case 'f': + mpd_qrescale(&tmp, dec, -spec->prec, ctx, + &workstatus); + dec = &tmp; + break; + } + } + + if (type == 'f') { + if (mpd_iszero(dec) && dec->exp > 0) { + mpd_qrescale(&tmp, dec, 0, ctx, &workstatus); + dec = &tmp; + } + } + + if (workstatus&MPD_Errors) { + *status |= (workstatus&MPD_Errors); + goto error; + } + } + + /* + * At this point, for all scaled or non-scaled decimals: + * 1) 1 <= digits <= MAX_PREC+1 + * 2) adjexp(scaled) = adjexp(orig) [+1] + * 3) case 'g': MIN_ETINY <= exp <= MAX_EMAX+1 + * case 'e': MIN_ETINY-MAX_PREC <= exp <= MAX_EMAX+1 + * case 'f': MIN_ETINY <= exp <= MAX_EMAX+1 + * 4) max memory alloc in _mpd_to_string: + * case 'g': MAX_PREC+36 + * case 'e': MAX_PREC+36 + * case 'f': 2*MPD_MAX_PREC+30 + */ + result.nbytes = _mpd_to_string(&result.data, dec, flags, dplace); + result.nchars = result.nbytes; + if (result.nbytes < 0) { + *status |= MPD_Malloc_error; + goto error; + } + + if (*spec->dot != '\0' && !mpd_isspecial(dec)) { + if (result.nchars > MPD_MAX_PREC+36) { + /* Since a group length of one is not explicitly + * disallowed, ensure that it is always possible to + * insert a four byte separator after each digit. */ + *status |= MPD_Invalid_operation; + mpd_free(result.data); + goto error; + } + if (!_mpd_apply_lconv(&result, spec, status)) { + goto error; + } + } + + if (spec->min_width) { + if (!_mpd_add_pad(&result, spec, status)) { + goto error; + } + } + + mpd_del(&tmp); + return result.data; + +error: + mpd_del(&tmp); + return NULL; +} + +char * +mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_spec_t spec; + + if (!mpd_parse_fmt_str(&spec, fmt, 1)) { + *status |= MPD_Invalid_operation; + return NULL; + } + + return mpd_qformat_spec(dec, &spec, ctx, status); +} + +/* + * The specification has a *condition* called Invalid_operation and an + * IEEE *signal* called Invalid_operation. The former corresponds to + * MPD_Invalid_operation, the latter to MPD_IEEE_Invalid_operation. + * MPD_IEEE_Invalid_operation comprises the following conditions: + * + * [MPD_Conversion_syntax, MPD_Division_impossible, MPD_Division_undefined, + * MPD_Fpu_error, MPD_Invalid_context, MPD_Invalid_operation, + * MPD_Malloc_error] + * + * In the following functions, 'flag' denotes the condition, 'signal' + * denotes the IEEE signal. + */ + +static const char *mpd_flag_string[MPD_NUM_FLAGS] = { + "Clamped", + "Conversion_syntax", + "Division_by_zero", + "Division_impossible", + "Division_undefined", + "Fpu_error", + "Inexact", + "Invalid_context", + "Invalid_operation", + "Malloc_error", + "Not_implemented", + "Overflow", + "Rounded", + "Subnormal", + "Underflow", +}; + +static const char *mpd_signal_string[MPD_NUM_FLAGS] = { + "Clamped", + "IEEE_Invalid_operation", + "Division_by_zero", + "IEEE_Invalid_operation", + "IEEE_Invalid_operation", + "IEEE_Invalid_operation", + "Inexact", + "IEEE_Invalid_operation", + "IEEE_Invalid_operation", + "IEEE_Invalid_operation", + "Not_implemented", + "Overflow", + "Rounded", + "Subnormal", + "Underflow", +}; + +/* print conditions to buffer, separated by spaces */ +int +mpd_snprint_flags(char *dest, int nmemb, uint32_t flags) +{ + char *cp; + int n, j; + + assert(nmemb >= MPD_MAX_FLAG_STRING); + + *dest = '\0'; cp = dest; + for (j = 0; j < MPD_NUM_FLAGS; j++) { + if (flags & (1U<= nmemb) return -1; + cp += n; nmemb -= n; + } + } + + if (cp != dest) { + *(--cp) = '\0'; + } + + return (int)(cp-dest); +} + +/* print conditions to buffer, in list form */ +int +mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[]) +{ + char *cp; + int n, j; + + assert(nmemb >= MPD_MAX_FLAG_LIST); + if (flag_string == NULL) { + flag_string = mpd_flag_string; + } + + *dest = '['; + *(dest+1) = '\0'; + cp = dest+1; + --nmemb; + + for (j = 0; j < MPD_NUM_FLAGS; j++) { + if (flags & (1U<= nmemb) return -1; + cp += n; nmemb -= n; + } + } + + /* erase the last ", " */ + if (cp != dest+1) { + cp -= 2; + } + + *cp++ = ']'; + *cp = '\0'; + + return (int)(cp-dest); /* strlen, without NUL terminator */ +} + +/* print signals to buffer, in list form */ +int +mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[]) +{ + char *cp; + int n, j; + int ieee_invalid_done = 0; + + assert(nmemb >= MPD_MAX_SIGNAL_LIST); + if (signal_string == NULL) { + signal_string = mpd_signal_string; + } + + *dest = '['; + *(dest+1) = '\0'; + cp = dest+1; + --nmemb; + + for (j = 0; j < MPD_NUM_FLAGS; j++) { + uint32_t f = flags & (1U<= nmemb) return -1; + cp += n; nmemb -= n; + } + } + + /* erase the last ", " */ + if (cp != dest+1) { + cp -= 2; + } + + *cp++ = ']'; + *cp = '\0'; + + return (int)(cp-dest); /* strlen, without NUL terminator */ +} + +/* The following two functions are mainly intended for debugging. */ +void +mpd_fprint(FILE *file, const mpd_t *dec) +{ + char *decstring; + + decstring = mpd_to_sci(dec, 1); + if (decstring != NULL) { + fprintf(file, "%s\n", decstring); + mpd_free(decstring); + } + else { + fputs("mpd_fprint: output error\n", file); /* GCOV_NOT_REACHED */ + } +} + +void +mpd_print(const mpd_t *dec) +{ + char *decstring; + + decstring = mpd_to_sci(dec, 1); + if (decstring != NULL) { + printf("%s\n", decstring); + mpd_free(decstring); + } + else { + fputs("mpd_fprint: output error\n", stderr); /* GCOV_NOT_REACHED */ + } +} + + diff --git a/Modules/_decimal/libmpdec/io.h b/Modules/_decimal/libmpdec/io.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/io.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef IO_H +#define IO_H + + +#include +#include "mpdecimal.h" + + +#if SIZE_MAX == MPD_SIZE_MAX + #define mpd_strtossize _mpd_strtossize +#else +static inline mpd_ssize_t +mpd_strtossize(const char *s, char **end, int base) +{ + int64_t retval; + + errno = 0; + retval = _mpd_strtossize(s, end, base); + if (errno == 0 && (retval > MPD_SSIZE_MAX || retval < MPD_SSIZE_MIN)) { + errno = ERANGE; + } + if (errno == ERANGE) { + return (retval < 0) ? MPD_SSIZE_MIN : MPD_SSIZE_MAX; + } + + return (mpd_ssize_t)retval; +} +#endif + + +#endif diff --git a/Modules/_decimal/libmpdec/literature/REFERENCES.txt b/Modules/_decimal/libmpdec/literature/REFERENCES.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/REFERENCES.txt @@ -0,0 +1,51 @@ + + +This document contains links to the literature used in the process of +creating the library. The list is probably not complete. + + +Mike Cowlishaw: General Decimal Arithmetic Specification +http://speleotrove.com/decimal/decarith.html + + +Jean-Michel Muller: On the definition of ulp (x) +lara.inist.fr/bitstream/2332/518/1/LIP-RR2005-09.pdf + + +T. E. Hull, A. Abrham: Properly rounded variable precision square root +http://portal.acm.org/citation.cfm?id=214413 + + +T. E. Hull, A. Abrham: Variable precision exponential function +http://portal.acm.org/citation.cfm?id=6498 + + +Roman E. Maeder: Storage allocation for the Karatsuba integer multiplication +algorithm. http://www.springerlink.com/content/w15058mj6v59t565/ + + +J. M. Pollard: The fast Fourier transform in a finite field +http://www.ams.org/journals/mcom/1971-25-114/S0025-5718-1971-0301966-0/home.html + + +David H. Bailey: FFTs in External or Hierarchical Memory +http://crd.lbl.gov/~dhbailey/dhbpapers/ + + +W. Morven Gentleman: Matrix Multiplication and Fast Fourier Transforms +http://www.alcatel-lucent.com/bstj/vol47-1968/articles/bstj47-6-1099.pdf + + +Mikko Tommila: Apfloat documentation +http://www.apfloat.org/apfloat/2.41/apfloat.pdf + + +Joerg Arndt: "Matters Computational" +http://www.jjj.de/fxt/ + + +Karl Hasselstrom: Fast Division of Large Integers +www.treskal.com/kalle/exjobb/original-report.pdf + + + diff --git a/Modules/_decimal/libmpdec/literature/bignum.txt b/Modules/_decimal/libmpdec/literature/bignum.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/bignum.txt @@ -0,0 +1,83 @@ + + +Bignum support (Fast Number Theoretic Transform or FNT): +======================================================== + +Bignum arithmetic in libmpdec uses the scheme for fast convolution +of integer sequences from: + +J. M. Pollard: The fast Fourier transform in a finite field +http://www.ams.org/journals/mcom/1971-25-114/S0025-5718-1971-0301966-0/home.html + + +The transform in a finite field can be used for convolution in the same +way as the Fourier Transform. The main advantages of the Number Theoretic +Transform are that it is both exact and very memory efficient. + + +Convolution in pseudo-code: +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + fnt_convolute(a, b): + x = fnt(a) # forward transform of a + y = fnt(b) # forward transform of b + z = pairwise multiply x[i] and y[i] + result = inv_fnt(z) # backward transform of z. + + +Extending the maximum transform length (Chinese Remainder Theorem): +------------------------------------------------------------------- + +The maximum transform length is quite limited when using a single +prime field. However, it is possible to use multiple primes and +recover the result using the Chinese Remainder Theorem. + + +Multiplication in pseudo-code: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + _mpd_fntmul(u, v): + c1 = fnt_convolute(u, v, P1) # convolute modulo prime1 + c2 = fnt_convolute(u, v, P2) # convolute modulo prime2 + c3 = fnt_convolute(u, v, P3) # convolute modulo prime3 + result = crt3(c1, c2, c3) # Chinese Remainder Theorem + + +Optimized transform functions: +------------------------------ + +There are three different fnt() functions: + + std_fnt: "standard" decimation in frequency transform for array lengths + of 2**n. Performs well up to 1024 words. + + sixstep: Cache-friendly algorithm for array lengths of 2**n. Outperforms + std_fnt for large arrays. + + fourstep: Algorithm for array lengths of 3 * 2**n. Also cache friendly + in large parts. + + +List of bignum-only files: +-------------------------- + +Functions from these files are only used in _mpd_fntmul(). + + umodarith.h -> fast low level routines for unsigned modular arithmetic + numbertheory.c -> routines for setting up the FNT + difradix2.c -> decimation in frequency transform, used as the + "base case" by the following three files: + + fnt.c -> standard transform for smaller arrays + sixstep.c -> transform large arrays of length 2**n + fourstep.c -> transform arrays of length 3 * 2**n + + convolute.c -> do the actual fast convolution, using one of + the three transform functions. + transpose.c -> transpositions needed for the sixstep algorithm. + crt.c -> Chinese Remainder Theorem: use information from three + transforms modulo three different primes to get the + final result. + + + diff --git a/Modules/_decimal/libmpdec/literature/fnt.py b/Modules/_decimal/libmpdec/literature/fnt.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/fnt.py @@ -0,0 +1,208 @@ +# +# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + + +###################################################################### +# This file lists and checks some of the constants and limits used # +# in libmpdec's Number Theoretic Transform. At the end of the file # +# there is an example function for the plain DFT transform. # +###################################################################### + + +# +# Number theoretic transforms are done in subfields of F(p). P[i] +# are the primes, D[i] = P[i] - 1 are highly composite and w[i] +# are the respective primitive roots of F(p). +# +# The strategy is to convolute two coefficients modulo all three +# primes, then use the Chinese Remainder Theorem on the three +# result arrays to recover the result in the usual base RADIX +# form. +# + +# ====================================================================== +# Primitive roots +# ====================================================================== + +# +# Verify primitive roots: +# +# For a prime field, r is a primitive root if and only if for all prime +# factors f of p-1, r**((p-1)/f) =/= 1 (mod p). +# +def prod(F, E): + """Check that the factorization of P-1 is correct. F is the list of + factors of P-1, E lists the number of occurrences of each factor.""" + x = 1 + for y, z in zip(F, E): + x *= y**z + return x + +def is_primitive_root(r, p, factors, exponents): + """Check if r is a primitive root of F(p).""" + if p != prod(factors, exponents) + 1: + return False + for f in factors: + q, control = divmod(p-1, f) + if control != 0: + return False + if pow(r, q, p) == 1: + return False + return True + + +# ================================================================= +# Constants and limits for the 64-bit version +# ================================================================= + +RADIX = 10**19 + +# Primes P1, P2 and P3: +P = [2**64-2**32+1, 2**64-2**34+1, 2**64-2**40+1] + +# P-1, highly composite. The transform length d is variable and +# must divide D = P-1. Since all D are divisible by 3 * 2**32, +# transform lengths can be 2**n or 3 * 2**n (where n <= 32). +D = [2**32 * 3 * (5 * 17 * 257 * 65537), + 2**34 * 3**2 * (7 * 11 * 31 * 151 * 331), + 2**40 * 3**2 * (5 * 7 * 13 * 17 * 241)] + +# Prime factors of P-1 and their exponents: +F = [(2,3,5,17,257,65537), (2,3,7,11,31,151,331), (2,3,5,7,13,17,241)] +E = [(32,1,1,1,1,1), (34,2,1,1,1,1,1), (40,2,1,1,1,1,1)] + +# Maximum transform length for 2**n. Above that only 3 * 2**31 +# or 3 * 2**32 are possible. +MPD_MAXTRANSFORM_2N = 2**32 + + +# Limits in the terminology of Pollard's paper: +m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array. +M1 = M2 = RADIX-1 # Maximum value per single word. +L = m2 * M1 * M2 +P[0] * P[1] * P[2] > 2 * L + + +# Primitive roots of F(P1), F(P2) and F(P3): +w = [7, 10, 19] + +# The primitive roots are correct: +for i in range(3): + if not is_primitive_root(w[i], P[i], F[i], E[i]): + print("FAIL") + + +# ================================================================= +# Constants and limits for the 32-bit version +# ================================================================= + +RADIX = 10**9 + +# Primes P1, P2 and P3: +P = [2113929217, 2013265921, 1811939329] + +# P-1, highly composite. All D = P-1 are divisible by 3 * 2**25, +# allowing for transform lengths up to 3 * 2**25 words. +D = [2**25 * 3**2 * 7, + 2**27 * 3 * 5, + 2**26 * 3**3] + +# Prime factors of P-1 and their exponents: +F = [(2,3,7), (2,3,5), (2,3)] +E = [(25,2,1), (27,1,1), (26,3)] + +# Maximum transform length for 2**n. Above that only 3 * 2**24 or +# 3 * 2**25 are possible. +MPD_MAXTRANSFORM_2N = 2**25 + + +# Limits in the terminology of Pollard's paper: +m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array. +M1 = M2 = RADIX-1 # Maximum value per single word. +L = m2 * M1 * M2 +P[0] * P[1] * P[2] > 2 * L + + +# Primitive roots of F(P1), F(P2) and F(P3): +w = [5, 31, 13] + +# The primitive roots are correct: +for i in range(3): + if not is_primitive_root(w[i], P[i], F[i], E[i]): + print("FAIL") + + +# ====================================================================== +# Example transform using a single prime +# ====================================================================== + +def ntt(lst, dir): + """Perform a transform on the elements of lst. len(lst) must + be 2**n or 3 * 2**n, where n <= 25. This is the slow DFT.""" + p = 2113929217 # prime + d = len(lst) # transform length + d_prime = pow(d, (p-2), p) # inverse of d + xi = (p-1)//d + w = 5 # primitive root of F(p) + r = pow(w, xi, p) # primitive root of the subfield + r_prime = pow(w, (p-1-xi), p) # inverse of r + if dir == 1: # forward transform + a = lst # input array + A = [0] * d # transformed values + for i in range(d): + s = 0 + for j in range(d): + s += a[j] * pow(r, i*j, p) + A[i] = s % p + return A + elif dir == -1: # backward transform + A = lst # input array + a = [0] * d # transformed values + for j in range(d): + s = 0 + for i in range(d): + s += A[i] * pow(r_prime, i*j, p) + a[j] = (d_prime * s) % p + return a + +def ntt_convolute(a, b): + """convolute arrays a and b.""" + assert(len(a) == len(b)) + x = ntt(a, 1) + y = ntt(b, 1) + for i in range(len(a)): + y[i] = y[i] * x[i] + r = ntt(y, -1) + return r + + +# Example: Two arrays representing 21 and 81 in little-endian: +a = [1, 2, 0, 0] +b = [1, 8, 0, 0] + +assert(ntt_convolute(a, b) == [1, 10, 16, 0]) +assert(21 * 81 == (1*10**0 + 10*10**1 + 16*10**2 + 0*10**3)) diff --git a/Modules/_decimal/libmpdec/literature/matrix-transform.txt b/Modules/_decimal/libmpdec/literature/matrix-transform.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/matrix-transform.txt @@ -0,0 +1,256 @@ + + +(* Copyright (c) 2011 Stefan Krah. All rights reserved. *) + + +The Matrix Fourier Transform: +============================= + +In libmpdec, the Matrix Fourier Transform [1] is called four-step transform +after a variant that appears in [2]. The algorithm requires that the input +array can be viewed as an R*C matrix. + +All operations are done modulo p. For readability, the proofs drop all +instances of (mod p). + + +Algorithm four-step (forward transform): +---------------------------------------- + + a := input array + d := len(a) = R * C + p := prime + w := primitive root of unity of the prime field + r := w**((p-1)/d) + A := output array + + 1) Apply a length R FNT to each column. + + 2) Multiply each matrix element (addressed by j*C+m) by r**(j*m). + + 3) Apply a length C FNT to each row. + + 4) Transpose the matrix. + + +Proof (forward transform): +-------------------------- + + The algorithm can be derived starting from the regular definition of + the finite-field transform of length d: + + d-1 + ,---- + \ + A[k] = | a[l] * r**(k * l) + / + `---- + l = 0 + + + The sum can be rearranged into the sum of the sums of columns: + + C-1 R-1 + ,---- ,---- + \ \ + = | | a[i * C + j] * r**(k * (i * C + j)) + / / + `---- `---- + j = 0 i = 0 + + + Extracting a constant from the inner sum: + + C-1 R-1 + ,---- ,---- + \ \ + = | r**k*j * | a[i * C + j] * r**(k * i * C) + / / + `---- `---- + j = 0 i = 0 + + + Without any loss of generality, let k = n * R + m, + where n < C and m < R: + + C-1 R-1 + ,---- ,---- + \ \ + A[n*R+m] = | r**(R*n*j) * r**(m*j) * | a[i*C+j] * r**(R*C*n*i) * r**(C*m*i) + / / + `---- `---- + j = 0 i = 0 + + + Since r = w ** ((p-1) / (R*C)): + + a) r**(R*C*n*i) = w**((p-1)*n*i) = 1 + + b) r**(C*m*i) = w**((p-1) / R) ** (m*i) = r_R ** (m*i) + + c) r**(R*n*j) = w**((p-1) / C) ** (n*j) = r_C ** (n*j) + + r_R := root of the subfield of length R. + r_C := root of the subfield of length C. + + + C-1 R-1 + ,---- ,---- + \ \ + A[n*R+m] = | r_C**(n*j) * [ r**(m*j) * | a[i*C+j] * r_R**(m*i) ] + / ^ / + `---- | `---- 1) transform the columns + j = 0 | i = 0 + ^ | + | `-- 2) multiply + | + `-- 3) transform the rows + + + Note that the entire RHS is a function of n and m and that the results + for each pair (n, m) are stored in Fortran order. + + Let the term in square brackets be f(m, j). Step 1) and 2) precalculate + the term for all (m, j). After that, the original matrix is now a lookup + table with the mth element in the jth column at location m * C + j. + + Let the complete RHS be g(m, n). Step 3) does an in-place transform of + length n on all rows. After that, the original matrix is now a lookup + table with the mth element in the nth column at location m * C + n. + + But each (m, n) pair should be written to location n * R + m. Therefore, + step 4) transposes the result of step 3). + + + +Algorithm four-step (inverse transform): +---------------------------------------- + + A := input array + d := len(A) = R * C + p := prime + d' := d**(p-2) # inverse of d + w := primitive root of unity of the prime field + r := w**((p-1)/d) # root of the subfield + r' := w**((p-1) - (p-1)/d) # inverse of r + a := output array + + 0) View the matrix as a C*R matrix. + + 1) Transpose the matrix, producing an R*C matrix. + + 2) Apply a length C FNT to each row. + + 3) Multiply each matrix element (addressed by i*C+n) by r**(i*n). + + 4) Apply a length R FNT to each column. + + +Proof (inverse transform): +-------------------------- + + The algorithm can be derived starting from the regular definition of + the finite-field inverse transform of length d: + + d-1 + ,---- + \ + a[k] = d' * | A[l] * r' ** (k * l) + / + `---- + l = 0 + + + The sum can be rearranged into the sum of the sums of columns. Note + that at this stage we still have a C*R matrix, so C denotes the number + of rows: + + R-1 C-1 + ,---- ,---- + \ \ + = d' * | | a[j * R + i] * r' ** (k * (j * R + i)) + / / + `---- `---- + i = 0 j = 0 + + + Extracting a constant from the inner sum: + + R-1 C-1 + ,---- ,---- + \ \ + = d' * | r' ** (k*i) * | a[j * R + i] * r' ** (k * j * R) + / / + `---- `---- + i = 0 j = 0 + + + Without any loss of generality, let k = m * C + n, + where m < R and n < C: + + R-1 C-1 + ,---- ,---- + \ \ + A[m*C+n] = d' * | r' ** (C*m*i) * r' ** (n*i) * | a[j*R+i] * r' ** (R*C*m*j) * r' ** (R*n*j) + / / + `---- `---- + i = 0 j = 0 + + + Since r' = w**((p-1) - (p-1)/d) and d = R*C: + + a) r' ** (R*C*m*j) = w**((p-1)*R*C*m*j - (p-1)*m*j) = 1 + + b) r' ** (C*m*i) = w**((p-1)*C - (p-1)/R) ** (m*i) = r_R' ** (m*i) + + c) r' ** (R*n*j) = r_C' ** (n*j) + + d) d' = d**(p-2) = (R*C) ** (p-2) = R**(p-2) * C**(p-2) = R' * C' + + r_R' := inverse of the root of the subfield of length R. + r_C' := inverse of the root of the subfield of length C. + R' := inverse of R + C' := inverse of C + + + R-1 C-1 + ,---- ,---- 2) transform the rows of a^T + \ \ + A[m*C+n] = R' * | r_R' ** (m*i) * [ r' ** (n*i) * C' * | a[j*R+i] * r_C' ** (n*j) ] + / ^ / ^ + `---- | `---- | + i = 0 | j = 0 | + ^ | `-- 1) Transpose input matrix + | `-- 3) multiply to address elements by + | i * C + j + `-- 3) transform the columns + + + + Note that the entire RHS is a function of m and n and that the results + for each pair (m, n) are stored in C order. + + Let the term in square brackets be f(n, i). Without step 1), the sum + would perform a length C transform on the columns of the input matrix. + This is a) inefficient and b) the results are needed in C order, so + step 1) exchanges rows and columns. + + Step 2) and 3) precalculate f(n, i) for all (n, i). After that, the + original matrix is now a lookup table with the ith element in the nth + column at location i * C + n. + + Let the complete RHS be g(m, n). Step 4) does an in-place transform of + length m on all columns. After that, the original matrix is now a lookup + table with the mth element in the nth column at location m * C + n, + which means that all A[k] = A[m * C + n] are in the correct order. + + +-- + + [1] Joerg Arndt: "Matters Computational" + http://www.jjj.de/fxt/ + [2] David H. Bailey: FFTs in External or Hierarchical Memory + http://crd.lbl.gov/~dhbailey/dhbpapers/ + + + diff --git a/Modules/_decimal/libmpdec/literature/mulmod-64.txt b/Modules/_decimal/libmpdec/literature/mulmod-64.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/mulmod-64.txt @@ -0,0 +1,127 @@ + + +(* Copyright (c) 2011 Stefan Krah. All rights reserved. *) + + +========================================================================== + Calculate (a * b) % p using special primes +========================================================================== + +A description of the algorithm can be found in the apfloat manual by +Tommila [1]. + + +Definitions: +------------ + +In the whole document, "==" stands for "is congruent with". + +Result of a * b in terms of high/low words: + + (1) hi * 2**64 + lo = a * b + +Special primes: + + (2) p = 2**64 - z + 1, where z = 2**n + +Single step modular reduction: + + (3) R(hi, lo) = hi * z - hi + lo + + +Strategy: +--------- + + a) Set (hi, lo) to the result of a * b. + + b) Set (hi', lo') to the result of R(hi, lo). + + c) Repeat step b) until 0 <= hi' * 2**64 + lo' < 2*p. + + d) If the result is less than p, return lo'. Otherwise return lo' - p. + + +The reduction step b) preserves congruence: +------------------------------------------- + + hi * 2**64 + lo == hi * z - hi + lo (mod p) + + Proof: + ~~~~~~ + + hi * 2**64 + lo = (2**64 - z + 1) * hi + z * hi - hi + lo + + = p * hi + z * hi - hi + lo + + == z * hi - hi + lo (mod p) + + +Maximum numbers of step b): +--------------------------- + +# To avoid unneccessary formalism, define: + +def R(hi, lo, z): + return divmod(hi * z - hi + lo, 2**64) + +# For simplicity, assume hi=2**64-1, lo=2**64-1 after the +# initial multiplication a * b. This is of course impossible +# but certainly covers all cases. + +# Then, for p1: +hi=2**64-1; lo=2**64-1; z=2**32 +p1 = 2**64 - z + 1 + +hi, lo = R(hi, lo, z) # First reduction +hi, lo = R(hi, lo, z) # Second reduction +hi * 2**64 + lo < 2 * p1 # True + +# For p2: +hi=2**64-1; lo=2**64-1; z=2**34 +p2 = 2**64 - z + 1 + +hi, lo = R(hi, lo, z) # First reduction +hi, lo = R(hi, lo, z) # Second reduction +hi, lo = R(hi, lo, z) # Third reduction +hi * 2**64 + lo < 2 * p2 # True + +# For p3: +hi=2**64-1; lo=2**64-1; z=2**40 +p3 = 2**64 - z + 1 + +hi, lo = R(hi, lo, z) # First reduction +hi, lo = R(hi, lo, z) # Second reduction +hi, lo = R(hi, lo, z) # Third reduction +hi * 2**64 + lo < 2 * p3 # True + + +Step d) preserves congruence and yields a result < p: +----------------------------------------------------- + + Case hi = 0: + + Case lo < p: trivial. + + Case lo >= p: + + lo == lo - p (mod p) # result is congruent + + p <= lo < 2*p -> 0 <= lo - p < p # result is in the correct range + + Case hi = 1: + + p < 2**64 /\ 2**64 + lo < 2*p -> lo < p # lo is always less than p + + 2**64 + lo == 2**64 + (lo - p) (mod p) # result is congruent + + = lo - p # exactly the same value as the previous RHS + # in uint64_t arithmetic. + + p < 2**64 + lo < 2*p -> 0 < 2**64 + (lo - p) < p # correct range + + + +[1] http://www.apfloat.org/apfloat/2.40/apfloat.pdf + + + diff --git a/Modules/_decimal/libmpdec/literature/mulmod-ppro.txt b/Modules/_decimal/libmpdec/literature/mulmod-ppro.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/mulmod-ppro.txt @@ -0,0 +1,269 @@ + + +(* Copyright (c) 2011 Stefan Krah. All rights reserved. *) + + +======================================================================== + Calculate (a * b) % p using the 80-bit x87 FPU +======================================================================== + +A description of the algorithm can be found in the apfloat manual by +Tommila [1]. + +The proof follows an argument made by Granlund/Montgomery in [2]. + + +Definitions and assumptions: +---------------------------- + +The 80-bit extended precision format uses 64 bits for the significand: + + (1) F = 64 + +The modulus is prime and less than 2**31: + + (2) 2 <= p < 2**31 + +The factors are less than p: + + (3) 0 <= a < p + (4) 0 <= b < p + +The product a * b is less than 2**62 and is thus exact in 64 bits: + + (5) n = a * b + +The product can be represented in terms of quotient and remainder: + + (6) n = q * p + r + +Using (3), (4) and the fact that p is prime, the remainder is always +greater than zero: + + (7) 0 <= q < p /\ 1 <= r < p + + +Strategy: +--------- + +Precalculate the 80-bit long double inverse of p, with a maximum +relative error of 2**(1-F): + + (8) pinv = (long double)1.0 / p + +Calculate an estimate for q = floor(n/p). The multiplication has another +maximum relative error of 2**(1-F): + + (9) qest = n * pinv + +If we can show that q < qest < q+1, then trunc(qest) = q. It is then +easy to recover the remainder r. The complete algorithm is: + + a) Set the control word to 64-bit precision and truncation mode. + + b) n = a * b # Calculate exact product. + + c) qest = n * pinv # Calculate estimate for the quotient. + + d) q = (qest+2**63)-2**63 # Truncate qest to the exact quotient. + + f) r = n - q * p # Calculate remainder. + + +Proof for q < qest < q+1: +------------------------- + +Using the cumulative error, the error bounds for qest are: + + n n * (1 + 2**(1-F))**2 + (9) --------------------- <= qest <= --------------------- + p * (1 + 2**(1-F))**2 p + + + Lemma 1: + -------- + n q * p + r + (10) q < --------------------- = --------------------- + p * (1 + 2**(1-F))**2 p * (1 + 2**(1-F))**2 + + + Proof: + ~~~~~~ + + (I) q * p * (1 + 2**(1-F))**2 < q * p + r + + (II) q * p * 2**(2-F) + q * p * 2**(2-2*F) < r + + Using (1) and (7), it is sufficient to show that: + + (III) q * p * 2**(-62) + q * p * 2**(-126) < 1 <= r + + (III) can easily be verified by substituting the largest possible + values p = 2**31-1 and q = 2**31-2. + + The critical cases occur when r = 1, n = m * p + 1. These cases + can be exhaustively verified with a test program. + + + Lemma 2: + -------- + + n * (1 + 2**(1-F))**2 (q * p + r) * (1 + 2**(1-F))**2 + (11) --------------------- = ------------------------------- < q + 1 + p p + + Proof: + ~~~~~~ + + (I) (q * p + r) + (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < q * p + p + + (II) (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < p - r + + Using (1) and (7), it is sufficient to show that: + + (III) (q * p + r) * 2**(-62) + (q * p + r) * 2**(-126) < 1 <= p - r + + (III) can easily be verified by substituting the largest possible + values p = 2**31-1, q = 2**31-2 and r = 2**31-2. + + The critical cases occur when r = (p - 1), n = m * p - 1. These cases + can be exhaustively verified with a test program. + + +[1] http://www.apfloat.org/apfloat/2.40/apfloat.pdf +[2] http://gmplib.org/~tege/divcnst-pldi94.pdf + [Section 7: "Use of floating point"] + + + +(* Coq proof for (10) and (11) *) + +Require Import ZArith. +Require Import QArith. +Require Import Qpower. +Require Import Qabs. +Require Import Psatz. + +Open Scope Q_scope. + + +Ltac qreduce T := + rewrite <- (Qred_correct (T)); simpl (Qred (T)). + +Theorem Qlt_move_right : + forall x y z:Q, x + z < y <-> x < y - z. +Proof. + intros. + split. + intros. + psatzl Q. + intros. + psatzl Q. +Qed. + +Theorem Qlt_mult_by_z : + forall x y z:Q, 0 < z -> (x < y <-> x * z < y * z). +Proof. + intros. + split. + intros. + apply Qmult_lt_compat_r. trivial. trivial. + intros. + rewrite <- (Qdiv_mult_l x z). rewrite <- (Qdiv_mult_l y z). + apply Qmult_lt_compat_r. + apply Qlt_shift_inv_l. + trivial. psatzl Q. trivial. psatzl Q. psatzl Q. +Qed. + +Theorem Qle_mult_quad : + forall (a b c d:Q), + 0 <= a -> a <= c -> + 0 <= b -> b <= d -> + a * b <= c * d. + intros. + psatz Q. +Qed. + + +Theorem q_lt_qest: + forall (p q r:Q), + (0 < p) -> (p <= (2#1)^31 - 1) -> + (0 <= q) -> (q <= p - 1) -> + (1 <= r) -> (r <= p - 1) -> + q < (q * p + r) / (p * (1 + (2#1)^(-63))^2). +Proof. + intros. + rewrite Qlt_mult_by_z with (z := (p * (1 + (2#1)^(-63))^2)). + + unfold Qdiv. + rewrite <- Qmult_assoc. + rewrite (Qmult_comm (/ (p * (1 + (2 # 1) ^ (-63)) ^ 2)) (p * (1 + (2 # 1) ^ (-63)) ^ 2)). + rewrite Qmult_inv_r. + rewrite Qmult_1_r. + + assert (q * (p * (1 + (2 # 1) ^ (-63)) ^ 2) == q * p + (q * p) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))). + qreduce ((1 + (2 # 1) ^ (-63)) ^ 2). + qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). + ring_simplify. + reflexivity. + rewrite H5. + + rewrite Qplus_comm. + rewrite Qlt_move_right. + ring_simplify (q * p + r - q * p). + qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). + + apply Qlt_le_trans with (y := 1). + rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617). + ring_simplify. + + apply Qle_lt_trans with (y := ((2 # 1) ^ 31 - (2#1)) * ((2 # 1) ^ 31 - 1)). + apply Qle_mult_quad. + assumption. psatzl Q. psatzl Q. psatzl Q. psatzl Q. psatzl Q. assumption. psatzl Q. psatzl Q. +Qed. + +Theorem qest_lt_qplus1: + forall (p q r:Q), + (0 < p) -> (p <= (2#1)^31 - 1) -> + (0 <= q) -> (q <= p - 1) -> + (1 <= r) -> (r <= p - 1) -> + ((q * p + r) * (1 + (2#1)^(-63))^2) / p < q + 1. +Proof. + intros. + rewrite Qlt_mult_by_z with (z := p). + + unfold Qdiv. + rewrite <- Qmult_assoc. + rewrite (Qmult_comm (/ p) p). + rewrite Qmult_inv_r. + rewrite Qmult_1_r. + + assert ((q * p + r) * (1 + (2 # 1) ^ (-63)) ^ 2 == q * p + r + (q * p + r) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))). + qreduce ((1 + (2 # 1) ^ (-63)) ^ 2). + qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). + ring_simplify. reflexivity. + rewrite H5. + + rewrite <- Qplus_assoc. rewrite <- Qplus_comm. rewrite Qlt_move_right. + ring_simplify ((q + 1) * p - q * p). + + rewrite <- Qplus_comm. rewrite Qlt_move_right. + + apply Qlt_le_trans with (y := 1). + qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). + + rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617). + ring_simplify. + + ring_simplify in H0. + apply Qle_lt_trans with (y := (2147483646 # 1) * (2147483647 # 1) + (2147483646 # 1)). + + apply Qplus_le_compat. + apply Qle_mult_quad. + assumption. psatzl Q. auto with qarith. assumption. psatzl Q. + auto with qarith. auto with qarith. + psatzl Q. psatzl Q. assumption. +Qed. + + + diff --git a/Modules/_decimal/libmpdec/literature/six-step.txt b/Modules/_decimal/libmpdec/literature/six-step.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/six-step.txt @@ -0,0 +1,63 @@ + + +(* Copyright (c) 2011 Stefan Krah. All rights reserved. *) + + +The Six Step Transform: +======================= + +In libmpdec, the six-step transform is the Matrix Fourier Transform (See +matrix-transform.txt) in disguise. It is called six-step transform after +a variant that appears in [1]. The algorithm requires that the input +array can be viewed as an R*C matrix. + + +Algorithm six-step (forward transform): +--------------------------------------- + + 1a) Transpose the matrix. + + 1b) Apply a length R FNT to each row. + + 1c) Transpose the matrix. + + 2) Multiply each matrix element (addressed by j*C+m) by r**(j*m). + + 3) Apply a length C FNT to each row. + + 4) Transpose the matrix. + +Note that steps 1a) - 1c) are exactly equivalent to step 1) of the Matrix +Fourier Transform. For large R, it is faster to transpose twice and do +a transform on the rows than to perform a column transpose directly. + + + +Algorithm six-step (inverse transform): +--------------------------------------- + + 0) View the matrix as a C*R matrix. + + 1) Transpose the matrix, producing an R*C matrix. + + 2) Apply a length C FNT to each row. + + 3) Multiply each matrix element (addressed by i*C+n) by r**(i*n). + + 4a) Transpose the matrix. + + 4b) Apply a length R FNT to each row. + + 4c) Transpose the matrix. + +Again, steps 4a) - 4c) are equivalent to step 4) of the Matrix Fourier +Transform. + + + +-- + + [1] David H. Bailey: FFTs in External or Hierarchical Memory + http://crd.lbl.gov/~dhbailey/dhbpapers/ + + diff --git a/Modules/_decimal/libmpdec/literature/umodarith.lisp b/Modules/_decimal/libmpdec/literature/umodarith.lisp new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/umodarith.lisp @@ -0,0 +1,692 @@ +; +; Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; 1. Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; +; 2. Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in the +; documentation and/or other materials provided with the distribution. +; +; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +; SUCH DAMAGE. +; + + +(in-package "ACL2") + +(include-book "arithmetic/top-with-meta" :dir :system) +(include-book "arithmetic-2/floor-mod/floor-mod" :dir :system) + + +;; ===================================================================== +;; Proofs for several functions in umodarith.h +;; ===================================================================== + + + +;; ===================================================================== +;; Helper theorems +;; ===================================================================== + +(defthm elim-mod-m= s m) (mod (- s m) base) s))) + s)) + +(defthmd addmod-correct + (implies (and (< 0 m) (< m base) + (< a m) (<= b m) + (natp m) (natp base) + (natp a) (natp b)) + (equal (addmod a b m base) + (mod (+ a b) m))) + :hints (("Goal" :cases ((<= base (+ a b)))) + ("Subgoal 2.1'" :use ((:instance elim-mod-m= a m) (- a m) a)) + (b (if (>= b m) (- b m) b)) + (d (mod (- a b) base)) + (d (if (< a b) (mod (+ d m) base) d))) + d)) + +; a < 2*m, b < 2*m +(defun ext-submod-2 (a b m base) + (let* ((a (mod a m)) + (b (mod b m)) + (d (mod (- a b) base)) + (d (if (< a b) (mod (+ d m) base) d))) + d)) + +(defthmd ext-submod-ext-submod-2-equal + (implies (and (< 0 m) (< m base) + (< a (* 2 m)) (< b (* 2 m)) + (natp m) (natp base) + (natp a) (natp b)) + (equal (ext-submod a b m base) + (ext-submod-2 a b m base)))) + +(defthmd ext-submod-2-correct + (implies (and (< 0 m) (< m base) + (< a (* 2 m)) (< b (* 2 m)) + (natp m) (natp base) + (natp a) (natp b)) + (equal (ext-submod-2 a b m base) + (mod (- a b) m)))) + + +;; ========================================================================= +;; dw-reduce is correct +;; ========================================================================= + +(defun dw-reduce (hi lo m base) + (let* ((r1 (mod hi m)) + (r2 (mod (+ (* r1 base) lo) m))) + r2)) + +(defthmd dw-reduce-correct + (implies (and (< 0 m) (< m base) + (< hi base) (< lo base) + (natp m) (natp base) + (natp hi) (natp lo)) + (equal (dw-reduce hi lo m base) + (mod (+ (* hi base) lo) m)))) + +(defthmd <=-multiply-both-sides-by-z + (implies (and (rationalp x) (rationalp y) + (< 0 z) (rationalp z)) + (equal (<= x y) + (<= (* z x) (* z y))))) + +(defthmd dw-reduce-aux1 + (implies (and (< 0 m) (< m base) + (natp m) (natp base) + (< lo base) (natp lo) + (< x m) (natp x)) + (< (+ lo (* base x)) (* base m))) + :hints (("Goal" :cases ((<= (+ x 1) m))) + ("Subgoal 1''" :cases ((<= (* base (+ x 1)) (* base m)))) + ("subgoal 1.2" :use ((:instance <=-multiply-both-sides-by-z + (x (+ 1 x)) + (y m) + (z base)))))) + +(defthm dw-reduce-aux2 + (implies (and (< x (* base m)) + (< 0 m) (< m base) + (natp m) (natp base) (natp x)) + (< (floor x m) base))) + +;; This is the necessary condition for using _mpd_div_words(). +(defthmd dw-reduce-second-quotient-fits-in-single-word + (implies (and (< 0 m) (< m base) + (< hi base) (< lo base) + (natp m) (natp base) + (natp hi) (natp lo) + (equal r1 (mod hi m))) + (< (floor (+ (* r1 base) lo) m) + base)) + :hints (("Goal" :cases ((< r1 m))) + ("Subgoal 1''" :cases ((< (+ lo (* base (mod hi m))) (* base m)))) + ("Subgoal 1.2" :use ((:instance dw-reduce-aux1 + (x (mod hi m))))))) + + +;; ========================================================================= +;; dw-submod is correct +;; ========================================================================= + +(defun dw-submod (a hi lo m base) + (let* ((r (dw-reduce hi lo m base)) + (d (mod (- a r) base)) + (d (if (< a r) (mod (+ d m) base) d))) + d)) + +(defthmd dw-submod-aux1 + (implies (and (natp a) (< 0 m) (natp m) + (natp x) (equal r (mod x m))) + (equal (mod (- a x) m) + (mod (- a r) m)))) + +(defthmd dw-submod-correct + (implies (and (< 0 m) (< m base) + (natp a) (< a m) + (< hi base) (< lo base) + (natp m) (natp base) + (natp hi) (natp lo)) + (equal (dw-submod a hi lo m base) + (mod (- a (+ (* base hi) lo)) m))) + :hints (("Goal" :in-theory (disable dw-reduce) + :use ((:instance dw-submod-aux1 + (x (+ lo (* base hi))) + (r (dw-reduce hi lo m base))) + (:instance dw-reduce-correct))))) + + +;; ========================================================================= +;; ANSI C arithmetic for uint64_t +;; ========================================================================= + +(defun add (a b) + (mod (+ a b) + (expt 2 64))) + +(defun sub (a b) + (mod (- a b) + (expt 2 64))) + +(defun << (w n) + (mod (* w (expt 2 n)) + (expt 2 64))) + +(defun >> (w n) + (floor w (expt 2 n))) + +;; join upper and lower half of a double word, yielding a 128 bit number +(defun join (hi lo) + (+ (* (expt 2 64) hi) lo)) + + +;; ============================================================================= +;; Fast modular reduction +;; ============================================================================= + +;; These are the three primes used in the Number Theoretic Transform. +;; A fast modular reduction scheme exists for all of them. +(defmacro p1 () + (+ (expt 2 64) (- (expt 2 32)) 1)) + +(defmacro p2 () + (+ (expt 2 64) (- (expt 2 34)) 1)) + +(defmacro p3 () + (+ (expt 2 64) (- (expt 2 40)) 1)) + + +;; reduce the double word number hi*2**64 + lo (mod p1) +(defun simple-mod-reduce-p1 (hi lo) + (+ (* (expt 2 32) hi) (- hi) lo)) + +;; reduce the double word number hi*2**64 + lo (mod p2) +(defun simple-mod-reduce-p2 (hi lo) + (+ (* (expt 2 34) hi) (- hi) lo)) + +;; reduce the double word number hi*2**64 + lo (mod p3) +(defun simple-mod-reduce-p3 (hi lo) + (+ (* (expt 2 40) hi) (- hi) lo)) + + +; ---------------------------------------------------------- +; The modular reductions given above are correct +; ---------------------------------------------------------- + +(defthmd congruence-p1-aux + (equal (* (expt 2 64) hi) + (+ (* (p1) hi) + (* (expt 2 32) hi) + (- hi)))) + +(defthmd congruence-p2-aux + (equal (* (expt 2 64) hi) + (+ (* (p2) hi) + (* (expt 2 34) hi) + (- hi)))) + +(defthmd congruence-p3-aux + (equal (* (expt 2 64) hi) + (+ (* (p3) hi) + (* (expt 2 40) hi) + (- hi)))) + +(defthmd mod-augment + (implies (and (rationalp x) + (rationalp y) + (rationalp m)) + (equal (mod (+ x y) m) + (mod (+ x (mod y m)) m)))) + +(defthmd simple-mod-reduce-p1-congruent + (implies (and (integerp hi) + (integerp lo)) + (equal (mod (simple-mod-reduce-p1 hi lo) (p1)) + (mod (join hi lo) (p1)))) + :hints (("Goal''" :use ((:instance congruence-p1-aux) + (:instance mod-augment + (m (p1)) + (x (+ (- hi) lo (* (expt 2 32) hi))) + (y (* (p1) hi))))))) + +(defthmd simple-mod-reduce-p2-congruent + (implies (and (integerp hi) + (integerp lo)) + (equal (mod (simple-mod-reduce-p2 hi lo) (p2)) + (mod (join hi lo) (p2)))) + :hints (("Goal''" :use ((:instance congruence-p2-aux) + (:instance mod-augment + (m (p2)) + (x (+ (- hi) lo (* (expt 2 34) hi))) + (y (* (p2) hi))))))) + +(defthmd simple-mod-reduce-p3-congruent + (implies (and (integerp hi) + (integerp lo)) + (equal (mod (simple-mod-reduce-p3 hi lo) (p3)) + (mod (join hi lo) (p3)))) + :hints (("Goal''" :use ((:instance congruence-p3-aux) + (:instance mod-augment + (m (p3)) + (x (+ (- hi) lo (* (expt 2 40) hi))) + (y (* (p3) hi))))))) + + +; --------------------------------------------------------------------- +; We need a number less than 2*p, so that we can use the trick from +; elim-mod-m> hi 32)) + (x (sub lo x)) + (hi (if (> x lo) (+ hi -1) hi)) + (y (<< y 32)) + (lo (add y x)) + (hi (if (< lo y) (+ hi 1) hi))) + (+ (* hi (expt 2 64)) lo))) + +(defun mod-reduce-p2 (hi lo) + (let* ((y hi) + (x y) + (hi (>> hi 30)) + (x (sub lo x)) + (hi (if (> x lo) (+ hi -1) hi)) + (y (<< y 34)) + (lo (add y x)) + (hi (if (< lo y) (+ hi 1) hi))) + (+ (* hi (expt 2 64)) lo))) + +(defun mod-reduce-p3 (hi lo) + (let* ((y hi) + (x y) + (hi (>> hi 24)) + (x (sub lo x)) + (hi (if (> x lo) (+ hi -1) hi)) + (y (<< y 40)) + (lo (add y x)) + (hi (if (< lo y) (+ hi 1) hi))) + (+ (* hi (expt 2 64)) lo))) + + +; ------------------------------------------------------------------------- +; The compiler friendly versions are equal to the simple versions +; ------------------------------------------------------------------------- + +(defthm mod-reduce-aux1 + (implies (and (<= 0 a) (natp a) (natp m) + (< (- m) b) (<= b 0) + (integerp b) + (< (mod (+ b a) m) + (mod a m))) + (equal (mod (+ b a) m) + (+ b (mod a m)))) + :hints (("Subgoal 2" :use ((:instance modaux-1b + (x (+ a b))))))) + +(defthm mod-reduce-aux2 + (implies (and (<= 0 a) (natp a) (natp m) + (< b m) (natp b) + (< (mod (+ b a) m) + (mod a m))) + (equal (+ m (mod (+ b a) m)) + (+ b (mod a m))))) + + +(defthm mod-reduce-aux3 + (implies (and (< 0 a) (natp a) (natp m) + (< (- m) b) (< b 0) + (integerp b) + (<= (mod a m) + (mod (+ b a) m))) + (equal (+ (- m) (mod (+ b a) m)) + (+ b (mod a m)))) + :hints (("Subgoal 1.2'" :use ((:instance modaux-1b + (x b)))) + ("Subgoal 1''" :use ((:instance modaux-2d + (x I)))))) + + +(defthm mod-reduce-aux4 + (implies (and (< 0 a) (natp a) (natp m) + (< b m) (natp b) + (<= (mod a m) + (mod (+ b a) m))) + (equal (mod (+ b a) m) + (+ b (mod a m))))) + + +(defthm mod-reduce-p1==simple-mod-reduce-p1 + (implies (and (< hi (expt 2 64)) + (< lo (expt 2 64)) + (natp hi) (natp lo)) + (equal (mod-reduce-p1 hi lo) + (simple-mod-reduce-p1 hi lo))) + :hints (("Goal" :in-theory (disable expt) + :cases ((< 0 hi))) + ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 32) hi))))) + ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 32) hi))))) + ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 32) hi))))) + ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 32) hi))))))) + + +(defthm mod-reduce-p2==simple-mod-reduce-p2 + (implies (and (< hi (expt 2 64)) + (< lo (expt 2 64)) + (natp hi) (natp lo)) + (equal (mod-reduce-p2 hi lo) + (simple-mod-reduce-p2 hi lo))) + :hints (("Goal" :cases ((< 0 hi))) + ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 34) hi))))) + ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 34) hi))))) + ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 34) hi))))) + ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 34) hi))))))) + + +(defthm mod-reduce-p3==simple-mod-reduce-p3 + (implies (and (< hi (expt 2 64)) + (< lo (expt 2 64)) + (natp hi) (natp lo)) + (equal (mod-reduce-p3 hi lo) + (simple-mod-reduce-p3 hi lo))) + :hints (("Goal" :cases ((< 0 hi))) + ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 40) hi))))) + ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 40) hi))))) + ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 40) hi))))) + ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 40) hi))))))) + + + diff --git a/Modules/_decimal/libmpdec/memory.c b/Modules/_decimal/libmpdec/memory.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/memory.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include "typearith.h" +#include "memory.h" + + +/* Guaranteed minimum allocation for a coefficient. May be changed once + at program start using mpd_setminalloc(). */ +mpd_ssize_t MPD_MINALLOC = MPD_MINALLOC_MIN; + +/* Custom allocation and free functions */ +void *(* mpd_mallocfunc)(size_t size) = malloc; +void *(* mpd_reallocfunc)(void *ptr, size_t size) = realloc; +void *(* mpd_callocfunc)(size_t nmemb, size_t size) = calloc; +void (* mpd_free)(void *ptr) = free; + + +/* emulate calloc if it is not available */ +void * +mpd_callocfunc_em(size_t nmemb, size_t size) +{ + void *ptr; + size_t req; + mpd_size_t overflow; + +#if MPD_SIZE_MAX < SIZE_MAX + /* full_coverage test only */ + if (nmemb > MPD_SIZE_MAX || size > MPD_SIZE_MAX) { + return NULL; + } +#endif + + req = mul_size_t_overflow((mpd_size_t)nmemb, (mpd_size_t)size, + &overflow); + if (overflow) { + return NULL; + } + + ptr = mpd_mallocfunc(req); + if (ptr == NULL) { + return NULL; + } + /* used on uint32_t or uint64_t */ + memset(ptr, 0, req); + + return ptr; +} + + +/* malloc with overflow checking */ +void * +mpd_alloc(mpd_size_t nmemb, mpd_size_t size) +{ + mpd_size_t req, overflow; + + req = mul_size_t_overflow(nmemb, size, &overflow); + if (overflow) { + return NULL; + } + + return mpd_mallocfunc(req); +} + +/* calloc with overflow checking */ +void * +mpd_calloc(mpd_size_t nmemb, mpd_size_t size) +{ + mpd_size_t overflow; + + (void)mul_size_t_overflow(nmemb, size, &overflow); + if (overflow) { + return NULL; + } + + return mpd_callocfunc(nmemb, size); +} + +/* realloc with overflow checking */ +void * +mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err) +{ + void *new; + mpd_size_t req, overflow; + + req = mul_size_t_overflow(nmemb, size, &overflow); + if (overflow) { + *err = 1; + return ptr; + } + + new = mpd_reallocfunc(ptr, req); + if (new == NULL) { + *err = 1; + return ptr; + } + + return new; +} + +/* struct hack malloc with overflow checking */ +void * +mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size) +{ + mpd_size_t req, overflow; + + req = mul_size_t_overflow(nmemb, size, &overflow); + if (overflow) { + return NULL; + } + + req = add_size_t_overflow(req, struct_size, &overflow); + if (overflow) { + return NULL; + } + + return mpd_mallocfunc(req); +} + + +/* Allocate a new decimal with a coefficient of length 'nwords'. In case + of an error the return value is NULL. */ +mpd_t * +mpd_qnew_size(mpd_ssize_t nwords) +{ + mpd_t *result; + + nwords = (nwords < MPD_MINALLOC) ? MPD_MINALLOC : nwords; + + result = mpd_alloc(1, sizeof *result); + if (result == NULL) { + return NULL; + } + + result->data = mpd_alloc(nwords, sizeof *result->data); + if (result->data == NULL) { + mpd_free(result); + return NULL; + } + + result->flags = 0; + result->exp = 0; + result->digits = 0; + result->len = 0; + result->alloc = nwords; + + return result; +} + +/* Allocate a new decimal with a coefficient of length MPD_MINALLOC. + In case of an error the return value is NULL. */ +mpd_t * +mpd_qnew(void) +{ + return mpd_qnew_size(MPD_MINALLOC); +} + +/* Allocate new decimal. Caller can check for NULL or MPD_Malloc_error. + Raises on error. */ +mpd_t * +mpd_new(mpd_context_t *ctx) +{ + mpd_t *result; + + result = mpd_qnew(); + if (result == NULL) { + mpd_addstatus_raise(ctx, MPD_Malloc_error); + } + return result; +} + +/* + * Input: 'result' is a static mpd_t with a static coefficient. + * Assumption: 'nwords' >= result->alloc. + * + * Resize the static coefficient to a larger dynamic one and copy the + * existing data. If successful, the value of 'result' is unchanged. + * Otherwise, set 'result' to NaN and update 'status' with MPD_Malloc_error. + */ +int +mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + mpd_uint_t *p = result->data; + + assert(nwords >= result->alloc); + + result->data = mpd_alloc(nwords, sizeof *result->data); + if (result->data == NULL) { + result->data = p; + mpd_set_qnan(result); + mpd_set_positive(result); + result->exp = result->digits = result->len = 0; + *status |= MPD_Malloc_error; + return 0; + } + + memcpy(result->data, p, result->len * (sizeof *result->data)); + result->alloc = nwords; + mpd_set_dynamic_data(result); + return 1; +} + +/* + * Input: 'result' is a static mpd_t with a static coefficient. + * + * Convert the coefficient to a dynamic one that is initialized to zero. If + * malloc fails, set 'result' to NaN and update 'status' with MPD_Malloc_error. + */ +int +mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + mpd_uint_t *p = result->data; + + result->data = mpd_calloc(nwords, sizeof *result->data); + if (result->data == NULL) { + result->data = p; + mpd_set_qnan(result); + mpd_set_positive(result); + result->exp = result->digits = result->len = 0; + *status |= MPD_Malloc_error; + return 0; + } + + result->alloc = nwords; + mpd_set_dynamic_data(result); + + return 1; +} + +/* + * Input: 'result' is a static or a dynamic mpd_t with a dynamic coefficient. + * Resize the coefficient to length 'nwords': + * Case nwords > result->alloc: + * If realloc is successful: + * 'result' has a larger coefficient but the same value. Return 1. + * Otherwise: + * Set 'result' to NaN, update status with MPD_Malloc_error and return 0. + * Case nwords < result->alloc: + * If realloc is successful: + * 'result' has a smaller coefficient. result->len is undefined. Return 1. + * Otherwise (unlikely): + * 'result' is unchanged. Reuse the now oversized coefficient. Return 1. + */ +int +mpd_realloc_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + uint8_t err = 0; + + result->data = mpd_realloc(result->data, nwords, sizeof *result->data, &err); + if (!err) { + result->alloc = nwords; + } + else if (nwords > result->alloc) { + mpd_set_qnan(result); + mpd_set_positive(result); + result->exp = result->digits = result->len = 0; + *status |= MPD_Malloc_error; + return 0; + } + + return 1; +} + + diff --git a/Modules/_decimal/libmpdec/memory.h b/Modules/_decimal/libmpdec/memory.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/memory.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef MEMORY_H +#define MEMORY_H + + +#include "mpdecimal.h" + + +int mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t size, uint32_t *status); +int mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status); +int mpd_realloc_dyn(mpd_t *result, mpd_ssize_t size, uint32_t *status); + + +#endif + + + diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/mpdecimal.c @@ -0,0 +1,7596 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include +#include +#include "basearith.h" +#include "bits.h" +#include "convolute.h" +#include "crt.h" +#include "errno.h" +#include "memory.h" +#include "typearith.h" +#include "umodarith.h" + +#ifdef PPRO + #if defined(_MSC_VER) + #include + #pragma fenv_access(on) + #elif !defined(__OpenBSD__) && !defined(__NetBSD__) + /* C99 */ + #include + #pragma STDC FENV_ACCESS ON + #endif +#endif + +#if defined(__x86_64__) && defined(__GLIBC__) && !defined(__INTEL_COMPILER) + #define USE_80BIT_LONG_DOUBLE +#endif + +#if defined(_MSC_VER) + #define ALWAYS_INLINE __forceinline +#elif defined(LEGACY_COMPILER) + #define ALWAYS_INLINE + #undef inline + #define inline +#else + #ifdef TEST_COVERAGE + #define ALWAYS_INLINE + #else + #define ALWAYS_INLINE inline __attribute__ ((always_inline)) + #endif +#endif + + +#define MPD_NEWTONDIV_CUTOFF 1024L + +#define MPD_NEW_STATIC(name, flags, exp, digits, len) \ + mpd_uint_t name##_data[MPD_MINALLOC_MAX]; \ + mpd_t name = {flags|MPD_STATIC|MPD_STATIC_DATA, exp, digits, \ + len, MPD_MINALLOC_MAX, name##_data} + +#define MPD_NEW_CONST(name, flags, exp, digits, len, alloc, initval) \ + mpd_uint_t name##_data[alloc] = {initval}; \ + mpd_t name = {flags|MPD_STATIC|MPD_CONST_DATA, exp, digits, \ + len, alloc, name##_data} + +#define MPD_NEW_SHARED(name, a) \ + mpd_t name = {(a->flags&~MPD_DATAFLAGS)|MPD_STATIC|MPD_SHARED_DATA, \ + a->exp, a->digits, a->len, a->alloc, a->data} + + +static mpd_uint_t data_one[1] = {1}; +static mpd_uint_t data_zero[1] = {0}; +static const mpd_t one = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_one}; +static const mpd_t minus_one = {MPD_NEG|MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, + data_one}; +static const mpd_t zero = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_zero}; + +static inline void _mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx, + uint32_t *status); +static void _settriple(mpd_t *result, uint8_t sign, mpd_uint_t a, + mpd_ssize_t exp); +static inline mpd_ssize_t _mpd_real_size(mpd_uint_t *data, mpd_ssize_t size); + +static void _mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status); +static inline void _mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status); +static void _mpd_qbarrett_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, + const mpd_t *b, uint32_t *status); +static inline void _mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, + uint8_t resultsign, const mpd_context_t *ctx, uint32_t *status); + +mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n); + + +/******************************************************************************/ +/* Performance critical inline functions */ +/******************************************************************************/ + +#ifdef CONFIG_64 +/* Digits in a word, primarily useful for the most significant word. */ +ALWAYS_INLINE int +mpd_word_digits(mpd_uint_t word) +{ + if (word < mpd_pow10[9]) { + if (word < mpd_pow10[4]) { + if (word < mpd_pow10[2]) { + return (word < mpd_pow10[1]) ? 1 : 2; + } + return (word < mpd_pow10[3]) ? 3 : 4; + } + if (word < mpd_pow10[6]) { + return (word < mpd_pow10[5]) ? 5 : 6; + } + if (word < mpd_pow10[8]) { + return (word < mpd_pow10[7]) ? 7 : 8; + } + return 9; + } + if (word < mpd_pow10[14]) { + if (word < mpd_pow10[11]) { + return (word < mpd_pow10[10]) ? 10 : 11; + } + if (word < mpd_pow10[13]) { + return (word < mpd_pow10[12]) ? 12 : 13; + } + return 14; + } + if (word < mpd_pow10[18]) { + if (word < mpd_pow10[16]) { + return (word < mpd_pow10[15]) ? 15 : 16; + } + return (word < mpd_pow10[17]) ? 17 : 18; + } + + return (word < mpd_pow10[19]) ? 19 : 20; +} +#else +ALWAYS_INLINE int +mpd_word_digits(mpd_uint_t word) +{ + if (word < mpd_pow10[4]) { + if (word < mpd_pow10[2]) { + return (word < mpd_pow10[1]) ? 1 : 2; + } + return (word < mpd_pow10[3]) ? 3 : 4; + } + if (word < mpd_pow10[6]) { + return (word < mpd_pow10[5]) ? 5 : 6; + } + if (word < mpd_pow10[8]) { + return (word < mpd_pow10[7]) ? 7 : 8; + } + + return (word < mpd_pow10[9]) ? 9 : 10; +} +#endif + + +/* Adjusted exponent */ +ALWAYS_INLINE mpd_ssize_t +mpd_adjexp(const mpd_t *dec) +{ + return (dec->exp + dec->digits) - 1; +} + +/* Etiny */ +ALWAYS_INLINE mpd_ssize_t +mpd_etiny(const mpd_context_t *ctx) +{ + return ctx->emin - (ctx->prec - 1); +} + +/* Etop: used for folding down in IEEE clamping */ +ALWAYS_INLINE mpd_ssize_t +mpd_etop(const mpd_context_t *ctx) +{ + return ctx->emax - (ctx->prec - 1); +} + +/* Most significant word */ +ALWAYS_INLINE mpd_uint_t +mpd_msword(const mpd_t *dec) +{ + assert(dec->len > 0); + return dec->data[dec->len-1]; +} + +/* Most significant digit of a word */ +inline mpd_uint_t +mpd_msd(mpd_uint_t word) +{ + int n; + + n = mpd_word_digits(word); + return word / mpd_pow10[n-1]; +} + +/* Least significant digit of a word */ +ALWAYS_INLINE mpd_uint_t +mpd_lsd(mpd_uint_t word) +{ + return word % 10; +} + +/* Coefficient size needed to store 'digits' */ +ALWAYS_INLINE mpd_ssize_t +mpd_digits_to_size(mpd_ssize_t digits) +{ + mpd_ssize_t q, r; + + _mpd_idiv_word(&q, &r, digits, MPD_RDIGITS); + return (r == 0) ? q : q+1; +} + +/* Number of digits in the exponent. Not defined for MPD_SSIZE_MIN. */ +inline int +mpd_exp_digits(mpd_ssize_t exp) +{ + exp = (exp < 0) ? -exp : exp; + return mpd_word_digits(exp); +} + +/* Canonical */ +ALWAYS_INLINE int +mpd_iscanonical(const mpd_t *dec UNUSED) +{ + return 1; +} + +/* Finite */ +ALWAYS_INLINE int +mpd_isfinite(const mpd_t *dec) +{ + return !(dec->flags & MPD_SPECIAL); +} + +/* Infinite */ +ALWAYS_INLINE int +mpd_isinfinite(const mpd_t *dec) +{ + return dec->flags & MPD_INF; +} + +/* NaN */ +ALWAYS_INLINE int +mpd_isnan(const mpd_t *dec) +{ + return dec->flags & (MPD_NAN|MPD_SNAN); +} + +/* Negative */ +ALWAYS_INLINE int +mpd_isnegative(const mpd_t *dec) +{ + return dec->flags & MPD_NEG; +} + +/* Positive */ +ALWAYS_INLINE int +mpd_ispositive(const mpd_t *dec) +{ + return !(dec->flags & MPD_NEG); +} + +/* qNaN */ +ALWAYS_INLINE int +mpd_isqnan(const mpd_t *dec) +{ + return dec->flags & MPD_NAN; +} + +/* Signed */ +ALWAYS_INLINE int +mpd_issigned(const mpd_t *dec) +{ + return dec->flags & MPD_NEG; +} + +/* sNaN */ +ALWAYS_INLINE int +mpd_issnan(const mpd_t *dec) +{ + return dec->flags & MPD_SNAN; +} + +/* Special */ +ALWAYS_INLINE int +mpd_isspecial(const mpd_t *dec) +{ + return dec->flags & MPD_SPECIAL; +} + +/* Zero */ +ALWAYS_INLINE int +mpd_iszero(const mpd_t *dec) +{ + return !mpd_isspecial(dec) && mpd_msword(dec) == 0; +} + +/* Test for zero when specials have been ruled out already */ +ALWAYS_INLINE int +mpd_iszerocoeff(const mpd_t *dec) +{ + return mpd_msword(dec) == 0; +} + +/* Normal */ +inline int +mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx) +{ + if (mpd_isspecial(dec)) return 0; + if (mpd_iszerocoeff(dec)) return 0; + + return mpd_adjexp(dec) >= ctx->emin; +} + +/* Subnormal */ +inline int +mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx) +{ + if (mpd_isspecial(dec)) return 0; + if (mpd_iszerocoeff(dec)) return 0; + + return mpd_adjexp(dec) < ctx->emin; +} + +/* Odd word */ +ALWAYS_INLINE int +mpd_isoddword(mpd_uint_t word) +{ + return word & 1; +} + +/* Odd coefficient */ +ALWAYS_INLINE int +mpd_isoddcoeff(const mpd_t *dec) +{ + return mpd_isoddword(dec->data[0]); +} + +/* 0 if dec is positive, 1 if dec is negative */ +ALWAYS_INLINE uint8_t +mpd_sign(const mpd_t *dec) +{ + return dec->flags & MPD_NEG; +} + +/* 1 if dec is positive, -1 if dec is negative */ +ALWAYS_INLINE int +mpd_arith_sign(const mpd_t *dec) +{ + return 1 - 2 * mpd_isnegative(dec); +} + +/* Radix */ +ALWAYS_INLINE long +mpd_radix(void) +{ + return 10; +} + +/* Dynamic decimal */ +ALWAYS_INLINE int +mpd_isdynamic(mpd_t *dec) +{ + return !(dec->flags & MPD_STATIC); +} + +/* Static decimal */ +ALWAYS_INLINE int +mpd_isstatic(mpd_t *dec) +{ + return dec->flags & MPD_STATIC; +} + +/* Data of decimal is dynamic */ +ALWAYS_INLINE int +mpd_isdynamic_data(mpd_t *dec) +{ + return !(dec->flags & MPD_DATAFLAGS); +} + +/* Data of decimal is static */ +ALWAYS_INLINE int +mpd_isstatic_data(mpd_t *dec) +{ + return dec->flags & MPD_STATIC_DATA; +} + +/* Data of decimal is shared */ +ALWAYS_INLINE int +mpd_isshared_data(mpd_t *dec) +{ + return dec->flags & MPD_SHARED_DATA; +} + +/* Data of decimal is const */ +ALWAYS_INLINE int +mpd_isconst_data(mpd_t *dec) +{ + return dec->flags & MPD_CONST_DATA; +} + + +/******************************************************************************/ +/* Inline memory handling */ +/******************************************************************************/ + +/* Fill destination with zeros */ +ALWAYS_INLINE void +mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len) +{ + mpd_size_t i; + + for (i = 0; i < len; i++) { + dest[i] = 0; + } +} + +/* Free a decimal */ +ALWAYS_INLINE void +mpd_del(mpd_t *dec) +{ + if (mpd_isdynamic_data(dec)) { + mpd_free(dec->data); + } + if (mpd_isdynamic(dec)) { + mpd_free(dec); + } +} + +/* + * Resize the coefficient. Existing data up to 'nwords' is left untouched. + * Return 1 on success, 0 otherwise. + * + * Input invariants: + * 1) MPD_MINALLOC <= result->alloc. + * 2) 0 <= result->len <= result->alloc. + * + * Case nwords > result->alloc: + * Case realloc success: + * The value of 'result' does not change. Return 1. + * Case realloc failure: + * 'result' is NaN, status is updated with MPD_Malloc_error. Return 0. + * + * Case nwords < result->alloc: + * Case is_static_data or nwords < MPD_MINALLOC or realloc failure [1]: + * 'result' is unchanged. Return 1. + * Case realloc success: + * The value of result is undefined (expected). Return 1. + * + * Case nwords == result->alloc: + * 'result' is unchanged. Return 1. + * + * [1] In that case the old (now oversized) area is still valid. + */ +ALWAYS_INLINE int +mpd_qresize(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + assert(!mpd_isconst_data(result)); /* illegal operation for a const */ + assert(!mpd_isshared_data(result)); /* illegal operation for a shared */ + + if (mpd_isstatic_data(result)) { + if (nwords > result->alloc) { + return mpd_switch_to_dyn(result, nwords, status); + } + } + else if (nwords != result->alloc && nwords >= MPD_MINALLOC) { + return mpd_realloc_dyn(result, nwords, status); + } + + return 1; +} + +/* Same as mpd_qresize, but the complete coefficient (including the old + * memory area!) is initialized to zero. */ +ALWAYS_INLINE int +mpd_qresize_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + assert(!mpd_isconst_data(result)); /* illegal operation for a const */ + assert(!mpd_isshared_data(result)); /* illegal operation for a shared */ + + if (mpd_isstatic_data(result)) { + if (nwords > result->alloc) { + return mpd_switch_to_dyn_zero(result, nwords, status); + } + } + else if (nwords != result->alloc && nwords >= MPD_MINALLOC) { + if (!mpd_realloc_dyn(result, nwords, status)) { + return 0; + } + } + + mpd_uint_zero(result->data, nwords); + + return 1; +} + +/* + * Reduce memory size for the coefficient to MPD_MINALLOC. In theory, + * realloc may fail even when reducing the memory size. But in that case + * the old memory area is always big enough, so checking for MPD_Malloc_error + * is not imperative. + */ +ALWAYS_INLINE void +mpd_minalloc(mpd_t *result) +{ + assert(!mpd_isconst_data(result)); /* illegal operation for a const */ + assert(!mpd_isshared_data(result)); /* illegal operation for a shared */ + + if (!mpd_isstatic_data(result) && result->alloc > MPD_MINALLOC) { + uint8_t err = 0; + result->data = mpd_realloc(result->data, MPD_MINALLOC, + sizeof *result->data, &err); + if (!err) { + result->alloc = MPD_MINALLOC; + } + } +} + +int +mpd_resize(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx) +{ + uint32_t status = 0; + if (!mpd_qresize(result, nwords, &status)) { + mpd_addstatus_raise(ctx, status); + return 0; + } + return 1; +} + +int +mpd_resize_zero(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx) +{ + uint32_t status = 0; + if (!mpd_qresize_zero(result, nwords, &status)) { + mpd_addstatus_raise(ctx, status); + return 0; + } + return 1; +} + + +/******************************************************************************/ +/* Set attributes of a decimal */ +/******************************************************************************/ + +/* Set digits. Assumption: result->len is initialized and > 0. */ +inline void +mpd_setdigits(mpd_t *result) +{ + mpd_ssize_t wdigits = mpd_word_digits(mpd_msword(result)); + result->digits = wdigits + (result->len-1) * MPD_RDIGITS; +} + +/* Set sign */ +ALWAYS_INLINE void +mpd_set_sign(mpd_t *result, uint8_t sign) +{ + result->flags &= ~MPD_NEG; + result->flags |= sign; +} + +/* Copy sign from another decimal */ +ALWAYS_INLINE void +mpd_signcpy(mpd_t *result, mpd_t *a) +{ + uint8_t sign = a->flags&MPD_NEG; + + result->flags &= ~MPD_NEG; + result->flags |= sign; +} + +/* Set infinity */ +ALWAYS_INLINE void +mpd_set_infinity(mpd_t *result) +{ + result->flags &= ~MPD_SPECIAL; + result->flags |= MPD_INF; +} + +/* Set qNaN */ +ALWAYS_INLINE void +mpd_set_qnan(mpd_t *result) +{ + result->flags &= ~MPD_SPECIAL; + result->flags |= MPD_NAN; +} + +/* Set sNaN */ +ALWAYS_INLINE void +mpd_set_snan(mpd_t *result) +{ + result->flags &= ~MPD_SPECIAL; + result->flags |= MPD_SNAN; +} + +/* Set to negative */ +ALWAYS_INLINE void +mpd_set_negative(mpd_t *result) +{ + result->flags |= MPD_NEG; +} + +/* Set to positive */ +ALWAYS_INLINE void +mpd_set_positive(mpd_t *result) +{ + result->flags &= ~MPD_NEG; +} + +/* Set to dynamic */ +ALWAYS_INLINE void +mpd_set_dynamic(mpd_t *result) +{ + result->flags &= ~MPD_STATIC; +} + +/* Set to static */ +ALWAYS_INLINE void +mpd_set_static(mpd_t *result) +{ + result->flags |= MPD_STATIC; +} + +/* Set data to dynamic */ +ALWAYS_INLINE void +mpd_set_dynamic_data(mpd_t *result) +{ + result->flags &= ~MPD_DATAFLAGS; +} + +/* Set data to static */ +ALWAYS_INLINE void +mpd_set_static_data(mpd_t *result) +{ + result->flags &= ~MPD_DATAFLAGS; + result->flags |= MPD_STATIC_DATA; +} + +/* Set data to shared */ +ALWAYS_INLINE void +mpd_set_shared_data(mpd_t *result) +{ + result->flags &= ~MPD_DATAFLAGS; + result->flags |= MPD_SHARED_DATA; +} + +/* Set data to const */ +ALWAYS_INLINE void +mpd_set_const_data(mpd_t *result) +{ + result->flags &= ~MPD_DATAFLAGS; + result->flags |= MPD_CONST_DATA; +} + +/* Clear flags, preserving memory attributes. */ +ALWAYS_INLINE void +mpd_clear_flags(mpd_t *result) +{ + result->flags &= (MPD_STATIC|MPD_DATAFLAGS); +} + +/* Set flags, preserving memory attributes. */ +ALWAYS_INLINE void +mpd_set_flags(mpd_t *result, uint8_t flags) +{ + result->flags &= (MPD_STATIC|MPD_DATAFLAGS); + result->flags |= flags; +} + +/* Copy flags, preserving memory attributes of result. */ +ALWAYS_INLINE void +mpd_copy_flags(mpd_t *result, const mpd_t *a) +{ + uint8_t aflags = a->flags; + result->flags &= (MPD_STATIC|MPD_DATAFLAGS); + result->flags |= (aflags & ~(MPD_STATIC|MPD_DATAFLAGS)); +} + +/* Initialize a workcontext from ctx. Set traps, flags and newtrap to 0. */ +static inline void +mpd_workcontext(mpd_context_t *workctx, const mpd_context_t *ctx) +{ + workctx->prec = ctx->prec; + workctx->emax = ctx->emax; + workctx->emin = ctx->emin; + workctx->round = ctx->round; + workctx->traps = 0; + workctx->status = 0; + workctx->newtrap = 0; + workctx->clamp = ctx->clamp; + workctx->allcr = ctx->allcr; +} + + +/******************************************************************************/ +/* Getting and setting parts of decimals */ +/******************************************************************************/ + +/* Flip the sign of a decimal */ +static inline void +_mpd_negate(mpd_t *dec) +{ + dec->flags ^= MPD_NEG; +} + +/* Set coefficient to zero */ +void +mpd_zerocoeff(mpd_t *result) +{ + mpd_minalloc(result); + result->digits = 1; + result->len = 1; + result->data[0] = 0; +} + +/* Set the coefficient to all nines. */ +void +mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t len, r; + + _mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS); + len = (r == 0) ? len : len+1; + + if (!mpd_qresize(result, len, status)) { + return; + } + + result->len = len; + result->digits = ctx->prec; + + --len; + if (r > 0) { + result->data[len--] = mpd_pow10[r]-1; + } + for (; len >= 0; --len) { + result->data[len] = MPD_RADIX-1; + } +} + +/* + * Cut off the most significant digits so that the rest fits in ctx->prec. + * Cannot fail. + */ +static void +_mpd_cap(mpd_t *result, const mpd_context_t *ctx) +{ + uint32_t dummy; + mpd_ssize_t len, r; + + if (result->len > 0 && result->digits > ctx->prec) { + _mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS); + len = (r == 0) ? len : len+1; + + if (r != 0) { + result->data[len-1] %= mpd_pow10[r]; + } + + len = _mpd_real_size(result->data, len); + /* resize to fewer words cannot fail */ + mpd_qresize(result, len, &dummy); + result->len = len; + mpd_setdigits(result); + } + if (mpd_iszero(result)) { + _settriple(result, mpd_sign(result), 0, result->exp); + } +} + +/* + * Cut off the most significant digits of a NaN payload so that the rest + * fits in ctx->prec - ctx->clamp. Cannot fail. + */ +static void +_mpd_fix_nan(mpd_t *result, const mpd_context_t *ctx) +{ + uint32_t dummy; + mpd_ssize_t prec; + mpd_ssize_t len, r; + + prec = ctx->prec - ctx->clamp; + if (result->len > 0 && result->digits > prec) { + if (prec == 0) { + mpd_minalloc(result); + result->len = result->digits = 0; + } + else { + _mpd_idiv_word(&len, &r, prec, MPD_RDIGITS); + len = (r == 0) ? len : len+1; + + if (r != 0) { + result->data[len-1] %= mpd_pow10[r]; + } + + len = _mpd_real_size(result->data, len); + /* resize to fewer words cannot fail */ + mpd_qresize(result, len, &dummy); + result->len = len; + mpd_setdigits(result); + if (mpd_iszerocoeff(result)) { + /* NaN0 is not a valid representation */ + result->len = result->digits = 0; + } + } + } +} + +/* + * Get n most significant digits from a decimal, where 0 < n <= MPD_UINT_DIGITS. + * Assumes MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for 32 and 64 bit + * machines. + * + * The result of the operation will be in lo. If the operation is impossible, + * hi will be nonzero. This is used to indicate an error. + */ +static inline void +_mpd_get_msdigits(mpd_uint_t *hi, mpd_uint_t *lo, const mpd_t *dec, + unsigned int n) +{ + mpd_uint_t r, tmp; + + assert(0 < n && n <= MPD_RDIGITS+1); + + _mpd_div_word(&tmp, &r, dec->digits, MPD_RDIGITS); + r = (r == 0) ? MPD_RDIGITS : r; /* digits in the most significant word */ + + *hi = 0; + *lo = dec->data[dec->len-1]; + if (n <= r) { + *lo /= mpd_pow10[r-n]; + } + else if (dec->len > 1) { + /* at this point 1 <= r < n <= MPD_RDIGITS+1 */ + _mpd_mul_words(hi, lo, *lo, mpd_pow10[n-r]); + tmp = dec->data[dec->len-2] / mpd_pow10[MPD_RDIGITS-(n-r)]; + *lo = *lo + tmp; + if (*lo < tmp) (*hi)++; + } +} + + +/******************************************************************************/ +/* Gathering information about a decimal */ +/******************************************************************************/ + +/* The real size of the coefficient without leading zero words. */ +static inline mpd_ssize_t +_mpd_real_size(mpd_uint_t *data, mpd_ssize_t size) +{ + while (size > 1 && data[size-1] == 0) { + size--; + } + + return size; +} + +/* Return number of trailing zeros. No errors are possible. */ +mpd_ssize_t +mpd_trail_zeros(const mpd_t *dec) +{ + mpd_uint_t word; + mpd_ssize_t i, tz = 0; + + for (i=0; i < dec->len; ++i) { + if (dec->data[i] != 0) { + word = dec->data[i]; + tz = i * MPD_RDIGITS; + while (word % 10 == 0) { + word /= 10; + tz++; + } + break; + } + } + + return tz; +} + +/* Integer: Undefined for specials */ +static int +_mpd_isint(const mpd_t *dec) +{ + mpd_ssize_t tz; + + if (mpd_iszerocoeff(dec)) { + return 1; + } + + tz = mpd_trail_zeros(dec); + return (dec->exp + tz >= 0); +} + +/* Integer */ +int +mpd_isinteger(const mpd_t *dec) +{ + if (mpd_isspecial(dec)) { + return 0; + } + return _mpd_isint(dec); +} + +/* Word is a power of 10 */ +static int +mpd_word_ispow10(mpd_uint_t word) +{ + int n; + + n = mpd_word_digits(word); + if (word == mpd_pow10[n-1]) { + return 1; + } + + return 0; +} + +/* Coefficient is a power of 10 */ +static int +mpd_coeff_ispow10(const mpd_t *dec) +{ + if (mpd_word_ispow10(mpd_msword(dec))) { + if (_mpd_isallzero(dec->data, dec->len-1)) { + return 1; + } + } + + return 0; +} + +/* All digits of a word are nines */ +static int +mpd_word_isallnine(mpd_uint_t word) +{ + int n; + + n = mpd_word_digits(word); + if (word == mpd_pow10[n]-1) { + return 1; + } + + return 0; +} + +/* All digits of the coefficient are nines */ +static int +mpd_coeff_isallnine(const mpd_t *dec) +{ + if (mpd_word_isallnine(mpd_msword(dec))) { + if (_mpd_isallnine(dec->data, dec->len-1)) { + return 1; + } + } + + return 0; +} + +/* Odd decimal: Undefined for non-integers! */ +int +mpd_isodd(const mpd_t *dec) +{ + mpd_uint_t q, r; + assert(mpd_isinteger(dec)); + if (mpd_iszerocoeff(dec)) return 0; + if (dec->exp < 0) { + _mpd_div_word(&q, &r, -dec->exp, MPD_RDIGITS); + q = dec->data[q] / mpd_pow10[r]; + return mpd_isoddword(q); + } + return dec->exp == 0 && mpd_isoddword(dec->data[0]); +} + +/* Even: Undefined for non-integers! */ +int +mpd_iseven(const mpd_t *dec) +{ + return !mpd_isodd(dec); +} + +/******************************************************************************/ +/* Getting and setting decimals */ +/******************************************************************************/ + +/* Internal function: Set a static decimal from a triple, no error checking. */ +static void +_ssettriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp) +{ + mpd_set_flags(result, sign); + result->exp = exp; + _mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX); + result->len = (result->data[1] == 0) ? 1 : 2; + mpd_setdigits(result); +} + +/* Internal function: Set a decimal from a triple, no error checking. */ +static void +_settriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp) +{ + mpd_minalloc(result); + mpd_set_flags(result, sign); + result->exp = exp; + _mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX); + result->len = (result->data[1] == 0) ? 1 : 2; + mpd_setdigits(result); +} + +/* Set a special number from a triple */ +void +mpd_setspecial(mpd_t *result, uint8_t sign, uint8_t type) +{ + mpd_minalloc(result); + result->flags &= ~(MPD_NEG|MPD_SPECIAL); + result->flags |= (sign|type); + result->exp = result->digits = result->len = 0; +} + +/* Set result of NaN with an error status */ +void +mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status) +{ + mpd_minalloc(result); + mpd_set_qnan(result); + mpd_set_positive(result); + result->exp = result->digits = result->len = 0; + *status |= flags; +} + +/* quietly set a static decimal from an mpd_ssize_t */ +void +mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_uint_t u; + uint8_t sign = MPD_POS; + + if (a < 0) { + if (a == MPD_SSIZE_MIN) { + u = (mpd_uint_t)MPD_SSIZE_MAX + + (-(MPD_SSIZE_MIN+MPD_SSIZE_MAX)); + } + else { + u = -a; + } + sign = MPD_NEG; + } + else { + u = a; + } + _ssettriple(result, sign, u, 0); + mpd_qfinalize(result, ctx, status); +} + +/* quietly set a static decimal from an mpd_uint_t */ +void +mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + _ssettriple(result, MPD_POS, a, 0); + mpd_qfinalize(result, ctx, status); +} + +/* quietly set a static decimal from an int32_t */ +void +mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qsset_ssize(result, a, ctx, status); +} + +/* quietly set a static decimal from a uint32_t */ +void +mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qsset_uint(result, a, ctx, status); +} + +#ifdef CONFIG_64 +/* quietly set a static decimal from an int64_t */ +void +mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qsset_ssize(result, a, ctx, status); +} + +/* quietly set a static decimal from a uint64_t */ +void +mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qsset_uint(result, a, ctx, status); +} +#endif + +/* quietly set a decimal from an mpd_ssize_t */ +void +mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_minalloc(result); + mpd_qsset_ssize(result, a, ctx, status); +} + +/* quietly set a decimal from an mpd_uint_t */ +void +mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + _settriple(result, MPD_POS, a, 0); + mpd_qfinalize(result, ctx, status); +} + +/* quietly set a decimal from an int32_t */ +void +mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qset_ssize(result, a, ctx, status); +} + +/* quietly set a decimal from a uint32_t */ +void +mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qset_uint(result, a, ctx, status); +} + +#if defined(CONFIG_32) && !defined(LEGACY_COMPILER) +/* set a decimal from a uint64_t */ +static void +_c32setu64(mpd_t *result, uint64_t u, uint8_t sign, uint32_t *status) +{ + mpd_uint_t w[3]; + uint64_t q; + int i, len; + + len = 0; + do { + q = u / MPD_RADIX; + w[len] = (mpd_uint_t)(u - q * MPD_RADIX); + u = q; len++; + } while (u != 0); + + if (!mpd_qresize(result, len, status)) { + return; + } + for (i = 0; i < len; i++) { + result->data[i] = w[i]; + } + + mpd_set_sign(result, sign); + result->exp = 0; + result->len = len; + mpd_setdigits(result); +} + +static void +_c32_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + _c32setu64(result, a, MPD_POS, status); + mpd_qfinalize(result, ctx, status); +} + +/* set a decimal from an int64_t */ +static void +_c32_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + uint64_t u; + uint8_t sign = MPD_POS; + + if (a < 0) { + if (a == INT64_MIN) { + u = (uint64_t)INT64_MAX + (-(INT64_MIN+INT64_MAX)); + } + else { + u = -a; + } + sign = MPD_NEG; + } + else { + u = a; + } + _c32setu64(result, u, sign, status); + mpd_qfinalize(result, ctx, status); +} +#endif /* CONFIG_32 && !LEGACY_COMPILER */ + +#ifndef LEGACY_COMPILER +/* quietly set a decimal from an int64_t */ +void +mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ +#ifdef CONFIG_64 + mpd_qset_ssize(result, a, ctx, status); +#else + _c32_qset_i64(result, a, ctx, status); +#endif +} + +/* quietly set a decimal from a uint64_t */ +void +mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ +#ifdef CONFIG_64 + mpd_qset_uint(result, a, ctx, status); +#else + _c32_qset_u64(result, a, ctx, status); +#endif +} +#endif /* !LEGACY_COMPILER */ + + +/* + * Quietly get an mpd_uint_t from a decimal. Assumes + * MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for + * 32 and 64 bit machines. + * + * If the operation is impossible, MPD_Invalid_operation is set. + */ +static mpd_uint_t +_mpd_qget_uint(int use_sign, const mpd_t *a, uint32_t *status) +{ + mpd_t tmp; + mpd_uint_t tmp_data[2]; + mpd_uint_t lo, hi; + + if (mpd_isspecial(a)) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + if (mpd_iszero(a)) { + return 0; + } + if (use_sign && mpd_isnegative(a)) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + + if (a->digits+a->exp > MPD_RDIGITS+1) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + + if (a->exp < 0) { + if (!_mpd_isint(a)) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + /* At this point a->digits+a->exp <= MPD_RDIGITS+1, + * so the shift fits. */ + tmp.data = tmp_data; + tmp.flags = MPD_STATIC|MPD_CONST_DATA; + mpd_qsshiftr(&tmp, a, -a->exp); + tmp.exp = 0; + a = &tmp; + } + + _mpd_get_msdigits(&hi, &lo, a, MPD_RDIGITS+1); + if (hi) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + + if (a->exp > 0) { + _mpd_mul_words(&hi, &lo, lo, mpd_pow10[a->exp]); + if (hi) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + } + + return lo; +} + +/* + * Sets Invalid_operation for: + * - specials + * - negative numbers (except negative zero) + * - non-integers + * - overflow + */ +mpd_uint_t +mpd_qget_uint(const mpd_t *a, uint32_t *status) +{ + return _mpd_qget_uint(1, a, status); +} + +/* Same as above, but gets the absolute value, i.e. the sign is ignored. */ +mpd_uint_t +mpd_qabs_uint(const mpd_t *a, uint32_t *status) +{ + return _mpd_qget_uint(0, a, status); +} + +/* quietly get an mpd_ssize_t from a decimal */ +mpd_ssize_t +mpd_qget_ssize(const mpd_t *a, uint32_t *status) +{ + mpd_uint_t u; + int isneg; + + u = mpd_qabs_uint(a, status); + if (*status&MPD_Invalid_operation) { + return MPD_SSIZE_MAX; + } + + isneg = mpd_isnegative(a); + if (u <= MPD_SSIZE_MAX) { + return isneg ? -((mpd_ssize_t)u) : (mpd_ssize_t)u; + } + else if (isneg && u-1 == MPD_SSIZE_MAX) { + return MPD_SSIZE_MIN; + } + + *status |= MPD_Invalid_operation; + return MPD_SSIZE_MAX; +} + +#ifdef CONFIG_64 +/* quietly get a uint64_t from a decimal */ +uint64_t +mpd_qget_u64(const mpd_t *a, uint32_t *status) +{ + return mpd_qget_uint(a, status); +} + +/* quietly get an int64_t from a decimal */ +int64_t +mpd_qget_i64(const mpd_t *a, uint32_t *status) +{ + return mpd_qget_ssize(a, status); +} +#else +/* quietly get a uint32_t from a decimal */ +uint32_t +mpd_qget_u32(const mpd_t *a, uint32_t *status) +{ + return mpd_qget_uint(a, status); +} + +/* quietly get an int32_t from a decimal */ +int32_t +mpd_qget_i32(const mpd_t *a, uint32_t *status) +{ + return mpd_qget_ssize(a, status); +} +#endif + + +/******************************************************************************/ +/* Filtering input of functions, finalizing output of functions */ +/******************************************************************************/ + +/* + * Check if the operand is NaN, copy to result and return 1 if this is + * the case. Copying can fail since NaNs are allowed to have a payload that + * does not fit in MPD_MINALLOC. + */ +int +mpd_qcheck_nan(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isnan(a)) { + *status |= mpd_issnan(a) ? MPD_Invalid_operation : 0; + mpd_qcopy(result, a, status); + mpd_set_qnan(result); + _mpd_fix_nan(result, ctx); + return 1; + } + return 0; +} + +/* + * Check if either operand is NaN, copy to result and return 1 if this + * is the case. Copying can fail since NaNs are allowed to have a payload + * that does not fit in MPD_MINALLOC. + */ +int +mpd_qcheck_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + if ((a->flags|b->flags)&(MPD_NAN|MPD_SNAN)) { + const mpd_t *choice = b; + if (mpd_issnan(a)) { + choice = a; + *status |= MPD_Invalid_operation; + } + else if (mpd_issnan(b)) { + *status |= MPD_Invalid_operation; + } + else if (mpd_isqnan(a)) { + choice = a; + } + mpd_qcopy(result, choice, status); + mpd_set_qnan(result); + _mpd_fix_nan(result, ctx); + return 1; + } + return 0; +} + +/* + * Check if one of the operands is NaN, copy to result and return 1 if this + * is the case. Copying can fail since NaNs are allowed to have a payload + * that does not fit in MPD_MINALLOC. + */ +static int +mpd_qcheck_3nans(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, + const mpd_context_t *ctx, uint32_t *status) +{ + if ((a->flags|b->flags|c->flags)&(MPD_NAN|MPD_SNAN)) { + const mpd_t *choice = c; + if (mpd_issnan(a)) { + choice = a; + *status |= MPD_Invalid_operation; + } + else if (mpd_issnan(b)) { + choice = b; + *status |= MPD_Invalid_operation; + } + else if (mpd_issnan(c)) { + *status |= MPD_Invalid_operation; + } + else if (mpd_isqnan(a)) { + choice = a; + } + else if (mpd_isqnan(b)) { + choice = b; + } + mpd_qcopy(result, choice, status); + mpd_set_qnan(result); + _mpd_fix_nan(result, ctx); + return 1; + } + return 0; +} + +/* Check if rounding digit 'rnd' leads to an increment. */ +static inline int +_mpd_rnd_incr(const mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx) +{ + int ld; + + switch (ctx->round) { + case MPD_ROUND_DOWN: case MPD_ROUND_TRUNC: + return 0; + case MPD_ROUND_HALF_UP: + return (rnd >= 5); + case MPD_ROUND_HALF_EVEN: + return (rnd > 5) || ((rnd == 5) && mpd_isoddcoeff(dec)); + case MPD_ROUND_CEILING: + return !(rnd == 0 || mpd_isnegative(dec)); + case MPD_ROUND_FLOOR: + return !(rnd == 0 || mpd_ispositive(dec)); + case MPD_ROUND_HALF_DOWN: + return (rnd > 5); + case MPD_ROUND_UP: + return !(rnd == 0); + case MPD_ROUND_05UP: + ld = (int)mpd_lsd(dec->data[0]); + return (!(rnd == 0) && (ld == 0 || ld == 5)); + default: + /* Without a valid context, further results will be undefined. */ + return 0; /* GCOV_NOT_REACHED */ + } +} + +/* + * Apply rounding to a decimal that has been right-shifted into a full + * precision decimal. If an increment leads to an overflow of the precision, + * adjust the coefficient and the exponent and check the new exponent for + * overflow. + */ +static inline void +_mpd_apply_round(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx, + uint32_t *status) +{ + if (_mpd_rnd_incr(dec, rnd, ctx)) { + /* We have a number with exactly ctx->prec digits. The increment + * can only lead to an overflow if the decimal is all nines. In + * that case, the result is a power of ten with prec+1 digits. + * + * If the precision is a multiple of MPD_RDIGITS, this situation is + * detected by _mpd_baseincr returning a carry. + * If the precision is not a multiple of MPD_RDIGITS, we have to + * check if the result has one digit too many. + */ + mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len); + if (carry) { + dec->data[dec->len-1] = mpd_pow10[MPD_RDIGITS-1]; + dec->exp += 1; + _mpd_check_exp(dec, ctx, status); + return; + } + mpd_setdigits(dec); + if (dec->digits > ctx->prec) { + mpd_qshiftr_inplace(dec, 1); + dec->exp += 1; + dec->digits = ctx->prec; + _mpd_check_exp(dec, ctx, status); + } + } +} + +/* + * Apply rounding to a decimal. Allow overflow of the precision. + */ +static inline void +_mpd_apply_round_excess(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx, + uint32_t *status) +{ + if (_mpd_rnd_incr(dec, rnd, ctx)) { + mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len); + if (carry) { + if (!mpd_qresize(dec, dec->len+1, status)) { + return; + } + dec->data[dec->len] = 1; + dec->len += 1; + } + mpd_setdigits(dec); + } +} + +/* + * Apply rounding to a decimal that has been right-shifted into a decimal + * with full precision or less. Return failure if an increment would + * overflow the precision. + */ +static inline int +_mpd_apply_round_fit(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx, + uint32_t *status) +{ + if (_mpd_rnd_incr(dec, rnd, ctx)) { + mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len); + if (carry) { + if (!mpd_qresize(dec, dec->len+1, status)) { + return 0; + } + dec->data[dec->len] = 1; + dec->len += 1; + } + mpd_setdigits(dec); + if (dec->digits > ctx->prec) { + mpd_seterror(dec, MPD_Invalid_operation, status); + return 0; + } + } + return 1; +} + +/* Check a normal number for overflow, underflow, clamping. If the operand + is modified, it will be zero, special or (sub)normal with a coefficient + that fits into the current context precision. */ +static inline void +_mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t adjexp, etiny, shift; + int rnd; + + adjexp = mpd_adjexp(dec); + if (adjexp > ctx->emax) { + + if (mpd_iszerocoeff(dec)) { + dec->exp = ctx->emax; + if (ctx->clamp) { + dec->exp -= (ctx->prec-1); + } + mpd_zerocoeff(dec); + *status |= MPD_Clamped; + return; + } + + switch (ctx->round) { + case MPD_ROUND_HALF_UP: case MPD_ROUND_HALF_EVEN: + case MPD_ROUND_HALF_DOWN: case MPD_ROUND_UP: + case MPD_ROUND_TRUNC: + mpd_setspecial(dec, mpd_sign(dec), MPD_INF); + break; + case MPD_ROUND_DOWN: case MPD_ROUND_05UP: + mpd_qmaxcoeff(dec, ctx, status); + dec->exp = ctx->emax - ctx->prec + 1; + break; + case MPD_ROUND_CEILING: + if (mpd_isnegative(dec)) { + mpd_qmaxcoeff(dec, ctx, status); + dec->exp = ctx->emax - ctx->prec + 1; + } + else { + mpd_setspecial(dec, MPD_POS, MPD_INF); + } + break; + case MPD_ROUND_FLOOR: + if (mpd_ispositive(dec)) { + mpd_qmaxcoeff(dec, ctx, status); + dec->exp = ctx->emax - ctx->prec + 1; + } + else { + mpd_setspecial(dec, MPD_NEG, MPD_INF); + } + break; + default: /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + + *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded; + + } /* fold down */ + else if (ctx->clamp && dec->exp > mpd_etop(ctx)) { + /* At this point adjexp=exp+digits-1 <= emax and exp > etop=emax-prec+1: + * (1) shift = exp -emax+prec-1 > 0 + * (2) digits+shift = exp+digits-1 - emax + prec <= prec */ + shift = dec->exp - mpd_etop(ctx); + if (!mpd_qshiftl(dec, dec, shift, status)) { + return; + } + dec->exp -= shift; + *status |= MPD_Clamped; + if (!mpd_iszerocoeff(dec) && adjexp < ctx->emin) { + /* Underflow is impossible, since exp < etiny=emin-prec+1 + * and exp > etop=emax-prec+1 would imply emax < emin. */ + *status |= MPD_Subnormal; + } + } + else if (adjexp < ctx->emin) { + + etiny = mpd_etiny(ctx); + + if (mpd_iszerocoeff(dec)) { + if (dec->exp < etiny) { + dec->exp = etiny; + mpd_zerocoeff(dec); + *status |= MPD_Clamped; + } + return; + } + + *status |= MPD_Subnormal; + if (dec->exp < etiny) { + /* At this point adjexp=exp+digits-1 < emin and exp < etiny=emin-prec+1: + * (1) shift = emin-prec+1 - exp > 0 + * (2) digits-shift = exp+digits-1 - emin + prec < prec */ + shift = etiny - dec->exp; + rnd = (int)mpd_qshiftr_inplace(dec, shift); + dec->exp = etiny; + /* We always have a spare digit in case of an increment. */ + _mpd_apply_round_excess(dec, rnd, ctx, status); + *status |= MPD_Rounded; + if (rnd) { + *status |= (MPD_Inexact|MPD_Underflow); + if (mpd_iszerocoeff(dec)) { + mpd_zerocoeff(dec); + *status |= MPD_Clamped; + } + } + } + /* Case exp >= etiny=emin-prec+1: + * (1) adjexp=exp+digits-1 < emin + * (2) digits < emin-exp+1 <= prec */ + } +} + +/* Transcendental functions do not always set Underflow reliably, + * since they only use as much precision as is necessary for correct + * rounding. If a result like 1.0000000000e-101 is finalized, there + * is no rounding digit that would trigger Underflow. But we can + * assume Inexact, so a short check suffices. */ +static inline void +mpd_check_underflow(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_adjexp(dec) < ctx->emin && !mpd_iszero(dec) && + dec->exp < mpd_etiny(ctx)) { + *status |= MPD_Underflow; + } +} + +/* Check if a normal number must be rounded after the exponent has been checked. */ +static inline void +_mpd_check_round(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t rnd; + mpd_ssize_t shift; + + /* must handle specials: _mpd_check_exp() can produce infinities or NaNs */ + if (mpd_isspecial(dec)) { + return; + } + + if (dec->digits > ctx->prec) { + shift = dec->digits - ctx->prec; + rnd = mpd_qshiftr_inplace(dec, shift); + dec->exp += shift; + _mpd_apply_round(dec, rnd, ctx, status); + *status |= MPD_Rounded; + if (rnd) { + *status |= MPD_Inexact; + } + } +} + +/* Finalize all operations. */ +void +mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_isspecial(result)) { + if (mpd_isnan(result)) { + _mpd_fix_nan(result, ctx); + } + return; + } + + _mpd_check_exp(result, ctx, status); + _mpd_check_round(result, ctx, status); +} + + +/******************************************************************************/ +/* Copying */ +/******************************************************************************/ + +/* Internal function: Copy a decimal, share data with src: USE WITH CARE! */ +static inline void +_mpd_copy_shared(mpd_t *dest, const mpd_t *src) +{ + dest->flags = src->flags; + dest->exp = src->exp; + dest->digits = src->digits; + dest->len = src->len; + dest->alloc = src->alloc; + dest->data = src->data; + + mpd_set_shared_data(dest); +} + +/* + * Copy a decimal. In case of an error, status is set to MPD_Malloc_error. + */ +int +mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status) +{ + if (result == a) return 1; + + if (!mpd_qresize(result, a->len, status)) { + return 0; + } + + mpd_copy_flags(result, a); + result->exp = a->exp; + result->digits = a->digits; + result->len = a->len; + memcpy(result->data, a->data, a->len * (sizeof *result->data)); + + return 1; +} + +/* + * Copy to a decimal with a static buffer. The caller has to make sure that + * the buffer is big enough. Cannot fail. + */ +static void +mpd_qcopy_static(mpd_t *result, const mpd_t *a) +{ + if (result == a) return; + + memcpy(result->data, a->data, a->len * (sizeof *result->data)); + + mpd_copy_flags(result, a); + result->exp = a->exp; + result->digits = a->digits; + result->len = a->len; +} + +/* + * Return a newly allocated copy of the operand. In case of an error, + * status is set to MPD_Malloc_error and the return value is NULL. + */ +mpd_t * +mpd_qncopy(const mpd_t *a) +{ + mpd_t *result; + + if ((result = mpd_qnew_size(a->len)) == NULL) { + return NULL; + } + memcpy(result->data, a->data, a->len * (sizeof *result->data)); + mpd_copy_flags(result, a); + result->exp = a->exp; + result->digits = a->digits; + result->len = a->len; + + return result; +} + +/* + * Copy a decimal and set the sign to positive. In case of an error, the + * status is set to MPD_Malloc_error. + */ +int +mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status) +{ + if (!mpd_qcopy(result, a, status)) { + return 0; + } + mpd_set_positive(result); + return 1; +} + +/* + * Copy a decimal and negate the sign. In case of an error, the + * status is set to MPD_Malloc_error. + */ +int +mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status) +{ + if (!mpd_qcopy(result, a, status)) { + return 0; + } + _mpd_negate(result); + return 1; +} + +/* + * Copy a decimal, setting the sign of the first operand to the sign of the + * second operand. In case of an error, the status is set to MPD_Malloc_error. + */ +int +mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status) +{ + uint8_t sign_b = mpd_sign(b); /* result may equal b! */ + + if (!mpd_qcopy(result, a, status)) { + return 0; + } + mpd_set_sign(result, sign_b); + return 1; +} + + +/******************************************************************************/ +/* Comparisons */ +/******************************************************************************/ + +/* + * For all functions that compare two operands and return an int the usual + * convention applies to the return value: + * + * -1 if op1 < op2 + * 0 if op1 == op2 + * 1 if op1 > op2 + * + * INT_MAX for error + */ + + +/* Convenience macro. If a and b are not equal, return from the calling + * function with the correct comparison value. */ +#define CMP_EQUAL_OR_RETURN(a, b) \ + if (a != b) { \ + if (a < b) { \ + return -1; \ + } \ + return 1; \ + } + +/* + * Compare the data of big and small. This function does the equivalent + * of first shifting small to the left and then comparing the data of + * big and small, except that no allocation for the left shift is needed. + */ +static int +_mpd_basecmp(mpd_uint_t *big, mpd_uint_t *small, mpd_size_t n, mpd_size_t m, + mpd_size_t shift) +{ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) + /* spurious uninitialized warnings */ + mpd_uint_t l=l, lprev=lprev, h=h; +#else + mpd_uint_t l, lprev, h; +#endif + mpd_uint_t q, r; + mpd_uint_t ph, x; + + assert(m > 0 && n >= m && shift > 0); + + _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS); + + if (r != 0) { + + ph = mpd_pow10[r]; + + --m; --n; + _mpd_divmod_pow10(&h, &lprev, small[m--], MPD_RDIGITS-r); + if (h != 0) { + CMP_EQUAL_OR_RETURN(big[n], h) + --n; + } + for (; m != MPD_SIZE_MAX; m--,n--) { + _mpd_divmod_pow10(&h, &l, small[m], MPD_RDIGITS-r); + x = ph * lprev + h; + CMP_EQUAL_OR_RETURN(big[n], x) + lprev = l; + } + x = ph * lprev; + CMP_EQUAL_OR_RETURN(big[q], x) + } + else { + while (--m != MPD_SIZE_MAX) { + CMP_EQUAL_OR_RETURN(big[m+q], small[m]) + } + } + + return !_mpd_isallzero(big, q); +} + +/* Compare two decimals with the same adjusted exponent. */ +static int +_mpd_cmp_same_adjexp(const mpd_t *a, const mpd_t *b) +{ + mpd_ssize_t shift, i; + + if (a->exp != b->exp) { + /* Cannot wrap: a->exp + a->digits = b->exp + b->digits, so + * a->exp - b->exp = b->digits - a->digits. */ + shift = a->exp - b->exp; + if (shift > 0) { + return -1 * _mpd_basecmp(b->data, a->data, b->len, a->len, shift); + } + else { + return _mpd_basecmp(a->data, b->data, a->len, b->len, -shift); + } + } + + /* + * At this point adjexp(a) == adjexp(b) and a->exp == b->exp, + * so a->digits == b->digits, therefore a->len == b->len. + */ + for (i = a->len-1; i >= 0; --i) { + CMP_EQUAL_OR_RETURN(a->data[i], b->data[i]) + } + + return 0; +} + +/* Compare two numerical values. */ +static int +_mpd_cmp(const mpd_t *a, const mpd_t *b) +{ + mpd_ssize_t adjexp_a, adjexp_b; + + /* equal pointers */ + if (a == b) { + return 0; + } + + /* infinities */ + if (mpd_isinfinite(a)) { + if (mpd_isinfinite(b)) { + return mpd_isnegative(b) - mpd_isnegative(a); + } + return mpd_arith_sign(a); + } + if (mpd_isinfinite(b)) { + return -mpd_arith_sign(b); + } + + /* zeros */ + if (mpd_iszerocoeff(a)) { + if (mpd_iszerocoeff(b)) { + return 0; + } + return -mpd_arith_sign(b); + } + if (mpd_iszerocoeff(b)) { + return mpd_arith_sign(a); + } + + /* different signs */ + if (mpd_sign(a) != mpd_sign(b)) { + return mpd_sign(b) - mpd_sign(a); + } + + /* different adjusted exponents */ + adjexp_a = mpd_adjexp(a); + adjexp_b = mpd_adjexp(b); + if (adjexp_a != adjexp_b) { + if (adjexp_a < adjexp_b) { + return -1 * mpd_arith_sign(a); + } + return mpd_arith_sign(a); + } + + /* same adjusted exponents */ + return _mpd_cmp_same_adjexp(a, b) * mpd_arith_sign(a); +} + +/* Compare the absolutes of two numerical values. */ +static int +_mpd_cmp_abs(const mpd_t *a, const mpd_t *b) +{ + mpd_ssize_t adjexp_a, adjexp_b; + + /* equal pointers */ + if (a == b) { + return 0; + } + + /* infinities */ + if (mpd_isinfinite(a)) { + if (mpd_isinfinite(b)) { + return 0; + } + return 1; + } + if (mpd_isinfinite(b)) { + return -1; + } + + /* zeros */ + if (mpd_iszerocoeff(a)) { + if (mpd_iszerocoeff(b)) { + return 0; + } + return -1; + } + if (mpd_iszerocoeff(b)) { + return 1; + } + + /* different adjusted exponents */ + adjexp_a = mpd_adjexp(a); + adjexp_b = mpd_adjexp(b); + if (adjexp_a != adjexp_b) { + if (adjexp_a < adjexp_b) { + return -1; + } + return 1; + } + + /* same adjusted exponents */ + return _mpd_cmp_same_adjexp(a, b); +} + +/* Compare two values and return an integer result. */ +int +mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status) +{ + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_isnan(a) || mpd_isnan(b)) { + *status |= MPD_Invalid_operation; + return INT_MAX; + } + } + + return _mpd_cmp(a, b); +} + +/* + * Compare a and b, convert the the usual integer result to a decimal and + * store it in 'result'. For convenience, the integer result of the comparison + * is returned. Comparisons involving NaNs return NaN/INT_MAX. + */ +int +mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return INT_MAX; + } + } + + c = _mpd_cmp(a, b); + _settriple(result, (c < 0), (c != 0), 0); + return c; +} + +/* Same as mpd_compare(), but signal for all NaNs, i.e. also for quiet NaNs. */ +int +mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + *status |= MPD_Invalid_operation; + return INT_MAX; + } + } + + c = _mpd_cmp(a, b); + _settriple(result, (c < 0), (c != 0), 0); + return c; +} + +/* Compare the operands using a total order. */ +int +mpd_cmp_total(const mpd_t *a, const mpd_t *b) +{ + mpd_t aa, bb; + int nan_a, nan_b; + int c; + + if (mpd_sign(a) != mpd_sign(b)) { + return mpd_sign(b) - mpd_sign(a); + } + + + if (mpd_isnan(a)) { + c = 1; + if (mpd_isnan(b)) { + nan_a = (mpd_isqnan(a)) ? 1 : 0; + nan_b = (mpd_isqnan(b)) ? 1 : 0; + if (nan_b == nan_a) { + if (a->len > 0 && b->len > 0) { + _mpd_copy_shared(&aa, a); + _mpd_copy_shared(&bb, b); + aa.exp = bb.exp = 0; + /* compare payload */ + c = _mpd_cmp_abs(&aa, &bb); + } + else { + c = (a->len > 0) - (b->len > 0); + } + } + else { + c = nan_a - nan_b; + } + } + } + else if (mpd_isnan(b)) { + c = -1; + } + else { + c = _mpd_cmp_abs(a, b); + if (c == 0 && a->exp != b->exp) { + c = (a->exp < b->exp) ? -1 : 1; + } + } + + return c * mpd_arith_sign(a); +} + +/* + * Compare a and b according to a total order, convert the usual integer result + * to a decimal and store it in 'result'. For convenience, the integer result + * of the comparison is returned. + */ +int +mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b) +{ + int c; + + c = mpd_cmp_total(a, b); + _settriple(result, (c < 0), (c != 0), 0); + return c; +} + +/* Compare the magnitude of the operands using a total order. */ +int +mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b) +{ + mpd_t aa, bb; + + _mpd_copy_shared(&aa, a); + _mpd_copy_shared(&bb, b); + + mpd_set_positive(&aa); + mpd_set_positive(&bb); + + return mpd_cmp_total(&aa, &bb); +} + +/* + * Compare the magnitude of a and b according to a total order, convert the + * the usual integer result to a decimal and store it in 'result'. + * For convenience, the integer result of the comparison is returned. + */ +int +mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b) +{ + int c; + + c = mpd_cmp_total_mag(a, b); + _settriple(result, (c < 0), (c != 0), 0); + return c; +} + +/* Determine an ordering for operands that are numerically equal. */ +static inline int +_mpd_cmp_numequal(const mpd_t *a, const mpd_t *b) +{ + int sign_a, sign_b; + int c; + + sign_a = mpd_sign(a); + sign_b = mpd_sign(b); + if (sign_a != sign_b) { + c = sign_b - sign_a; + } + else { + c = (a->exp < b->exp) ? -1 : 1; + c *= mpd_arith_sign(a); + } + + return c; +} + + +/******************************************************************************/ +/* Shifting the coefficient */ +/******************************************************************************/ + +/* + * Shift the coefficient of the operand to the left, no check for specials. + * Both operands may be the same pointer. If the result length has to be + * increased, mpd_qresize() might fail with MPD_Malloc_error. + */ +int +mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status) +{ + mpd_ssize_t size; + + assert(n >= 0); + + if (mpd_iszerocoeff(a) || n == 0) { + return mpd_qcopy(result, a, status); + } + + size = mpd_digits_to_size(a->digits+n); + if (!mpd_qresize(result, size, status)) { + return 0; /* result is NaN */ + } + + _mpd_baseshiftl(result->data, a->data, size, a->len, n); + + mpd_copy_flags(result, a); + result->len = size; + result->exp = a->exp; + result->digits = a->digits+n; + + return 1; +} + +/* Determine the rounding indicator if all digits of the coefficient are shifted + * out of the picture. */ +static mpd_uint_t +_mpd_get_rnd(const mpd_uint_t *data, mpd_ssize_t len, int use_msd) +{ + mpd_uint_t rnd = 0, rest = 0, word; + + word = data[len-1]; + /* special treatment for the most significant digit if shift == digits */ + if (use_msd) { + _mpd_divmod_pow10(&rnd, &rest, word, mpd_word_digits(word)-1); + if (len > 1 && rest == 0) { + rest = !_mpd_isallzero(data, len-1); + } + } + else { + rest = !_mpd_isallzero(data, len); + } + + return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd; +} + +/* + * Same as mpd_qshiftr(), but 'result' is a static array. It is the + * caller's responsibility to make sure that the array is big enough. + * The function cannot fail. + */ +mpd_uint_t +mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n) +{ + mpd_uint_t rnd; + mpd_ssize_t size; + + assert(n >= 0); + + if (mpd_iszerocoeff(a) || n == 0) { + mpd_qcopy_static(result, a); + return 0; + } + + if (n >= a->digits) { + rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits)); + mpd_zerocoeff(result); + result->digits = 1; + size = 1; + } + else { + result->digits = a->digits-n; + size = mpd_digits_to_size(result->digits); + rnd = _mpd_baseshiftr(result->data, a->data, a->len, n); + } + + mpd_copy_flags(result, a); + result->exp = a->exp; + result->len = size; + + return rnd; +} + +/* + * Inplace shift of the coefficient to the right, no check for specials. + * Returns the rounding indicator for mpd_rnd_incr(). + * The function cannot fail. + */ +mpd_uint_t +mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n) +{ + uint32_t dummy; + mpd_uint_t rnd; + mpd_ssize_t size; + + assert(n >= 0); + + if (mpd_iszerocoeff(result) || n == 0) { + return 0; + } + + if (n >= result->digits) { + rnd = _mpd_get_rnd(result->data, result->len, (n==result->digits)); + mpd_zerocoeff(result); + result->digits = 1; + size = 1; + } + else { + rnd = _mpd_baseshiftr(result->data, result->data, result->len, n); + result->digits -= n; + size = mpd_digits_to_size(result->digits); + /* reducing the size cannot fail */ + mpd_qresize(result, size, &dummy); + } + + result->len = size; + + return rnd; +} + +/* + * Shift the coefficient of the operand to the right, no check for specials. + * Both operands may be the same pointer. Returns the rounding indicator to + * be used by mpd_rnd_incr(). If the result length has to be increased, + * mpd_qcopy() or mpd_qresize() might fail with MPD_Malloc_error. In those + * cases, MPD_UINT_MAX is returned. + */ +mpd_uint_t +mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status) +{ + mpd_uint_t rnd; + mpd_ssize_t size; + + assert(n >= 0); + + if (mpd_iszerocoeff(a) || n == 0) { + if (!mpd_qcopy(result, a, status)) { + return MPD_UINT_MAX; + } + return 0; + } + + if (n >= a->digits) { + rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits)); + mpd_zerocoeff(result); + result->digits = 1; + size = 1; + } + else { + result->digits = a->digits-n; + size = mpd_digits_to_size(result->digits); + if (result == a) { + rnd = _mpd_baseshiftr(result->data, a->data, a->len, n); + /* reducing the size cannot fail */ + mpd_qresize(result, size, status); + } + else { + if (!mpd_qresize(result, size, status)) { + return MPD_UINT_MAX; + } + rnd = _mpd_baseshiftr(result->data, a->data, a->len, n); + } + } + + mpd_copy_flags(result, a); + result->exp = a->exp; + result->len = size; + + return rnd; +} + + +/******************************************************************************/ +/* Miscellaneous operations */ +/******************************************************************************/ + +/* Logical And */ +void +mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + const mpd_t *big = a, *small = b; + mpd_uint_t x, y, z, xbit, ybit; + int k, mswdigits; + mpd_ssize_t i; + + if (mpd_isspecial(a) || mpd_isspecial(b) || + mpd_isnegative(a) || mpd_isnegative(b) || + a->exp != 0 || b->exp != 0) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (b->digits > a->digits) { + big = b; + small = a; + } + if (!mpd_qresize(result, big->len, status)) { + return; + } + + + /* full words */ + for (i = 0; i < small->len-1; i++) { + x = small->data[i]; + y = big->data[i]; + z = 0; + for (k = 0; k < MPD_RDIGITS; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit&ybit) ? mpd_pow10[k] : 0; + } + result->data[i] = z; + } + /* most significant word of small */ + x = small->data[i]; + y = big->data[i]; + z = 0; + mswdigits = mpd_word_digits(x); + for (k = 0; k < mswdigits; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit&ybit) ? mpd_pow10[k] : 0; + } + result->data[i++] = z; + + /* scan the rest of y for digit > 1 */ + for (; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + } + /* scan the rest of big for digit > 1 */ + for (; i < big->len; i++) { + y = big->data[i]; + for (k = 0; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + } + } + + mpd_clear_flags(result); + result->exp = 0; + result->len = _mpd_real_size(result->data, small->len); + mpd_qresize(result, result->len, status); + mpd_setdigits(result); + _mpd_cap(result, ctx); + return; + +invalid_operation: + mpd_seterror(result, MPD_Invalid_operation, status); +} + +/* Class of an operand. Returns a pointer to the constant name. */ +const char * +mpd_class(const mpd_t *a, const mpd_context_t *ctx) +{ + if (mpd_isnan(a)) { + if (mpd_isqnan(a)) + return "NaN"; + else + return "sNaN"; + } + else if (mpd_ispositive(a)) { + if (mpd_isinfinite(a)) + return "+Infinity"; + else if (mpd_iszero(a)) + return "+Zero"; + else if (mpd_isnormal(a, ctx)) + return "+Normal"; + else + return "+Subnormal"; + } + else { + if (mpd_isinfinite(a)) + return "-Infinity"; + else if (mpd_iszero(a)) + return "-Zero"; + else if (mpd_isnormal(a, ctx)) + return "-Normal"; + else + return "-Subnormal"; + } +} + +/* Logical Xor */ +void +mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_uint_t x, z, xbit; + mpd_ssize_t i, digits, len; + mpd_ssize_t q, r; + int k; + + if (mpd_isspecial(a) || mpd_isnegative(a) || a->exp != 0) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + digits = (a->digits < ctx->prec) ? ctx->prec : a->digits; + _mpd_idiv_word(&q, &r, digits, MPD_RDIGITS); + len = (r == 0) ? q : q+1; + if (!mpd_qresize(result, len, status)) { + return; + } + + for (i = 0; i < len; i++) { + x = (i < a->len) ? a->data[i] : 0; + z = 0; + for (k = 0; k < MPD_RDIGITS; k++) { + xbit = x % 10; + x /= 10; + if (xbit > 1) { + goto invalid_operation; + } + z += !xbit ? mpd_pow10[k] : 0; + } + result->data[i] = z; + } + + mpd_clear_flags(result); + result->exp = 0; + result->len = _mpd_real_size(result->data, len); + mpd_qresize(result, result->len, status); + mpd_setdigits(result); + _mpd_cap(result, ctx); + return; + +invalid_operation: + mpd_seterror(result, MPD_Invalid_operation, status); +} + +/* Exponent of the magnitude of the most significant digit of the operand. */ +void +mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + mpd_setspecial(result, MPD_POS, MPD_INF); + } + else if (mpd_iszerocoeff(a)) { + mpd_setspecial(result, MPD_NEG, MPD_INF); + *status |= MPD_Division_by_zero; + } + else { + mpd_qset_ssize(result, mpd_adjexp(a), ctx, status); + } +} + +/* Logical Or */ +void +mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + const mpd_t *big = a, *small = b; + mpd_uint_t x, y, z, xbit, ybit; + int k, mswdigits; + mpd_ssize_t i; + + if (mpd_isspecial(a) || mpd_isspecial(b) || + mpd_isnegative(a) || mpd_isnegative(b) || + a->exp != 0 || b->exp != 0) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (b->digits > a->digits) { + big = b; + small = a; + } + if (!mpd_qresize(result, big->len, status)) { + return; + } + + + /* full words */ + for (i = 0; i < small->len-1; i++) { + x = small->data[i]; + y = big->data[i]; + z = 0; + for (k = 0; k < MPD_RDIGITS; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit|ybit) ? mpd_pow10[k] : 0; + } + result->data[i] = z; + } + /* most significant word of small */ + x = small->data[i]; + y = big->data[i]; + z = 0; + mswdigits = mpd_word_digits(x); + for (k = 0; k < mswdigits; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit|ybit) ? mpd_pow10[k] : 0; + } + + /* scan and copy the rest of y for digit > 1 */ + for (; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + z += ybit*mpd_pow10[k]; + } + result->data[i++] = z; + /* scan and copy the rest of big for digit > 1 */ + for (; i < big->len; i++) { + y = big->data[i]; + for (k = 0; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + } + result->data[i] = big->data[i]; + } + + mpd_clear_flags(result); + result->exp = 0; + result->len = _mpd_real_size(result->data, big->len); + mpd_qresize(result, result->len, status); + mpd_setdigits(result); + _mpd_cap(result, ctx); + return; + +invalid_operation: + mpd_seterror(result, MPD_Invalid_operation, status); +} + +/* + * Rotate the coefficient of a by b->data digits. b must be an integer with + * exponent 0. + */ +void +mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + MPD_NEW_STATIC(tmp,0,0,0,0); + MPD_NEW_STATIC(big,0,0,0,0); + MPD_NEW_STATIC(small,0,0,0,0); + mpd_ssize_t n, lshift, rshift; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + } + if (b->exp != 0 || mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + n = mpd_qget_ssize(b, &workstatus); + if (workstatus&MPD_Invalid_operation) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (n > ctx->prec || n < -ctx->prec) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(a)) { + mpd_qcopy(result, a, status); + return; + } + + if (n >= 0) { + lshift = n; + rshift = ctx->prec-n; + } + else { + lshift = ctx->prec+n; + rshift = -n; + } + + if (a->digits > ctx->prec) { + if (!mpd_qcopy(&tmp, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + _mpd_cap(&tmp, ctx); + a = &tmp; + } + + if (!mpd_qshiftl(&big, a, lshift, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + _mpd_cap(&big, ctx); + + if (mpd_qshiftr(&small, a, rshift, status) == MPD_UINT_MAX) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + _mpd_qadd(result, &big, &small, ctx, status); + + +finish: + mpd_del(&tmp); + mpd_del(&big); + mpd_del(&small); +} + +/* + * b must be an integer with exponent 0 and in the range +-2*(emax + prec). + * XXX: In my opinion +-(2*emax + prec) would be more sensible. + * The result is a with the value of b added to its exponent. + */ +void +mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_uint_t n, maxjump; +#ifndef LEGACY_COMPILER + int64_t exp; +#else + mpd_uint_t x; + int x_sign, n_sign; + mpd_ssize_t exp; +#endif + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + } + if (b->exp != 0 || mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + n = mpd_qabs_uint(b, &workstatus); + /* the spec demands this */ + maxjump = 2 * (mpd_uint_t)(ctx->emax + ctx->prec); + + if (n > maxjump || workstatus&MPD_Invalid_operation) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(a)) { + mpd_qcopy(result, a, status); + return; + } + +#ifndef LEGACY_COMPILER + exp = a->exp + (int64_t)n * mpd_arith_sign(b); + exp = (exp > MPD_EXP_INF) ? MPD_EXP_INF : exp; + exp = (exp < MPD_EXP_CLAMP) ? MPD_EXP_CLAMP : exp; +#else + x = (a->exp < 0) ? -a->exp : a->exp; + x_sign = (a->exp < 0) ? 1 : 0; + n_sign = mpd_isnegative(b) ? 1 : 0; + + if (x_sign == n_sign) { + x = x + n; + if (x < n) x = MPD_UINT_MAX; + } + else { + x_sign = (x >= n) ? x_sign : n_sign; + x = (x >= n) ? x - n : n - x; + } + if (!x_sign && x > MPD_EXP_INF) x = MPD_EXP_INF; + if (x_sign && x > -MPD_EXP_CLAMP) x = -MPD_EXP_CLAMP; + exp = x_sign ? -((mpd_ssize_t)x) : (mpd_ssize_t)x; +#endif + + mpd_qcopy(result, a, status); + result->exp = (mpd_ssize_t)exp; + + mpd_qfinalize(result, ctx, status); +} + +/* + * Shift the coefficient by n digits, positive n is a left shift. In the case + * of a left shift, the result is decapitated to fit the context precision. If + * you don't want that, use mpd_shiftl(). + */ +void +mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + mpd_qcopy(result, a, status); + return; + } + + if (n >= 0 && n <= ctx->prec) { + mpd_qshiftl(result, a, n, status); + _mpd_cap(result, ctx); + } + else if (n < 0 && n >= -ctx->prec) { + if (!mpd_qcopy(result, a, status)) { + return; + } + _mpd_cap(result, ctx); + mpd_qshiftr_inplace(result, -n); + } + else { + mpd_seterror(result, MPD_Invalid_operation, status); + } +} + +/* + * Same as mpd_shiftn(), but the shift is specified by the decimal b, which + * must be an integer with a zero exponent. Infinities remain infinities. + */ +void +mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, + uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_ssize_t n; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + } + if (b->exp != 0 || mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + n = mpd_qget_ssize(b, &workstatus); + if (workstatus&MPD_Invalid_operation) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (n > ctx->prec || n < -ctx->prec) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(a)) { + mpd_qcopy(result, a, status); + return; + } + + if (n >= 0) { + mpd_qshiftl(result, a, n, status); + _mpd_cap(result, ctx); + } + else { + if (!mpd_qcopy(result, a, status)) { + return; + } + _mpd_cap(result, ctx); + mpd_qshiftr_inplace(result, -n); + } +} + +/* Logical Xor */ +void +mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + const mpd_t *big = a, *small = b; + mpd_uint_t x, y, z, xbit, ybit; + int k, mswdigits; + mpd_ssize_t i; + + if (mpd_isspecial(a) || mpd_isspecial(b) || + mpd_isnegative(a) || mpd_isnegative(b) || + a->exp != 0 || b->exp != 0) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (b->digits > a->digits) { + big = b; + small = a; + } + if (!mpd_qresize(result, big->len, status)) { + return; + } + + + /* full words */ + for (i = 0; i < small->len-1; i++) { + x = small->data[i]; + y = big->data[i]; + z = 0; + for (k = 0; k < MPD_RDIGITS; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit^ybit) ? mpd_pow10[k] : 0; + } + result->data[i] = z; + } + /* most significant word of small */ + x = small->data[i]; + y = big->data[i]; + z = 0; + mswdigits = mpd_word_digits(x); + for (k = 0; k < mswdigits; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit^ybit) ? mpd_pow10[k] : 0; + } + + /* scan and copy the rest of y for digit > 1 */ + for (; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + z += ybit*mpd_pow10[k]; + } + result->data[i++] = z; + /* scan and copy the rest of big for digit > 1 */ + for (; i < big->len; i++) { + y = big->data[i]; + for (k = 0; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + } + result->data[i] = big->data[i]; + } + + mpd_clear_flags(result); + result->exp = 0; + result->len = _mpd_real_size(result->data, big->len); + mpd_qresize(result, result->len, status); + mpd_setdigits(result); + _mpd_cap(result, ctx); + return; + +invalid_operation: + mpd_seterror(result, MPD_Invalid_operation, status); +} + + +/******************************************************************************/ +/* Arithmetic operations */ +/******************************************************************************/ + +/* + * The absolute value of a. If a is negative, the result is the same + * as the result of the minus operation. Otherwise, the result is the + * result of the plus operation. + */ +void +mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + } + + if (mpd_isnegative(a)) { + mpd_qminus(result, a, ctx, status); + } + else { + mpd_qplus(result, a, ctx, status); + } + + mpd_qfinalize(result, ctx, status); +} + +static inline void +_mpd_ptrswap(mpd_t **a, mpd_t **b) +{ + mpd_t *t = *a; + *a = *b; + *b = t; +} + +/* Add or subtract infinities. */ +static void +_mpd_qaddsub_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b, + uint32_t *status) +{ + if (mpd_isinfinite(a)) { + if (mpd_sign(a) != sign_b && mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + } + else { + mpd_setspecial(result, mpd_sign(a), MPD_INF); + } + return; + } + assert(mpd_isinfinite(b)); + mpd_setspecial(result, sign_b, MPD_INF); +} + +/* Add or subtract non-special numbers. */ +static void +_mpd_qaddsub(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_t *big, *small; + MPD_NEW_STATIC(big_aligned,0,0,0,0); + MPD_NEW_CONST(tiny,0,0,0,1,1,1); + mpd_uint_t carry; + mpd_ssize_t newsize, shift; + mpd_ssize_t exp, i; + int swap = 0; + + + /* compare exponents */ + big = (mpd_t *)a; small = (mpd_t *)b; + if (big->exp != small->exp) { + if (small->exp > big->exp) { + _mpd_ptrswap(&big, &small); + swap++; + } + if (!mpd_iszerocoeff(big)) { + /* Test for adjexp(small) + big->digits < adjexp(big), if big-digits > prec + * Test for adjexp(small) + prec + 1 < adjexp(big), if big-digits <= prec + * If true, the magnitudes of the numbers are so far apart that one can as + * well add or subtract 1*10**big->exp. */ + exp = big->exp - 1; + exp += (big->digits > ctx->prec) ? 0 : big->digits-ctx->prec-1; + if (mpd_adjexp(small) < exp) { + mpd_copy_flags(&tiny, small); + tiny.exp = exp; + tiny.digits = 1; + tiny.len = 1; + tiny.data[0] = mpd_iszerocoeff(small) ? 0 : 1; + small = &tiny; + } + /* this cannot wrap: the difference is positive and <= maxprec+1 */ + shift = big->exp - small->exp; + if (!mpd_qshiftl(&big_aligned, big, shift, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + big = &big_aligned; + } + } + result->exp = small->exp; + + + /* compare length of coefficients */ + if (big->len < small->len) { + _mpd_ptrswap(&big, &small); + swap++; + } + + newsize = big->len; + if (!mpd_qresize(result, newsize, status)) { + goto finish; + } + + if (mpd_sign(a) == sign_b) { + + carry = _mpd_baseadd(result->data, big->data, small->data, + big->len, small->len); + + if (carry) { + newsize = big->len + 1; + if (!mpd_qresize(result, newsize, status)) { + goto finish; + } + result->data[newsize-1] = carry; + } + + result->len = newsize; + mpd_set_flags(result, sign_b); + } + else { + if (big->len == small->len) { + for (i=big->len-1; i >= 0; --i) { + if (big->data[i] != small->data[i]) { + if (big->data[i] < small->data[i]) { + _mpd_ptrswap(&big, &small); + swap++; + } + break; + } + } + } + + _mpd_basesub(result->data, big->data, small->data, + big->len, small->len); + newsize = _mpd_real_size(result->data, big->len); + /* resize to smaller cannot fail */ + (void)mpd_qresize(result, newsize, status); + + result->len = newsize; + sign_b = (swap & 1) ? sign_b : mpd_sign(a); + mpd_set_flags(result, sign_b); + + if (mpd_iszerocoeff(result)) { + mpd_set_positive(result); + if (ctx->round == MPD_ROUND_FLOOR) { + mpd_set_negative(result); + } + } + } + + mpd_setdigits(result); + +finish: + mpd_del(&big_aligned); +} + +/* Add a and b. No specials, no finalizing. */ +static void +_mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + _mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status); +} + +/* Subtract b from a. No specials, no finalizing. */ +static void +_mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + _mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status); +} + +/* Add a and b. */ +void +mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + _mpd_qaddsub_inf(result, a, b, mpd_sign(b), status); + return; + } + + _mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status); + mpd_qfinalize(result, ctx, status); +} + +/* Subtract b from a. */ +void +mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + _mpd_qaddsub_inf(result, a, b, !mpd_sign(b), status); + return; + } + + _mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status); + mpd_qfinalize(result, ctx, status); +} + +/* Add decimal and mpd_ssize_t. */ +void +mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_ssize(&bb, b, &maxcontext, status); + mpd_qadd(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Add decimal and mpd_uint_t. */ +void +mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_uint(&bb, b, &maxcontext, status); + mpd_qadd(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Subtract mpd_ssize_t from decimal. */ +void +mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_ssize(&bb, b, &maxcontext, status); + mpd_qsub(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Subtract mpd_uint_t from decimal. */ +void +mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_uint(&bb, b, &maxcontext, status); + mpd_qsub(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Add decimal and int32_t. */ +void +mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qadd_ssize(result, a, b, ctx, status); +} + +/* Add decimal and uint32_t. */ +void +mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qadd_uint(result, a, b, ctx, status); +} + +#ifdef CONFIG_64 +/* Add decimal and int64_t. */ +void +mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qadd_ssize(result, a, b, ctx, status); +} + +/* Add decimal and uint64_t. */ +void +mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qadd_uint(result, a, b, ctx, status); +} +#endif + +/* Subtract int32_t from decimal. */ +void +mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qsub_ssize(result, a, b, ctx, status); +} + +/* Subtract uint32_t from decimal. */ +void +mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qsub_uint(result, a, b, ctx, status); +} + +#ifdef CONFIG_64 +/* Subtract int64_t from decimal. */ +void +mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qsub_ssize(result, a, b, ctx, status); +} + +/* Subtract uint64_t from decimal. */ +void +mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qsub_uint(result, a, b, ctx, status); +} +#endif + + +/* Divide infinities. */ +static void +_mpd_qdiv_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_isinfinite(a)) { + if (mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF); + return; + } + assert(mpd_isinfinite(b)); + _settriple(result, mpd_sign(a)^mpd_sign(b), 0, mpd_etiny(ctx)); + *status |= MPD_Clamped; +} + +enum {NO_IDEAL_EXP, SET_IDEAL_EXP}; +/* Divide a by b. */ +static void +_mpd_qdiv(int action, mpd_t *q, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + MPD_NEW_STATIC(aligned,0,0,0,0); + mpd_uint_t ld; + mpd_ssize_t shift, exp, tz; + mpd_ssize_t newsize; + mpd_ssize_t ideal_exp; + mpd_uint_t rem; + uint8_t sign_a = mpd_sign(a); + uint8_t sign_b = mpd_sign(b); + + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(q, a, b, ctx, status)) { + return; + } + _mpd_qdiv_inf(q, a, b, ctx, status); + return; + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_seterror(q, MPD_Division_undefined, status); + } + else { + mpd_setspecial(q, sign_a^sign_b, MPD_INF); + *status |= MPD_Division_by_zero; + } + return; + } + if (mpd_iszerocoeff(a)) { + exp = a->exp - b->exp; + _settriple(q, sign_a^sign_b, 0, exp); + mpd_qfinalize(q, ctx, status); + return; + } + + shift = (b->digits - a->digits) + ctx->prec + 1; + ideal_exp = a->exp - b->exp; + exp = ideal_exp - shift; + if (shift > 0) { + if (!mpd_qshiftl(&aligned, a, shift, status)) { + mpd_seterror(q, MPD_Malloc_error, status); + goto finish; + } + a = &aligned; + } + else if (shift < 0) { + shift = -shift; + if (!mpd_qshiftl(&aligned, b, shift, status)) { + mpd_seterror(q, MPD_Malloc_error, status); + goto finish; + } + b = &aligned; + } + + + newsize = a->len - b->len + 1; + if ((q != b && q != a) || (q == b && newsize > b->len)) { + if (!mpd_qresize(q, newsize, status)) { + mpd_seterror(q, MPD_Malloc_error, status); + goto finish; + } + } + + + if (b->len == 1) { + rem = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]); + } + else if (a->len < 2*MPD_NEWTONDIV_CUTOFF && + b->len < MPD_NEWTONDIV_CUTOFF) { + int ret = _mpd_basedivmod(q->data, NULL, a->data, b->data, + a->len, b->len); + if (ret < 0) { + mpd_seterror(q, MPD_Malloc_error, status); + goto finish; + } + rem = ret; + } + else { + MPD_NEW_STATIC(r,0,0,0,0); + _mpd_qbarrett_divmod(q, &r, a, b, status); + if (mpd_isspecial(q) || mpd_isspecial(&r)) { + mpd_del(&r); + goto finish; + } + rem = !mpd_iszerocoeff(&r); + mpd_del(&r); + newsize = q->len; + } + + newsize = _mpd_real_size(q->data, newsize); + /* resize to smaller cannot fail */ + mpd_qresize(q, newsize, status); + q->len = newsize; + mpd_setdigits(q); + + shift = ideal_exp - exp; + if (rem) { + ld = mpd_lsd(q->data[0]); + if (ld == 0 || ld == 5) { + q->data[0] += 1; + } + } + else if (action == SET_IDEAL_EXP && shift > 0) { + tz = mpd_trail_zeros(q); + shift = (tz > shift) ? shift : tz; + mpd_qshiftr_inplace(q, shift); + exp += shift; + } + + mpd_set_flags(q, sign_a^sign_b); + q->exp = exp; + + +finish: + mpd_del(&aligned); + mpd_qfinalize(q, ctx, status); +} + +/* Divide a by b. */ +void +mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + _mpd_qdiv(SET_IDEAL_EXP, q, a, b, ctx, status); +} + +/* Internal function. */ +static void +_mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + MPD_NEW_STATIC(aligned,0,0,0,0); + mpd_ssize_t qsize, rsize; + mpd_ssize_t ideal_exp, expdiff, shift; + uint8_t sign_a = mpd_sign(a); + uint8_t sign_ab = mpd_sign(a)^mpd_sign(b); + + + ideal_exp = (a->exp > b->exp) ? b->exp : a->exp; + if (mpd_iszerocoeff(a)) { + if (!mpd_qcopy(r, a, status)) { + goto nanresult; /* GCOV_NOT_REACHED */ + } + r->exp = ideal_exp; + _settriple(q, sign_ab, 0, 0); + return; + } + + expdiff = mpd_adjexp(a) - mpd_adjexp(b); + if (expdiff < 0) { + if (a->exp > b->exp) { + /* positive and less than b->digits - a->digits */ + shift = a->exp - b->exp; + if (!mpd_qshiftl(r, a, shift, status)) { + goto nanresult; + } + r->exp = ideal_exp; + } + else { + if (!mpd_qcopy(r, a, status)) { + goto nanresult; + } + } + _settriple(q, sign_ab, 0, 0); + return; + } + if (expdiff > ctx->prec) { + *status |= MPD_Division_impossible; + goto nanresult; + } + + + /* + * At this point we have: + * (1) 0 <= a->exp + a->digits - b->exp - b->digits <= prec + * (2) a->exp - b->exp >= b->digits - a->digits + * (3) a->exp - b->exp <= prec + b->digits - a->digits + */ + if (a->exp != b->exp) { + shift = a->exp - b->exp; + if (shift > 0) { + /* by (3), after the shift a->digits <= prec + b->digits */ + if (!mpd_qshiftl(&aligned, a, shift, status)) { + goto nanresult; + } + a = &aligned; + } + else { + shift = -shift; + /* by (2), after the shift b->digits <= a->digits */ + if (!mpd_qshiftl(&aligned, b, shift, status)) { + goto nanresult; + } + b = &aligned; + } + } + + + qsize = a->len - b->len + 1; + if (!(q == a && qsize < a->len) && !(q == b && qsize < b->len)) { + if (!mpd_qresize(q, qsize, status)) { + goto nanresult; + } + } + + rsize = b->len; + if (!(r == a && rsize < a->len)) { + if (!mpd_qresize(r, rsize, status)) { + goto nanresult; + } + } + + if (b->len == 1) { + if (a->len == 1) { + _mpd_div_word(&q->data[0], &r->data[0], a->data[0], b->data[0]); + } + else { + r->data[0] = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]); + } + } + else if (a->len < 2*MPD_NEWTONDIV_CUTOFF && + b->len < MPD_NEWTONDIV_CUTOFF) { + int ret; + ret = _mpd_basedivmod(q->data, r->data, a->data, b->data, + a->len, b->len); + if (ret == -1) { + *status |= MPD_Malloc_error; + goto nanresult; + } + } + else { + _mpd_qbarrett_divmod(q, r, a, b, status); + if (mpd_isspecial(q) || mpd_isspecial(r)) { + goto nanresult; + } + if (mpd_isinfinite(q) || q->digits > ctx->prec) { + *status |= MPD_Division_impossible; + goto nanresult; + } + qsize = q->len; + rsize = r->len; + } + + qsize = _mpd_real_size(q->data, qsize); + /* resize to smaller cannot fail */ + mpd_qresize(q, qsize, status); + q->len = qsize; + mpd_setdigits(q); + mpd_set_flags(q, sign_ab); + q->exp = 0; + if (q->digits > ctx->prec) { + *status |= MPD_Division_impossible; + goto nanresult; + } + + rsize = _mpd_real_size(r->data, rsize); + /* resize to smaller cannot fail */ + mpd_qresize(r, rsize, status); + r->len = rsize; + mpd_setdigits(r); + mpd_set_flags(r, sign_a); + r->exp = ideal_exp; + +out: + mpd_del(&aligned); + return; + +nanresult: + mpd_setspecial(q, MPD_POS, MPD_NAN); + mpd_setspecial(r, MPD_POS, MPD_NAN); + goto out; +} + +/* Integer division with remainder. */ +void +mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + uint8_t sign = mpd_sign(a)^mpd_sign(b); + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(q, a, b, ctx, status)) { + mpd_qcopy(r, q, status); + return; + } + if (mpd_isinfinite(a)) { + if (mpd_isinfinite(b)) { + mpd_setspecial(q, MPD_POS, MPD_NAN); + } + else { + mpd_setspecial(q, sign, MPD_INF); + } + mpd_setspecial(r, MPD_POS, MPD_NAN); + *status |= MPD_Invalid_operation; + return; + } + if (mpd_isinfinite(b)) { + if (!mpd_qcopy(r, a, status)) { + mpd_seterror(q, MPD_Malloc_error, status); + return; + } + mpd_qfinalize(r, ctx, status); + _settriple(q, sign, 0, 0); + return; + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_setspecial(q, MPD_POS, MPD_NAN); + mpd_setspecial(r, MPD_POS, MPD_NAN); + *status |= MPD_Division_undefined; + } + else { + mpd_setspecial(q, sign, MPD_INF); + mpd_setspecial(r, MPD_POS, MPD_NAN); + *status |= (MPD_Division_by_zero|MPD_Invalid_operation); + } + return; + } + + _mpd_qdivmod(q, r, a, b, ctx, status); + mpd_qfinalize(q, ctx, status); + mpd_qfinalize(r, ctx, status); +} + +void +mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + MPD_NEW_STATIC(r,0,0,0,0); + uint8_t sign = mpd_sign(a)^mpd_sign(b); + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(q, a, b, ctx, status)) { + return; + } + if (mpd_isinfinite(a) && mpd_isinfinite(b)) { + mpd_seterror(q, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(a)) { + mpd_setspecial(q, sign, MPD_INF); + return; + } + if (mpd_isinfinite(b)) { + _settriple(q, sign, 0, 0); + return; + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_seterror(q, MPD_Division_undefined, status); + } + else { + mpd_setspecial(q, sign, MPD_INF); + *status |= MPD_Division_by_zero; + } + return; + } + + + _mpd_qdivmod(q, &r, a, b, ctx, status); + mpd_del(&r); + mpd_qfinalize(q, ctx, status); +} + +/* Divide decimal by mpd_ssize_t. */ +void +mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_ssize(&bb, b, &maxcontext, status); + mpd_qdiv(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Divide decimal by mpd_uint_t. */ +void +mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_uint(&bb, b, &maxcontext, status); + mpd_qdiv(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Divide decimal by int32_t. */ +void +mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qdiv_ssize(result, a, b, ctx, status); +} + +/* Divide decimal by uint32_t. */ +void +mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qdiv_uint(result, a, b, ctx, status); +} + +#ifdef CONFIG_64 +/* Divide decimal by int64_t. */ +void +mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qdiv_ssize(result, a, b, ctx, status); +} + +/* Divide decimal by uint64_t. */ +void +mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qdiv_uint(result, a, b, ctx, status); +} +#endif + +#if defined(_MSC_VER) + /* conversion from 'double' to 'mpd_ssize_t', possible loss of data */ + #pragma warning(disable:4244) +#endif +/* + * Get the number of iterations for the Horner scheme in _mpd_qexp(). + */ +static inline mpd_ssize_t +_mpd_get_exp_iterations(const mpd_t *a, mpd_ssize_t prec) +{ + mpd_uint_t dummy; + mpd_uint_t msdigits; + double f; + + /* 9 is MPD_RDIGITS for 32 bit platforms */ + _mpd_get_msdigits(&dummy, &msdigits, a, 9); + f = ((double)msdigits + 1) / mpd_pow10[mpd_word_digits(msdigits)]; + +#ifdef CONFIG_64 + #ifdef USE_80BIT_LONG_DOUBLE + return ceill((1.435*(long double)prec - 1.182) + / log10l((long double)prec/f)); + #else + /* prec > floor((1ULL<<53) / 1.435) */ + if (prec > 6276793905742851LL) { + return MPD_SSIZE_MAX; + } + return ceil((1.435*(double)prec - 1.182) / log10((double)prec/f)); + #endif +#else /* CONFIG_32 */ + return ceil((1.435*(double)prec - 1.182) / log10((double)prec/f)); + #if defined(_MSC_VER) + #pragma warning(default:4244) + #endif +#endif +} + +/* + * Internal function, specials have been dealt with. + * + * The algorithm is from Hull&Abrham, Variable Precision Exponential Function, + * ACM Transactions on Mathematical Software, Vol. 12, No. 2, June 1986. + * + * Main differences: + * + * - The number of iterations for the Horner scheme is calculated using the + * C log10() function. + * + * - The analysis for early abortion has been adapted for the mpd_t + * ranges. + */ +static void +_mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(tmp,0,0,0,0); + MPD_NEW_STATIC(sum,0,0,0,0); + MPD_NEW_CONST(word,0,0,0,1,1,1); + mpd_ssize_t j, n, t; + + assert(!mpd_isspecial(a)); + + /* + * We are calculating e^x = e^(r*10^t) = (e^r)^(10^t), where r < 1 and t >= 0. + * + * If t > 0, we have: + * + * (1) 0.1 <= r < 1, so e^r >= e^0.1. Overflow in the final power operation + * will occur when (e^0.1)^(10^t) > 10^(emax+1). If we consider MAX_EMAX, + * this will happen for t > 10 (32 bit) or (t > 19) (64 bit). + * + * (2) -1 < r <= -0.1, so e^r > e^-1. Underflow in the final power operation + * will occur when (e^-1)^(10^t) < 10^(etiny-1). If we consider MIN_ETINY, + * this will also happen for t > 10 (32 bit) or (t > 19) (64 bit). + */ +#if defined(CONFIG_64) + #define MPD_EXP_MAX_T 19 +#elif defined(CONFIG_32) + #define MPD_EXP_MAX_T 10 +#endif + t = a->digits + a->exp; + t = (t > 0) ? t : 0; + if (t > MPD_EXP_MAX_T) { + if (mpd_ispositive(a)) { + mpd_setspecial(result, MPD_POS, MPD_INF); + *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded; + } + else { + _settriple(result, MPD_POS, 0, mpd_etiny(ctx)); + *status |= (MPD_Inexact|MPD_Rounded|MPD_Subnormal| + MPD_Underflow|MPD_Clamped); + } + return; + } + + mpd_maxcontext(&workctx); + workctx.prec = ctx->prec + t + 2; + workctx.prec = (workctx.prec < 9) ? 9 : workctx.prec; + workctx.round = MPD_ROUND_HALF_EVEN; + + if ((n = _mpd_get_exp_iterations(a, workctx.prec)) == MPD_SSIZE_MAX) { + mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_UNLIKELY */ + goto finish; /* GCOV_UNLIKELY */ + } + + if (!mpd_qcopy(result, a, status)) { + goto finish; + } + result->exp -= t; + + _settriple(&sum, MPD_POS, 1, 0); + + for (j = n-1; j >= 1; j--) { + word.data[0] = j; + mpd_setdigits(&word); + mpd_qdiv(&tmp, result, &word, &workctx, &workctx.status); + mpd_qmul(&sum, &sum, &tmp, &workctx, &workctx.status); + mpd_qadd(&sum, &sum, &one, &workctx, &workctx.status); + } + +#ifdef CONFIG_64 + _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status); +#else + if (t <= MPD_MAX_POW10) { + _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status); + } + else { + t -= MPD_MAX_POW10; + _mpd_qpow_uint(&tmp, &sum, mpd_pow10[MPD_MAX_POW10], MPD_POS, + &workctx, status); + _mpd_qpow_uint(result, &tmp, mpd_pow10[t], MPD_POS, &workctx, status); + } +#endif + + +finish: + mpd_del(&tmp); + mpd_del(&sum); + *status |= (workctx.status&MPD_Errors); + *status |= (MPD_Inexact|MPD_Rounded); +} + +/* exp(a) */ +void +mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + _settriple(result, MPD_POS, 0, 0); + } + else { + mpd_setspecial(result, MPD_POS, MPD_INF); + } + return; + } + if (mpd_iszerocoeff(a)) { + _settriple(result, MPD_POS, 1, 0); + return; + } + + workctx = *ctx; + workctx.round = MPD_ROUND_HALF_EVEN; + + if (ctx->allcr) { + MPD_NEW_STATIC(t1, 0,0,0,0); + MPD_NEW_STATIC(t2, 0,0,0,0); + MPD_NEW_STATIC(ulp, 0,0,0,0); + MPD_NEW_STATIC(aa, 0,0,0,0); + mpd_ssize_t prec; + + if (result == a) { + if (!mpd_qcopy(&aa, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + a = &aa; + } + + workctx.clamp = 0; + prec = ctx->prec + 3; + while (1) { + workctx.prec = prec; + _mpd_qexp(result, a, &workctx, status); + _ssettriple(&ulp, MPD_POS, 1, + result->exp + result->digits-workctx.prec-1); + + workctx.prec = ctx->prec; + mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status); + mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status); + if (mpd_isspecial(result) || mpd_iszerocoeff(result) || + mpd_qcmp(&t1, &t2, status) == 0) { + workctx.clamp = ctx->clamp; + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + break; + } + prec += MPD_RDIGITS; + } + mpd_del(&t1); + mpd_del(&t2); + mpd_del(&ulp); + mpd_del(&aa); + } + else { + _mpd_qexp(result, a, &workctx, status); + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + } +} + +/* Fused multiply-add: (a * b) + c, with a single final rounding. */ +void +mpd_qfma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_t *cc = (mpd_t *)c; + + if (result == c) { + if ((cc = mpd_qncopy(c)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + } + + _mpd_qmul(result, a, b, ctx, &workstatus); + if (!(workstatus&MPD_Invalid_operation)) { + mpd_qadd(result, result, cc, ctx, &workstatus); + } + + if (cc != c) mpd_del(cc); + *status |= workstatus; +} + +static inline int +ln_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], mpd_ssize_t maxprec, + mpd_ssize_t initprec) +{ + mpd_ssize_t k; + int i; + + assert(maxprec >= 2 && initprec >= 2); + if (maxprec <= initprec) return -1; + + i = 0; k = maxprec; + do { + k = (k+2) / 2; + klist[i++] = k; + } while (k > initprec); + + return i-1; +} + +#ifdef CONFIG_64 +#if MPD_RDIGITS != 19 + #error "mpdecimal.c: MPD_RDIGITS must be 19." +#endif +static const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = { + 6983716328982174407ULL, 9089704281976336583ULL, 1515961135648465461ULL, + 4416816335727555703ULL, 2900988039194170265ULL, 2307925037472986509ULL, + 107598438319191292ULL, 3466624107184669231ULL, 4450099781311469159ULL, + 9807828059751193854ULL, 7713456862091670584ULL, 1492198849978748873ULL, + 6528728696511086257ULL, 2385392051446341972ULL, 8692180205189339507ULL, + 6518769751037497088ULL, 2375253577097505395ULL, 9095610299291824318ULL, + 982748238504564801ULL, 5438635917781170543ULL, 7547331541421808427ULL, + 752371033310119785ULL, 3171643095059950878ULL, 9785265383207606726ULL, + 2932258279850258550ULL, 5497347726624257094ULL, 2976979522110718264ULL, + 9221477656763693866ULL, 1979650047149510504ULL, 6674183485704422507ULL, + 9702766860595249671ULL, 9278096762712757753ULL, 9314848524948644871ULL, + 6826928280848118428ULL, 754403708474699401ULL, 230105703089634572ULL, + 1929203337658714166ULL, 7589402567763113569ULL, 4208241314695689016ULL, + 2922455440575892572ULL, 9356734206705811364ULL, 2684916746550586856ULL, + 644507064800027750ULL, 9476834636167921018ULL, 5659121373450747856ULL, + 2835522011480466371ULL, 6470806855677432162ULL, 7141748003688084012ULL, + 9619404400222105101ULL, 5504893431493939147ULL, 6674744042432743651ULL, + 2287698219886746543ULL, 7773262884616336622ULL, 1985283935053089653ULL, + 4680843799894826233ULL, 8168948290720832555ULL, 8067566662873690987ULL, + 6248633409525465082ULL, 9829834196778404228ULL, 3524802359972050895ULL, + 3327900967572609677ULL, 110148862877297603ULL, 179914546843642076ULL, + 2302585092994045684ULL +}; +#else +#if MPD_RDIGITS != 9 + #error "mpdecimal.c: MPD_RDIGITS must be 9." +#endif +static const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = { + 401682692UL, 708474699UL, 720754403UL, 30896345UL, 602301057UL, 765871416UL, + 192920333UL, 763113569UL, 589402567UL, 956890167UL, 82413146UL, 589257242UL, + 245544057UL, 811364292UL, 734206705UL, 868569356UL, 167465505UL, 775026849UL, + 706480002UL, 18064450UL, 636167921UL, 569476834UL, 734507478UL, 156591213UL, + 148046637UL, 283552201UL, 677432162UL, 470806855UL, 880840126UL, 417480036UL, + 210510171UL, 940440022UL, 939147961UL, 893431493UL, 436515504UL, 440424327UL, + 654366747UL, 821988674UL, 622228769UL, 884616336UL, 537773262UL, 350530896UL, + 319852839UL, 989482623UL, 468084379UL, 720832555UL, 168948290UL, 736909878UL, + 675666628UL, 546508280UL, 863340952UL, 404228624UL, 834196778UL, 508959829UL, + 23599720UL, 967735248UL, 96757260UL, 603332790UL, 862877297UL, 760110148UL, + 468436420UL, 401799145UL, 299404568UL, 230258509UL +}; +#endif +/* _mpd_ln10 is used directly for precisions smaller than MINALLOC_MAX*RDIGITS. + Otherwise, it serves as the initial approximation for calculating ln(10). */ +static const mpd_t _mpd_ln10 = { + MPD_STATIC|MPD_CONST_DATA, -(MPD_MINALLOC_MAX*MPD_RDIGITS-1), + MPD_MINALLOC_MAX*MPD_RDIGITS, MPD_MINALLOC_MAX, MPD_MINALLOC_MAX, + (mpd_uint_t *)mpd_ln10_data +}; + +/* Set 'result' to ln(10), with 'prec' digits, using ROUND_HALF_EVEN. */ +void +mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status) +{ + mpd_context_t varcontext, maxcontext; + MPD_NEW_STATIC(tmp, 0,0,0,0); + MPD_NEW_CONST(static10, 0,0,2,1,1,10); + mpd_ssize_t klist[MPD_MAX_PREC_LOG2]; + mpd_uint_t rnd; + mpd_ssize_t shift; + int i; + + assert(prec >= 1); + + shift = MPD_MINALLOC_MAX*MPD_RDIGITS-prec; + shift = shift < 0 ? 0 : shift; + + rnd = mpd_qshiftr(result, &_mpd_ln10, shift, status); + if (rnd == MPD_UINT_MAX) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + result->exp = -(result->digits-1); + + mpd_maxcontext(&maxcontext); + if (prec < MPD_MINALLOC_MAX*MPD_RDIGITS) { + maxcontext.prec = prec; + _mpd_apply_round_excess(result, rnd, &maxcontext, status); + *status |= (MPD_Inexact|MPD_Rounded); + return; + } + + mpd_maxcontext(&varcontext); + varcontext.round = MPD_ROUND_TRUNC; + + i = ln_schedule_prec(klist, prec+2, result->digits); + for (; i >= 0; i--) { + varcontext.prec = 2*klist[i]+3; + result->flags ^= MPD_NEG; + _mpd_qexp(&tmp, result, &varcontext, status); + result->flags ^= MPD_NEG; + mpd_qmul(&tmp, &static10, &tmp, &varcontext, status); + mpd_qsub(&tmp, &tmp, &one, &maxcontext, status); + mpd_qadd(result, result, &tmp, &maxcontext, status); + if (mpd_isspecial(result)) { + break; + } + } + + mpd_del(&tmp); + maxcontext.prec = prec; + mpd_qfinalize(result, &maxcontext, status); +} + +/* Initial approximations for the ln() iteration */ +static const uint16_t lnapprox[900] = { + /* index 0 - 400: log((i+100)/100) * 1000 */ + 0, 10, 20, 30, 39, 49, 58, 68, 77, 86, 95, 104, 113, 122, 131, 140, 148, 157, + 166, 174, 182, 191, 199, 207, 215, 223, 231, 239, 247, 255, 262, 270, 278, + 285, 293, 300, 308, 315, 322, 329, 336, 344, 351, 358, 365, 372, 378, 385, + 392, 399, 406, 412, 419, 425, 432, 438, 445, 451, 457, 464, 470, 476, 482, + 489, 495, 501, 507, 513, 519, 525, 531, 536, 542, 548, 554, 560, 565, 571, + 577, 582, 588, 593, 599, 604, 610, 615, 621, 626, 631, 637, 642, 647, 652, + 658, 663, 668, 673, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, + 732, 737, 742, 747, 751, 756, 761, 766, 770, 775, 779, 784, 788, 793, 798, + 802, 806, 811, 815, 820, 824, 829, 833, 837, 842, 846, 850, 854, 859, 863, + 867, 871, 876, 880, 884, 888, 892, 896, 900, 904, 908, 912, 916, 920, 924, + 928, 932, 936, 940, 944, 948, 952, 956, 959, 963, 967, 971, 975, 978, 982, + 986, 990, 993, 997, 1001, 1004, 1008, 1012, 1015, 1019, 1022, 1026, 1030, + 1033, 1037, 1040, 1044, 1047, 1051, 1054, 1058, 1061, 1065, 1068, 1072, 1075, + 1078, 1082, 1085, 1089, 1092, 1095, 1099, 1102, 1105, 1109, 1112, 1115, 1118, + 1122, 1125, 1128, 1131, 1135, 1138, 1141, 1144, 1147, 1151, 1154, 1157, 1160, + 1163, 1166, 1169, 1172, 1176, 1179, 1182, 1185, 1188, 1191, 1194, 1197, 1200, + 1203, 1206, 1209, 1212, 1215, 1218, 1221, 1224, 1227, 1230, 1233, 1235, 1238, + 1241, 1244, 1247, 1250, 1253, 1256, 1258, 1261, 1264, 1267, 1270, 1273, 1275, + 1278, 1281, 1284, 1286, 1289, 1292, 1295, 1297, 1300, 1303, 1306, 1308, 1311, + 1314, 1316, 1319, 1322, 1324, 1327, 1330, 1332, 1335, 1338, 1340, 1343, 1345, + 1348, 1351, 1353, 1356, 1358, 1361, 1364, 1366, 1369, 1371, 1374, 1376, 1379, + 1381, 1384, 1386, 1389, 1391, 1394, 1396, 1399, 1401, 1404, 1406, 1409, 1411, + 1413, 1416, 1418, 1421, 1423, 1426, 1428, 1430, 1433, 1435, 1437, 1440, 1442, + 1445, 1447, 1449, 1452, 1454, 1456, 1459, 1461, 1463, 1466, 1468, 1470, 1472, + 1475, 1477, 1479, 1482, 1484, 1486, 1488, 1491, 1493, 1495, 1497, 1500, 1502, + 1504, 1506, 1509, 1511, 1513, 1515, 1517, 1520, 1522, 1524, 1526, 1528, 1530, + 1533, 1535, 1537, 1539, 1541, 1543, 1545, 1548, 1550, 1552, 1554, 1556, 1558, + 1560, 1562, 1564, 1567, 1569, 1571, 1573, 1575, 1577, 1579, 1581, 1583, 1585, + 1587, 1589, 1591, 1593, 1595, 1597, 1599, 1601, 1603, 1605, 1607, 1609, + /* index 401 - 899: -log((i+100)/1000) * 1000 */ + 691, 689, 687, 685, 683, 681, 679, 677, 675, 673, 671, 669, 668, 666, 664, + 662, 660, 658, 656, 654, 652, 650, 648, 646, 644, 642, 641, 639, 637, 635, + 633, 631, 629, 627, 626, 624, 622, 620, 618, 616, 614, 612, 611, 609, 607, + 605, 603, 602, 600, 598, 596, 594, 592, 591, 589, 587, 585, 583, 582, 580, + 578, 576, 574, 573, 571, 569, 567, 566, 564, 562, 560, 559, 557, 555, 553, + 552, 550, 548, 546, 545, 543, 541, 540, 538, 536, 534, 533, 531, 529, 528, + 526, 524, 523, 521, 519, 518, 516, 514, 512, 511, 509, 508, 506, 504, 502, + 501, 499, 498, 496, 494, 493, 491, 489, 488, 486, 484, 483, 481, 480, 478, + 476, 475, 473, 472, 470, 468, 467, 465, 464, 462, 460, 459, 457, 456, 454, + 453, 451, 449, 448, 446, 445, 443, 442, 440, 438, 437, 435, 434, 432, 431, + 429, 428, 426, 425, 423, 422, 420, 419, 417, 416, 414, 412, 411, 410, 408, + 406, 405, 404, 402, 400, 399, 398, 396, 394, 393, 392, 390, 389, 387, 386, + 384, 383, 381, 380, 378, 377, 375, 374, 372, 371, 370, 368, 367, 365, 364, + 362, 361, 360, 358, 357, 355, 354, 352, 351, 350, 348, 347, 345, 344, 342, + 341, 340, 338, 337, 336, 334, 333, 331, 330, 328, 327, 326, 324, 323, 322, + 320, 319, 318, 316, 315, 313, 312, 311, 309, 308, 306, 305, 304, 302, 301, + 300, 298, 297, 296, 294, 293, 292, 290, 289, 288, 286, 285, 284, 282, 281, + 280, 278, 277, 276, 274, 273, 272, 270, 269, 268, 267, 265, 264, 263, 261, + 260, 259, 258, 256, 255, 254, 252, 251, 250, 248, 247, 246, 245, 243, 242, + 241, 240, 238, 237, 236, 234, 233, 232, 231, 229, 228, 227, 226, 224, 223, + 222, 221, 219, 218, 217, 216, 214, 213, 212, 211, 210, 208, 207, 206, 205, + 203, 202, 201, 200, 198, 197, 196, 195, 194, 192, 191, 190, 189, 188, 186, + 185, 184, 183, 182, 180, 179, 178, 177, 176, 174, 173, 172, 171, 170, 168, + 167, 166, 165, 164, 162, 161, 160, 159, 158, 157, 156, 154, 153, 152, 151, + 150, 148, 147, 146, 145, 144, 143, 142, 140, 139, 138, 137, 136, 135, 134, + 132, 131, 130, 129, 128, 127, 126, 124, 123, 122, 121, 120, 119, 118, 116, + 115, 114, 113, 112, 111, 110, 109, 108, 106, 105, 104, 103, 102, 101, 100, + 99, 98, 97, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 84, 83, 82, 81, 80, 79, + 78, 77, 76, 75, 74, 73, 72, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, + 58, 57, 56, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, + 38, 37, 36, 35, 34, 33, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, + 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 +}; + +/* Internal ln() function that does not check for specials, zero or one. */ +static void +_mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t varcontext, maxcontext; + mpd_t *z = (mpd_t *) result; + MPD_NEW_STATIC(v,0,0,0,0); + MPD_NEW_STATIC(vtmp,0,0,0,0); + MPD_NEW_STATIC(tmp,0,0,0,0); + mpd_ssize_t klist[MPD_MAX_PREC_LOG2]; + mpd_ssize_t maxprec, shift, t; + mpd_ssize_t a_digits, a_exp; + mpd_uint_t dummy, x; + int i; + + assert(!mpd_isspecial(a) && !mpd_iszerocoeff(a)); + + /* + * We are calculating ln(a) = ln(v * 10^t) = ln(v) + t*ln(10), + * where 0.5 < v <= 5. + */ + if (!mpd_qcopy(&v, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + + /* Initial approximation: we have at least one non-zero digit */ + _mpd_get_msdigits(&dummy, &x, &v, 3); + if (x < 10) x *= 10; + if (x < 100) x *= 10; + x -= 100; + + /* a may equal z */ + a_digits = a->digits; + a_exp = a->exp; + + mpd_minalloc(z); + mpd_clear_flags(z); + z->data[0] = lnapprox[x]; + z->len = 1; + z->exp = -3; + mpd_setdigits(z); + + if (x <= 400) { + v.exp = -(a_digits - 1); + t = a_exp + a_digits - 1; + } + else { + v.exp = -a_digits; + t = a_exp + a_digits; + mpd_set_negative(z); + } + + mpd_maxcontext(&maxcontext); + mpd_maxcontext(&varcontext); + varcontext.round = MPD_ROUND_TRUNC; + + maxprec = ctx->prec + 2; + if (x <= 10 || x >= 805) { + /* v is close to 1: Estimate the magnitude of the logarithm. + * If v = 1 or ln(v) will underflow, skip the loop. Otherwise, + * adjust the precision upwards in order to obtain a sufficient + * number of significant digits. + * + * 1) x/(1+x) < ln(1+x) < x, for x > -1, x != 0 + * + * 2) (v-1)/v < ln(v) < v-1 + */ + mpd_t *lower = &tmp; + mpd_t *upper = &vtmp; + int cmp = _mpd_cmp(&v, &one); + + varcontext.round = MPD_ROUND_CEILING; + varcontext.prec = maxprec; + mpd_qsub(upper, &v, &one, &varcontext, &varcontext.status); + varcontext.round = MPD_ROUND_FLOOR; + mpd_qdiv(lower, upper, &v, &varcontext, &varcontext.status); + varcontext.round = MPD_ROUND_TRUNC; + + if (cmp < 0) { + _mpd_ptrswap(&upper, &lower); + } + if (mpd_adjexp(upper) < mpd_etiny(ctx)) { + _settriple(z, (cmp<0), 1, mpd_etiny(ctx)-1); + goto postloop; + } + /* XXX optimization: t == 0 && mpd_adjexp(lower) < 0 */ + if (mpd_adjexp(lower) < 0) { + maxprec = maxprec - mpd_adjexp(lower); + } + } + + i = ln_schedule_prec(klist, maxprec, 2); + for (; i >= 0; i--) { + varcontext.prec = 2*klist[i]+3; + z->flags ^= MPD_NEG; + _mpd_qexp(&tmp, z, &varcontext, status); + z->flags ^= MPD_NEG; + + if (v.digits > varcontext.prec) { + shift = v.digits - varcontext.prec; + mpd_qshiftr(&vtmp, &v, shift, status); + vtmp.exp += shift; + mpd_qmul(&tmp, &vtmp, &tmp, &varcontext, status); + } + else { + mpd_qmul(&tmp, &v, &tmp, &varcontext, status); + } + + mpd_qsub(&tmp, &tmp, &one, &maxcontext, status); + mpd_qadd(z, z, &tmp, &maxcontext, status); + if (mpd_isspecial(z)) { + break; + } + } + +postloop: + mpd_qln10(&v, maxprec+2, status); + mpd_qmul_ssize(&tmp, &v, t, &maxcontext, status); + varcontext.prec = maxprec+2; + mpd_qadd(result, &tmp, z, &varcontext, status); + + +finish: + mpd_del(&v); + mpd_del(&vtmp); + mpd_del(&tmp); +} + +/* ln(a) */ +void +mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + mpd_ssize_t adjexp, t; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + mpd_setspecial(result, MPD_POS, MPD_INF); + return; + } + if (mpd_iszerocoeff(a)) { + mpd_setspecial(result, MPD_NEG, MPD_INF); + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (_mpd_cmp(a, &one) == 0) { + _settriple(result, MPD_POS, 0, 0); + return; + } + /* Check if the result will overflow. + * + * 1) adjexp(a) + 1 > log10(a) >= adjexp(a) + * + * 2) |log10(a)| >= adjexp(a), if adjexp(a) >= 0 + * |log10(a)| > -adjexp(a)-1, if adjexp(a) < 0 + * + * 3) |log(a)| > 2*|log10(a)| + */ + adjexp = mpd_adjexp(a); + t = (adjexp < 0) ? -adjexp-1 : adjexp; + t *= 2; + if (mpd_exp_digits(t)-1 > ctx->emax) { + *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded; + mpd_setspecial(result, (adjexp<0), MPD_INF); + return; + } + + workctx = *ctx; + workctx.round = MPD_ROUND_HALF_EVEN; + + if (ctx->allcr) { + MPD_NEW_STATIC(t1, 0,0,0,0); + MPD_NEW_STATIC(t2, 0,0,0,0); + MPD_NEW_STATIC(ulp, 0,0,0,0); + MPD_NEW_STATIC(aa, 0,0,0,0); + mpd_ssize_t prec; + + if (result == a) { + if (!mpd_qcopy(&aa, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + a = &aa; + } + + workctx.clamp = 0; + prec = ctx->prec + 3; + while (1) { + workctx.prec = prec; + _mpd_qln(result, a, &workctx, status); + _ssettriple(&ulp, MPD_POS, 1, + result->exp + result->digits-workctx.prec-1); + + workctx.prec = ctx->prec; + mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status); + mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status); + if (mpd_isspecial(result) || mpd_iszerocoeff(result) || + mpd_qcmp(&t1, &t2, status) == 0) { + workctx.clamp = ctx->clamp; + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + break; + } + prec += MPD_RDIGITS; + } + mpd_del(&t1); + mpd_del(&t2); + mpd_del(&ulp); + mpd_del(&aa); + } + else { + _mpd_qln(result, a, &workctx, status); + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + } +} + +/* Internal log10() function that does not check for specials, zero, ... */ +static void +_mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(ln10,0,0,0,0); + + mpd_maxcontext(&workctx); + workctx.prec = ctx->prec + 3; + _mpd_qln(result, a, &workctx, status); + mpd_qln10(&ln10, workctx.prec, status); + + workctx = *ctx; + workctx.round = MPD_ROUND_HALF_EVEN; + _mpd_qdiv(NO_IDEAL_EXP, result, result, &ln10, &workctx, status); + + mpd_del(&ln10); +} + +/* log10(a) */ +void +mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + mpd_ssize_t adjexp, t; + + workctx = *ctx; + workctx.round = MPD_ROUND_HALF_EVEN; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + mpd_setspecial(result, MPD_POS, MPD_INF); + return; + } + if (mpd_iszerocoeff(a)) { + mpd_setspecial(result, MPD_NEG, MPD_INF); + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_coeff_ispow10(a)) { + uint8_t sign = 0; + adjexp = mpd_adjexp(a); + if (adjexp < 0) { + sign = 1; + adjexp = -adjexp; + } + _settriple(result, sign, adjexp, 0); + mpd_qfinalize(result, &workctx, status); + return; + } + /* Check if the result will overflow. + * + * 1) adjexp(a) + 1 > log10(a) >= adjexp(a) + * + * 2) |log10(a)| >= adjexp(a), if adjexp(a) >= 0 + * |log10(a)| > -adjexp(a)-1, if adjexp(a) < 0 + */ + adjexp = mpd_adjexp(a); + t = (adjexp < 0) ? -adjexp-1 : adjexp; + if (mpd_exp_digits(t)-1 > ctx->emax) { + *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded; + mpd_setspecial(result, (adjexp<0), MPD_INF); + return; + } + + if (ctx->allcr) { + MPD_NEW_STATIC(t1, 0,0,0,0); + MPD_NEW_STATIC(t2, 0,0,0,0); + MPD_NEW_STATIC(ulp, 0,0,0,0); + MPD_NEW_STATIC(aa, 0,0,0,0); + mpd_ssize_t prec; + + if (result == a) { + if (!mpd_qcopy(&aa, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + a = &aa; + } + + workctx.clamp = 0; + prec = ctx->prec + 3; + while (1) { + workctx.prec = prec; + _mpd_qlog10(result, a, &workctx, status); + _ssettriple(&ulp, MPD_POS, 1, + result->exp + result->digits-workctx.prec-1); + + workctx.prec = ctx->prec; + mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status); + mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status); + if (mpd_isspecial(result) || mpd_iszerocoeff(result) || + mpd_qcmp(&t1, &t2, status) == 0) { + workctx.clamp = ctx->clamp; + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + break; + } + prec += MPD_RDIGITS; + } + mpd_del(&t1); + mpd_del(&t2); + mpd_del(&ulp); + mpd_del(&aa); + } + else { + _mpd_qlog10(result, a, &workctx, status); + mpd_check_underflow(result, &workctx, status); + } +} + +/* + * Maximum of the two operands. Attention: If one operand is a quiet NaN and the + * other is numeric, the numeric operand is returned. This may not be what one + * expects. + */ +void +mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isqnan(a) && !mpd_isnan(b)) { + mpd_qcopy(result, b, status); + } + else if (mpd_isqnan(b) && !mpd_isnan(a)) { + mpd_qcopy(result, a, status); + } + else if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + else { + c = _mpd_cmp(a, b); + if (c == 0) { + c = _mpd_cmp_numequal(a, b); + } + + if (c < 0) { + mpd_qcopy(result, b, status); + } + else { + mpd_qcopy(result, a, status); + } + } + + mpd_qfinalize(result, ctx, status); +} + +/* + * Maximum magnitude: Same as mpd_max(), but compares the operands with their + * sign ignored. + */ +void +mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isqnan(a) && !mpd_isnan(b)) { + mpd_qcopy(result, b, status); + } + else if (mpd_isqnan(b) && !mpd_isnan(a)) { + mpd_qcopy(result, a, status); + } + else if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + else { + c = _mpd_cmp_abs(a, b); + if (c == 0) { + c = _mpd_cmp_numequal(a, b); + } + + if (c < 0) { + mpd_qcopy(result, b, status); + } + else { + mpd_qcopy(result, a, status); + } + } + + mpd_qfinalize(result, ctx, status); +} + +/* + * Minimum of the two operands. Attention: If one operand is a quiet NaN and the + * other is numeric, the numeric operand is returned. This may not be what one + * expects. + */ +void +mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isqnan(a) && !mpd_isnan(b)) { + mpd_qcopy(result, b, status); + } + else if (mpd_isqnan(b) && !mpd_isnan(a)) { + mpd_qcopy(result, a, status); + } + else if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + else { + c = _mpd_cmp(a, b); + if (c == 0) { + c = _mpd_cmp_numequal(a, b); + } + + if (c < 0) { + mpd_qcopy(result, a, status); + } + else { + mpd_qcopy(result, b, status); + } + } + + mpd_qfinalize(result, ctx, status); +} + +/* + * Minimum magnitude: Same as mpd_min(), but compares the operands with their + * sign ignored. + */ +void +mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isqnan(a) && !mpd_isnan(b)) { + mpd_qcopy(result, b, status); + } + else if (mpd_isqnan(b) && !mpd_isnan(a)) { + mpd_qcopy(result, a, status); + } + else if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + else { + c = _mpd_cmp_abs(a, b); + if (c == 0) { + c = _mpd_cmp_numequal(a, b); + } + + if (c < 0) { + mpd_qcopy(result, a, status); + } + else { + mpd_qcopy(result, b, status); + } + } + + mpd_qfinalize(result, ctx, status); +} + +/* Minimum space needed for the result array in _karatsuba_rec(). */ +static inline mpd_size_t +_kmul_resultsize(mpd_size_t la, mpd_size_t lb) +{ + mpd_size_t n, m; + + n = add_size_t(la, lb); + n = add_size_t(n, 1); + + m = (la+1)/2 + 1; + m = mul_size_t(m, 3); + + return (m > n) ? m : n; +} + +/* Work space needed in _karatsuba_rec(). lim >= 4 */ +static inline mpd_size_t +_kmul_worksize(mpd_size_t n, mpd_size_t lim) +{ + mpd_size_t m; + + if (n <= lim) { + return 0; + } + + m = (n+1)/2 + 1; + + return add_size_t(mul_size_t(m, 2), _kmul_worksize(m, lim)); +} + + +#define MPD_KARATSUBA_BASECASE 16 /* must be >= 4 */ + +/* + * Add the product of a and b to c. + * c must be _kmul_resultsize(la, lb) in size. + * w is used as a work array and must be _kmul_worksize(a, lim) in size. + * Roman E. Maeder, Storage Allocation for the Karatsuba Integer Multiplication + * Algorithm. In "Design and implementation of symbolic computation systems", + * Springer, 1993, ISBN 354057235X, 9783540572350. + */ +static void +_karatsuba_rec(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b, + mpd_uint_t *w, mpd_size_t la, mpd_size_t lb) +{ + mpd_size_t m, lt; + + assert(la >= lb && lb > 0); + assert(la <= MPD_KARATSUBA_BASECASE || w != NULL); + + if (la <= MPD_KARATSUBA_BASECASE) { + _mpd_basemul(c, a, b, la, lb); + return; + } + + m = (la+1)/2; // ceil(la/2) + + /* lb <= m < la */ + if (lb <= m) { + + /* lb can now be larger than la-m */ + if (lb > la-m) { + lt = lb + lb + 1; // space needed for result array + mpd_uint_zero(w, lt); // clear result array + _karatsuba_rec(w, b, a+m, w+lt, lb, la-m); // b*ah + } + else { + lt = (la-m) + (la-m) + 1; // space needed for result array + mpd_uint_zero(w, lt); // clear result array + _karatsuba_rec(w, a+m, b, w+lt, la-m, lb); // ah*b + } + _mpd_baseaddto(c+m, w, (la-m)+lb); // add ah*b*B**m + + lt = m + m + 1; // space needed for the result array + mpd_uint_zero(w, lt); // clear result array + _karatsuba_rec(w, a, b, w+lt, m, lb); // al*b + _mpd_baseaddto(c, w, m+lb); // add al*b + + return; + } + + /* la >= lb > m */ + memcpy(w, a, m * sizeof *w); + w[m] = 0; + _mpd_baseaddto(w, a+m, la-m); + + memcpy(w+(m+1), b, m * sizeof *w); + w[m+1+m] = 0; + _mpd_baseaddto(w+(m+1), b+m, lb-m); + + _karatsuba_rec(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1); + + lt = (la-m) + (la-m) + 1; + mpd_uint_zero(w, lt); + + _karatsuba_rec(w, a+m, b+m, w+lt, la-m, lb-m); + + _mpd_baseaddto(c+2*m, w, (la-m) + (lb-m)); + _mpd_basesubfrom(c+m, w, (la-m) + (lb-m)); + + lt = m + m + 1; + mpd_uint_zero(w, lt); + + _karatsuba_rec(w, a, b, w+lt, m, m); + _mpd_baseaddto(c, w, m+m); + _mpd_basesubfrom(c+m, w, m+m); + + return; +} + +/* + * Multiply u and v, using Karatsuba multiplication. Returns a pointer + * to the result or NULL in case of failure (malloc error). + * Conditions: ulen >= vlen, ulen >= 4 + */ +mpd_uint_t * +_mpd_kmul(const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t ulen, mpd_size_t vlen, + mpd_size_t *rsize) +{ + mpd_uint_t *result = NULL, *w = NULL; + mpd_size_t m; + + assert(ulen >= 4); + assert(ulen >= vlen); + + *rsize = _kmul_resultsize(ulen, vlen); + if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) { + return NULL; + } + + m = _kmul_worksize(ulen, MPD_KARATSUBA_BASECASE); + if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) { + mpd_free(result); + return NULL; + } + + _karatsuba_rec(result, u, v, w, ulen, vlen); + + + if (w) mpd_free(w); + return result; +} + + +/* Determine the minimum length for the number theoretic transform. */ +static inline mpd_size_t +_mpd_get_transform_len(mpd_size_t rsize) +{ + mpd_size_t log2rsize; + mpd_size_t x, step; + + assert(rsize >= 4); + log2rsize = mpd_bsr(rsize); + + if (rsize <= 1024) { + x = ((mpd_size_t)1)<>1; + x += step; + return (rsize <= x) ? x : x + step; + } + else if (rsize <= MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2) { + return MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2; + } + else if (rsize <= 3*MPD_MAXTRANSFORM_2N) { + return 3*MPD_MAXTRANSFORM_2N; + } + else { + return MPD_SIZE_MAX; + } +} + +#ifdef PPRO +#ifndef _MSC_VER +static inline unsigned short +_mpd_get_control87(void) +{ + unsigned short cw; + + __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); + return cw; +} + +static inline void +_mpd_set_control87(unsigned short cw) +{ + __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); +} +#endif + +unsigned int +mpd_set_fenv(void) +{ + unsigned int cw; +#ifdef _MSC_VER + unsigned int flags = + _EM_INVALID|_EM_DENORMAL|_EM_ZERODIVIDE|_EM_OVERFLOW| + _EM_UNDERFLOW|_EM_INEXACT|_RC_CHOP|_PC_64; + unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC; + unsigned int dummy; + + __control87_2(0, 0, &cw, NULL); + __control87_2(flags, mask, &dummy, NULL); +#else + cw = _mpd_get_control87(); + _mpd_set_control87(cw|0xF3F); +#endif + return cw; +} + +void +mpd_restore_fenv(unsigned int cw) +{ +#ifdef _MSC_VER + unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC; + unsigned int dummy; + + __control87_2(cw, mask, &dummy, NULL); +#else + _mpd_set_control87((unsigned short)cw); +#endif +} +#endif /* PPRO */ + +/* + * Multiply u and v, using the fast number theoretic transform. Returns + * a pointer to the result or NULL in case of failure (malloc error). + */ +mpd_uint_t * +_mpd_fntmul(const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t ulen, mpd_size_t vlen, + mpd_size_t *rsize) +{ + mpd_uint_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *vtmp = NULL; + mpd_size_t n; + +#ifdef PPRO + unsigned int cw; + cw = mpd_set_fenv(); +#endif + + *rsize = add_size_t(ulen, vlen); + if ((n = _mpd_get_transform_len(*rsize)) == MPD_SIZE_MAX) { + goto malloc_error; + } + + if ((c1 = mpd_calloc(sizeof *c1, n)) == NULL) { + goto malloc_error; + } + if ((c2 = mpd_calloc(sizeof *c2, n)) == NULL) { + goto malloc_error; + } + if ((c3 = mpd_calloc(sizeof *c3, n)) == NULL) { + goto malloc_error; + } + + memcpy(c1, u, ulen * (sizeof *c1)); + memcpy(c2, u, ulen * (sizeof *c2)); + memcpy(c3, u, ulen * (sizeof *c3)); + + if (u == v) { + if (!fnt_autoconvolute(c1, n, P1) || + !fnt_autoconvolute(c2, n, P2) || + !fnt_autoconvolute(c3, n, P3)) { + goto malloc_error; + } + } + else { + if ((vtmp = mpd_calloc(sizeof *vtmp, n)) == NULL) { + goto malloc_error; + } + + memcpy(vtmp, v, vlen * (sizeof *vtmp)); + if (!fnt_convolute(c1, vtmp, n, P1)) { + mpd_free(vtmp); + goto malloc_error; + } + + memcpy(vtmp, v, vlen * (sizeof *vtmp)); + mpd_uint_zero(vtmp+vlen, n-vlen); + if (!fnt_convolute(c2, vtmp, n, P2)) { + mpd_free(vtmp); + goto malloc_error; + } + + memcpy(vtmp, v, vlen * (sizeof *vtmp)); + mpd_uint_zero(vtmp+vlen, n-vlen); + if (!fnt_convolute(c3, vtmp, n, P3)) { + mpd_free(vtmp); + goto malloc_error; + } + + mpd_free(vtmp); + } + + crt3(c1, c2, c3, *rsize); + +out: +#ifdef PPRO + mpd_restore_fenv(cw); +#endif + if (c2) mpd_free(c2); + if (c3) mpd_free(c3); + return c1; + +malloc_error: + if (c1) mpd_free(c1); + c1 = NULL; + goto out; +} + + +/* + * Karatsuba multiplication with FNT/basemul as the base case. + */ +static int +_karatsuba_rec_fnt(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b, + mpd_uint_t *w, mpd_size_t la, mpd_size_t lb) +{ + mpd_size_t m, lt; + + assert(la >= lb && lb > 0); + assert(la <= 3*(MPD_MAXTRANSFORM_2N/2) || w != NULL); + + if (la <= 3*(MPD_MAXTRANSFORM_2N/2)) { + + if (lb <= 192) { + _mpd_basemul(c, b, a, lb, la); + } + else { + mpd_uint_t *result; + mpd_size_t dummy; + + if ((result = _mpd_fntmul(a, b, la, lb, &dummy)) == NULL) { + return 0; + } + memcpy(c, result, (la+lb) * (sizeof *result)); + mpd_free(result); + } + return 1; + } + + m = (la+1)/2; // ceil(la/2) + + /* lb <= m < la */ + if (lb <= m) { + + /* lb can now be larger than la-m */ + if (lb > la-m) { + lt = lb + lb + 1; // space needed for result array + mpd_uint_zero(w, lt); // clear result array + if (!_karatsuba_rec_fnt(w, b, a+m, w+lt, lb, la-m)) { // b*ah + return 0; /* GCOV_UNLIKELY */ + } + } + else { + lt = (la-m) + (la-m) + 1; // space needed for result array + mpd_uint_zero(w, lt); // clear result array + if (!_karatsuba_rec_fnt(w, a+m, b, w+lt, la-m, lb)) { // ah*b + return 0; /* GCOV_UNLIKELY */ + } + } + _mpd_baseaddto(c+m, w, (la-m)+lb); // add ah*b*B**m + + lt = m + m + 1; // space needed for the result array + mpd_uint_zero(w, lt); // clear result array + if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, lb)) { // al*b + return 0; /* GCOV_UNLIKELY */ + } + _mpd_baseaddto(c, w, m+lb); // add al*b + + return 1; + } + + /* la >= lb > m */ + memcpy(w, a, m * sizeof *w); + w[m] = 0; + _mpd_baseaddto(w, a+m, la-m); + + memcpy(w+(m+1), b, m * sizeof *w); + w[m+1+m] = 0; + _mpd_baseaddto(w+(m+1), b+m, lb-m); + + if (!_karatsuba_rec_fnt(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1)) { + return 0; /* GCOV_UNLIKELY */ + } + + lt = (la-m) + (la-m) + 1; + mpd_uint_zero(w, lt); + + if (!_karatsuba_rec_fnt(w, a+m, b+m, w+lt, la-m, lb-m)) { + return 0; /* GCOV_UNLIKELY */ + } + + _mpd_baseaddto(c+2*m, w, (la-m) + (lb-m)); + _mpd_basesubfrom(c+m, w, (la-m) + (lb-m)); + + lt = m + m + 1; + mpd_uint_zero(w, lt); + + if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, m)) { + return 0; /* GCOV_UNLIKELY */ + } + _mpd_baseaddto(c, w, m+m); + _mpd_basesubfrom(c+m, w, m+m); + + return 1; +} + +/* + * Multiply u and v, using Karatsuba multiplication with the FNT as the + * base case. Returns a pointer to the result or NULL in case of failure + * (malloc error). Conditions: ulen >= vlen, ulen >= 4. + */ +mpd_uint_t * +_mpd_kmul_fnt(const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t ulen, mpd_size_t vlen, + mpd_size_t *rsize) +{ + mpd_uint_t *result = NULL, *w = NULL; + mpd_size_t m; + + assert(ulen >= 4); + assert(ulen >= vlen); + + *rsize = _kmul_resultsize(ulen, vlen); + if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) { + return NULL; + } + + m = _kmul_worksize(ulen, 3*(MPD_MAXTRANSFORM_2N/2)); + if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) { + mpd_free(result); /* GCOV_UNLIKELY */ + return NULL; /* GCOV_UNLIKELY */ + } + + if (!_karatsuba_rec_fnt(result, u, v, w, ulen, vlen)) { + mpd_free(result); + result = NULL; + } + + + if (w) mpd_free(w); + return result; +} + + +/* Deal with the special cases of multiplying infinities. */ +static void +_mpd_qmul_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status) +{ + if (mpd_isinfinite(a)) { + if (mpd_iszero(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + } + else { + mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF); + } + return; + } + assert(mpd_isinfinite(b)); + if (mpd_iszero(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + } + else { + mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF); + } +} + +/* + * Internal function: Multiply a and b. _mpd_qmul deals with specials but + * does NOT finalize the result. This is for use in mpd_fma(). + */ +static inline void +_mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_t *big = (mpd_t *)a, *small = (mpd_t *)b; + mpd_uint_t *rdata = NULL; + mpd_uint_t rbuf[MPD_MINALLOC_MAX]; + mpd_size_t rsize, i; + + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + _mpd_qmul_inf(result, a, b, status); + return; + } + + if (small->len > big->len) { + _mpd_ptrswap(&big, &small); + } + + rsize = big->len + small->len; + + if (big->len == 1) { + _mpd_singlemul(result->data, big->data[0], small->data[0]); + goto finish; + } + if (rsize <= (mpd_size_t)MPD_MINALLOC_MAX) { + if (big->len == 2) { + _mpd_mul_2_le2(rbuf, big->data, small->data, small->len); + } + else { + mpd_uint_zero(rbuf, rsize); + if (small->len == 1) { + _mpd_shortmul(rbuf, big->data, big->len, small->data[0]); + } + else { + _mpd_basemul(rbuf, small->data, big->data, small->len, big->len); + } + } + if (!mpd_qresize(result, rsize, status)) { + return; + } + for(i = 0; i < rsize; i++) { + result->data[i] = rbuf[i]; + } + goto finish; + } + + + if (small->len == 1) { + if ((rdata = mpd_calloc(rsize, sizeof *rdata)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + _mpd_shortmul(rdata, big->data, big->len, small->data[0]); + } + else if (rsize <= 1024) { + rdata = _mpd_kmul(big->data, small->data, big->len, small->len, &rsize); + if (rdata == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + } + else if (rsize <= 3*MPD_MAXTRANSFORM_2N) { + rdata = _mpd_fntmul(big->data, small->data, big->len, small->len, &rsize); + if (rdata == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + } + else { + rdata = _mpd_kmul_fnt(big->data, small->data, big->len, small->len, &rsize); + if (rdata == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); /* GCOV_UNLIKELY */ + return; /* GCOV_UNLIKELY */ + } + } + + if (mpd_isdynamic_data(result)) { + mpd_free(result->data); + } + result->data = rdata; + result->alloc = rsize; + mpd_set_dynamic_data(result); + + +finish: + mpd_set_flags(result, mpd_sign(a)^mpd_sign(b)); + result->exp = big->exp + small->exp; + result->len = _mpd_real_size(result->data, rsize); + /* resize to smaller cannot fail */ + mpd_qresize(result, result->len, status); + mpd_setdigits(result); +} + +/* Multiply a and b. */ +void +mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + _mpd_qmul(result, a, b, ctx, status); + mpd_qfinalize(result, ctx, status); +} + +/* Multiply decimal and mpd_ssize_t. */ +void +mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_ssize(&bb, b, &maxcontext, status); + mpd_qmul(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Multiply decimal and mpd_uint_t. */ +void +mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_uint(&bb, b, &maxcontext, status); + mpd_qmul(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +void +mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qmul_ssize(result, a, b, ctx, status); +} + +void +mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qmul_uint(result, a, b, ctx, status); +} + +#ifdef CONFIG_64 +void +mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qmul_ssize(result, a, b, ctx, status); +} + +void +mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qmul_uint(result, a, b, ctx, status); +} +#endif + +/* Like the minus operator. */ +void +mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + } + + if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) { + mpd_qcopy_abs(result, a, status); + } + else { + mpd_qcopy_negate(result, a, status); + } + + mpd_qfinalize(result, ctx, status); +} + +/* Like the plus operator. */ +void +mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + } + + if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) { + mpd_qcopy_abs(result, a, status); + } + else { + mpd_qcopy(result, a, status); + } + + mpd_qfinalize(result, ctx, status); +} + +/* The largest representable number that is smaller than the operand. */ +void +mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; /* function context */ + MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1); + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isinfinite(a)) { + if (mpd_isnegative(a)) { + mpd_qcopy(result, a, status); + return; + } + else { + mpd_clear_flags(result); + mpd_qmaxcoeff(result, ctx, status); + if (mpd_isnan(result)) { + return; + } + result->exp = ctx->emax - ctx->prec + 1; + return; + } + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + + mpd_workcontext(&workctx, ctx); + workctx.round = MPD_ROUND_FLOOR; + + if (!mpd_qcopy(result, a, status)) { + return; + } + + mpd_qfinalize(result, &workctx, &workctx.status); + if (workctx.status&(MPD_Inexact|MPD_Errors)) { + *status |= (workctx.status&MPD_Errors); + return; + } + + workctx.status = 0; + mpd_qsub(result, a, &tiny, &workctx, &workctx.status); + *status |= (workctx.status&MPD_Errors); +} + +/* The smallest representable number that is larger than the operand. */ +void +mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1); + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isinfinite(a)) { + if (mpd_ispositive(a)) { + mpd_qcopy(result, a, status); + } + else { + mpd_clear_flags(result); + mpd_qmaxcoeff(result, ctx, status); + if (mpd_isnan(result)) { + return; + } + mpd_set_flags(result, MPD_NEG); + result->exp = mpd_etop(ctx); + } + return; + } + } + + mpd_workcontext(&workctx, ctx); + workctx.round = MPD_ROUND_CEILING; + + if (!mpd_qcopy(result, a, status)) { + return; + } + + mpd_qfinalize(result, &workctx, &workctx.status); + if (workctx.status & (MPD_Inexact|MPD_Errors)) { + *status |= (workctx.status&MPD_Errors); + return; + } + + workctx.status = 0; + mpd_qadd(result, a, &tiny, &workctx, &workctx.status); + *status |= (workctx.status&MPD_Errors); +} + +/* + * The number closest to the first operand that is in the direction towards + * the second operand. + */ +void +mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isnan(a) || mpd_isnan(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) + return; + } + + c = _mpd_cmp(a, b); + if (c == 0) { + mpd_qcopy_sign(result, a, b, status); + return; + } + + if (c < 0) { + mpd_qnext_plus(result, a, ctx, status); + } + else { + mpd_qnext_minus(result, a, ctx, status); + } + + if (mpd_isinfinite(result)) { + *status |= (MPD_Overflow|MPD_Rounded|MPD_Inexact); + } + else if (mpd_adjexp(result) < ctx->emin) { + *status |= (MPD_Underflow|MPD_Subnormal|MPD_Rounded|MPD_Inexact); + if (mpd_iszero(result)) { + *status |= MPD_Clamped; + } + } +} + +/* + * Internal function: Integer power with mpd_uint_t exponent, base is modified! + * Function can fail with MPD_Malloc_error. + */ +static inline void +_mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_uint_t n; + + if (exp == 0) { + _settriple(result, resultsign, 1, 0); /* GCOV_NOT_REACHED */ + return; /* GCOV_NOT_REACHED */ + } + + if (!mpd_qcopy(result, base, status)) { + return; + } + + n = mpd_bits[mpd_bsr(exp)]; + while (n >>= 1) { + mpd_qmul(result, result, result, ctx, &workstatus); + if (exp & n) { + mpd_qmul(result, result, base, ctx, &workstatus); + } + if (workstatus & (MPD_Overflow|MPD_Clamped)) { + break; + } + } + + *status |= workstatus; + mpd_set_sign(result, resultsign); +} + +/* + * Internal function: Integer power with mpd_t exponent, tbase and texp + * are modified!! Function can fail with MPD_Malloc_error. + */ +static inline void +_mpd_qpow_mpd(mpd_t *result, mpd_t *tbase, mpd_t *texp, uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_context_t maxctx; + MPD_NEW_CONST(two,0,0,1,1,1,2); + + + mpd_maxcontext(&maxctx); + + /* resize to smaller cannot fail */ + mpd_qcopy(result, &one, status); + + while (!mpd_iszero(texp)) { + if (mpd_isodd(texp)) { + mpd_qmul(result, result, tbase, ctx, &workstatus); + *status |= workstatus; + if (workstatus & (MPD_Overflow|MPD_Clamped)) { + break; + } + } + mpd_qmul(tbase, tbase, tbase, ctx, &workstatus); + mpd_qdivint(texp, texp, &two, &maxctx, &workstatus); + if (mpd_isnan(tbase) || mpd_isnan(texp)) { + mpd_seterror(result, workstatus&MPD_Errors, status); + return; + } + } + mpd_set_sign(result, resultsign); +} + +/* + * The power function for integer exponents. + */ +static void +_mpd_qpow_int(mpd_t *result, const mpd_t *base, const mpd_t *exp, + uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(tbase,0,0,0,0); + MPD_NEW_STATIC(texp,0,0,0,0); + mpd_ssize_t n; + + + mpd_workcontext(&workctx, ctx); + workctx.prec += (exp->digits + exp->exp + 2); + workctx.round = MPD_ROUND_HALF_EVEN; + workctx.clamp = 0; + if (mpd_isnegative(exp)) { + mpd_qdiv(&tbase, &one, base, &workctx, status); + if (*status&MPD_Errors) { + mpd_setspecial(result, MPD_POS, MPD_NAN); + goto finish; + } + } + else { + if (!mpd_qcopy(&tbase, base, status)) { + mpd_setspecial(result, MPD_POS, MPD_NAN); + goto finish; + } + } + + n = mpd_qabs_uint(exp, &workctx.status); + if (workctx.status&MPD_Invalid_operation) { + if (!mpd_qcopy(&texp, exp, status)) { + mpd_setspecial(result, MPD_POS, MPD_NAN); /* GCOV_UNLIKELY */ + goto finish; /* GCOV_UNLIKELY */ + } + _mpd_qpow_mpd(result, &tbase, &texp, resultsign, &workctx, status); + } + else { + _mpd_qpow_uint(result, &tbase, n, resultsign, &workctx, status); + } + + if (mpd_isinfinite(result)) { + /* for ROUND_DOWN, ROUND_FLOOR, etc. */ + _settriple(result, resultsign, 1, MPD_EXP_INF); + } + +finish: + mpd_del(&tbase); + mpd_del(&texp); + mpd_qfinalize(result, ctx, status); +} + +/* + * This is an internal function that does not check for NaNs. + */ +static int +_qcheck_pow_one_inf(mpd_t *result, const mpd_t *base, uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t shift; + int cmp; + + if ((cmp = _mpd_cmp(base, &one)) == 0) { + shift = ctx->prec-1; + mpd_qshiftl(result, &one, shift, status); + result->exp = -shift; + mpd_set_flags(result, resultsign); + *status |= (MPD_Inexact|MPD_Rounded); + } + + return cmp; +} + +/* + * If base equals one, calculate the correct power of one result. + * Otherwise, result is undefined. Return the value of the comparison + * against 1. + * + * This is an internal function that does not check for specials. + */ +static int +_qcheck_pow_one(mpd_t *result, const mpd_t *base, const mpd_t *exp, + uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_ssize_t shift; + int cmp; + + if ((cmp = _mpd_cmp_abs(base, &one)) == 0) { + if (_mpd_isint(exp)) { + if (mpd_isnegative(exp)) { + _settriple(result, resultsign, 1, 0); + return 0; + } + /* 1.000**3 = 1.000000000 */ + mpd_qmul_ssize(result, exp, -base->exp, ctx, &workstatus); + if (workstatus&MPD_Errors) { + *status |= (workstatus&MPD_Errors); + return 0; + } + /* digits-1 after exponentiation */ + shift = mpd_qget_ssize(result, &workstatus); + /* shift is MPD_SSIZE_MAX if result is too large */ + if (shift > ctx->prec-1) { + shift = ctx->prec-1; + *status |= MPD_Rounded; + } + } + else if (mpd_ispositive(base)) { + shift = ctx->prec-1; + *status |= (MPD_Inexact|MPD_Rounded); + } + else { + return -2; /* GCOV_NOT_REACHED */ + } + if (!mpd_qshiftl(result, &one, shift, status)) { + return 0; + } + result->exp = -shift; + mpd_set_flags(result, resultsign); + } + + return cmp; +} + +/* + * Detect certain over/underflow of x**y. + * ACL2 proof: pow_bounds.lisp. + * + * Symbols: + * + * e: EXP_INF or EXP_CLAMP + * x: base + * y: exponent + * + * omega(e) = log10(abs(e)) + * zeta(x) = log10(abs(log10(x))) + * theta(y) = log10(abs(y)) + * + * Upper and lower bounds: + * + * ub_omega(e) = ceil(log10(abs(e))) + * lb_theta(y) = floor(log10(abs(y))) + * + * | floor(log10(floor(abs(log10(x))))) if x < 1/10 or x >= 10 + * lb_zeta(x) = | floor(log10(abs(x-1)/10)) if 1/10 <= x < 1 + * | floor(log10(abs((x-1)/100))) if 1 < x < 10 + * + * ub_omega(e) and lb_theta(y) are obviously upper and lower bounds + * for omega(e) and theta(y). + * + * lb_zeta is a lower bound for zeta(x): + * + * x < 1/10 or x >= 10: + * + * abs(log10(x)) >= 1, so the outer log10 is well defined. Since log10 + * is strictly increasing, the end result is a lower bound. + * + * 1/10 <= x < 1: + * + * We use: log10(x) <= (x-1)/log(10) + * abs(log10(x)) >= abs(x-1)/log(10) + * abs(log10(x)) >= abs(x-1)/10 + * + * 1 < x < 10: + * + * We use: (x-1)/(x*log(10)) < log10(x) + * abs((x-1)/100) < abs(log10(x)) + * + * XXX: abs((x-1)/10) would work, need ACL2 proof. + * + * + * Let (0 < x < 1 and y < 0) or (x > 1 and y > 0). (H1) + * Let ub_omega(exp_inf) < lb_zeta(x) + lb_theta(y) (H2) + * + * Then: + * log10(abs(exp_inf)) < log10(abs(log10(x))) + log10(abs(y)). (1) + * exp_inf < log10(x) * y (2) + * 10**exp_inf < x**y (3) + * + * Let (0 < x < 1 and y > 0) or (x > 1 and y < 0). (H3) + * Let ub_omega(exp_clamp) < lb_zeta(x) + lb_theta(y) (H4) + * + * Then: + * log10(abs(exp_clamp)) < log10(abs(log10(x))) + log10(abs(y)). (4) + * log10(x) * y < exp_clamp (5) + * x**y < 10**exp_clamp (6) + * + */ +static mpd_ssize_t +_lower_bound_zeta(const mpd_t *x, uint32_t *status) +{ + mpd_context_t maxctx; + MPD_NEW_STATIC(scratch,0,0,0,0); + mpd_ssize_t t, u; + + t = mpd_adjexp(x); + if (t > 0) { + /* x >= 10 -> floor(log10(floor(abs(log10(x))))) */ + return mpd_exp_digits(t) - 1; + } + else if (t < -1) { + /* x < 1/10 -> floor(log10(floor(abs(log10(x))))) */ + return mpd_exp_digits(t+1) - 1; + } + else { + mpd_maxcontext(&maxctx); + mpd_qsub(&scratch, x, &one, &maxctx, status); + if (mpd_isspecial(&scratch)) { + mpd_del(&scratch); + return MPD_SSIZE_MAX; + } + u = mpd_adjexp(&scratch); + mpd_del(&scratch); + + /* t == -1, 1/10 <= x < 1 -> floor(log10(abs(x-1)/10)) + * t == 0, 1 < x < 10 -> floor(log10(abs(x-1)/100)) */ + return (t == 0) ? u-2 : u-1; + } +} + +/* + * Detect cases of certain overflow/underflow in the power function. + * Assumptions: x != 1, y != 0. The proof above is for positive x. + * If x is negative and y is an odd integer, x**y == -(abs(x)**y), + * so the analysis does not change. + */ +static int +_qcheck_pow_bounds(mpd_t *result, const mpd_t *x, const mpd_t *y, + uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + MPD_NEW_SHARED(abs_x, x); + mpd_ssize_t ub_omega, lb_zeta, lb_theta; + uint8_t sign; + + mpd_set_positive(&abs_x); + + lb_theta = mpd_adjexp(y); + lb_zeta = _lower_bound_zeta(&abs_x, status); + if (lb_zeta == MPD_SSIZE_MAX) { + mpd_seterror(result, MPD_Malloc_error, status); + return 1; + } + + sign = (mpd_adjexp(&abs_x) < 0) ^ mpd_sign(y); + if (sign == 0) { + /* (0 < |x| < 1 and y < 0) or (|x| > 1 and y > 0) */ + ub_omega = mpd_exp_digits(ctx->emax); + if (ub_omega < lb_zeta + lb_theta) { + _settriple(result, resultsign, 1, MPD_EXP_INF); + mpd_qfinalize(result, ctx, status); + return 1; + } + } + else { + /* (0 < |x| < 1 and y > 0) or (|x| > 1 and y < 0). */ + ub_omega = mpd_exp_digits(mpd_etiny(ctx)); + if (ub_omega < lb_zeta + lb_theta) { + _settriple(result, resultsign, 1, mpd_etiny(ctx)-1); + mpd_qfinalize(result, ctx, status); + return 1; + } + } + + return 0; +} + +/* + * TODO: Implement algorithm for computing exact powers from decimal.py. + * In order to prevent infinite loops, this has to be called before + * using Ziv's strategy for correct rounding. + */ +/* +static int +_mpd_qpow_exact(mpd_t *result, const mpd_t *base, const mpd_t *exp, + const mpd_context_t *ctx, uint32_t *status) +{ + return 0; +} +*/ + +/* The power function for real exponents */ +static void +_mpd_qpow_real(mpd_t *result, const mpd_t *base, const mpd_t *exp, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(texp,0,0,0,0); + + if (!mpd_qcopy(&texp, exp, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + + mpd_maxcontext(&workctx); + workctx.prec = (base->digits > ctx->prec) ? base->digits : ctx->prec; + workctx.prec += (4 + MPD_EXPDIGITS); + workctx.round = MPD_ROUND_HALF_EVEN; + workctx.allcr = ctx->allcr; + + mpd_qln(result, base, &workctx, &workctx.status); + mpd_qmul(result, result, &texp, &workctx, &workctx.status); + mpd_qexp(result, result, &workctx, status); + + mpd_del(&texp); + *status |= (workctx.status&MPD_Errors); + *status |= (MPD_Inexact|MPD_Rounded); +} + +/* The power function: base**exp */ +void +mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp, + const mpd_context_t *ctx, uint32_t *status) +{ + uint8_t resultsign = 0; + int intexp = 0; + int cmp; + + if (mpd_isspecial(base) || mpd_isspecial(exp)) { + if (mpd_qcheck_nans(result, base, exp, ctx, status)) { + return; + } + } + if (mpd_isinteger(exp)) { + intexp = 1; + resultsign = mpd_isnegative(base) && mpd_isodd(exp); + } + + if (mpd_iszero(base)) { + if (mpd_iszero(exp)) { + mpd_seterror(result, MPD_Invalid_operation, status); + } + else if (mpd_isnegative(exp)) { + mpd_setspecial(result, resultsign, MPD_INF); + } + else { + _settriple(result, resultsign, 0, 0); + } + return; + } + if (mpd_isnegative(base)) { + if (!intexp || mpd_isinfinite(exp)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + } + if (mpd_isinfinite(exp)) { + /* power of one */ + cmp = _qcheck_pow_one_inf(result, base, resultsign, ctx, status); + if (cmp == 0) { + return; + } + else { + cmp *= mpd_arith_sign(exp); + if (cmp < 0) { + _settriple(result, resultsign, 0, 0); + } + else { + mpd_setspecial(result, resultsign, MPD_INF); + } + } + return; + } + if (mpd_isinfinite(base)) { + if (mpd_iszero(exp)) { + _settriple(result, resultsign, 1, 0); + } + else if (mpd_isnegative(exp)) { + _settriple(result, resultsign, 0, 0); + } + else { + mpd_setspecial(result, resultsign, MPD_INF); + } + return; + } + if (mpd_iszero(exp)) { + _settriple(result, resultsign, 1, 0); + return; + } + if (_qcheck_pow_one(result, base, exp, resultsign, ctx, status) == 0) { + return; + } + if (_qcheck_pow_bounds(result, base, exp, resultsign, ctx, status)) { + return; + } + + if (intexp) { + _mpd_qpow_int(result, base, exp, resultsign, ctx, status); + } + else { + _mpd_qpow_real(result, base, exp, ctx, status); + if (!mpd_isspecial(result) && _mpd_cmp(result, &one) == 0) { + mpd_ssize_t shift = ctx->prec-1; + mpd_qshiftl(result, &one, shift, status); + result->exp = -shift; + } + if (mpd_isinfinite(result)) { + /* for ROUND_DOWN, ROUND_FLOOR, etc. */ + _settriple(result, MPD_POS, 1, MPD_EXP_INF); + } + mpd_qfinalize(result, ctx, status); + } +} + +/* + * Internal function: Integer powmod with mpd_uint_t exponent, base is modified! + * Function can fail with MPD_Malloc_error. + */ +static inline void +_mpd_qpowmod_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, + mpd_t *mod, uint32_t *status) +{ + mpd_context_t maxcontext; + + mpd_maxcontext(&maxcontext); + + /* resize to smaller cannot fail */ + mpd_qcopy(result, &one, status); + + while (exp > 0) { + if (exp & 1) { + mpd_qmul(result, result, base, &maxcontext, status); + mpd_qrem(result, result, mod, &maxcontext, status); + } + mpd_qmul(base, base, base, &maxcontext, status); + mpd_qrem(base, base, mod, &maxcontext, status); + exp >>= 1; + } +} + +/* The powmod function: (base**exp) % mod */ +void +mpd_qpowmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, + const mpd_t *mod, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(tbase,0,0,0,0); + MPD_NEW_STATIC(texp,0,0,0,0); + MPD_NEW_STATIC(tmod,0,0,0,0); + MPD_NEW_STATIC(tmp,0,0,0,0); + MPD_NEW_CONST(two,0,0,1,1,1,2); + mpd_ssize_t tbase_exp, texp_exp; + mpd_ssize_t i; + mpd_t t; + mpd_uint_t r; + uint8_t sign; + + + if (mpd_isspecial(base) || mpd_isspecial(exp) || mpd_isspecial(mod)) { + if (mpd_qcheck_3nans(result, base, exp, mod, ctx, status)) { + return; + } + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + + if (!_mpd_isint(base) || !_mpd_isint(exp) || !_mpd_isint(mod)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_iszerocoeff(mod)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mod->digits+mod->exp > ctx->prec) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + sign = (mpd_isnegative(base)) && (mpd_isodd(exp)); + if (mpd_iszerocoeff(exp)) { + if (mpd_iszerocoeff(base)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + r = (_mpd_cmp_abs(mod, &one)==0) ? 0 : 1; + _settriple(result, sign, r, 0); + return; + } + if (mpd_isnegative(exp)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_iszerocoeff(base)) { + _settriple(result, sign, 0, 0); + return; + } + + if (!mpd_qcopy(&tmod, mod, status)) { + goto mpd_errors; + } + mpd_set_positive(&tmod); + + mpd_maxcontext(&maxcontext); + + mpd_qround_to_int(&tbase, base, &maxcontext, status); + mpd_qround_to_int(&texp, exp, &maxcontext, status); + mpd_qround_to_int(&tmod, &tmod, &maxcontext, status); + + tbase_exp = tbase.exp; + tbase.exp = 0; + texp_exp = texp.exp; + texp.exp = 0; + + /* base = (base.int % modulo * pow(10, base.exp, modulo)) % modulo */ + mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status); + _settriple(result, MPD_POS, 1, tbase_exp); + mpd_qrem(result, result, &tmod, &maxcontext, status); + mpd_qmul(&tbase, &tbase, result, &maxcontext, status); + mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status); + if (mpd_isspecial(&tbase) || + mpd_isspecial(&texp) || + mpd_isspecial(&tmod)) { + goto mpd_errors; + } + + for (i = 0; i < texp_exp; i++) { + _mpd_qpowmod_uint(&tmp, &tbase, 10, &tmod, status); + t = tmp; + tmp = tbase; + tbase = t; + } + if (mpd_isspecial(&tbase)) { + goto mpd_errors; /* GCOV_UNLIKELY */ + } + + /* resize to smaller cannot fail */ + mpd_qcopy(result, &one, status); + while (mpd_isfinite(&texp) && !mpd_iszero(&texp)) { + if (mpd_isodd(&texp)) { + mpd_qmul(result, result, &tbase, &maxcontext, status); + mpd_qrem(result, result, &tmod, &maxcontext, status); + } + mpd_qmul(&tbase, &tbase, &tbase, &maxcontext, status); + mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status); + mpd_qdivint(&texp, &texp, &two, &maxcontext, status); + } + if (mpd_isspecial(&texp) || mpd_isspecial(&tbase) || + mpd_isspecial(&tmod) || mpd_isspecial(result)) { + /* MPD_Malloc_error */ + goto mpd_errors; + } + else { + mpd_set_sign(result, sign); + } + +out: + mpd_del(&tbase); + mpd_del(&texp); + mpd_del(&tmod); + mpd_del(&tmp); + mpd_qfinalize(result, ctx, status); + return; + +mpd_errors: + mpd_setspecial(result, MPD_POS, MPD_NAN); + goto out; +} + +void +mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_ssize_t b_exp = b->exp; + mpd_ssize_t expdiff, shift; + mpd_uint_t rnd; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + if (mpd_isinfinite(a) && mpd_isinfinite(b)) { + mpd_qcopy(result, a, status); + return; + } + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + if (b->exp > ctx->emax || b->exp < mpd_etiny(ctx)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + if (mpd_iszero(a)) { + _settriple(result, mpd_sign(a), 0, b->exp); + mpd_qfinalize(result, ctx, status); + return; + } + + + expdiff = a->exp - b->exp; + if (a->digits + expdiff > ctx->prec) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + if (expdiff >= 0) { + shift = expdiff; + if (!mpd_qshiftl(result, a, shift, status)) { + return; + } + result->exp = b_exp; + } + else { + /* At this point expdiff < 0 and a->digits+expdiff <= prec, + * so the shift before an increment will fit in prec. */ + shift = -expdiff; + rnd = mpd_qshiftr(result, a, shift, status); + if (rnd == MPD_UINT_MAX) { + return; + } + result->exp = b_exp; + if (!_mpd_apply_round_fit(result, rnd, ctx, status)) { + return; + } + workstatus |= MPD_Rounded; + if (rnd) { + workstatus |= MPD_Inexact; + } + } + + if (mpd_adjexp(result) > ctx->emax || + mpd_adjexp(result) < mpd_etiny(ctx)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + *status |= workstatus; + mpd_qfinalize(result, ctx, status); +} + +void +mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_ssize_t shift, maxexp, maxshift; + uint8_t sign_a = mpd_sign(a); + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + mpd_qcopy(result, a, status); + return; + } + + if (!mpd_qcopy(result, a, status)) { + return; + } + mpd_qfinalize(result, ctx, status); + if (mpd_isspecial(result)) { + return; + } + if (mpd_iszero(result)) { + _settriple(result, sign_a, 0, 0); + return; + } + + shift = mpd_trail_zeros(result); + maxexp = (ctx->clamp) ? mpd_etop(ctx) : ctx->emax; + /* After the finalizing above result->exp <= maxexp. */ + maxshift = maxexp - result->exp; + shift = (shift > maxshift) ? maxshift : shift; + + mpd_qshiftr_inplace(result, shift); + result->exp += shift; +} + +void +mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, + uint32_t *status) +{ + MPD_NEW_STATIC(q,0,0,0,0); + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(r, a, b, ctx, status)) { + return; + } + if (mpd_isinfinite(a)) { + mpd_seterror(r, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(b)) { + mpd_qcopy(r, a, status); + mpd_qfinalize(r, ctx, status); + return; + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_seterror(r, MPD_Division_undefined, status); + } + else { + mpd_seterror(r, MPD_Invalid_operation, status); + } + return; + } + + _mpd_qdivmod(&q, r, a, b, ctx, status); + mpd_del(&q); + mpd_qfinalize(r, ctx, status); +} + +void +mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(btmp,0,0,0,0); + MPD_NEW_STATIC(q,0,0,0,0); + mpd_ssize_t expdiff, floordigits; + int cmp, isodd, allnine; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(r, a, b, ctx, status)) { + return; + } + if (mpd_isinfinite(a)) { + mpd_seterror(r, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(b)) { + mpd_qcopy(r, a, status); + mpd_qfinalize(r, ctx, status); + return; + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_seterror(r, MPD_Division_undefined, status); + } + else { + mpd_seterror(r, MPD_Invalid_operation, status); + } + return; + } + + if (r == b) { + if (!mpd_qcopy(&btmp, b, status)) { + mpd_seterror(r, MPD_Malloc_error, status); + return; + } + b = &btmp; + } + + workctx = *ctx; + workctx.prec = a->digits; + workctx.prec = (workctx.prec > ctx->prec) ? workctx.prec : ctx->prec; + + _mpd_qdivmod(&q, r, a, b, &workctx, status); + if (mpd_isnan(&q) || mpd_isnan(r) || q.digits > ctx->prec) { + mpd_seterror(r, MPD_Division_impossible, status); + goto finish; + } + if (mpd_iszerocoeff(r)) { + goto finish; + } + + /* Deal with cases like rmnx078: + * remaindernear 999999999.5 1 -> NaN Division_impossible */ + expdiff = mpd_adjexp(b) - mpd_adjexp(r); + if (-1 <= expdiff && expdiff <= 1) { + + mpd_qtrunc(&q, &q, &workctx, &workctx.status); + allnine = mpd_coeff_isallnine(&q); + floordigits = q.digits; + isodd = mpd_isodd(&q); + + mpd_maxcontext(&workctx); + if (mpd_sign(a) == mpd_sign(b)) { + _mpd_qsub(&q, r, b, &workctx, &workctx.status); + if (workctx.status&MPD_Errors) { + mpd_seterror(r, workctx.status&MPD_Errors, status); + goto finish; + } + } + else { + _mpd_qadd(&q, r, b, &workctx, &workctx.status); + if (workctx.status&MPD_Errors) { + mpd_seterror(r, workctx.status&MPD_Errors, status); + goto finish; + } + } + + cmp = mpd_cmp_total_mag(&q, r); + if (cmp < 0 || (cmp == 0 && isodd)) { + if (allnine && floordigits == ctx->prec) { + mpd_seterror(r, MPD_Division_impossible, status); + goto finish; + } + mpd_qcopy(r, &q, status); + *status &= ~MPD_Rounded; + } + } + + +finish: + mpd_del(&btmp); + mpd_del(&q); + mpd_qfinalize(r, ctx, status); +} + +static void +_mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t expdiff, shift; + mpd_uint_t rnd; + + if (mpd_isspecial(a)) { + mpd_qcopy(result, a, status); + return; + } + + if (mpd_iszero(a)) { + _settriple(result, mpd_sign(a), 0, exp); + return; + } + + expdiff = a->exp - exp; + if (expdiff >= 0) { + shift = expdiff; + if (a->digits + shift > MPD_MAX_PREC+1) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (!mpd_qshiftl(result, a, shift, status)) { + return; + } + result->exp = exp; + } + else { + shift = -expdiff; + rnd = mpd_qshiftr(result, a, shift, status); + if (rnd == MPD_UINT_MAX) { + return; + } + result->exp = exp; + _mpd_apply_round_excess(result, rnd, ctx, status); + *status |= MPD_Rounded; + if (rnd) { + *status |= MPD_Inexact; + } + } + + if (mpd_issubnormal(result, ctx)) { + *status |= MPD_Subnormal; + } +} + +/* + * Rescale a number so that it has exponent 'exp'. Does not regard context + * precision, emax, emin, but uses the rounding mode. Special numbers are + * quietly copied. Restrictions: + * + * MPD_MIN_ETINY <= exp <= MPD_MAX_EMAX+1 + * result->digits <= MPD_MAX_PREC+1 + */ +void +mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, + const mpd_context_t *ctx, uint32_t *status) +{ + if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + _mpd_qrescale(result, a, exp, ctx, status); +} + +/* + * Same as mpd_qrescale, but with relaxed restrictions. The result of this + * function should only be used for formatting a number and never as input + * for other operations. + * + * MPD_MIN_ETINY-MPD_MAX_PREC <= exp <= MPD_MAX_EMAX+1 + * result->digits <= MPD_MAX_PREC+1 + */ +void +mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, + const mpd_context_t *ctx, uint32_t *status) +{ + if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY-MPD_MAX_PREC) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + _mpd_qrescale(result, a, exp, ctx, status); +} + +/* Round to an integer according to 'action' and ctx->round. */ +enum {TO_INT_EXACT, TO_INT_SILENT, TO_INT_TRUNC}; +static void +_mpd_qround_to_integral(int action, mpd_t *result, const mpd_t *a, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t rnd; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + mpd_qcopy(result, a, status); + return; + } + if (a->exp >= 0) { + mpd_qcopy(result, a, status); + return; + } + if (mpd_iszerocoeff(a)) { + _settriple(result, mpd_sign(a), 0, 0); + return; + } + + rnd = mpd_qshiftr(result, a, -a->exp, status); + if (rnd == MPD_UINT_MAX) { + return; + } + result->exp = 0; + + if (action == TO_INT_EXACT || action == TO_INT_SILENT) { + _mpd_apply_round_excess(result, rnd, ctx, status); + if (action == TO_INT_EXACT) { + *status |= MPD_Rounded; + if (rnd) { + *status |= MPD_Inexact; + } + } + } +} + +void +mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + (void)_mpd_qround_to_integral(TO_INT_EXACT, result, a, ctx, status); +} + +void +mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a, ctx, status); +} + +void +mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + (void)_mpd_qround_to_integral(TO_INT_TRUNC, result, a, ctx, status); +} + +void +mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx = *ctx; + workctx.round = MPD_ROUND_FLOOR; + (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a, + &workctx, status); +} + +void +mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx = *ctx; + workctx.round = MPD_ROUND_CEILING; + (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a, + &workctx, status); +} + +int +mpd_same_quantum(const mpd_t *a, const mpd_t *b) +{ + if (mpd_isspecial(a) || mpd_isspecial(b)) { + return ((mpd_isnan(a) && mpd_isnan(b)) || + (mpd_isinfinite(a) && mpd_isinfinite(b))); + } + + return a->exp == b->exp; +} + +/* Schedule the increase in precision for the Newton iteration. */ +static inline int +recpr_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], + mpd_ssize_t maxprec, mpd_ssize_t initprec) +{ + mpd_ssize_t k; + int i; + + assert(maxprec > 0 && initprec > 0); + if (maxprec <= initprec) return -1; + + i = 0; k = maxprec; + do { + k = (k+1) / 2; + klist[i++] = k; + } while (k > initprec); + + return i-1; +} + +/* + * Initial approximation for the reciprocal. Result has MPD_RDIGITS-2 + * significant digits. + */ +static void +_mpd_qreciprocal_approx(mpd_t *z, const mpd_t *v, uint32_t *status) +{ + mpd_uint_t p10data[2] = {0, mpd_pow10[MPD_RDIGITS-2]}; /* 10**(2*MPD_RDIGITS-2) */ + mpd_uint_t dummy, word; + int n; + + _mpd_get_msdigits(&dummy, &word, v, MPD_RDIGITS); + n = mpd_word_digits(word); + word *= mpd_pow10[MPD_RDIGITS-n]; + + mpd_qresize(z, 2, status); + (void)_mpd_shortdiv(z->data, p10data, 2, word); + + mpd_clear_flags(z); + z->exp = -(v->exp + v->digits) - (MPD_RDIGITS-2); + z->len = (z->data[1] == 0) ? 1 : 2; + mpd_setdigits(z); +} + +/* Reciprocal, calculated with Newton's Method. Assumption: result != a. */ +static void +_mpd_qreciprocal(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t varcontext, maxcontext; + mpd_t *z = result; /* current approximation */ + mpd_t *v; /* a, normalized to a number between 0.1 and 1 */ + MPD_NEW_SHARED(vtmp, a); /* by default v will share data with a */ + MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */ + MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */ + MPD_NEW_CONST(two,0,0,1,1,1,2); /* const 2 */ + mpd_ssize_t klist[MPD_MAX_PREC_LOG2]; + mpd_ssize_t adj, maxprec, initprec; + uint8_t sign = mpd_sign(a); + int i; + + v = &vtmp; + assert(result != a); + + mpd_clear_flags(v); + adj = v->digits + v->exp; + v->exp = -v->digits; + + /* initial approximation */ + _mpd_qreciprocal_approx(z, v, status); + + mpd_maxcontext(&varcontext); + mpd_maxcontext(&maxcontext); + varcontext.round = MPD_ROUND_TRUNC; + maxcontext.round = MPD_ROUND_TRUNC; + + maxprec = (v->digits > ctx->prec) ? v->digits : ctx->prec; + maxprec += 2; + initprec = MPD_RDIGITS-3; + + i = recpr_schedule_prec(klist, maxprec, initprec); + for (; i >= 0; i--) { + mpd_qmul(&s, z, z, &maxcontext, status); + varcontext.prec = 2*klist[i] + 5; + if (v->digits > varcontext.prec) { + mpd_qshiftr(&t, v, v->digits-varcontext.prec, status); + t.exp = -varcontext.prec; + mpd_qmul(&t, &t, &s, &varcontext, status); + } + else { + mpd_qmul(&t, v, &s, &varcontext, status); + } + mpd_qmul(&s, z, &two, &maxcontext, status); + mpd_qsub(z, &s, &t, &maxcontext, status); + } + + if (!mpd_isspecial(z)) { + z->exp -= adj; + mpd_set_flags(z, sign); + } + + mpd_del(&s); + mpd_del(&t); + mpd_qfinalize(z, ctx, status); +} + +/* + * Integer division with remainder of the coefficients: coeff(a) / coeff(b). + * This function is for large numbers where it is faster to divide by + * multiplying the dividend by the reciprocal of the divisor. + * The inexact result is fixed by a small loop, which should not take + * more than 2 iterations. + */ +static void +_mpd_qbarrett_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, + uint32_t *status) +{ + mpd_context_t workctx; + mpd_t *qq = q, *rr = r; + mpd_t aa, bb; + int k; + + mpd_maxcontext(&workctx); + _mpd_copy_shared(&aa, a); + _mpd_copy_shared(&bb, b); + + mpd_set_positive(&aa); + mpd_set_positive(&bb); + aa.exp = 0; + bb.exp = 0; + + if (q == a || q == b) { + if ((qq = mpd_qnew()) == NULL) { + *status |= MPD_Malloc_error; + goto nanresult; + } + } + if (r == a || r == b) { + if ((rr = mpd_qnew()) == NULL) { + *status |= MPD_Malloc_error; + goto nanresult; + } + } + + /* maximum length of q + 3 digits */ + workctx.prec = aa.digits - bb.digits + 1 + 3; + /* we get the reciprocal with precision maxlen(q) + 3 */ + _mpd_qreciprocal(rr, &bb, &workctx, &workctx.status); + + mpd_qmul(qq, &aa, rr, &workctx, &workctx.status); + mpd_qtrunc(qq, qq, &workctx, &workctx.status); + + workctx.prec = aa.digits + 3; + /* get the remainder */ + mpd_qmul(rr, &bb, qq, &workctx, &workctx.status); + mpd_qsub(rr, &aa, rr, &workctx, &workctx.status); + + /* Fix the result. Algorithm from: Karl Hasselstrom, Fast Division of Large Integers */ + for (k = 0;; k++) { + if (mpd_isspecial(rr)) { + *status |= (workctx.status&MPD_Errors); + goto nanresult; + } + if (k > 2) { + mpd_err_warn("libmpdec: internal error in " /* GCOV_NOT_REACHED */ + "_mpd_qbarrett_divmod: please report"); /* GCOV_NOT_REACHED */ + *status |= MPD_Invalid_operation; /* GCOV_NOT_REACHED */ + goto nanresult; /* GCOV_NOT_REACHED */ + } + else if (_mpd_cmp(&zero, rr) == 1) { + mpd_qadd(rr, rr, &bb, &workctx, &workctx.status); + mpd_qadd(qq, qq, &minus_one, &workctx, &workctx.status); + } + else if (_mpd_cmp(rr, &bb) == -1) { + break; + } + else { + mpd_qsub(rr, rr, &bb, &workctx, &workctx.status); + mpd_qadd(qq, qq, &one, &workctx, &workctx.status); + } + } + + if (qq != q) { + if (!mpd_qcopy(q, qq, status)) { + goto nanresult; /* GCOV_UNLIKELY */ + } + mpd_del(qq); + } + if (rr != r) { + if (!mpd_qcopy(r, rr, status)) { + goto nanresult; /* GCOV_UNLIKELY */ + } + mpd_del(rr); + } + + *status |= (workctx.status&MPD_Errors); + return; + + +nanresult: + if (qq && qq != q) mpd_del(qq); + if (rr && rr != r) mpd_del(rr); + mpd_setspecial(q, MPD_POS, MPD_NAN); + mpd_setspecial(r, MPD_POS, MPD_NAN); +} + +static inline int +invroot_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], + mpd_ssize_t maxprec, mpd_ssize_t initprec) +{ + mpd_ssize_t k; + int i; + + assert(maxprec >= 3 && initprec >= 3); + if (maxprec <= initprec) return -1; + + i = 0; k = maxprec; + do { + k = (k+3) / 2; + klist[i++] = k; + } while (k > initprec); + + return i-1; +} + +/* + * Initial approximation for the inverse square root. + * + * Input: + * v := 7 or 8 decimal digits with an implicit exponent of 10**-6, + * representing a number 1 <= x < 100. + * + * Output: + * An approximation to 1/sqrt(v) + */ +static inline void +_invroot_init_approx(mpd_t *z, mpd_uint_t v) +{ + mpd_uint_t lo = 1000; + mpd_uint_t hi = 10000; + mpd_uint_t a, sq; + + assert(v >= lo*lo && v < (hi+1)*(hi+1)); + + for(;;) { + a = (lo + hi) / 2; + sq = a * a; + if (v >= sq) { + if (v < sq + 2*a + 1) { + break; + } + lo = a + 1; + } + else { + hi = a - 1; + } + } + + /* At this point a/1000 is an approximation to sqrt(v). */ + mpd_minalloc(z); + mpd_clear_flags(z); + z->data[0] = 1000000000UL / a; + z->len = 1; + z->exp = -6; + mpd_setdigits(z); +} + +static void +_mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_context_t varcontext, maxcontext; + mpd_t *z = result; /* current approximation */ + mpd_t *v; /* a, normalized to a number between 1 and 100 */ + MPD_NEW_SHARED(vtmp, a); /* by default v will share data with a */ + MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */ + MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */ + MPD_NEW_CONST(one_half,0,-1,1,1,1,5); + MPD_NEW_CONST(three,0,0,1,1,1,3); + mpd_ssize_t klist[MPD_MAX_PREC_LOG2]; + mpd_ssize_t ideal_exp, shift; + mpd_ssize_t adj, tz; + mpd_ssize_t maxprec, fracdigits; + mpd_uint_t x, dummy; + int i, n; + + + ideal_exp = -(a->exp - (a->exp & 1)) / 2; + + v = &vtmp; + if (result == a) { + if ((v = mpd_qncopy(a)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + } + + /* normalize a to 1 <= v < 100 */ + if ((v->digits+v->exp) & 1) { + fracdigits = v->digits - 1; + v->exp = -fracdigits; + n = (v->digits > 7) ? 7 : (int)v->digits; + _mpd_get_msdigits(&dummy, &x, v, n); + if (n < 7) { + x *= mpd_pow10[7-n]; + } + } + else { + fracdigits = v->digits - 2; + v->exp = -fracdigits; + n = (v->digits > 8) ? 8 : (int)v->digits; + _mpd_get_msdigits(&dummy, &x, v, n); + if (n < 8) { + x *= mpd_pow10[8-n]; + } + } + adj = (a->exp-v->exp) / 2; + + /* initial approximation */ + _invroot_init_approx(z, x); + + mpd_maxcontext(&maxcontext); + mpd_maxcontext(&varcontext); + varcontext.round = MPD_ROUND_TRUNC; + maxprec = ctx->prec + 2; + + i = invroot_schedule_prec(klist, maxprec, 3); + for (; i >= 0; i--) { + varcontext.prec = 2*klist[i]+2; + mpd_qmul(&s, z, z, &maxcontext, &workstatus); + if (v->digits > varcontext.prec) { + shift = v->digits - varcontext.prec; + mpd_qshiftr(&t, v, shift, &workstatus); + t.exp += shift; + mpd_qmul(&t, &t, &s, &varcontext, &workstatus); + } + else { + mpd_qmul(&t, v, &s, &varcontext, &workstatus); + } + mpd_qsub(&t, &three, &t, &maxcontext, &workstatus); + mpd_qmul(z, z, &t, &varcontext, &workstatus); + mpd_qmul(z, z, &one_half, &maxcontext, &workstatus); + } + + z->exp -= adj; + + tz = mpd_trail_zeros(result); + shift = ideal_exp - result->exp; + shift = (tz > shift) ? shift : tz; + if (shift > 0) { + mpd_qshiftr_inplace(result, shift); + result->exp += shift; + } + + + mpd_del(&s); + mpd_del(&t); + if (v != &vtmp) mpd_del(v); + *status |= (workstatus&MPD_Errors); + varcontext = *ctx; + varcontext.round = MPD_ROUND_HALF_EVEN; + mpd_qfinalize(result, &varcontext, status); +} + +void +mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + /* positive infinity */ + _settriple(result, MPD_POS, 0, mpd_etiny(ctx)); + *status |= MPD_Clamped; + return; + } + if (mpd_iszero(a)) { + mpd_setspecial(result, mpd_sign(a), MPD_INF); + *status |= MPD_Division_by_zero; + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + _mpd_qinvroot(result, a, ctx, status); +} + +/* + * Ensure correct rounding. Algorithm after Hull & Abrham, "Properly Rounded + * Variable Precision Square Root", ACM Transactions on Mathematical Software, + * Vol. 11, No. 3. + */ +static void +_mpd_fix_sqrt(mpd_t *result, const mpd_t *a, mpd_t *tmp, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxctx; + MPD_NEW_CONST(u,0,0,1,1,1,5); + + mpd_maxcontext(&maxctx); + u.exp = u.digits - ctx->prec + result->exp - 1; + + _mpd_qsub(tmp, result, &u, &maxctx, status); + if (*status&MPD_Errors) goto nanresult; + + _mpd_qmul(tmp, tmp, tmp, &maxctx, status); + if (*status&MPD_Errors) goto nanresult; + + if (_mpd_cmp(tmp, a) == 1) { + u.exp += 1; + u.data[0] = 1; + _mpd_qsub(result, result, &u, &maxctx, status); + } + else { + _mpd_qadd(tmp, result, &u, &maxctx, status); + if (*status&MPD_Errors) goto nanresult; + + _mpd_qmul(tmp, tmp, tmp, &maxctx, status); + if (*status&MPD_Errors) goto nanresult; + + if (_mpd_cmp(tmp, a) == -1) { + u.exp += 1; + u.data[0] = 1; + _mpd_qadd(result, result, &u, &maxctx, status); + } + } + + return; + +nanresult: + mpd_setspecial(result, MPD_POS, MPD_NAN); +} + +void +mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_context_t varcontext; + mpd_t *z = result; /* current approximation */ + MPD_NEW_STATIC(v,0,0,0,0); /* a, normalized to a number between 1 and 10 */ + MPD_NEW_STATIC(vtmp,0,0,0,0); + MPD_NEW_STATIC(tmp,0,0,0,0); + mpd_ssize_t ideal_exp, shift; + mpd_ssize_t target_prec, fracdigits; + mpd_ssize_t a_exp, a_digits; + mpd_ssize_t adj, tz; + mpd_uint_t dummy, t; + int exact = 0; + + + varcontext = *ctx; + varcontext.round = MPD_ROUND_HALF_EVEN; + ideal_exp = (a->exp - (a->exp & 1)) / 2; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + mpd_setspecial(result, MPD_POS, MPD_INF); + return; + } + if (mpd_iszero(a)) { + _settriple(result, mpd_sign(a), 0, ideal_exp); + mpd_qfinalize(result, ctx, status); + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + if (!mpd_qcopy(&v, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + + a_exp = a->exp; + a_digits = a->digits; + + /* normalize a to 1 <= v < 100 */ + if ((v.digits+v.exp) & 1) { + fracdigits = v.digits - 1; + v.exp = -fracdigits; + _mpd_get_msdigits(&dummy, &t, &v, 3); + t = t < 100 ? t*10 : t; + t = t < 100 ? t*10 : t; + } + else { + fracdigits = v.digits - 2; + v.exp = -fracdigits; + _mpd_get_msdigits(&dummy, &t, &v, 4); + t = t < 1000 ? t*10 : t; + t = t < 1000 ? t*10 : t; + t = t < 1000 ? t*10 : t; + } + adj = (a_exp-v.exp) / 2; + + + /* use excess digits */ + target_prec = (a_digits > ctx->prec) ? a_digits : ctx->prec; + target_prec += 2; + varcontext.prec = target_prec + 3; + + /* invroot is much faster for large numbers */ + _mpd_qinvroot(&tmp, &v, &varcontext, &workstatus); + + varcontext.prec = target_prec; + _mpd_qdiv(NO_IDEAL_EXP, z, &one, &tmp, &varcontext, &workstatus); + + + tz = mpd_trail_zeros(result); + if ((result->digits-tz)*2-1 <= v.digits) { + _mpd_qmul(&tmp, result, result, &varcontext, &workstatus); + if (workstatus&MPD_Errors) { + mpd_seterror(result, workstatus&MPD_Errors, status); + goto finish; + } + exact = (_mpd_cmp(&tmp, &v) == 0); + } + *status |= (workstatus&MPD_Errors); + + if (!exact && !mpd_isspecial(result) && !mpd_iszero(result)) { + _mpd_fix_sqrt(result, &v, &tmp, &varcontext, status); + if (mpd_isspecial(result)) goto finish; + *status |= (MPD_Rounded|MPD_Inexact); + } + + result->exp += adj; + if (exact) { + shift = ideal_exp - result->exp; + shift = (tz > shift) ? shift : tz; + if (shift > 0) { + mpd_qshiftr_inplace(result, shift); + result->exp += shift; + } + } + + +finish: + mpd_del(&v); + mpd_del(&vtmp); + mpd_del(&tmp); + varcontext.prec = ctx->prec; + mpd_qfinalize(result, &varcontext, status); +} + + +/******************************************************************************/ +/* Base conversions */ +/******************************************************************************/ + +/* + * Returns the space needed to represent an integer mpd_t in base 'base'. + * The result is undefined for non-integers. + * + * Max space needed: + * + * base^n >= 10^(digits+exp) + * n >= log10(10^(digits+exp))/log10(base) = (digits+exp) / log10(base) + */ +size_t +mpd_sizeinbase(mpd_t *a, uint32_t base) +{ + size_t x; + + assert(mpd_isinteger(a)); + if (mpd_iszero(a)) { + return 1; + } + + x = a->digits+a->exp; + +#ifdef CONFIG_64 + #ifdef USE_80BIT_LONG_DOUBLE + return (long double)x / log10(base) + 3; + #else + /* x > floor(((1ULL<<53)-3) * log10(2)) */ + if (x > 2711437152599294ULL) { + return SIZE_MAX; + } + return (double)x / log10(base) + 3; + #endif +#else /* CONFIG_32 */ +{ + double y = x / log10(base) + 3; + return (y > SIZE_MAX) ? SIZE_MAX : (size_t)y; +} +#endif +} + +/* + * Returns the space needed to import a base 'base' integer of length 'srclen'. + */ +static inline mpd_ssize_t +_mpd_importsize(size_t srclen, uint32_t base) +{ +#if SIZE_MAX == UINT64_MAX + #ifdef USE_80BIT_LONG_DOUBLE + long double x = (long double)srclen * (log10(base)/MPD_RDIGITS) + 3; + #else + double x; + if (srclen > (1ULL<<53)) { + return MPD_SSIZE_MAX; + } + x = (double)srclen * (log10(base)/MPD_RDIGITS) + 3; + #endif +#else + double x = srclen * (log10(base)/MPD_RDIGITS) + 3; +#endif + return (x > MPD_MAXIMPORT) ? MPD_SSIZE_MAX : (mpd_ssize_t)x; +} + + +static inline size_t +_to_base_u16(uint16_t *w, size_t wlen, mpd_uint_t wbase, + mpd_uint_t *u, mpd_ssize_t ulen) +{ + size_t n = 0; + + assert(wlen > 0 && ulen > 0); + + do { + w[n++] = (uint16_t)_mpd_shortdiv(u, u, ulen, wbase); + /* ulen will be at least 1. u[ulen-1] can only be zero if ulen == 1 */ + ulen = _mpd_real_size(u, ulen); + + } while (u[ulen-1] != 0 && n < wlen); + + /* proper termination condition */ + assert(u[ulen-1] == 0); + + return n; +} + +static inline void +_from_base_u16(mpd_uint_t *w, mpd_ssize_t wlen, + const mpd_uint_t *u, size_t ulen, uint32_t ubase) +{ + mpd_ssize_t m = 1; + mpd_uint_t carry; + + assert(wlen > 0 && ulen > 0); + + w[0] = u[--ulen]; + while (--ulen != SIZE_MAX && m < wlen) { + _mpd_shortmul(w, w, m, ubase); + m = _mpd_real_size(w, m+1); + carry = _mpd_shortadd(w, m, u[ulen]); + if (carry) w[m++] = carry; + } + + /* proper termination condition */ + assert(ulen == SIZE_MAX); +} + +/* target base wbase <= source base ubase */ +static inline size_t +_baseconv_to_smaller(uint32_t *w, size_t wlen, mpd_uint_t wbase, + mpd_uint_t *u, mpd_ssize_t ulen, mpd_uint_t ubase) +{ + size_t n = 0; + + assert(wlen > 0 && ulen > 0); + + do { + w[n++] = (uint32_t)_mpd_shortdiv_b(u, u, ulen, wbase, ubase); + /* ulen will be at least 1. u[ulen-1] can only be zero if ulen == 1 */ + ulen = _mpd_real_size(u, ulen); + + } while (u[ulen-1] != 0 && n < wlen); + + /* proper termination condition */ + assert(u[ulen-1] == 0); + + return n; +} + +/* target base wbase >= source base ubase */ +static inline void +_baseconv_to_larger(mpd_uint_t *w, mpd_ssize_t wlen, mpd_uint_t wbase, + const mpd_uint_t *u, size_t ulen, mpd_uint_t ubase) +{ + mpd_ssize_t m = 1; + mpd_uint_t carry; + + assert(wlen > 0 && ulen > 0); + + w[0] = u[--ulen]; + while (--ulen != SIZE_MAX && m < wlen) { + _mpd_shortmul_b(w, w, m, ubase, wbase); + m = _mpd_real_size(w, m+1); + carry = _mpd_shortadd_b(w, m, u[ulen], wbase); + if (carry) w[m++] = carry; + } + + /* proper termination condition */ + assert(ulen == SIZE_MAX); +} + + +/* + * Converts an integer mpd_t to a multiprecision integer with + * base <= UINT16_MAX+1. The least significant word of the result + * is rdata[0]. + */ +size_t +mpd_qexport_u16(uint16_t *rdata, size_t rlen, uint32_t rbase, + const mpd_t *src, uint32_t *status) +{ + mpd_t *tsrc; + size_t n; + + assert(rbase <= (1U<<16)); + assert(rlen <= SIZE_MAX/(sizeof *rdata)); + + if (mpd_isspecial(src) || !_mpd_isint(src)) { + *status |= MPD_Invalid_operation; + return SIZE_MAX; + } + + memset(rdata, 0, rlen * (sizeof *rdata)); + + if (mpd_iszero(src)) { + return 1; + } + + if ((tsrc = mpd_qnew()) == NULL) { + *status |= MPD_Malloc_error; + return SIZE_MAX; + } + + if (src->exp >= 0) { + if (!mpd_qshiftl(tsrc, src, src->exp, status)) { + mpd_del(tsrc); + return SIZE_MAX; + } + } + else { + if (mpd_qshiftr(tsrc, src, -src->exp, status) == MPD_UINT_MAX) { + mpd_del(tsrc); + return SIZE_MAX; + } + } + + n = _to_base_u16(rdata, rlen, rbase, tsrc->data, tsrc->len); + + mpd_del(tsrc); + return n; +} + +/* + * Converts an integer mpd_t to a multiprecision integer with + * base <= UINT32_MAX. The least significant word of the result + * is rdata[0]. + */ +size_t +mpd_qexport_u32(uint32_t *rdata, size_t rlen, uint32_t rbase, + const mpd_t *src, uint32_t *status) +{ + mpd_t *tsrc; + size_t n; + + if (mpd_isspecial(src) || !_mpd_isint(src)) { + *status |= MPD_Invalid_operation; + return SIZE_MAX; + } +#if MPD_SIZE_MAX < SIZE_MAX + if (rlen > MPD_SSIZE_MAX) { + *status |= MPD_Invalid_operation; + return SIZE_MAX; + } +#endif + + assert(rlen <= SIZE_MAX/(sizeof *rdata)); + memset(rdata, 0, rlen * (sizeof *rdata)); + + if (mpd_iszero(src)) { + return 1; + } + + if ((tsrc = mpd_qnew()) == NULL) { + *status |= MPD_Malloc_error; + return SIZE_MAX; + } + + if (src->exp >= 0) { + if (!mpd_qshiftl(tsrc, src, src->exp, status)) { + mpd_del(tsrc); + return SIZE_MAX; + } + } + else { + if (mpd_qshiftr(tsrc, src, -src->exp, status) == MPD_UINT_MAX) { + mpd_del(tsrc); + return SIZE_MAX; + } + } + +#ifdef CONFIG_64 + n = _baseconv_to_smaller(rdata, rlen, rbase, + tsrc->data, tsrc->len, MPD_RADIX); +#else + if (rbase <= MPD_RADIX) { + n = _baseconv_to_smaller(rdata, rlen, rbase, + tsrc->data, tsrc->len, MPD_RADIX); + } + else { + _baseconv_to_larger(rdata, (mpd_ssize_t)rlen, rbase, + tsrc->data, tsrc->len, MPD_RADIX); + n = _mpd_real_size(rdata, (mpd_ssize_t)rlen); + } +#endif + + mpd_del(tsrc); + return n; +} + + +/* + * Converts a multiprecision integer with base <= UINT16_MAX+1 to an mpd_t. + * The least significant word of the source is srcdata[0]. + */ +void +mpd_qimport_u16(mpd_t *result, + const uint16_t *srcdata, size_t srclen, + uint8_t srcsign, uint32_t srcbase, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t *usrc; /* uint16_t src copied to an mpd_uint_t array */ + mpd_ssize_t rlen; /* length of the result */ + size_t n = 0; + + assert(srclen > 0); + assert(srcbase <= (1U<<16)); + + if ((rlen = _mpd_importsize(srclen, srcbase)) == MPD_SSIZE_MAX) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (srclen > MPD_SIZE_MAX/(sizeof *usrc)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if ((usrc = mpd_alloc((mpd_size_t)srclen, sizeof *usrc)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + for (n = 0; n < srclen; n++) { + usrc[n] = srcdata[n]; + } + + /* result->data is initialized to zero */ + if (!mpd_qresize_zero(result, rlen, status)) { + goto finish; + } + + _from_base_u16(result->data, rlen, usrc, srclen, srcbase); + + mpd_set_flags(result, srcsign); + result->exp = 0; + result->len = _mpd_real_size(result->data, rlen); + mpd_setdigits(result); + + mpd_qresize(result, result->len, status); + mpd_qfinalize(result, ctx, status); + + +finish: + mpd_free(usrc); +} + +/* + * Converts a multiprecision integer with base <= UINT32_MAX to an mpd_t. + * The least significant word of the source is srcdata[0]. + */ +void +mpd_qimport_u32(mpd_t *result, + const uint32_t *srcdata, size_t srclen, + uint8_t srcsign, uint32_t srcbase, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t *usrc; /* uint32_t src copied to an mpd_uint_t array */ + mpd_ssize_t rlen; /* length of the result */ + size_t n = 0; + + assert(srclen > 0); + + if ((rlen = _mpd_importsize(srclen, srcbase)) == MPD_SSIZE_MAX) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (srclen > MPD_SIZE_MAX/(sizeof *usrc)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if ((usrc = mpd_alloc((mpd_size_t)srclen, sizeof *usrc)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + for (n = 0; n < srclen; n++) { + usrc[n] = srcdata[n]; + } + + /* result->data is initialized to zero */ + if (!mpd_qresize_zero(result, rlen, status)) { + goto finish; + } + +#ifdef CONFIG_64 + _baseconv_to_larger(result->data, rlen, MPD_RADIX, + usrc, srclen, srcbase); +#else + if (srcbase <= MPD_RADIX) { + _baseconv_to_larger(result->data, rlen, MPD_RADIX, + usrc, srclen, srcbase); + } + else { + _baseconv_to_smaller(result->data, rlen, MPD_RADIX, + usrc, (mpd_ssize_t)srclen, srcbase); + } +#endif + + mpd_set_flags(result, srcsign); + result->exp = 0; + result->len = _mpd_real_size(result->data, rlen); + mpd_setdigits(result); + + mpd_qresize(result, result->len, status); + mpd_qfinalize(result, ctx, status); + + +finish: + mpd_free(usrc); +} + + + diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/mpdecimal.h @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef MPDECIMAL_H +#define MPDECIMAL_H + + +#ifdef __cplusplus +extern "C" { +#define __STDC_LIMIT_MACROS +#endif + + +#ifndef _MSC_VER + #include "pyconfig.h" +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #include "vccompat.h" + #ifndef UNUSED + #define UNUSED + #endif + #define EXTINLINE extern inline +#else + #ifdef HAVE_STDINT_H + #include + #endif + #ifdef HAVE_INTTYPES_H + #include + #endif + #ifndef __GNUC_STDC_INLINE__ + #define __GNUC_STDC_INLINE__ + #endif + #if defined(__GNUC__) && !defined(__INTEL_COMPILER) + #define UNUSED __attribute__((unused)) + #else + #define UNUSED + #endif + #define EXTINLINE +#endif + + +#if !defined(LEGACY_COMPILER) + #if !defined(UINT64_MAX) + /* The following #error is just a warning. If the compiler indeed does + * not have uint64_t, it is perfectly safe to comment out the #error. */ + #error "Warning: Compiler without uint64_t. Comment out this line." + #define LEGACY_COMPILER + #endif +#endif + + +/******************************************************************************/ +/* Configuration */ +/******************************************************************************/ + +#if defined(UNIVERSAL) + #if defined(CONFIG_64) || defined(CONFIG_32) + #error "cannot use CONFIG_64 or CONFIG_32 with UNIVERSAL." + #endif + #if defined(__ppc__) + #define CONFIG_32 + #define ANSI + #elif defined(__ppc64__) + #define CONFIG_64 + #define ANSI + #elif defined(__i386__) + #define CONFIG_32 + #define ANSI + #elif defined(__x86_64__) + #define CONFIG_64 + #define ASM + #else + #error "unknown architecture for universal build." + #endif +#endif + + +/* BEGIN CONFIG_64 */ +#if defined(CONFIG_64) +/* types for modular and base arithmetic */ +#define MPD_UINT_MAX UINT64_MAX +#define MPD_BITS_PER_UINT 64 +typedef uint64_t mpd_uint_t; /* unsigned mod type */ + +#define MPD_SIZE_MAX SIZE_MAX +typedef size_t mpd_size_t; /* unsigned size type */ + +/* type for exp, digits, len, prec */ +#define MPD_SSIZE_MAX INT64_MAX +#define MPD_SSIZE_MIN INT64_MIN +typedef int64_t mpd_ssize_t; +#define _mpd_strtossize strtoll + +/* decimal arithmetic */ +#define MPD_RADIX 10000000000000000000ULL /* 10**19 */ +#define MPD_RDIGITS 19 +#define MPD_MAX_POW10 19 +#define MPD_EXPDIGITS 19 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */ + +#define MPD_MAXTRANSFORM_2N 4294967296ULL /* 2**32 */ +#define MPD_MAX_PREC 999999999999999999LL +#define MPD_MAX_PREC_LOG2 64 +#define MPD_ELIMIT 1000000000000000000LL +#define MPD_MAX_EMAX 999999999999999999LL /* ELIMIT-1 */ +#define MPD_MIN_EMIN (-999999999999999999LL) /* -EMAX */ +#define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1)) +#define MPD_EXP_INF 2000000000000000001LL +#define MPD_EXP_CLAMP (-4000000000000000001LL) +#define MPD_MAXIMPORT 105263157894736842L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */ + +/* conversion specifiers */ +#define PRI_mpd_uint_t PRIu64 +#define PRI_mpd_ssize_t PRIi64 +/* END CONFIG_64 */ + + +/* BEGIN CONFIG_32 */ +#elif defined(CONFIG_32) +/* types for modular and base arithmetic */ +#define MPD_UINT_MAX UINT32_MAX +#define MPD_BITS_PER_UINT 32 +typedef uint32_t mpd_uint_t; /* unsigned mod type */ + +#ifndef LEGACY_COMPILER +#define MPD_UUINT_MAX UINT64_MAX +typedef uint64_t mpd_uuint_t; /* double width unsigned mod type */ +#endif + +#define MPD_SIZE_MAX SIZE_MAX +typedef size_t mpd_size_t; /* unsigned size type */ + +/* type for dec->len, dec->exp, ctx->prec */ +#define MPD_SSIZE_MAX INT32_MAX +#define MPD_SSIZE_MIN INT32_MIN +typedef int32_t mpd_ssize_t; +#define _mpd_strtossize strtol + +/* decimal arithmetic */ +#define MPD_RADIX 1000000000UL /* 10**9 */ +#define MPD_RDIGITS 9 +#define MPD_MAX_POW10 9 +#define MPD_EXPDIGITS 10 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */ + +#define MPD_MAXTRANSFORM_2N 33554432UL /* 2**25 */ +#define MPD_MAX_PREC 425000000L +#define MPD_MAX_PREC_LOG2 32 +#define MPD_ELIMIT 425000001L +#define MPD_MAX_EMAX 425000000L /* ELIMIT-1 */ +#define MPD_MIN_EMIN (-425000000L) /* -EMAX */ +#define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1)) +#define MPD_EXP_INF 1000000001L /* allows for emax=999999999 in the tests */ +#define MPD_EXP_CLAMP (-2000000001L) /* allows for emin=-999999999 in the tests */ +#define MPD_MAXIMPORT 94444445L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */ + +/* conversion specifiers */ +#define PRI_mpd_uint_t PRIu32 +#define PRI_mpd_ssize_t PRIi32 +/* END CONFIG_32 */ + +#else + #error "define CONFIG_64 or CONFIG_32" +#endif +/* END CONFIG */ + + +#if MPD_SIZE_MAX != MPD_UINT_MAX + #error "unsupported platform: need mpd_size_t == mpd_uint_t" +#endif + + +/******************************************************************************/ +/* Context */ +/******************************************************************************/ + +enum { + MPD_ROUND_UP, /* round away from 0 */ + MPD_ROUND_DOWN, /* round toward 0 (truncate) */ + MPD_ROUND_CEILING, /* round toward +infinity */ + MPD_ROUND_FLOOR, /* round toward -infinity */ + MPD_ROUND_HALF_UP, /* 0.5 is rounded up */ + MPD_ROUND_HALF_DOWN, /* 0.5 is rounded down */ + MPD_ROUND_HALF_EVEN, /* 0.5 is rounded to even */ + MPD_ROUND_05UP, /* round zero or five away from 0 */ + MPD_ROUND_TRUNC, /* truncate, but set infinity */ + MPD_ROUND_GUARD +}; + +enum { MPD_CLAMP_DEFAULT, MPD_CLAMP_IEEE_754, MPD_CLAMP_GUARD }; + +extern const char *mpd_round_string[MPD_ROUND_GUARD]; +extern const char *mpd_clamp_string[MPD_CLAMP_GUARD]; + + +typedef struct { + mpd_ssize_t prec; /* precision */ + mpd_ssize_t emax; /* max positive exp */ + mpd_ssize_t emin; /* min negative exp */ + uint32_t traps; /* status events that should be trapped */ + uint32_t status; /* status flags */ + uint32_t newtrap; /* set by mpd_addstatus_raise() */ + int round; /* rounding mode */ + int clamp; /* clamp mode */ + int allcr; /* all functions correctly rounded */ +} mpd_context_t; + + +/* Status flags */ +#define MPD_Clamped 0x00000001U +#define MPD_Conversion_syntax 0x00000002U +#define MPD_Division_by_zero 0x00000004U +#define MPD_Division_impossible 0x00000008U +#define MPD_Division_undefined 0x00000010U +#define MPD_Fpu_error 0x00000020U +#define MPD_Inexact 0x00000040U +#define MPD_Invalid_context 0x00000080U +#define MPD_Invalid_operation 0x00000100U +#define MPD_Malloc_error 0x00000200U +#define MPD_Not_implemented 0x00000400U +#define MPD_Overflow 0x00000800U +#define MPD_Rounded 0x00001000U +#define MPD_Subnormal 0x00002000U +#define MPD_Underflow 0x00004000U +#define MPD_Max_status (0x00008000U-1U) + +/* Conditions that result in an IEEE 754 exception */ +#define MPD_IEEE_Invalid_operation (MPD_Conversion_syntax | \ + MPD_Division_impossible | \ + MPD_Division_undefined | \ + MPD_Fpu_error | \ + MPD_Invalid_context | \ + MPD_Invalid_operation | \ + MPD_Malloc_error) \ + +/* Errors that require the result of an operation to be set to NaN */ +#define MPD_Errors (MPD_IEEE_Invalid_operation | \ + MPD_Division_by_zero) + +/* Default traps */ +#define MPD_Traps (MPD_IEEE_Invalid_operation | \ + MPD_Division_by_zero | \ + MPD_Overflow | \ + MPD_Underflow) + +/* Official name */ +#define MPD_Insufficient_storage MPD_Malloc_error + +/* IEEE 754 interchange format contexts */ +#define MPD_IEEE_CONTEXT_MAX_BITS 512 /* 16*(log2(MPD_MAX_EMAX / 3)-3) */ +#define MPD_DECIMAL32 32 +#define MPD_DECIMAL64 64 +#define MPD_DECIMAL128 128 + + +#define MPD_MINALLOC_MIN 2 +#define MPD_MINALLOC_MAX 64 +extern mpd_ssize_t MPD_MINALLOC; +extern void (* mpd_traphandler)(mpd_context_t *); +void mpd_dflt_traphandler(mpd_context_t *); + +void mpd_setminalloc(mpd_ssize_t n); +void mpd_init(mpd_context_t *ctx, mpd_ssize_t prec); + +void mpd_maxcontext(mpd_context_t *ctx); +void mpd_defaultcontext(mpd_context_t *ctx); +void mpd_basiccontext(mpd_context_t *ctx); +int mpd_ieee_context(mpd_context_t *ctx, int bits); + +mpd_ssize_t mpd_getprec(const mpd_context_t *ctx); +mpd_ssize_t mpd_getemax(const mpd_context_t *ctx); +mpd_ssize_t mpd_getemin(const mpd_context_t *ctx); +int mpd_getround(const mpd_context_t *ctx); +uint32_t mpd_gettraps(const mpd_context_t *ctx); +uint32_t mpd_getstatus(const mpd_context_t *ctx); +int mpd_getclamp(const mpd_context_t *ctx); +int mpd_getcr(const mpd_context_t *ctx); + +int mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec); +int mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax); +int mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin); +int mpd_qsetround(mpd_context_t *ctx, int newround); +int mpd_qsettraps(mpd_context_t *ctx, uint32_t flags); +int mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags); +int mpd_qsetclamp(mpd_context_t *ctx, int c); +int mpd_qsetcr(mpd_context_t *ctx, int c); +void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags); + + +/******************************************************************************/ +/* Decimal Arithmetic */ +/******************************************************************************/ + +/* mpd_t flags */ +#define MPD_POS ((uint8_t)0) +#define MPD_NEG ((uint8_t)1) +#define MPD_INF ((uint8_t)2) +#define MPD_NAN ((uint8_t)4) +#define MPD_SNAN ((uint8_t)8) +#define MPD_SPECIAL (MPD_INF|MPD_NAN|MPD_SNAN) +#define MPD_STATIC ((uint8_t)16) +#define MPD_STATIC_DATA ((uint8_t)32) +#define MPD_SHARED_DATA ((uint8_t)64) +#define MPD_CONST_DATA ((uint8_t)128) +#define MPD_DATAFLAGS (MPD_STATIC_DATA|MPD_SHARED_DATA|MPD_CONST_DATA) + +/* mpd_t */ +typedef struct { + uint8_t flags; + mpd_ssize_t exp; + mpd_ssize_t digits; + mpd_ssize_t len; + mpd_ssize_t alloc; + mpd_uint_t *data; +} mpd_t; + + +typedef unsigned char uchar; + + +/******************************************************************************/ +/* Quiet, thread-safe functions */ +/******************************************************************************/ + +/* format specification */ +typedef struct { + mpd_ssize_t min_width; /* minimum field width */ + mpd_ssize_t prec; /* fraction digits or significant digits */ + char type; /* conversion specifier */ + char align; /* alignment */ + char sign; /* sign printing/alignment */ + char fill[5]; /* fill character */ + const char *dot; /* decimal point */ + const char *sep; /* thousands separator */ + const char *grouping; /* grouping of digits */ +} mpd_spec_t; + +/* output to a string */ +char *mpd_to_sci(const mpd_t *dec, int fmt); +char *mpd_to_eng(const mpd_t *dec, int fmt); +mpd_ssize_t mpd_to_sci_size(char **res, const mpd_t *dec, int fmt); +mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt); +int mpd_validate_lconv(mpd_spec_t *spec); +int mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps); +char * mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status); +char *mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, uint32_t *status); + +#define MPD_NUM_FLAGS 15 +#define MPD_MAX_FLAG_STRING 208 +#define MPD_MAX_FLAG_LIST (MPD_MAX_FLAG_STRING+18) +#define MPD_MAX_SIGNAL_LIST 121 +int mpd_snprint_flags(char *dest, int nmemb, uint32_t flags); +int mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[]); +int mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[]); + +/* output to a file */ +void mpd_fprint(FILE *file, const mpd_t *dec); +void mpd_print(const mpd_t *dec); + +/* assignment from a string */ +void mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx, uint32_t *status); + +/* set to NaN with error flags */ +void mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status); +/* set a special with sign and type */ +void mpd_setspecial(mpd_t *dec, uint8_t sign, uint8_t type); +/* set coefficient to zero or all nines */ +void mpd_zerocoeff(mpd_t *result); +void mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); + +/* quietly assign a C integer type to an mpd_t */ +void mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); +#ifndef LEGACY_COMPILER +void mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); +#endif + +/* quietly assign a C integer type to an mpd_t with a static coefficient */ +void mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); + +/* quietly get a C integer type from an mpd_t */ +mpd_ssize_t mpd_qget_ssize(const mpd_t *dec, uint32_t *status); +mpd_uint_t mpd_qget_uint(const mpd_t *dec, uint32_t *status); +mpd_uint_t mpd_qabs_uint(const mpd_t *dec, uint32_t *status); + + +/* quiet functions */ +int mpd_qcheck_nan(mpd_t *nanresult, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +int mpd_qcheck_nans(mpd_t *nanresult, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); + +const char * mpd_class(const mpd_t *a, const mpd_context_t *ctx); + +int mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status); +mpd_t *mpd_qncopy(const mpd_t *a); +int mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status); +int mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status); +int mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status); + +void mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +int mpd_same_quantum(const mpd_t *a, const mpd_t *b); + +void mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +int mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); +mpd_uint_t mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); +mpd_uint_t mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n); +void mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx, uint32_t *status); + +int mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status); +int mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +int mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +int mpd_cmp_total(const mpd_t *a, const mpd_t *b); +int mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b); +int mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b); +int mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b); + +void mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); + +void mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); +void mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); +void mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qfma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_context_t *ctx, uint32_t *status); +void mpd_qpowmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, const mpd_context_t *ctx, uint32_t *status); +void mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status); +void mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); + + +size_t mpd_sizeinbase(mpd_t *a, uint32_t base); +void mpd_qimport_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, + uint8_t srcsign, uint32_t srcbase, + const mpd_context_t *ctx, uint32_t *status); +void mpd_qimport_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, + uint8_t srcsign, uint32_t srcbase, + const mpd_context_t *ctx, uint32_t *status); +size_t mpd_qexport_u16(uint16_t *rdata, size_t rlen, uint32_t base, + const mpd_t *src, uint32_t *status); +size_t mpd_qexport_u32(uint32_t *rdata, size_t rlen, uint32_t base, + const mpd_t *src, uint32_t *status); + + +/******************************************************************************/ +/* Signalling functions */ +/******************************************************************************/ + +char * mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx); +void mpd_import_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); +void mpd_import_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); +size_t mpd_export_u16(uint16_t *rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); +size_t mpd_export_u32(uint32_t *rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); +void mpd_finalize(mpd_t *result, mpd_context_t *ctx); +int mpd_check_nan(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +int mpd_check_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_set_string(mpd_t *result, const char *s, mpd_context_t *ctx); +void mpd_maxcoeff(mpd_t *result, mpd_context_t *ctx); +void mpd_sset_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); +void mpd_sset_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); +void mpd_sset_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); +void mpd_sset_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); +void mpd_set_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); +void mpd_set_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); +void mpd_set_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); +void mpd_set_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); +#ifndef LEGACY_COMPILER +void mpd_set_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); +void mpd_set_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); +#endif +mpd_ssize_t mpd_get_ssize(const mpd_t *a, mpd_context_t *ctx); +mpd_uint_t mpd_get_uint(const mpd_t *a, mpd_context_t *ctx); +mpd_uint_t mpd_abs_uint(const mpd_t *a, mpd_context_t *ctx); +void mpd_and(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_canonical(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_copy_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_copy_negate(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_copy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_invert(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_logb(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_or(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_rotate(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_scaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_shiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); +mpd_uint_t mpd_shiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); +void mpd_shiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); +void mpd_shift(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_xor(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +int mpd_cmp(const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +int mpd_compare(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +int mpd_compare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_add(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_add_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); +void mpd_add_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); +void mpd_add_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); +void mpd_add_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); +void mpd_sub(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_sub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); +void mpd_sub_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); +void mpd_sub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); +void mpd_sub_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); +void mpd_div(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_div_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); +void mpd_div_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); +void mpd_div_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); +void mpd_div_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); +void mpd_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_divint(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_exp(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_fma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, mpd_context_t *ctx); +void mpd_ln(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_log10(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_max(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_max_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_min(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_min_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_mul(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_mul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); +void mpd_mul_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); +void mpd_mul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); +void mpd_mul_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); +void mpd_next_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_next_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_next_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_pow(mpd_t *result, const mpd_t *base, const mpd_t *exp, mpd_context_t *ctx); +void mpd_powmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, mpd_context_t *ctx); +void mpd_quantize(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_rescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, mpd_context_t *ctx); +void mpd_reduce(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_rem(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_rem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_round_to_intx(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_round_to_int(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_trunc(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_floor(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_ceil(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_sqrt(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_invroot(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); + + +/******************************************************************************/ +/* Configuration specific */ +/******************************************************************************/ + +#ifdef CONFIG_64 +void mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); +int64_t mpd_qget_i64(const mpd_t *dec, uint32_t *status); +uint64_t mpd_qget_u64(const mpd_t *dec, uint32_t *status); + +void mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); + +void mpd_sset_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); +void mpd_sset_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); +int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx); +uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx); + +void mpd_add_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); +void mpd_add_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); +void mpd_sub_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); +void mpd_sub_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); +void mpd_div_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); +void mpd_div_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); +void mpd_mul_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); +void mpd_mul_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); +#else +int32_t mpd_qget_i32(const mpd_t *dec, uint32_t *status); +uint32_t mpd_qget_u32(const mpd_t *dec, uint32_t *status); +int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx); +uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx); +#endif + + +/******************************************************************************/ +/* Get attributes of a decimal */ +/******************************************************************************/ + +EXTINLINE mpd_ssize_t mpd_adjexp(const mpd_t *dec); +EXTINLINE mpd_ssize_t mpd_etiny(const mpd_context_t *ctx); +EXTINLINE mpd_ssize_t mpd_etop(const mpd_context_t *ctx); +EXTINLINE mpd_uint_t mpd_msword(const mpd_t *dec); +EXTINLINE int mpd_word_digits(mpd_uint_t word); +/* most significant digit of a word */ +EXTINLINE mpd_uint_t mpd_msd(mpd_uint_t word); +/* least significant digit of a word */ +EXTINLINE mpd_uint_t mpd_lsd(mpd_uint_t word); +/* coefficient size needed to store 'digits' */ +EXTINLINE mpd_ssize_t mpd_digits_to_size(mpd_ssize_t digits); +/* number of digits in the exponent, undefined for MPD_SSIZE_MIN */ +EXTINLINE int mpd_exp_digits(mpd_ssize_t exp); +EXTINLINE int mpd_iscanonical(const mpd_t *dec UNUSED); +EXTINLINE int mpd_isfinite(const mpd_t *dec); +EXTINLINE int mpd_isinfinite(const mpd_t *dec); +EXTINLINE int mpd_isinteger(const mpd_t *dec); +EXTINLINE int mpd_isnan(const mpd_t *dec); +EXTINLINE int mpd_isnegative(const mpd_t *dec); +EXTINLINE int mpd_ispositive(const mpd_t *dec); +EXTINLINE int mpd_isqnan(const mpd_t *dec); +EXTINLINE int mpd_issigned(const mpd_t *dec); +EXTINLINE int mpd_issnan(const mpd_t *dec); +EXTINLINE int mpd_isspecial(const mpd_t *dec); +EXTINLINE int mpd_iszero(const mpd_t *dec); +/* undefined for special numbers */ +EXTINLINE int mpd_iszerocoeff(const mpd_t *dec); +EXTINLINE int mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx); +EXTINLINE int mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx); +/* odd word */ +EXTINLINE int mpd_isoddword(mpd_uint_t word); +/* odd coefficient */ +EXTINLINE int mpd_isoddcoeff(const mpd_t *dec); +/* odd decimal, only defined for integers */ +int mpd_isodd(const mpd_t *dec); +/* even decimal, only defined for integers */ +int mpd_iseven(const mpd_t *dec); +/* 0 if dec is positive, 1 if dec is negative */ +EXTINLINE uint8_t mpd_sign(const mpd_t *dec); +/* 1 if dec is positive, -1 if dec is negative */ +EXTINLINE int mpd_arith_sign(const mpd_t *dec); +EXTINLINE long mpd_radix(void); +EXTINLINE int mpd_isdynamic(mpd_t *dec); +EXTINLINE int mpd_isstatic(mpd_t *dec); +EXTINLINE int mpd_isdynamic_data(mpd_t *dec); +EXTINLINE int mpd_isstatic_data(mpd_t *dec); +EXTINLINE int mpd_isshared_data(mpd_t *dec); +EXTINLINE int mpd_isconst_data(mpd_t *dec); +EXTINLINE mpd_ssize_t mpd_trail_zeros(const mpd_t *dec); + + +/******************************************************************************/ +/* Set attributes of a decimal */ +/******************************************************************************/ + +/* set number of decimal digits in the coefficient */ +EXTINLINE void mpd_setdigits(mpd_t *result); +EXTINLINE void mpd_set_sign(mpd_t *result, uint8_t sign); +/* copy sign from another decimal */ +EXTINLINE void mpd_signcpy(mpd_t *result, mpd_t *a); +EXTINLINE void mpd_set_infinity(mpd_t *result); +EXTINLINE void mpd_set_qnan(mpd_t *result); +EXTINLINE void mpd_set_snan(mpd_t *result); +EXTINLINE void mpd_set_negative(mpd_t *result); +EXTINLINE void mpd_set_positive(mpd_t *result); +EXTINLINE void mpd_set_dynamic(mpd_t *result); +EXTINLINE void mpd_set_static(mpd_t *result); +EXTINLINE void mpd_set_dynamic_data(mpd_t *result); +EXTINLINE void mpd_set_static_data(mpd_t *result); +EXTINLINE void mpd_set_shared_data(mpd_t *result); +EXTINLINE void mpd_set_const_data(mpd_t *result); +EXTINLINE void mpd_clear_flags(mpd_t *result); +EXTINLINE void mpd_set_flags(mpd_t *result, uint8_t flags); +EXTINLINE void mpd_copy_flags(mpd_t *result, const mpd_t *a); + + +/******************************************************************************/ +/* Error Macros */ +/******************************************************************************/ + +#define mpd_err_fatal(...) \ + do {fprintf(stderr, "%s:%d: error: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ + exit(1); \ + } while (0) +#define mpd_err_warn(...) \ + do {fprintf(stderr, "%s:%d: warning: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ + } while (0) + + +/******************************************************************************/ +/* Memory handling */ +/******************************************************************************/ + +extern void *(* mpd_mallocfunc)(size_t size); +extern void *(* mpd_callocfunc)(size_t nmemb, size_t size); +extern void *(* mpd_reallocfunc)(void *ptr, size_t size); +extern void (* mpd_free)(void *ptr); + +void *mpd_callocfunc_em(size_t nmemb, size_t size); + +void *mpd_alloc(mpd_size_t nmemb, mpd_size_t size); +void *mpd_calloc(mpd_size_t nmemb, mpd_size_t size); +void *mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err); +void *mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size); + +mpd_t *mpd_qnew(void); +mpd_t *mpd_new(mpd_context_t *ctx); +mpd_t *mpd_qnew_size(mpd_ssize_t size); +void mpd_del(mpd_t *dec); + +void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len); +int mpd_qresize(mpd_t *result, mpd_ssize_t size, uint32_t *status); +int mpd_qresize_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status); +void mpd_minalloc(mpd_t *result); + +int mpd_resize(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx); +int mpd_resize_zero(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx); + + +#ifdef __cplusplus +} /* END extern "C" */ +#endif + + +#endif /* MPDECIMAL_H */ + + + diff --git a/Modules/_decimal/libmpdec/numbertheory.c b/Modules/_decimal/libmpdec/numbertheory.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/numbertheory.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include "bits.h" +#include "umodarith.h" +#include "numbertheory.h" + + +/* Bignum: Initialize the Number Theoretic Transform. */ + + +/* + * Return the nth root of unity in F(p). This corresponds to e**((2*pi*i)/n) + * in the Fourier transform. We have w**n == 1 (mod p). + * n := transform length. + * sign := -1 for forward transform, 1 for backward transform. + * modnum := one of {P1, P2, P3}. + */ +mpd_uint_t +_mpd_getkernel(mpd_uint_t n, int sign, int modnum) +{ + mpd_uint_t umod, p, r, xi; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + + SETMODULUS(modnum); + r = mpd_roots[modnum]; /* primitive root of F(p) */ + p = umod; + xi = (p-1) / n; + + if (sign == -1) + return POWMOD(r, (p-1-xi)); + else + return POWMOD(r, xi); +} + +/* + * Initialize and return transform parameters. + * n := transform length. + * sign := -1 for forward transform, 1 for backward transform. + * modnum := one of {P1, P2, P3}. + */ +struct fnt_params * +_mpd_init_fnt_params(mpd_size_t n, int sign, int modnum) +{ + struct fnt_params *tparams; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t kernel, w; + mpd_uint_t i; + mpd_size_t nhalf; + + assert(ispower2(n)); + assert(sign == -1 || sign == 1); + assert(P1 <= modnum && modnum <= P3); + + nhalf = n/2; + tparams = mpd_sh_alloc(sizeof *tparams, nhalf, sizeof (mpd_uint_t)); + if (tparams == NULL) { + return NULL; + } + + SETMODULUS(modnum); + kernel = _mpd_getkernel(n, sign, modnum); + + tparams->modnum = modnum; + tparams->modulus = umod; + tparams->kernel = kernel; + + /* wtable[] := w**0, w**1, ..., w**(nhalf-1) */ + w = 1; + for (i = 0; i < nhalf; i++) { + tparams->wtable[i] = w; + w = MULMOD(w, kernel); + } + + return tparams; +} + +/* Initialize wtable of size three. */ +void +_mpd_init_w3table(mpd_uint_t w3table[3], int sign, int modnum) +{ + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t kernel; + + SETMODULUS(modnum); + kernel = _mpd_getkernel(3, sign, modnum); + + w3table[0] = 1; + w3table[1] = kernel; + w3table[2] = POWMOD(kernel, 2); +} + + diff --git a/Modules/_decimal/libmpdec/numbertheory.h b/Modules/_decimal/libmpdec/numbertheory.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/numbertheory.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef NUMBER_THEORY_H +#define NUMBER_THEORY_H + + +#include "constants.h" +#include "mpdecimal.h" + + +/* transform parameters */ +struct fnt_params { + int modnum; + mpd_uint_t modulus; + mpd_uint_t kernel; + mpd_uint_t wtable[]; +}; + + +mpd_uint_t _mpd_getkernel(mpd_uint_t n, int sign, int modnum); +struct fnt_params *_mpd_init_fnt_params(mpd_size_t n, int sign, int modnum); +void _mpd_init_w3table(mpd_uint_t w3table[3], int sign, int modnum); + + +#ifdef PPRO +static inline void +ppro_setmodulus(int modnum, mpd_uint_t *umod, double *dmod, uint32_t dinvmod[3]) +{ + *dmod = *umod = mpd_moduli[modnum]; + dinvmod[0] = mpd_invmoduli[modnum][0]; + dinvmod[1] = mpd_invmoduli[modnum][1]; + dinvmod[2] = mpd_invmoduli[modnum][2]; +} +#else +static inline void +std_setmodulus(int modnum, mpd_uint_t *umod) +{ + *umod = mpd_moduli[modnum]; +} +#endif + + +#endif + + diff --git a/Modules/_decimal/libmpdec/sixstep.c b/Modules/_decimal/libmpdec/sixstep.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/sixstep.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include "bits.h" +#include "difradix2.h" +#include "numbertheory.h" +#include "transpose.h" +#include "umodarith.h" +#include "sixstep.h" + + +/* Bignum: Cache efficient Matrix Fourier Transform for arrays of the + form 2**n (See literature/six-step.txt). */ + + +/* forward transform with sign = -1 */ +int +six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + struct fnt_params *tparams; + mpd_size_t log2n, C, R; + mpd_uint_t kernel; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t *x, w0, w1, wstep; + mpd_size_t i, k; + + + assert(ispower2(n)); + assert(n >= 16); + assert(n <= MPD_MAXTRANSFORM_2N); + + log2n = mpd_bsr(n); + C = ((mpd_size_t)1) << (log2n / 2); /* number of columns */ + R = ((mpd_size_t)1) << (log2n - (log2n / 2)); /* number of rows */ + + + /* Transpose the matrix. */ + if (!transpose_pow2(a, R, C)) { + return 0; + } + + /* Length R transform on the rows. */ + if ((tparams = _mpd_init_fnt_params(R, -1, modnum)) == NULL) { + return 0; + } + for (x = a; x < a+n; x += R) { + fnt_dif2(x, R, tparams); + } + + /* Transpose the matrix. */ + if (!transpose_pow2(a, C, R)) { + mpd_free(tparams); + return 0; + } + + /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */ + SETMODULUS(modnum); + kernel = _mpd_getkernel(n, -1, modnum); + for (i = 1; i < R; i++) { + w0 = 1; /* r**(i*0): initial value for k=0 */ + w1 = POWMOD(kernel, i); /* r**(i*1): initial value for k=1 */ + wstep = MULMOD(w1, w1); /* r**(2*i) */ + for (k = 0; k < C; k += 2) { + mpd_uint_t x0 = a[i*C+k]; + mpd_uint_t x1 = a[i*C+k+1]; + MULMOD2(&x0, w0, &x1, w1); + MULMOD2C(&w0, &w1, wstep); /* r**(i*(k+2)) = r**(i*k) * r**(2*i) */ + a[i*C+k] = x0; + a[i*C+k+1] = x1; + } + } + + /* Length C transform on the rows. */ + if (C != R) { + mpd_free(tparams); + if ((tparams = _mpd_init_fnt_params(C, -1, modnum)) == NULL) { + return 0; + } + } + for (x = a; x < a+n; x += C) { + fnt_dif2(x, C, tparams); + } + mpd_free(tparams); + +#if 0 /* An unordered transform is sufficient for convolution. */ + /* Transpose the matrix. */ + if (!transpose_pow2(a, R, C)) { + return 0; + } +#endif + + return 1; +} + + +/* reverse transform, sign = 1 */ +int +inv_six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + struct fnt_params *tparams; + mpd_size_t log2n, C, R; + mpd_uint_t kernel; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t *x, w0, w1, wstep; + mpd_size_t i, k; + + + assert(ispower2(n)); + assert(n >= 16); + assert(n <= MPD_MAXTRANSFORM_2N); + + log2n = mpd_bsr(n); + C = ((mpd_size_t)1) << (log2n / 2); /* number of columns */ + R = ((mpd_size_t)1) << (log2n - (log2n / 2)); /* number of rows */ + + +#if 0 /* An unordered transform is sufficient for convolution. */ + /* Transpose the matrix, producing an R*C matrix. */ + if (!transpose_pow2(a, C, R)) { + return 0; + } +#endif + + /* Length C transform on the rows. */ + if ((tparams = _mpd_init_fnt_params(C, 1, modnum)) == NULL) { + return 0; + } + for (x = a; x < a+n; x += C) { + fnt_dif2(x, C, tparams); + } + + /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */ + SETMODULUS(modnum); + kernel = _mpd_getkernel(n, 1, modnum); + for (i = 1; i < R; i++) { + w0 = 1; + w1 = POWMOD(kernel, i); + wstep = MULMOD(w1, w1); + for (k = 0; k < C; k += 2) { + mpd_uint_t x0 = a[i*C+k]; + mpd_uint_t x1 = a[i*C+k+1]; + MULMOD2(&x0, w0, &x1, w1); + MULMOD2C(&w0, &w1, wstep); + a[i*C+k] = x0; + a[i*C+k+1] = x1; + } + } + + /* Transpose the matrix. */ + if (!transpose_pow2(a, R, C)) { + mpd_free(tparams); + return 0; + } + + /* Length R transform on the rows. */ + if (R != C) { + mpd_free(tparams); + if ((tparams = _mpd_init_fnt_params(R, 1, modnum)) == NULL) { + return 0; + } + } + for (x = a; x < a+n; x += R) { + fnt_dif2(x, R, tparams); + } + mpd_free(tparams); + + /* Transpose the matrix. */ + if (!transpose_pow2(a, C, R)) { + return 0; + } + + return 1; +} + + diff --git a/Modules/_decimal/libmpdec/sixstep.h b/Modules/_decimal/libmpdec/sixstep.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/sixstep.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef SIX_STEP_H +#define SIX_STEP_H + + +#include "mpdecimal.h" +#include + + +int six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); +int inv_six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); + + +#endif diff --git a/Modules/_decimal/libmpdec/transpose.c b/Modules/_decimal/libmpdec/transpose.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/transpose.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include +#include +#include "bits.h" +#include "constants.h" +#include "typearith.h" +#include "transpose.h" + + +#define BUFSIZE 4096 +#define SIDE 128 + + +/* Bignum: The transpose functions are used for very large transforms + in sixstep.c and fourstep.c. */ + + +/* Definition of the matrix transpose */ +void +std_trans(mpd_uint_t dest[], mpd_uint_t src[], mpd_size_t rows, mpd_size_t cols) +{ + mpd_size_t idest, isrc; + mpd_size_t r, c; + + for (r = 0; r < rows; r++) { + isrc = r * cols; + idest = r; + for (c = 0; c < cols; c++) { + dest[idest] = src[isrc]; + isrc += 1; + idest += rows; + } + } +} + +/* + * Swap half-rows of 2^n * (2*2^n) matrix. + * FORWARD_CYCLE: even/odd permutation of the halfrows. + * BACKWARD_CYCLE: reverse the even/odd permutation. + */ +static int +swap_halfrows_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols, int dir) +{ + mpd_uint_t buf1[BUFSIZE]; + mpd_uint_t buf2[BUFSIZE]; + mpd_uint_t *readbuf, *writebuf, *hp; + mpd_size_t *done, dbits; + mpd_size_t b = BUFSIZE, stride; + mpd_size_t hn, hmax; /* halfrow number */ + mpd_size_t m, r=0; + mpd_size_t offset; + mpd_size_t next; + + + assert(cols == mul_size_t(2, rows)); + + if (dir == FORWARD_CYCLE) { + r = rows; + } + else if (dir == BACKWARD_CYCLE) { + r = 2; + } + else { + abort(); /* GCOV_NOT_REACHED */ + } + + m = cols - 1; + hmax = rows; /* cycles start at odd halfrows */ + dbits = 8 * sizeof *done; + if ((done = mpd_calloc(hmax/(sizeof *done) + 1, sizeof *done)) == NULL) { + return 0; + } + + for (hn = 1; hn <= hmax; hn += 2) { + + if (done[hn/dbits] & mpd_bits[hn%dbits]) { + continue; + } + + readbuf = buf1; writebuf = buf2; + + for (offset = 0; offset < cols/2; offset += b) { + + stride = (offset + b < cols/2) ? b : cols/2-offset; + + hp = matrix + hn*cols/2; + memcpy(readbuf, hp+offset, stride*(sizeof *readbuf)); + pointerswap(&readbuf, &writebuf); + + next = mulmod_size_t(hn, r, m); + hp = matrix + next*cols/2; + + while (next != hn) { + + memcpy(readbuf, hp+offset, stride*(sizeof *readbuf)); + memcpy(hp+offset, writebuf, stride*(sizeof *writebuf)); + pointerswap(&readbuf, &writebuf); + + done[next/dbits] |= mpd_bits[next%dbits]; + + next = mulmod_size_t(next, r, m); + hp = matrix + next*cols/2; + + } + + memcpy(hp+offset, writebuf, stride*(sizeof *writebuf)); + + done[hn/dbits] |= mpd_bits[hn%dbits]; + } + } + + mpd_free(done); + return 1; +} + +/* In-place transpose of a square matrix */ +static inline void +squaretrans(mpd_uint_t *buf, mpd_size_t cols) +{ + mpd_uint_t tmp; + mpd_size_t idest, isrc; + mpd_size_t r, c; + + for (r = 0; r < cols; r++) { + c = r+1; + isrc = r*cols + c; + idest = c*cols + r; + for (c = r+1; c < cols; c++) { + tmp = buf[isrc]; + buf[isrc] = buf[idest]; + buf[idest] = tmp; + isrc += 1; + idest += cols; + } + } +} + +/* + * Transpose 2^n * 2^n matrix. For cache efficiency, the matrix is split into + * square blocks with side length 'SIDE'. First, the blocks are transposed, + * then a square tranposition is done on each individual block. + */ +static void +squaretrans_pow2(mpd_uint_t *matrix, mpd_size_t size) +{ + mpd_uint_t buf1[SIDE*SIDE]; + mpd_uint_t buf2[SIDE*SIDE]; + mpd_uint_t *to, *from; + mpd_size_t b = size; + mpd_size_t r, c; + mpd_size_t i; + + while (b > SIDE) b >>= 1; + + for (r = 0; r < size; r += b) { + + for (c = r; c < size; c += b) { + + from = matrix + r*size + c; + to = buf1; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += size; + to += b; + } + squaretrans(buf1, b); + + if (r == c) { + to = matrix + r*size + c; + from = buf1; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += b; + to += size; + } + continue; + } + else { + from = matrix + c*size + r; + to = buf2; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += size; + to += b; + } + squaretrans(buf2, b); + + to = matrix + c*size + r; + from = buf1; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += b; + to += size; + } + + to = matrix + r*size + c; + from = buf2; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += b; + to += size; + } + } + } + } + +} + +/* + * In-place transposition of a 2^n x 2^n or a 2^n x (2*2^n) + * or a (2*2^n) x 2^n matrix. + */ +int +transpose_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols) +{ + mpd_size_t size = mul_size_t(rows, cols); + + assert(ispower2(rows)); + assert(ispower2(cols)); + + if (cols == rows) { + squaretrans_pow2(matrix, rows); + } + else if (cols == mul_size_t(2, rows)) { + if (!swap_halfrows_pow2(matrix, rows, cols, FORWARD_CYCLE)) { + return 0; + } + squaretrans_pow2(matrix, rows); + squaretrans_pow2(matrix+(size/2), rows); + } + else if (rows == mul_size_t(2, cols)) { + squaretrans_pow2(matrix, cols); + squaretrans_pow2(matrix+(size/2), cols); + if (!swap_halfrows_pow2(matrix, cols, rows, BACKWARD_CYCLE)) { + return 0; + } + } + else { + abort(); /* GCOV_NOT_REACHED */ + } + + return 1; +} + + diff --git a/Modules/_decimal/libmpdec/transpose.h b/Modules/_decimal/libmpdec/transpose.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/transpose.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef TRANSPOSE_H +#define TRANSPOSE_H + + +#include "mpdecimal.h" +#include + + +enum {FORWARD_CYCLE, BACKWARD_CYCLE}; + + +void std_trans(mpd_uint_t dest[], mpd_uint_t src[], mpd_size_t rows, mpd_size_t cols); +int transpose_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols); +void transpose_3xpow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols); + + +static inline void pointerswap(mpd_uint_t **a, mpd_uint_t **b) +{ + mpd_uint_t *tmp; + + tmp = *b; + *b = *a; + *a = tmp; +} + + +#endif diff --git a/Modules/_decimal/libmpdec/typearith.h b/Modules/_decimal/libmpdec/typearith.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/typearith.h @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef TYPEARITH_H +#define TYPEARITH_H + + +#include "mpdecimal.h" + + +/*****************************************************************************/ +/* Low level native arithmetic on basic types */ +/*****************************************************************************/ + + +/** ------------------------------------------------------------ + ** Double width multiplication and division + ** ------------------------------------------------------------ + */ + +#if defined(CONFIG_64) +#if defined(ANSI) +#if defined(HAVE_UINT128_T) +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + __uint128_t hl; + + hl = (__uint128_t)a * b; + + *hi = hl >> 64; + *lo = (mpd_uint_t)hl; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + __uint128_t hl; + + hl = ((__uint128_t)hi<<64) + lo; + *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */ + *r = (mpd_uint_t)(hl - (__uint128_t)(*q) * d); +} +#else +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + uint32_t w[4], carry; + uint32_t ah, al, bh, bl; + uint64_t hl; + + ah = (uint32_t)(a>>32); al = (uint32_t)a; + bh = (uint32_t)(b>>32); bl = (uint32_t)b; + + hl = (uint64_t)al * bl; + w[0] = (uint32_t)hl; + carry = (uint32_t)(hl>>32); + + hl = (uint64_t)ah * bl + carry; + w[1] = (uint32_t)hl; + w[2] = (uint32_t)(hl>>32); + + hl = (uint64_t)al * bh + w[1]; + w[1] = (uint32_t)hl; + carry = (uint32_t)(hl>>32); + + hl = ((uint64_t)ah * bh + w[2]) + carry; + w[2] = (uint32_t)hl; + w[3] = (uint32_t)(hl>>32); + + *hi = ((uint64_t)w[3]<<32) + w[2]; + *lo = ((uint64_t)w[1]<<32) + w[0]; +} + +/* + * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt + * http://www.hackersdelight.org/permissions.htm: + * "You are free to use, copy, and distribute any of the code on this web + * site, whether modified by you or not. You need not give attribution." + * + * Slightly modified, comments are mine. + */ +static inline int +nlz(uint64_t x) +{ + int n; + + if (x == 0) return(64); + + n = 0; + if (x <= 0x00000000FFFFFFFF) {n = n +32; x = x <<32;} + if (x <= 0x0000FFFFFFFFFFFF) {n = n +16; x = x <<16;} + if (x <= 0x00FFFFFFFFFFFFFF) {n = n + 8; x = x << 8;} + if (x <= 0x0FFFFFFFFFFFFFFF) {n = n + 4; x = x << 4;} + if (x <= 0x3FFFFFFFFFFFFFFF) {n = n + 2; x = x << 2;} + if (x <= 0x7FFFFFFFFFFFFFFF) {n = n + 1;} + + return n; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0, + mpd_uint_t v) +{ + const mpd_uint_t b = 4294967296; + mpd_uint_t un1, un0, + vn1, vn0, + q1, q0, + un32, un21, un10, + rhat, t; + int s; + + assert(u1 < v); + + s = nlz(v); + v = v << s; + vn1 = v >> 32; + vn0 = v & 0xFFFFFFFF; + + t = (s == 0) ? 0 : u0 >> (64 - s); + un32 = (u1 << s) | t; + un10 = u0 << s; + + un1 = un10 >> 32; + un0 = un10 & 0xFFFFFFFF; + + q1 = un32 / vn1; + rhat = un32 - q1*vn1; +again1: + if (q1 >= b || q1*vn0 > b*rhat + un1) { + q1 = q1 - 1; + rhat = rhat + vn1; + if (rhat < b) goto again1; + } + + /* + * Before again1 we had: + * (1) q1*vn1 + rhat = un32 + * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1 + * + * The statements inside the if-clause do not change the value + * of the left-hand side of (2), and the loop is only exited + * if q1*vn0 <= rhat*b + un1, so: + * + * (3) q1*vn1*b + q1*vn0 <= un32*b + un1 + * (4) q1*v <= un32*b + un1 + * (5) 0 <= un32*b + un1 - q1*v + * + * By (5) we are certain that the possible add-back step from + * Knuth's algorithm D is never required. + * + * Since the final quotient is less than 2**64, the following + * must be true: + * + * (6) un32*b + un1 - q1*v <= UINT64_MAX + * + * This means that in the following line, the high words + * of un32*b and q1*v can be discarded without any effect + * on the result. + */ + un21 = un32*b + un1 - q1*v; + + q0 = un21 / vn1; + rhat = un21 - q0*vn1; +again2: + if (q0 >= b || q0*vn0 > b*rhat + un0) { + q0 = q0 - 1; + rhat = rhat + vn1; + if (rhat < b) goto again2; + } + + *q = q1*b + q0; + *r = (un21*b + un0 - q0*v) >> s; +} +#endif + +/* END ANSI */ +#elif defined(ASM) +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + mpd_uint_t h, l; + + asm ( "mulq %3\n\t" + : "=d" (h), "=a" (l) + : "%a" (a), "rm" (b) + : "cc" + ); + + *hi = h; + *lo = l; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + mpd_uint_t qq, rr; + + asm ( "divq %4\n\t" + : "=a" (qq), "=d" (rr) + : "a" (lo), "d" (hi), "rm" (d) + : "cc" + ); + + *q = qq; + *r = rr; +} +/* END GCC ASM */ +#elif defined(MASM) +#include +#pragma intrinsic(_umul128) + +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + *lo = _umul128(a, b, hi); +} + +void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d); + +/* END MASM (_MSC_VER) */ +#else + #error "need platform specific 128 bit multiplication and division" +#endif + +#define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d +static inline void +_mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp) +{ + assert(exp <= 19); + + if (exp <= 9) { + if (exp <= 4) { + switch (exp) { + case 0: *q = v; *r = 0; break; + case 1: DIVMOD(q, r, v, 10UL); break; + case 2: DIVMOD(q, r, v, 100UL); break; + case 3: DIVMOD(q, r, v, 1000UL); break; + case 4: DIVMOD(q, r, v, 10000UL); break; + } + } + else { + switch (exp) { + case 5: DIVMOD(q, r, v, 100000UL); break; + case 6: DIVMOD(q, r, v, 1000000UL); break; + case 7: DIVMOD(q, r, v, 10000000UL); break; + case 8: DIVMOD(q, r, v, 100000000UL); break; + case 9: DIVMOD(q, r, v, 1000000000UL); break; + } + } + } + else { + if (exp <= 14) { + switch (exp) { + case 10: DIVMOD(q, r, v, 10000000000ULL); break; + case 11: DIVMOD(q, r, v, 100000000000ULL); break; + case 12: DIVMOD(q, r, v, 1000000000000ULL); break; + case 13: DIVMOD(q, r, v, 10000000000000ULL); break; + case 14: DIVMOD(q, r, v, 100000000000000ULL); break; + } + } + else { + switch (exp) { + case 15: DIVMOD(q, r, v, 1000000000000000ULL); break; + case 16: DIVMOD(q, r, v, 10000000000000000ULL); break; + case 17: DIVMOD(q, r, v, 100000000000000000ULL); break; + case 18: DIVMOD(q, r, v, 1000000000000000000ULL); break; + case 19: DIVMOD(q, r, v, 10000000000000000000ULL); break; /* GCOV_NOT_REACHED */ + } + } + } +} + +/* END CONFIG_64 */ +#elif defined(CONFIG_32) +#if defined(ANSI) +#if !defined(LEGACY_COMPILER) +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + mpd_uuint_t hl; + + hl = (mpd_uuint_t)a * b; + + *hi = hl >> 32; + *lo = (mpd_uint_t)hl; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + mpd_uuint_t hl; + + hl = ((mpd_uuint_t)hi<<32) + lo; + *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */ + *r = (mpd_uint_t)(hl - (mpd_uuint_t)(*q) * d); +} +/* END ANSI + uint64_t */ +#else +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + uint16_t w[4], carry; + uint16_t ah, al, bh, bl; + uint32_t hl; + + ah = (uint16_t)(a>>16); al = (uint16_t)a; + bh = (uint16_t)(b>>16); bl = (uint16_t)b; + + hl = (uint32_t)al * bl; + w[0] = (uint16_t)hl; + carry = (uint16_t)(hl>>16); + + hl = (uint32_t)ah * bl + carry; + w[1] = (uint16_t)hl; + w[2] = (uint16_t)(hl>>16); + + hl = (uint32_t)al * bh + w[1]; + w[1] = (uint16_t)hl; + carry = (uint16_t)(hl>>16); + + hl = ((uint32_t)ah * bh + w[2]) + carry; + w[2] = (uint16_t)hl; + w[3] = (uint16_t)(hl>>16); + + *hi = ((uint32_t)w[3]<<16) + w[2]; + *lo = ((uint32_t)w[1]<<16) + w[0]; +} + +/* + * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt + * http://www.hackersdelight.org/permissions.htm: + * "You are free to use, copy, and distribute any of the code on this web + * site, whether modified by you or not. You need not give attribution." + * + * Slightly modified, comments are mine. + */ +static inline int +nlz(uint32_t x) +{ + int n; + + if (x == 0) return(32); + + n = 0; + if (x <= 0x0000FFFF) {n = n +16; x = x <<16;} + if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;} + if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;} + if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;} + if (x <= 0x7FFFFFFF) {n = n + 1;} + + return n; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0, + mpd_uint_t v) +{ + const mpd_uint_t b = 65536; + mpd_uint_t un1, un0, + vn1, vn0, + q1, q0, + un32, un21, un10, + rhat, t; + int s; + + assert(u1 < v); + + s = nlz(v); + v = v << s; + vn1 = v >> 16; + vn0 = v & 0xFFFF; + + t = (s == 0) ? 0 : u0 >> (32 - s); + un32 = (u1 << s) | t; + un10 = u0 << s; + + un1 = un10 >> 16; + un0 = un10 & 0xFFFF; + + q1 = un32 / vn1; + rhat = un32 - q1*vn1; +again1: + if (q1 >= b || q1*vn0 > b*rhat + un1) { + q1 = q1 - 1; + rhat = rhat + vn1; + if (rhat < b) goto again1; + } + + /* + * Before again1 we had: + * (1) q1*vn1 + rhat = un32 + * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1 + * + * The statements inside the if-clause do not change the value + * of the left-hand side of (2), and the loop is only exited + * if q1*vn0 <= rhat*b + un1, so: + * + * (3) q1*vn1*b + q1*vn0 <= un32*b + un1 + * (4) q1*v <= un32*b + un1 + * (5) 0 <= un32*b + un1 - q1*v + * + * By (5) we are certain that the possible add-back step from + * Knuth's algorithm D is never required. + * + * Since the final quotient is less than 2**32, the following + * must be true: + * + * (6) un32*b + un1 - q1*v <= UINT32_MAX + * + * This means that in the following line, the high words + * of un32*b and q1*v can be discarded without any effect + * on the result. + */ + un21 = un32*b + un1 - q1*v; + + q0 = un21 / vn1; + rhat = un21 - q0*vn1; +again2: + if (q0 >= b || q0*vn0 > b*rhat + un0) { + q0 = q0 - 1; + rhat = rhat + vn1; + if (rhat < b) goto again2; + } + + *q = q1*b + q0; + *r = (un21*b + un0 - q0*v) >> s; +} +#endif /* END ANSI + LEGACY_COMPILER */ + +/* END ANSI */ +#elif defined(ASM) +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + mpd_uint_t h, l; + + asm ( "mull %3\n\t" + : "=d" (h), "=a" (l) + : "%a" (a), "rm" (b) + : "cc" + ); + + *hi = h; + *lo = l; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + mpd_uint_t qq, rr; + + asm ( "divl %4\n\t" + : "=a" (qq), "=d" (rr) + : "a" (lo), "d" (hi), "rm" (d) + : "cc" + ); + + *q = qq; + *r = rr; +} +/* END GCC ASM */ +#elif defined(MASM) +static inline void __cdecl +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + mpd_uint_t h, l; + + __asm { + mov eax, a + mul b + mov h, edx + mov l, eax + } + + *hi = h; + *lo = l; +} + +static inline void __cdecl +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + mpd_uint_t qq, rr; + + __asm { + mov eax, lo + mov edx, hi + div d + mov qq, eax + mov rr, edx + } + + *q = qq; + *r = rr; +} +/* END MASM (_MSC_VER) */ +#else + #error "need platform specific 64 bit multiplication and division" +#endif + +#define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d +static inline void +_mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp) +{ + assert(exp <= 9); + + if (exp <= 4) { + switch (exp) { + case 0: *q = v; *r = 0; break; + case 1: DIVMOD(q, r, v, 10UL); break; + case 2: DIVMOD(q, r, v, 100UL); break; + case 3: DIVMOD(q, r, v, 1000UL); break; + case 4: DIVMOD(q, r, v, 10000UL); break; + } + } + else { + switch (exp) { + case 5: DIVMOD(q, r, v, 100000UL); break; + case 6: DIVMOD(q, r, v, 1000000UL); break; + case 7: DIVMOD(q, r, v, 10000000UL); break; + case 8: DIVMOD(q, r, v, 100000000UL); break; + case 9: DIVMOD(q, r, v, 1000000000UL); break; /* GCOV_NOT_REACHED */ + } + } +} +/* END CONFIG_32 */ + +/* NO CONFIG */ +#else + #error "define CONFIG_64 or CONFIG_32" +#endif /* CONFIG */ + + +static inline void +_mpd_div_word(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t d) +{ + *q = v / d; + *r = v - *q * d; +} + +static inline void +_mpd_idiv_word(mpd_ssize_t *q, mpd_ssize_t *r, mpd_ssize_t v, mpd_ssize_t d) +{ + *q = v / d; + *r = v - *q * d; +} + + +/** ------------------------------------------------------------ + ** Arithmetic with overflow checking + ** ------------------------------------------------------------ + */ + +/* The following macros do call exit() in case of an overflow. + If the library is used correctly (i.e. with valid context + parameters), such overflows cannot occur. The macros are used + as sanity checks in a couple of strategic places and should + be viewed as a handwritten version of gcc's -ftrapv option. */ + +static inline mpd_size_t +add_size_t(mpd_size_t a, mpd_size_t b) +{ + if (a > MPD_SIZE_MAX - b) { + mpd_err_fatal("add_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */ + } + return a + b; +} + +static inline mpd_size_t +sub_size_t(mpd_size_t a, mpd_size_t b) +{ + if (b > a) { + mpd_err_fatal("sub_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */ + } + return a - b; +} + +#if MPD_SIZE_MAX != MPD_UINT_MAX + #error "adapt mul_size_t() and mulmod_size_t()" +#endif + +static inline mpd_size_t +mul_size_t(mpd_size_t a, mpd_size_t b) +{ + mpd_uint_t hi, lo; + + _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b); + if (hi) { + mpd_err_fatal("mul_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */ + } + return lo; +} + +static inline mpd_size_t +add_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow) +{ + mpd_size_t ret; + + *overflow = 0; + ret = a + b; + if (ret < a) *overflow = 1; + return ret; +} + +static inline mpd_size_t +mul_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow) +{ + mpd_uint_t lo; + + _mpd_mul_words((mpd_uint_t *)overflow, &lo, (mpd_uint_t)a, + (mpd_uint_t)b); + return lo; +} + +static inline mpd_ssize_t +mod_mpd_ssize_t(mpd_ssize_t a, mpd_ssize_t m) +{ + mpd_ssize_t r = a % m; + return (r < 0) ? r + m : r; +} + +static inline mpd_size_t +mulmod_size_t(mpd_size_t a, mpd_size_t b, mpd_size_t m) +{ + mpd_uint_t hi, lo; + mpd_uint_t q, r; + + _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b); + _mpd_div_words(&q, &r, hi, lo, (mpd_uint_t)m); + + return r; +} + + +#endif /* TYPEARITH_H */ + + + diff --git a/Modules/_decimal/libmpdec/umodarith.h b/Modules/_decimal/libmpdec/umodarith.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/umodarith.h @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef UMODARITH_H +#define UMODARITH_H + + +#include "constants.h" +#include "mpdecimal.h" +#include "typearith.h" + + +/* Bignum: Low level routines for unsigned modular arithmetic. These are + used in the fast convolution functions for very large coefficients. */ + + +/**************************************************************************/ +/* ANSI modular arithmetic */ +/**************************************************************************/ + + +/* + * Restrictions: a < m and b < m + * ACL2 proof: umodarith.lisp: addmod-correct + */ +static inline mpd_uint_t +addmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t s; + + s = a + b; + s = (s < a) ? s - m : s; + s = (s >= m) ? s - m : s; + + return s; +} + +/* + * Restrictions: a < m and b < m + * ACL2 proof: umodarith.lisp: submod-2-correct + */ +static inline mpd_uint_t +submod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t d; + + d = a - b; + d = (a < b) ? d + m : d; + + return d; +} + +/* + * Restrictions: a < 2m and b < 2m + * ACL2 proof: umodarith.lisp: section ext-submod + */ +static inline mpd_uint_t +ext_submod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t d; + + a = (a >= m) ? a - m : a; + b = (b >= m) ? b - m : b; + + d = a - b; + d = (a < b) ? d + m : d; + + return d; +} + +/* + * Reduce double word modulo m. + * Restrictions: m != 0 + * ACL2 proof: umodarith.lisp: section dw-reduce + */ +static inline mpd_uint_t +dw_reduce(mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t m) +{ + mpd_uint_t r1, r2, w; + + _mpd_div_word(&w, &r1, hi, m); + _mpd_div_words(&w, &r2, r1, lo, m); + + return r2; +} + +/* + * Subtract double word from a. + * Restrictions: a < m + * ACL2 proof: umodarith.lisp: section dw-submod + */ +static inline mpd_uint_t +dw_submod(mpd_uint_t a, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t m) +{ + mpd_uint_t d, r; + + r = dw_reduce(hi, lo, m); + d = a - r; + d = (a < r) ? d + m : d; + + return d; +} + +#ifdef CONFIG_64 + +/**************************************************************************/ +/* 64-bit modular arithmetic */ +/**************************************************************************/ + +/* + * A proof of the algorithm is in literature/mulmod-64.txt. An ACL2 + * proof is in umodarith.lisp: section "Fast modular reduction". + * + * Algorithm: calculate (a * b) % p: + * + * a) hi, lo <- a * b # Calculate a * b. + * + * b) hi, lo <- R(hi, lo) # Reduce modulo p. + * + * c) Repeat step b) until 0 <= hi * 2**64 + lo < 2*p. + * + * d) If the result is less than p, return lo. Otherwise return lo - p. + */ + +static inline mpd_uint_t +x64_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t hi, lo, x, y; + + + _mpd_mul_words(&hi, &lo, a, b); + + if (m & (1ULL<<32)) { /* P1 */ + + /* first reduction */ + x = y = hi; + hi >>= 32; + + x = lo - x; + if (x > lo) hi--; + + y <<= 32; + lo = y + x; + if (lo < y) hi++; + + /* second reduction */ + x = y = hi; + hi >>= 32; + + x = lo - x; + if (x > lo) hi--; + + y <<= 32; + lo = y + x; + if (lo < y) hi++; + + return (hi || lo >= m ? lo - m : lo); + } + else if (m & (1ULL<<34)) { /* P2 */ + + /* first reduction */ + x = y = hi; + hi >>= 30; + + x = lo - x; + if (x > lo) hi--; + + y <<= 34; + lo = y + x; + if (lo < y) hi++; + + /* second reduction */ + x = y = hi; + hi >>= 30; + + x = lo - x; + if (x > lo) hi--; + + y <<= 34; + lo = y + x; + if (lo < y) hi++; + + /* third reduction */ + x = y = hi; + hi >>= 30; + + x = lo - x; + if (x > lo) hi--; + + y <<= 34; + lo = y + x; + if (lo < y) hi++; + + return (hi || lo >= m ? lo - m : lo); + } + else { /* P3 */ + + /* first reduction */ + x = y = hi; + hi >>= 24; + + x = lo - x; + if (x > lo) hi--; + + y <<= 40; + lo = y + x; + if (lo < y) hi++; + + /* second reduction */ + x = y = hi; + hi >>= 24; + + x = lo - x; + if (x > lo) hi--; + + y <<= 40; + lo = y + x; + if (lo < y) hi++; + + /* third reduction */ + x = y = hi; + hi >>= 24; + + x = lo - x; + if (x > lo) hi--; + + y <<= 40; + lo = y + x; + if (lo < y) hi++; + + return (hi || lo >= m ? lo - m : lo); + } +} + +static inline void +x64_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m) +{ + *a = x64_mulmod(*a, w, m); + *b = x64_mulmod(*b, w, m); +} + +static inline void +x64_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + mpd_uint_t m) +{ + *a0 = x64_mulmod(*a0, b0, m); + *a1 = x64_mulmod(*a1, b1, m); +} + +static inline mpd_uint_t +x64_powmod(mpd_uint_t base, mpd_uint_t exp, mpd_uint_t umod) +{ + mpd_uint_t r = 1; + + while (exp > 0) { + if (exp & 1) + r = x64_mulmod(r, base, umod); + base = x64_mulmod(base, base, umod); + exp >>= 1; + } + + return r; +} + +/* END CONFIG_64 */ +#else /* CONFIG_32 */ + + +/**************************************************************************/ +/* 32-bit modular arithmetic */ +/**************************************************************************/ + +#if defined(ANSI) +#if !defined(LEGACY_COMPILER) +/* HAVE_UINT64_T */ +static inline mpd_uint_t +std_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + return ((mpd_uuint_t) a * b) % m; +} + +static inline void +std_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m) +{ + *a = ((mpd_uuint_t) *a * w) % m; + *b = ((mpd_uuint_t) *b * w) % m; +} + +static inline void +std_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + mpd_uint_t m) +{ + *a0 = ((mpd_uuint_t) *a0 * b0) % m; + *a1 = ((mpd_uuint_t) *a1 * b1) % m; +} +/* END HAVE_UINT64_T */ +#else +/* LEGACY_COMPILER */ +static inline mpd_uint_t +std_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t hi, lo, q, r; + _mpd_mul_words(&hi, &lo, a, b); + _mpd_div_words(&q, &r, hi, lo, m); + return r; +} + +static inline void +std_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m) +{ + *a = std_mulmod(*a, w, m); + *b = std_mulmod(*b, w, m); +} + +static inline void +std_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + mpd_uint_t m) +{ + *a0 = std_mulmod(*a0, b0, m); + *a1 = std_mulmod(*a1, b1, m); +} +/* END LEGACY_COMPILER */ +#endif + +static inline mpd_uint_t +std_powmod(mpd_uint_t base, mpd_uint_t exp, mpd_uint_t umod) +{ + mpd_uint_t r = 1; + + while (exp > 0) { + if (exp & 1) + r = std_mulmod(r, base, umod); + base = std_mulmod(base, base, umod); + exp >>= 1; + } + + return r; +} +#endif /* ANSI CONFIG_32 */ + + +/**************************************************************************/ +/* Pentium Pro modular arithmetic */ +/**************************************************************************/ + +/* + * A proof of the algorithm is in literature/mulmod-ppro.txt. The FPU + * control word must be set to 64-bit precision and truncation mode + * prior to using these functions. + * + * Algorithm: calculate (a * b) % p: + * + * p := prime < 2**31 + * pinv := (long double)1.0 / p (precalculated) + * + * a) n = a * b # Calculate exact product. + * b) qest = n * pinv # Calculate estimate for q = n / p. + * c) q = (qest+2**63)-2**63 # Truncate qest to the exact quotient. + * d) r = n - q * p # Calculate remainder. + * + * Remarks: + * + * - p = dmod and pinv = dinvmod. + * - dinvmod points to an array of three uint32_t, which is interpreted + * as an 80 bit long double by fldt. + * - Intel compilers prior to version 11 do not seem to handle the + * __GNUC__ inline assembly correctly. + * - random tests are provided in tests/extended/ppro_mulmod.c + */ + +#if defined(PPRO) +#if defined(ASM) + +/* Return (a * b) % dmod */ +static inline mpd_uint_t +ppro_mulmod(mpd_uint_t a, mpd_uint_t b, double *dmod, uint32_t *dinvmod) +{ + mpd_uint_t retval; + + asm ( + "fildl %2\n\t" + "fildl %1\n\t" + "fmulp %%st, %%st(1)\n\t" + "fldt (%4)\n\t" + "fmul %%st(1), %%st\n\t" + "flds %5\n\t" + "fadd %%st, %%st(1)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fldl (%3)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fistpl %0\n\t" + : "=m" (retval) + : "m" (a), "m" (b), "r" (dmod), "r" (dinvmod), "m" (MPD_TWO63) + : "st", "memory" + ); + + return retval; +} + +/* + * Two modular multiplications in parallel: + * *a0 = (*a0 * w) % dmod + * *a1 = (*a1 * w) % dmod + */ +static inline void +ppro_mulmod2c(mpd_uint_t *a0, mpd_uint_t *a1, mpd_uint_t w, + double *dmod, uint32_t *dinvmod) +{ + asm ( + "fildl %2\n\t" + "fildl (%1)\n\t" + "fmul %%st(1), %%st\n\t" + "fxch %%st(1)\n\t" + "fildl (%0)\n\t" + "fmulp %%st, %%st(1) \n\t" + "fldt (%4)\n\t" + "flds %5\n\t" + "fld %%st(2)\n\t" + "fmul %%st(2)\n\t" + "fadd %%st(1)\n\t" + "fsub %%st(1)\n\t" + "fmull (%3)\n\t" + "fsubrp %%st, %%st(3)\n\t" + "fxch %%st(2)\n\t" + "fistpl (%0)\n\t" + "fmul %%st(2)\n\t" + "fadd %%st(1)\n\t" + "fsubp %%st, %%st(1)\n\t" + "fmull (%3)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fistpl (%1)\n\t" + : : "r" (a0), "r" (a1), "m" (w), + "r" (dmod), "r" (dinvmod), + "m" (MPD_TWO63) + : "st", "memory" + ); +} + +/* + * Two modular multiplications in parallel: + * *a0 = (*a0 * b0) % dmod + * *a1 = (*a1 * b1) % dmod + */ +static inline void +ppro_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + double *dmod, uint32_t *dinvmod) +{ + asm ( + "fildl %3\n\t" + "fildl (%2)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fildl %1\n\t" + "fildl (%0)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fldt (%5)\n\t" + "fld %%st(2)\n\t" + "fmul %%st(1), %%st\n\t" + "fxch %%st(1)\n\t" + "fmul %%st(2), %%st\n\t" + "flds %6\n\t" + "fldl (%4)\n\t" + "fxch %%st(3)\n\t" + "fadd %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fadd %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fsub %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fsubp %%st, %%st(1)\n\t" + "fxch %%st(1)\n\t" + "fmul %%st(2), %%st\n\t" + "fxch %%st(1)\n\t" + "fmulp %%st, %%st(2)\n\t" + "fsubrp %%st, %%st(3)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fxch %%st(1)\n\t" + "fistpl (%2)\n\t" + "fistpl (%0)\n\t" + : : "r" (a0), "m" (b0), "r" (a1), "m" (b1), + "r" (dmod), "r" (dinvmod), + "m" (MPD_TWO63) + : "st", "memory" + ); +} +/* END PPRO GCC ASM */ +#elif defined(MASM) + +/* Return (a * b) % dmod */ +static inline mpd_uint_t __cdecl +ppro_mulmod(mpd_uint_t a, mpd_uint_t b, double *dmod, uint32_t *dinvmod) +{ + mpd_uint_t retval; + + __asm { + mov eax, dinvmod + mov edx, dmod + fild b + fild a + fmulp st(1), st + fld TBYTE PTR [eax] + fmul st, st(1) + fld MPD_TWO63 + fadd st(1), st + fsubp st(1), st + fld QWORD PTR [edx] + fmulp st(1), st + fsubp st(1), st + fistp retval + } + + return retval; +} + +/* + * Two modular multiplications in parallel: + * *a0 = (*a0 * w) % dmod + * *a1 = (*a1 * w) % dmod + */ +static inline mpd_uint_t __cdecl +ppro_mulmod2c(mpd_uint_t *a0, mpd_uint_t *a1, mpd_uint_t w, + double *dmod, uint32_t *dinvmod) +{ + __asm { + mov ecx, dmod + mov edx, a1 + mov ebx, dinvmod + mov eax, a0 + fild w + fild DWORD PTR [edx] + fmul st, st(1) + fxch st(1) + fild DWORD PTR [eax] + fmulp st(1), st + fld TBYTE PTR [ebx] + fld MPD_TWO63 + fld st(2) + fmul st, st(2) + fadd st, st(1) + fsub st, st(1) + fmul QWORD PTR [ecx] + fsubp st(3), st + fxch st(2) + fistp DWORD PTR [eax] + fmul st, st(2) + fadd st, st(1) + fsubrp st(1), st + fmul QWORD PTR [ecx] + fsubp st(1), st + fistp DWORD PTR [edx] + } +} + +/* + * Two modular multiplications in parallel: + * *a0 = (*a0 * b0) % dmod + * *a1 = (*a1 * b1) % dmod + */ +static inline void __cdecl +ppro_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + double *dmod, uint32_t *dinvmod) +{ + __asm { + mov ecx, dmod + mov edx, a1 + mov ebx, dinvmod + mov eax, a0 + fild b1 + fild DWORD PTR [edx] + fmulp st(1), st + fild b0 + fild DWORD PTR [eax] + fmulp st(1), st + fld TBYTE PTR [ebx] + fld st(2) + fmul st, st(1) + fxch st(1) + fmul st, st(2) + fld DWORD PTR MPD_TWO63 + fld QWORD PTR [ecx] + fxch st(3) + fadd st, st(1) + fxch st(2) + fadd st, st(1) + fxch st(2) + fsub st, st(1) + fxch st(2) + fsubrp st(1), st + fxch st(1) + fmul st, st(2) + fxch st(1) + fmulp st(2), st + fsubp st(3), st + fsubp st(1), st + fxch st(1) + fistp DWORD PTR [edx] + fistp DWORD PTR [eax] + } +} +#endif /* PPRO MASM (_MSC_VER) */ + + +/* Return (base ** exp) % dmod */ +static inline mpd_uint_t +ppro_powmod(mpd_uint_t base, mpd_uint_t exp, double *dmod, uint32_t *dinvmod) +{ + mpd_uint_t r = 1; + + while (exp > 0) { + if (exp & 1) + r = ppro_mulmod(r, base, dmod, dinvmod); + base = ppro_mulmod(base, base, dmod, dinvmod); + exp >>= 1; + } + + return r; +} +#endif /* PPRO */ +#endif /* CONFIG_32 */ + + +#endif /* UMODARITH_H */ + + + diff --git a/Modules/_decimal/libmpdec/vccompat.h b/Modules/_decimal/libmpdec/vccompat.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/vccompat.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef VCCOMPAT_H +#define VCCOMPAT_H + + +/* Visual C fixes: no stdint.h, no snprintf ... */ +#ifdef _MSC_VER + #include "vcstdint.h" + #undef inline + #define inline __inline + #undef random + #define random rand + #undef srandom + #define srandom srand + #undef snprintf + #define snprintf sprintf_s + #define HAVE_SNPRINTF + #undef strncasecmp + #define strncasecmp _strnicmp + #undef strcasecmp + #define strcasecmp _stricmp + #undef strtoll + #define strtoll _strtoi64 + #define strdup _strdup + #define PRIi64 "I64i" + #define PRIu64 "I64u" + #define PRIi32 "I32i" + #define PRIu32 "I32u" +#endif + + +#endif /* VCCOMPAT_H */ + + + diff --git a/Modules/_decimal/libmpdec/vcdiv64.asm b/Modules/_decimal/libmpdec/vcdiv64.asm new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/vcdiv64.asm @@ -0,0 +1,48 @@ +; +; Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; 1. Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; +; 2. Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in the +; documentation and/or other materials provided with the distribution. +; +; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +; SUCH DAMAGE. +; + + +PUBLIC _mpd_div_words +_TEXT SEGMENT +q$ = 8 +r$ = 16 +hi$ = 24 +lo$ = 32 +d$ = 40 +_mpd_div_words PROC + mov r10, rdx + mov rdx, r8 + mov rax, r9 + div QWORD PTR d$[rsp] + mov QWORD PTR [r10], rdx + mov QWORD PTR [rcx], rax + ret 0 +_mpd_div_words ENDP +_TEXT ENDS +END + + diff --git a/Modules/_decimal/libmpdec/vcstdint.h b/Modules/_decimal/libmpdec/vcstdint.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/vcstdint.h @@ -0,0 +1,232 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#if (_MSC_VER < 1300) && defined(__cplusplus) + extern "C++" { +#endif +# include +#if (_MSC_VER < 1300) && defined(__cplusplus) + } +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/Modules/_decimal/tests/README.txt b/Modules/_decimal/tests/README.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/README.txt @@ -0,0 +1,15 @@ + + +This directory contains extended tests and a benchmark against decimal.py: + + bench.py -> Benchmark for small and large precisions. + Usage: ../../../python bench.py + + formathelper.py -> + randdec.py -> Generate test cases for deccheck.py. + randfloat.py -> + + deccheck.py -> Run extended tests. + Usage: ../../../python deccheck.py [--short|--medium|--long|--all] + + diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/bench.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python + +# +# Copyright (C) 2001-2012 Python Software Foundation. All Rights Reserved. +# Modified and extended by Stefan Krah. +# + +# Usage: ../../../python bench.py + + +import time +from math import log, ceil +from test.support import import_fresh_module + +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) + + +# Pi function from the decimal.py documentation +def pi_float(prec): + """native float""" + lasts, t, s, n, na, d, da = 0, 3.0, 3, 1, 0, 0, 24 + while s != lasts: + lasts = s + n, na = n+na, na+8 + d, da = d+da, da+32 + t = (t * n) / d + s += t + return s + +def pi_cdecimal(prec): + """cdecimal""" + C.getcontext().prec = prec + D = C.Decimal + lasts, t, s, n, na, d, da = D(0), D(3), D(3), D(1), D(0), D(0), D(24) + while s != lasts: + lasts = s + n, na = n+na, na+8 + d, da = d+da, da+32 + t = (t * n) / d + s += t + return s + +def pi_decimal(prec): + """decimal""" + P.getcontext().prec = prec + D = P.Decimal + lasts, t, s, n, na, d, da = D(0), D(3), D(3), D(1), D(0), D(0), D(24) + while s != lasts: + lasts = s + n, na = n+na, na+8 + d, da = d+da, da+32 + t = (t * n) / d + s += t + return s + +def factorial(n, m): + if (n > m): + return factorial(m, n) + elif m == 0: + return 1 + elif n == m: + return n + else: + return factorial(n, (n+m)//2) * factorial((n+m)//2 + 1, m) + + +print("\n# ======================================================================") +print("# Calculating pi, 10000 iterations") +print("# ======================================================================\n") + +for prec in [9, 19]: + print("\nPrecision: %d decimal digits\n" % prec) + for func in [pi_float, pi_cdecimal, pi_decimal]: + start = time.time() + for i in range(10000): + x = func(prec) + print("%s:" % func.__name__.replace("pi_", "")) + print("result: %s" % str(x)) + print("time: %fs\n" % (time.time()-start)) + + +print("\n# ======================================================================") +print("# Factorial") +print("# ======================================================================\n") + +C.getcontext().prec = C.MAX_PREC + +for n in [100000, 1000000]: + + print("n = %d\n" % n) + + # C version of decimal + start_calc = time.time() + x = factorial(C.Decimal(n), 0) + end_calc = time.time() + start_conv = time.time() + sx = str(x) + end_conv = time.time() + print("cdecimal:") + print("calculation time: %fs" % (end_calc-start_calc)) + print("conversion time: %fs\n" % (end_conv-start_conv)) + + # Python integers + start_calc = time.time() + y = factorial(n, 0) + end_calc = time.time() + start_conv = time.time() + sy = str(y) + end_conv = time.time() + + print("int:") + print("calculation time: %fs" % (end_calc-start_calc)) + print("conversion time: %fs\n\n" % (end_conv-start_conv)) + + assert(sx == sy) diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/deccheck.py @@ -0,0 +1,1074 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# +# Usage: python deccheck.py [--short|--medium|--long|--all] +# + +import sys, random +from copy import copy +from collections import defaultdict +from test.support import import_fresh_module +from randdec import randfloat, all_unary, all_binary, all_ternary +from formathelper import rand_format, rand_locale + +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) +EXIT_STATUS = 0 + + +# Contains all categories of Decimal methods. +Functions = { + # Plain unary: + 'unary': ( + '__abs__', '__bool__', '__ceil__', '__complex__', '__copy__', + '__floor__', '__float__', '__hash__', '__int__', '__neg__', + '__pos__', '__reduce__', '__repr__', '__str__', '__trunc__', + 'adjusted', 'as_tuple', 'canonical', 'conjugate', 'copy_abs', + 'copy_negate', 'is_canonical', 'is_finite', 'is_infinite', + 'is_nan', 'is_qnan', 'is_signed', 'is_snan', 'is_zero', 'radix' + ), + # Unary with optional context: + 'unary_ctx': ( + 'exp', 'is_normal', 'is_subnormal', 'ln', 'log10', 'logb', + 'logical_invert', 'next_minus', 'next_plus', 'normalize', + 'number_class', 'sqrt', 'to_eng_string' + ), + # Unary with optional rounding mode and context: + 'unary_rnd_ctx': ('to_integral', 'to_integral_exact', 'to_integral_value'), + # Plain binary: + 'binary': ( + '__add__', '__divmod__', '__eq__', '__floordiv__', '__ge__', '__gt__', + '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__pow__', + '__radd__', '__rdivmod__', '__rfloordiv__', '__rmod__', '__rmul__', + '__rpow__', '__rsub__', '__rtruediv__', '__sub__', '__truediv__', + 'compare_total', 'compare_total_mag', 'copy_sign', 'quantize', + 'same_quantum' + ), + # Binary with optional context: + 'binary_ctx': ( + 'compare', 'compare_signal', 'logical_and', 'logical_or', 'logical_xor', + 'max', 'max_mag', 'min', 'min_mag', 'next_toward', 'remainder_near', + 'rotate', 'scaleb', 'shift' + ), + # Plain ternary: + 'ternary': ('__pow__',), + # Ternary with optional context: + 'ternary_ctx': ('fma',), + # Special: + 'special': ('__format__', '__reduce_ex__', '__round__', 'from_float', + 'quantize'), + # Properties: + 'property': ('real', 'imag') +} + +# Contains all categories of Context methods. The n-ary classification +# applies to the number of Decimal arguments. +ContextFunctions = { + # Plain nullary: + 'nullary': ('context.__hash__', 'context.__reduce__', 'context.radix'), + # Plain unary: + 'unary': ('context.abs', 'context.canonical', 'context.copy_abs', + 'context.copy_decimal', 'context.copy_negate', + 'context.create_decimal', 'context.exp', 'context.is_canonical', + 'context.is_finite', 'context.is_infinite', 'context.is_nan', + 'context.is_normal', 'context.is_qnan', 'context.is_signed', + 'context.is_snan', 'context.is_subnormal', 'context.is_zero', + 'context.ln', 'context.log10', 'context.logb', + 'context.logical_invert', 'context.minus', 'context.next_minus', + 'context.next_plus', 'context.normalize', 'context.number_class', + 'context.plus', 'context.sqrt', 'context.to_eng_string', + 'context.to_integral', 'context.to_integral_exact', + 'context.to_integral_value', 'context.to_sci_string' + ), + # Plain binary: + 'binary': ('context.add', 'context.compare', 'context.compare_signal', + 'context.compare_total', 'context.compare_total_mag', + 'context.copy_sign', 'context.divide', 'context.divide_int', + 'context.divmod', 'context.logical_and', 'context.logical_or', + 'context.logical_xor', 'context.max', 'context.max_mag', + 'context.min', 'context.min_mag', 'context.multiply', + 'context.next_toward', 'context.power', 'context.quantize', + 'context.remainder', 'context.remainder_near', 'context.rotate', + 'context.same_quantum', 'context.scaleb', 'context.shift', + 'context.subtract' + ), + # Plain ternary: + 'ternary': ('context.fma', 'context.power'), + # Special: + 'special': ('context.__reduce_ex__', 'context.create_decimal_from_float') +} + +# Functions that require a restricted exponent range for reasonable runtimes. +UnaryRestricted = [ + '__ceil__', '__floor__', '__int__', '__long__', '__trunc__', + 'to_integral', 'to_integral_value' +] + +BinaryRestricted = ['__round__'] + +TernaryRestricted = ['__pow__', 'context.power'] + + +# ====================================================================== +# Unified Context +# ====================================================================== + +# Translate symbols. +CondMap = { + C.Clamped: P.Clamped, + C.ConversionSyntax: P.ConversionSyntax, + C.DivisionByZero: P.DivisionByZero, + C.DivisionImpossible: P.InvalidOperation, + C.DivisionUndefined: P.DivisionUndefined, + C.Inexact: P.Inexact, + C.InvalidContext: P.InvalidContext, + C.InvalidOperation: P.InvalidOperation, + C.Overflow: P.Overflow, + C.Rounded: P.Rounded, + C.Subnormal: P.Subnormal, + C.Underflow: P.Underflow, + C.FloatOperation: P.FloatOperation, +} + +RoundMap = { + C.ROUND_UP: P.ROUND_UP, + C.ROUND_DOWN: P.ROUND_DOWN, + C.ROUND_CEILING: P.ROUND_CEILING, + C.ROUND_FLOOR: P.ROUND_FLOOR, + C.ROUND_HALF_UP: P.ROUND_HALF_UP, + C.ROUND_HALF_DOWN: P.ROUND_HALF_DOWN, + C.ROUND_HALF_EVEN: P.ROUND_HALF_EVEN, + C.ROUND_05UP: P.ROUND_05UP +} +RoundModes = RoundMap.items() + + +class Context(object): + """Provides a convenient way of syncing the C and P contexts""" + + __slots__ = ['c', 'p'] + + def __init__(self, c_ctx=None, p_ctx=None): + """Initialization is from the C context""" + self.c = C.getcontext() if c_ctx is None else c_ctx + self.p = P.getcontext() if p_ctx is None else p_ctx + self.p.prec = self.c.prec + self.p.Emin = self.c.Emin + self.p.Emax = self.c.Emax + self.p.rounding = RoundMap[self.c.rounding] + self.p.capitals = self.c.capitals + self.settraps([sig for sig in self.c.traps if self.c.traps[sig]]) + self.setstatus([sig for sig in self.c.flags if self.c.flags[sig]]) + self.p.clamp = self.c.clamp + + def __str__(self): + return str(self.c) + '\n' + str(self.p) + + def getprec(self): + assert(self.c.prec == self.p.prec) + return self.c.prec + + def setprec(self, val): + self.c.prec = val + self.p.prec = val + + def getemin(self): + assert(self.c.Emin == self.p.Emin) + return self.c.Emin + + def setemin(self, val): + self.c.Emin = val + self.p.Emin = val + + def getemax(self): + assert(self.c.Emax == self.p.Emax) + return self.c.Emax + + def setemax(self, val): + self.c.Emax = val + self.p.Emax = val + + def getround(self): + assert(self.c.rounding == RoundMap[self.p.rounding]) + return self.c.rounding + + def setround(self, val): + self.c.rounding = val + self.p.rounding = RoundMap[val] + + def getcapitals(self): + assert(self.c.capitals == self.p.capitals) + return self.c.capitals + + def setcapitals(self, val): + self.c.capitals = val + self.p.capitals = val + + def getclamp(self): + assert(self.c.clamp == self.p.clamp) + return self.c.clamp + + def setclamp(self, val): + self.c.clamp = val + self.p.clamp = val + + prec = property(getprec, setprec) + Emin = property(getemin, setemin) + Emax = property(getemax, setemax) + rounding = property(getround, setround) + clamp = property(getclamp, setclamp) + capitals = property(getcapitals, setcapitals) + + def clear_traps(self): + self.c.clear_traps() + for trap in self.p.traps: + self.p.traps[trap] = False + + def clear_status(self): + self.c.clear_flags() + self.p.clear_flags() + + def settraps(self, lst): + """lst: C signal list""" + self.clear_traps() + for signal in lst: + self.c.traps[signal] = True + self.p.traps[CondMap[signal]] = True + + def setstatus(self, lst): + """lst: C signal list""" + self.clear_status() + for signal in lst: + self.c.flags[signal] = True + self.p.flags[CondMap[signal]] = True + + def assert_eq_status(self): + """assert equality of C and P status""" + for signal in self.c.flags: + if self.c.flags[signal] == (not self.p.flags[CondMap[signal]]): + return False + return True + + +# We don't want exceptions so that we can compare the status flags. +context = Context() +context.Emin = C.MIN_EMIN +context.Emax = C.MAX_EMAX +context.clear_traps() + +# When creating decimals, _decimal is ultimately limited by the maximum +# context values. We emulate this restriction for decimal.py. +maxcontext = P.Context( + prec=C.MAX_PREC, + Emin=C.MIN_EMIN, + Emax=C.MAX_EMAX, + rounding=P.ROUND_HALF_UP, + capitals=1 +) +maxcontext.clamp = 0 + +def RestrictedDecimal(value): + maxcontext.traps = copy(context.p.traps) + maxcontext.clear_flags() + if isinstance(value, str): + value = value.strip() + dec = maxcontext.create_decimal(value) + if maxcontext.flags[P.Inexact] or \ + maxcontext.flags[P.Rounded] or \ + maxcontext.flags[P.InvalidOperation]: + return context.p._raise_error(P.InvalidOperation) + if maxcontext.flags[P.FloatOperation]: + context.p.flags[P.FloatOperation] = True + return dec + + +# ====================================================================== +# TestSet: Organize data and events during a single test case +# ====================================================================== + +class RestrictedList(list): + """List that can only be modified by appending items.""" + def __getattribute__(self, name): + if name != 'append': + raise AttributeError("unsupported operation") + return list.__getattribute__(self, name) + def unsupported(self, *_): + raise AttributeError("unsupported operation") + __add__ = __delattr__ = __delitem__ = __iadd__ = __imul__ = unsupported + __mul__ = __reversed__ = __rmul__ = __setattr__ = __setitem__ = unsupported + +class TestSet(object): + """A TestSet contains the original input operands, converted operands, + Python exceptions that occurred either during conversion or during + execution of the actual function, and the final results. + + For safety, most attributes are lists that only support the append + operation. + + If a function name is prefixed with 'context.', the corresponding + context method is called. + """ + def __init__(self, funcname, operands): + if funcname.startswith("context."): + self.funcname = funcname.replace("context.", "") + self.contextfunc = True + else: + self.funcname = funcname + self.contextfunc = False + self.op = operands # raw operand tuple + self.context = context # context used for the operation + self.cop = RestrictedList() # converted C.Decimal operands + self.cex = RestrictedList() # Python exceptions for C.Decimal + self.cresults = RestrictedList() # C.Decimal results + self.pop = RestrictedList() # converted P.Decimal operands + self.pex = RestrictedList() # Python exceptions for P.Decimal + self.presults = RestrictedList() # P.Decimal results + + +# ====================================================================== +# SkipHandler: skip known discrepancies +# ====================================================================== + +class SkipHandler: + """Handle known discrepancies between decimal.py and _decimal.so. + These are either ULP differences in the power function or + extremely minor issues.""" + + def __init__(self): + self.ulpdiff = 0 + self.powmod_zeros = 0 + self.maxctx = P.Context(Emax=10**18, Emin=-10**18) + + def default(self, t): + return False + __ge__ = __gt__ = __le__ = __lt__ = __ne__ = __eq__ = default + __reduce__ = __format__ = __repr__ = __str__ = default + + def harrison_ulp(self, dec): + """ftp://ftp.inria.fr/INRIA/publication/publi-pdf/RR/RR-5504.pdf""" + a = dec.next_plus() + b = dec.next_minus() + return abs(a - b) + + def standard_ulp(self, dec, prec): + return P._dec_from_triple(0, '1', dec._exp+len(dec._int)-prec) + + def rounding_direction(self, x, mode): + """Determine the effective direction of the rounding when + the exact result x is rounded according to mode. + Return -1 for downwards, 0 for undirected, 1 for upwards, + 2 for ROUND_05UP.""" + cmp = 1 if x.compare_total(P.Decimal("+0")) >= 0 else -1 + + if mode in (P.ROUND_HALF_EVEN, P.ROUND_HALF_UP, P.ROUND_HALF_DOWN): + return 0 + elif mode == P.ROUND_CEILING: + return 1 + elif mode == P.ROUND_FLOOR: + return -1 + elif mode == P.ROUND_UP: + return cmp + elif mode == P.ROUND_DOWN: + return -cmp + elif mode == P.ROUND_05UP: + return 2 + else: + raise ValueError("Unexpected rounding mode: %s" % mode) + + def check_ulpdiff(self, exact, rounded): + # current precision + p = context.p.prec + + # Convert infinities to the largest representable number + 1. + x = exact + if exact.is_infinite(): + x = P._dec_from_triple(exact._sign, '10', context.p.Emax) + y = rounded + if rounded.is_infinite(): + y = P._dec_from_triple(rounded._sign, '10', context.p.Emax) + + # err = (rounded - exact) / ulp(rounded) + self.maxctx.prec = p * 2 + t = self.maxctx.subtract(y, x) + if context.c.flags[C.Clamped] or \ + context.c.flags[C.Underflow]: + # The standard ulp does not work in Underflow territory. + ulp = self.harrison_ulp(y) + else: + ulp = self.standard_ulp(y, p) + # Error in ulps. + err = self.maxctx.divide(t, ulp) + + dir = self.rounding_direction(x, context.p.rounding) + if dir == 0: + if P.Decimal("-0.6") < err < P.Decimal("0.6"): + return True + elif dir == 1: # directed, upwards + if P.Decimal("-0.1") < err < P.Decimal("1.1"): + return True + elif dir == -1: # directed, downwards + if P.Decimal("-1.1") < err < P.Decimal("0.1"): + return True + else: # ROUND_05UP + if P.Decimal("-1.1") < err < P.Decimal("1.1"): + return True + + print("ulp: %s error: %s exact: %s c_rounded: %s" + % (ulp, err, exact, rounded)) + return False + + def bin_resolve_ulp(self, t): + """Check if results of _decimal's power function are within the + allowed ulp ranges.""" + # NaNs are beyond repair. + if t.rc.is_nan() or t.rp.is_nan(): + return False + + # "exact" result, double precision, half_even + self.maxctx.prec = context.p.prec * 2 + + op1, op2 = t.pop[0], t.pop[1] + if t.contextfunc: + exact = getattr(self.maxctx, t.funcname)(op1, op2) + else: + exact = getattr(op1, t.funcname)(op2, context=self.maxctx) + + # _decimal's rounded result + rounded = P.Decimal(t.cresults[0]) + + self.ulpdiff += 1 + return self.check_ulpdiff(exact, rounded) + + ############################ Correct rounding ############################# + def resolve_underflow(self, t): + """In extremely rare cases where the infinite precision result is just + below etiny, cdecimal does not set Subnormal/Underflow. Example: + + setcontext(Context(prec=21, rounding=ROUND_UP, Emin=-55, Emax=85)) + Decimal("1.00000000000000000000000000000000000000000000000" + "0000000100000000000000000000000000000000000000000" + "0000000000000025").ln() + """ + if t.cresults != t.presults: + return False # Results must be identical. + if context.c.flags[C.Rounded] and \ + context.c.flags[C.Inexact] and \ + context.p.flags[P.Rounded] and \ + context.p.flags[P.Inexact]: + return True # Subnormal/Underflow may be missing. + return False + + def exp(self, t): + """Resolve Underflow or ULP difference.""" + return self.resolve_underflow(t) + + def log10(self, t): + """Resolve Underflow or ULP difference.""" + return self.resolve_underflow(t) + + def ln(self, t): + """Resolve Underflow or ULP difference.""" + return self.resolve_underflow(t) + + def __pow__(self, t): + """Always calls the resolve function. C.Decimal does not have correct + rounding for the power function.""" + if context.c.flags[C.Rounded] and \ + context.c.flags[C.Inexact] and \ + context.p.flags[P.Rounded] and \ + context.p.flags[P.Inexact]: + return self.bin_resolve_ulp(t) + else: + return False + power = __rpow__ = __pow__ + + ############################## Technicalities ############################# + def __float__(self, t): + """NaN comparison in the verify() function obviously gives an + incorrect answer: nan == nan -> False""" + if t.cop[0].is_nan() and t.pop[0].is_nan(): + return True + return False + __complex__ = __float__ + + def __radd__(self, t): + """decimal.py gives precedence to the first NaN; this is + not important, as __radd__ will not be called for + two decimal arguments.""" + if t.rc.is_nan() and t.rp.is_nan(): + return True + return False + __rmul__ = __radd__ + + ################################ Various ################################## + def __round__(self, t): + """Exception: Decimal('1').__round__(-100000000000000000000000000) + Should it really be InvalidOperation?""" + if t.rc is None and t.rp.is_nan(): + return True + return False + +shandler = SkipHandler() +def skip_error(t): + return getattr(shandler, t.funcname, shandler.default)(t) + + +# ====================================================================== +# Handling verification errors +# ====================================================================== + +class VerifyError(Exception): + """Verification failed.""" + pass + +def function_as_string(t): + if t.contextfunc: + cargs = t.cop + pargs = t.pop + cfunc = "c_func: %s(" % t.funcname + pfunc = "p_func: %s(" % t.funcname + else: + cself, cargs = t.cop[0], t.cop[1:] + pself, pargs = t.pop[0], t.pop[1:] + cfunc = "c_func: %s.%s(" % (repr(cself), t.funcname) + pfunc = "p_func: %s.%s(" % (repr(pself), t.funcname) + + err = cfunc + for arg in cargs: + err += "%s, " % repr(arg) + err = err.rstrip(", ") + err += ")\n" + + err += pfunc + for arg in pargs: + err += "%s, " % repr(arg) + err = err.rstrip(", ") + err += ")" + + return err + +def raise_error(t): + global EXIT_STATUS + + if skip_error(t): + return + EXIT_STATUS = 1 + + err = "Error in %s:\n\n" % t.funcname + err += "input operands: %s\n\n" % (t.op,) + err += function_as_string(t) + err += "\n\nc_result: %s\np_result: %s\n\n" % (t.cresults, t.presults) + err += "c_exceptions: %s\np_exceptions: %s\n\n" % (t.cex, t.pex) + err += "%s\n\n" % str(t.context) + + raise VerifyError(err) + + +# ====================================================================== +# Main testing functions +# +# The procedure is always (t is the TestSet): +# +# convert(t) -> Initialize the TestSet as necessary. +# +# Return 0 for early abortion (e.g. if a TypeError +# occurs during conversion, there is nothing to test). +# +# Return 1 for continuing with the test case. +# +# callfuncs(t) -> Call the relevant function for each implementation +# and record the results in the TestSet. +# +# verify(t) -> Verify the results. If verification fails, details +# are printed to stdout. +# ====================================================================== + +def convert(t, convstr=True): + """ t is the testset. At this stage the testset contains a tuple of + operands t.op of various types. For decimal methods the first + operand (self) is always converted to Decimal. If 'convstr' is + true, string operands are converted as well. + + Context operands are of type deccheck.Context, rounding mode + operands are given as a tuple (C.rounding, P.rounding). + + Other types (float, int, etc.) are left unchanged. + """ + for i, op in enumerate(t.op): + + context.clear_status() + + if not t.contextfunc and i == 0 or \ + convstr and isinstance(op, str): + try: + c = C.Decimal(op) + cex = None + except (TypeError, ValueError, OverflowError) as e: + c = None + cex = e.__class__ + + try: + p = RestrictedDecimal(op) + pex = None + except (TypeError, ValueError, OverflowError) as e: + p = None + pex = e.__class__ + + t.cop.append(c) + t.cex.append(cex) + t.pop.append(p) + t.pex.append(pex) + + if cex is pex: + if str(c) != str(p) or not context.assert_eq_status(): + raise_error(t) + if cex and pex: + # nothing to test + return 0 + else: + raise_error(t) + + elif isinstance(op, Context): + t.context = op + t.cop.append(op.c) + t.pop.append(op.p) + + elif op in RoundModes: + t.cop.append(op[0]) + t.pop.append(op[1]) + + else: + t.cop.append(op) + t.pop.append(op) + + return 1 + +def callfuncs(t): + """ t is the testset. At this stage the testset contains operand lists + t.cop and t.pop for the C and Python versions of decimal. + For Decimal methods, the first operands are of type C.Decimal and + P.Decimal respectively. The remaining operands can have various types. + For Context methods, all operands can have any type. + + t.rc and t.rp are the results of the operation. + """ + context.clear_status() + + try: + if t.contextfunc: + cargs = t.cop + t.rc = getattr(context.c, t.funcname)(*cargs) + else: + cself = t.cop[0] + cargs = t.cop[1:] + t.rc = getattr(cself, t.funcname)(*cargs) + t.cex.append(None) + except (TypeError, ValueError, OverflowError, MemoryError) as e: + t.rc = None + t.cex.append(e.__class__) + + try: + if t.contextfunc: + pargs = t.pop + t.rp = getattr(context.p, t.funcname)(*pargs) + else: + pself = t.pop[0] + pargs = t.pop[1:] + t.rp = getattr(pself, t.funcname)(*pargs) + t.pex.append(None) + except (TypeError, ValueError, OverflowError, MemoryError) as e: + t.rp = None + t.pex.append(e.__class__) + +def verify(t, stat): + """ t is the testset. At this stage the testset contains the following + tuples: + + t.op: original operands + t.cop: C.Decimal operands (see convert for details) + t.pop: P.Decimal operands (see convert for details) + t.rc: C result + t.rp: Python result + + t.rc and t.rp can have various types. + """ + t.cresults.append(str(t.rc)) + t.presults.append(str(t.rp)) + if isinstance(t.rc, C.Decimal) and isinstance(t.rp, P.Decimal): + # General case: both results are Decimals. + t.cresults.append(t.rc.to_eng_string()) + t.cresults.append(t.rc.as_tuple()) + t.cresults.append(str(t.rc.imag)) + t.cresults.append(str(t.rc.real)) + t.presults.append(t.rp.to_eng_string()) + t.presults.append(t.rp.as_tuple()) + t.presults.append(str(t.rp.imag)) + t.presults.append(str(t.rp.real)) + + nc = t.rc.number_class().lstrip('+-s') + stat[nc] += 1 + else: + # Results from e.g. __divmod__ can only be compared as strings. + if not isinstance(t.rc, tuple) and not isinstance(t.rp, tuple): + if t.rc != t.rp: + raise_error(t) + stat[type(t.rc).__name__] += 1 + + # The return value lists must be equal. + if t.cresults != t.presults: + raise_error(t) + # The Python exception lists (TypeError, etc.) must be equal. + if t.cex != t.pex: + raise_error(t) + # The context flags must be equal. + if not t.context.assert_eq_status(): + raise_error(t) + + +# ====================================================================== +# Main test loops +# +# test_method(method, testspecs, testfunc) -> +# +# Loop through various context settings. The degree of +# thoroughness is determined by 'testspec'. For each +# setting, call 'testfunc'. Generally, 'testfunc' itself +# a loop, iterating through many test cases generated +# by the functions in randdec.py. +# +# test_n-ary(method, prec, exp_range, restricted_range, itr, stat) -> +# +# 'test_unary', 'test_binary' and 'test_ternary' are the +# main test functions passed to 'test_method'. They deal +# with the regular cases. The thoroughness of testing is +# determined by 'itr'. +# +# 'prec', 'exp_range' and 'restricted_range' are passed +# to the test-generating functions and limit the generated +# values. In some cases, for reasonable run times a +# maximum exponent of 9999 is required. +# +# The 'stat' parameter is passed down to the 'verify' +# function, which records statistics for the result values. +# ====================================================================== + +def log(fmt, args=None): + if args: + sys.stdout.write(''.join((fmt, '\n')) % args) + else: + sys.stdout.write(''.join((str(fmt), '\n'))) + sys.stdout.flush() + +def test_method(method, testspecs, testfunc): + """Iterate a test function through many context settings.""" + log("testing %s ...", method) + stat = defaultdict(int) + for spec in testspecs: + if 'samples' in spec: + spec['prec'] = sorted(random.sample(range(1, 101), + spec['samples'])) + for prec in spec['prec']: + context.prec = prec + for expts in spec['expts']: + emin, emax = expts + if emin == 'rand': + context.Emin = random.randrange(-1000, 0) + context.Emax = random.randrange(prec, 1000) + else: + context.Emin, context.Emax = emin, emax + if prec > context.Emax: continue + log(" prec: %d emin: %d emax: %d", + (context.prec, context.Emin, context.Emax)) + restr_range = 9999 if context.Emax > 9999 else context.Emax+99 + for rounding in sorted(RoundMap): + context.rounding = rounding + context.capitals = random.randrange(2) + if spec['clamp'] == 'rand': + context.clamp = random.randrange(2) + else: + context.clamp = spec['clamp'] + exprange = context.c.Emax + testfunc(method, prec, exprange, restr_range, + spec['iter'], stat) + log(" result types: %s" % sorted([t for t in stat.items()])) + +def test_unary(method, prec, exp_range, restricted_range, itr, stat): + """Iterate a unary function through many test cases.""" + if method in UnaryRestricted: + exp_range = restricted_range + for op in all_unary(prec, exp_range, itr): + t = TestSet(method, op) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_binary(method, prec, exp_range, restricted_range, itr, stat): + """Iterate a binary function through many test cases.""" + if method in BinaryRestricted: + exp_range = restricted_range + for op in all_binary(prec, exp_range, itr): + t = TestSet(method, op) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_ternary(method, prec, exp_range, restricted_range, itr, stat): + """Iterate a ternary function through many test cases.""" + if method in TernaryRestricted: + exp_range = restricted_range + for op in all_ternary(prec, exp_range, itr): + t = TestSet(method, op) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_format(method, prec, exp_range, restricted_range, itr, stat): + """Iterate the __format__ method through many test cases.""" + for op in all_unary(prec, exp_range, itr): + fmt1 = rand_format(chr(random.randrange(32, 128)), 'EeGgn') + fmt2 = rand_locale() + for fmt in (fmt1, fmt2): + fmtop = (op[0], fmt) + t = TestSet(method, fmtop) + try: + if not convert(t, convstr=False): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + for op in all_unary(prec, 9999, itr): + fmt1 = rand_format(chr(random.randrange(32, 128)), 'Ff%') + fmt2 = rand_locale() + for fmt in (fmt1, fmt2): + fmtop = (op[0], fmt) + t = TestSet(method, fmtop) + try: + if not convert(t, convstr=False): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_round(method, prec, exprange, restricted_range, itr, stat): + """Iterate the __round__ method through many test cases.""" + for op in all_unary(prec, 9999, itr): + n = random.randrange(10) + roundop = (op[0], n) + t = TestSet(method, roundop) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_from_float(method, prec, exprange, restricted_range, itr, stat): + """Iterate the __float__ method through many test cases.""" + for rounding in sorted(RoundMap): + context.rounding = rounding + for i in range(1000): + f = randfloat() + op = (f,) if method.startswith("context.") else ("sNaN", f) + t = TestSet(method, op) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def randcontext(exprange): + c = Context(C.Context(), P.Context()) + c.Emax = random.randrange(1, exprange+1) + c.Emin = random.randrange(-exprange, 0) + maxprec = 100 if c.Emax >= 100 else c.Emax + c.prec = random.randrange(1, maxprec+1) + c.clamp = random.randrange(2) + c.clear_traps() + return c + +def test_quantize_api(method, prec, exprange, restricted_range, itr, stat): + """Iterate the 'quantize' method through many test cases, using + the optional arguments.""" + for op in all_binary(prec, restricted_range, itr): + for rounding in RoundModes: + c = randcontext(exprange) + quantizeop = (op[0], op[1], rounding, c) + t = TestSet(method, quantizeop) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + + +def check_untested(funcdict, c_cls, p_cls): + """Determine untested, C-only and Python-only attributes. + Uncomment print lines for debugging.""" + c_attr = set(dir(c_cls)) + p_attr = set(dir(p_cls)) + intersect = c_attr & p_attr + + funcdict['c_only'] = tuple(sorted(c_attr-intersect)) + funcdict['p_only'] = tuple(sorted(p_attr-intersect)) + + tested = set() + for lst in funcdict.values(): + for v in lst: + v = v.replace("context.", "") if c_cls == C.Context else v + tested.add(v) + + funcdict['untested'] = tuple(sorted(intersect-tested)) + + #for key in ('untested', 'c_only', 'p_only'): + # s = 'Context' if c_cls == C.Context else 'Decimal' + # print("\n%s %s:\n%s" % (s, key, funcdict[key])) + + +if __name__ == '__main__': + + import time + + randseed = int(time.time()) + random.seed(randseed) + + # Set up the testspecs list. A testspec is simply a dictionary + # that determines the amount of different contexts that 'test_method' + # will generate. + base_expts = [(C.MIN_EMIN, C.MAX_EMAX)] + if C.MAX_EMAX == 999999999999999999: + base_expts.append((-999999999, 999999999)) + + # Basic contexts. + base = { + 'expts': base_expts, + 'prec': [], + 'clamp': 'rand', + 'iter': None, + 'samples': None, + } + # Contexts with small values for prec, emin, emax. + small = { + 'prec': [1, 2, 3, 4, 5], + 'expts': [(-1, 1), (-2, 2), (-3, 3), (-4, 4), (-5, 5)], + 'clamp': 'rand', + 'iter': None + } + # IEEE interchange format. + ieee = [ + # DECIMAL32 + {'prec': [7], 'expts': [(-95, 96)], 'clamp': 1, 'iter': None}, + # DECIMAL64 + {'prec': [16], 'expts': [(-383, 384)], 'clamp': 1, 'iter': None}, + # DECIMAL128 + {'prec': [34], 'expts': [(-6143, 6144)], 'clamp': 1, 'iter': None} + ] + + if '--medium' in sys.argv: + base['expts'].append(('rand', 'rand')) + # 5 random precisions + base['samples'] = 5 + testspecs = [small] + ieee + [base] + if '--long' in sys.argv: + base['expts'].append(('rand', 'rand')) + # 10 random precisions + base['samples'] = 10 + testspecs = [small] + ieee + [base] + elif '--all' in sys.argv: + base['expts'].append(('rand', 'rand')) + # All precisions in [1, 100] + base['samples'] = 100 + testspecs = [small] + ieee + [base] + else: # --short + rand_ieee = random.choice(ieee) + base['iter'] = small['iter'] = rand_ieee['iter'] = 1 + # 1 random precision and exponent pair + base['samples'] = 1 + base['expts'] = [random.choice(base_expts)] + # 1 random precision and exponent pair + prec = random.randrange(1, 6) + small['prec'] = [prec] + small['expts'] = [(-prec, prec)] + testspecs = [small, rand_ieee, base] + + check_untested(Functions, C.Decimal, P.Decimal) + check_untested(ContextFunctions, C.Context, P.Context) + + + log("\n\nRandom seed: %d\n\n", randseed) + + # Decimal methods: + for method in Functions['unary'] + Functions['unary_ctx'] + \ + Functions['unary_rnd_ctx']: + test_method(method, testspecs, test_unary) + + for method in Functions['binary'] + Functions['binary_ctx']: + test_method(method, testspecs, test_binary) + + for method in Functions['ternary'] + Functions['ternary_ctx']: + test_method(method, testspecs, test_ternary) + + test_method('__format__', testspecs, test_format) + test_method('__round__', testspecs, test_round) + test_method('from_float', testspecs, test_from_float) + test_method('quantize', testspecs, test_quantize_api) + + # Context methods: + for method in ContextFunctions['unary']: + test_method(method, testspecs, test_unary) + + for method in ContextFunctions['binary']: + test_method(method, testspecs, test_binary) + + for method in ContextFunctions['ternary']: + test_method(method, testspecs, test_ternary) + + test_method('context.create_decimal_from_float', testspecs, test_from_float) + + + sys.exit(EXIT_STATUS) diff --git a/Modules/_decimal/tests/formathelper.py b/Modules/_decimal/tests/formathelper.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/formathelper.py @@ -0,0 +1,344 @@ +# +# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + + +# Generate PEP-3101 format strings. + + +import os, sys, locale, random +import platform, subprocess +from test.support import import_fresh_module +from distutils.spawn import find_executable + +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) + + +windows_lang_strings = [ + "chinese", "chinese-simplified", "chinese-traditional", "czech", "danish", + "dutch", "belgian", "english", "australian", "canadian", "english-nz", + "english-uk", "english-us", "finnish", "french", "french-belgian", + "french-canadian", "french-swiss", "german", "german-austrian", + "german-swiss", "greek", "hungarian", "icelandic", "italian", "italian-swiss", + "japanese", "korean", "norwegian", "norwegian-bokmal", "norwegian-nynorsk", + "polish", "portuguese", "portuguese-brazil", "russian", "slovak", "spanish", + "spanish-mexican", "spanish-modern", "swedish", "turkish", +] + +preferred_encoding = { + 'cs_CZ': 'ISO8859-2', + 'cs_CZ.iso88592': 'ISO8859-2', + 'czech': 'ISO8859-2', + 'eesti': 'ISO8859-1', + 'estonian': 'ISO8859-1', + 'et_EE': 'ISO8859-15', + 'et_EE.ISO-8859-15': 'ISO8859-15', + 'et_EE.iso885915': 'ISO8859-15', + 'et_EE.iso88591': 'ISO8859-1', + 'fi_FI.iso88591': 'ISO8859-1', + 'fi_FI': 'ISO8859-15', + 'fi_FI at euro': 'ISO8859-15', + 'fi_FI.iso885915 at euro': 'ISO8859-15', + 'finnish': 'ISO8859-1', + 'lv_LV': 'ISO8859-13', + 'lv_LV.iso885913': 'ISO8859-13', + 'nb_NO': 'ISO8859-1', + 'nb_NO.iso88591': 'ISO8859-1', + 'bokmal': 'ISO8859-1', + 'nn_NO': 'ISO8859-1', + 'nn_NO.iso88591': 'ISO8859-1', + 'no_NO': 'ISO8859-1', + 'norwegian': 'ISO8859-1', + 'nynorsk': 'ISO8859-1', + 'ru_RU': 'ISO8859-5', + 'ru_RU.iso88595': 'ISO8859-5', + 'russian': 'ISO8859-5', + 'ru_RU.KOI8-R': 'KOI8-R', + 'ru_RU.koi8r': 'KOI8-R', + 'ru_RU.CP1251': 'CP1251', + 'ru_RU.cp1251': 'CP1251', + 'sk_SK': 'ISO8859-2', + 'sk_SK.iso88592': 'ISO8859-2', + 'slovak': 'ISO8859-2', + 'sv_FI': 'ISO8859-1', + 'sv_FI.iso88591': 'ISO8859-1', + 'sv_FI at euro': 'ISO8859-15', + 'sv_FI.iso885915 at euro': 'ISO8859-15', + 'uk_UA': 'KOI8-U', + 'uk_UA.koi8u': 'KOI8-U' +} + +integers = [ + "", + "1", + "12", + "123", + "1234", + "12345", + "123456", + "1234567", + "12345678", + "123456789", + "1234567890", + "12345678901", + "123456789012", + "1234567890123", + "12345678901234", + "123456789012345", + "1234567890123456", + "12345678901234567", + "123456789012345678", + "1234567890123456789", + "12345678901234567890", + "123456789012345678901", + "1234567890123456789012", +] + +numbers = [ + "0", "-0", "+0", + "0.0", "-0.0", "+0.0", + "0e0", "-0e0", "+0e0", + ".0", "-.0", + ".1", "-.1", + "1.1", "-1.1", + "1e1", "-1e1" +] + +# Get the list of available locales. +if platform.system() == 'Windows': + locale_list = windows_lang_strings +else: + locale_list = ['C'] + if os.path.isfile("/var/lib/locales/supported.d/local"): + # On Ubuntu, `locale -a` gives the wrong case for some locales, + # so we get the correct names directly: + with open("/var/lib/locales/supported.d/local") as f: + locale_list = [loc.split()[0] for loc in f.readlines() \ + if not loc.startswith('#')] + elif find_executable('locale'): + locale_list = subprocess.Popen(["locale", "-a"], + stdout=subprocess.PIPE).communicate()[0] + try: + locale_list = locale_list.decode() + except UnicodeDecodeError: + # Some distributions insist on using latin-1 characters + # in their locale names. + locale_list = locale_list.decode('latin-1') + locale_list = locale_list.split('\n') +try: + locale_list.remove('') +except ValueError: + pass + +# Debian +if os.path.isfile("/etc/locale.alias"): + with open("/etc/locale.alias") as f: + while 1: + try: + line = f.readline() + except UnicodeDecodeError: + continue + if line == "": + break + if line.startswith('#'): + continue + x = line.split() + if len(x) == 2: + if x[0] in locale_list: + locale_list.remove(x[0]) + +# FreeBSD +if platform.system() == 'FreeBSD': + # http://www.freebsd.org/cgi/query-pr.cgi?pr=142173 + # en_GB.US-ASCII has 163 as the currency symbol. + for loc in ['it_CH.ISO8859-1', 'it_CH.ISO8859-15', 'it_CH.UTF-8', + 'it_IT.ISO8859-1', 'it_IT.ISO8859-15', 'it_IT.UTF-8', + 'sl_SI.ISO8859-2', 'sl_SI.UTF-8', + 'en_GB.US-ASCII']: + try: + locale_list.remove(loc) + except ValueError: + pass + +# Print a testcase in the format of the IBM tests (for runtest.c): +def get_preferred_encoding(): + loc = locale.setlocale(locale.LC_CTYPE) + if loc in preferred_encoding: + return preferred_encoding[loc] + else: + return locale.getpreferredencoding() + +def printit(testno, s, fmt, encoding=None): + if not encoding: + encoding = get_preferred_encoding() + try: + result = format(P.Decimal(s), fmt) + fmt = str(fmt.encode(encoding))[2:-1] + result = str(result.encode(encoding))[2:-1] + if "'" in result: + sys.stdout.write("xfmt%d format %s '%s' -> \"%s\"\n" + % (testno, s, fmt, result)) + else: + sys.stdout.write("xfmt%d format %s '%s' -> '%s'\n" + % (testno, s, fmt, result)) + except Exception as err: + sys.stderr.write("%s %s %s\n" % (err, s, fmt)) + + +# Check if an integer can be converted to a valid fill character. +def check_fillchar(i): + try: + c = chr(i) + c.encode('utf-8').decode() + format(P.Decimal(0), c + '<19g') + if c in ("'", '"', '\\'): + return None + return c + except: + return None + +# Generate all unicode characters that are accepted as +# fill characters by decimal.py. +def all_fillchars(): + for i in range(32, 0x110002): + c = check_fillchar(i) + if c: yield c + +# Return random fill character. +def rand_fillchar(): + while 1: + i = random.randrange(32, 0x110002) + c = check_fillchar(i) + if c: return c + +# Generate random format strings +# [[fill]align][sign][#][0][width][.precision][type] +def rand_format(fill, typespec='EeGgFfn%'): + active = sorted(random.sample(range(7), random.randrange(8))) + have_align = 0 + s = '' + for elem in active: + if elem == 0: # fill+align + s += fill + s += random.choice('<>=^') + have_align = 1 + elif elem == 1: # sign + s += random.choice('+- ') + elif elem == 2 and not have_align: # zeropad + s += '0' + elif elem == 3: # width + s += str(random.randrange(1, 100)) + elif elem == 4: # thousands separator + s += ',' + elif elem == 5: # prec + s += '.' + s += str(random.randrange(100)) + elif elem == 6: + if 4 in active: c = typespec.replace('n', '') + else: c = typespec + s += random.choice(c) + return s + +# Partially brute force all possible format strings containing a thousands +# separator. Fall back to random where the runtime would become excessive. +# [[fill]align][sign][#][0][width][,][.precision][type] +def all_format_sep(): + for align in ('', '<', '>', '=', '^'): + for fill in ('', 'x'): + if align == '': fill = '' + for sign in ('', '+', '-', ' '): + for zeropad in ('', '0'): + if align != '': zeropad = '' + for width in ['']+[str(y) for y in range(1, 15)]+['101']: + for prec in ['']+['.'+str(y) for y in range(15)]: + # for type in ('', 'E', 'e', 'G', 'g', 'F', 'f', '%'): + type = random.choice(('', 'E', 'e', 'G', 'g', 'F', 'f', '%')) + yield ''.join((fill, align, sign, zeropad, width, ',', prec, type)) + +# Partially brute force all possible format strings with an 'n' specifier. +# [[fill]align][sign][#][0][width][,][.precision][type] +def all_format_loc(): + for align in ('', '<', '>', '=', '^'): + for fill in ('', 'x'): + if align == '': fill = '' + for sign in ('', '+', '-', ' '): + for zeropad in ('', '0'): + if align != '': zeropad = '' + for width in ['']+[str(y) for y in range(1, 20)]+['101']: + for prec in ['']+['.'+str(y) for y in range(1, 20)]: + yield ''.join((fill, align, sign, zeropad, width, prec, 'n')) + +# Generate random format strings with a unicode fill character +# [[fill]align][sign][#][0][width][,][.precision][type] +def randfill(fill): + active = sorted(random.sample(range(5), random.randrange(6))) + s = '' + s += str(fill) + s += random.choice('<>=^') + for elem in active: + if elem == 0: # sign + s += random.choice('+- ') + elif elem == 1: # width + s += str(random.randrange(1, 100)) + elif elem == 2: # thousands separator + s += ',' + elif elem == 3: # prec + s += '.' + s += str(random.randrange(100)) + elif elem == 4: + if 2 in active: c = 'EeGgFf%' + else: c = 'EeGgFfn%' + s += random.choice(c) + return s + +# Generate random format strings with random locale setting +# [[fill]align][sign][#][0][width][,][.precision][type] +def rand_locale(): + try: + loc = random.choice(locale_list) + locale.setlocale(locale.LC_ALL, loc) + except locale.Error as err: + pass + active = sorted(random.sample(range(5), random.randrange(6))) + s = '' + have_align = 0 + for elem in active: + if elem == 0: # fill+align + s += chr(random.randrange(32, 128)) + s += random.choice('<>=^') + have_align = 1 + elif elem == 1: # sign + s += random.choice('+- ') + elif elem == 2 and not have_align: # zeropad + s += '0' + elif elem == 3: # width + s += str(random.randrange(1, 100)) + elif elem == 4: # prec + s += '.' + s += str(random.randrange(100)) + s += 'n' + return s diff --git a/Modules/_decimal/tests/randdec.py b/Modules/_decimal/tests/randdec.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/randdec.py @@ -0,0 +1,559 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + + +# Generate test cases for deccheck.py. + + +# +# Grammar from http://speleotrove.com/decimal/daconvs.html +# +# sign ::= '+' | '-' +# digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | +# '8' | '9' +# indicator ::= 'e' | 'E' +# digits ::= digit [digit]... +# decimal-part ::= digits '.' [digits] | ['.'] digits +# exponent-part ::= indicator [sign] digits +# infinity ::= 'Infinity' | 'Inf' +# nan ::= 'NaN' [digits] | 'sNaN' [digits] +# numeric-value ::= decimal-part [exponent-part] | infinity +# numeric-string ::= [sign] numeric-value | [sign] nan +# + + +from random import randrange, sample +from fractions import Fraction +from randfloat import un_randfloat, bin_randfloat, tern_randfloat + + +def sign(): + if randrange(2): + if randrange(2): return '+' + return '' + return '-' + +def indicator(): + return "eE"[randrange(2)] + +def digits(maxprec): + if maxprec == 0: return '' + return str(randrange(10**maxprec)) + +def dot(): + if randrange(2): return '.' + return '' + +def decimal_part(maxprec): + if randrange(100) > 60: # integers + return digits(maxprec) + if randrange(2): + intlen = randrange(1, maxprec+1) + fraclen = maxprec-intlen + intpart = digits(intlen) + fracpart = digits(fraclen) + return ''.join((intpart, '.', fracpart)) + else: + return ''.join((dot(), digits(maxprec))) + +def expdigits(maxexp): + return str(randrange(maxexp)) + +def exponent_part(maxexp): + return ''.join((indicator(), sign(), expdigits(maxexp))) + +def infinity(): + if randrange(2): return 'Infinity' + return 'Inf' + +def nan(): + d = '' + if randrange(2): + d = digits(randrange(99)) + if randrange(2): + return ''.join(('NaN', d)) + else: + return ''.join(('sNaN', d)) + +def numeric_value(maxprec, maxexp): + if randrange(100) > 90: + return infinity() + exp_part = '' + if randrange(100) > 60: + exp_part = exponent_part(maxexp) + return ''.join((decimal_part(maxprec), exp_part)) + +def numeric_string(maxprec, maxexp): + if randrange(100) > 95: + return ''.join((sign(), nan())) + else: + return ''.join((sign(), numeric_value(maxprec, maxexp))) + +def randdec(maxprec, maxexp): + return numeric_string(maxprec, maxexp) + +def rand_adjexp(maxprec, maxadjexp): + d = digits(maxprec) + maxexp = maxadjexp-len(d)+1 + if maxexp == 0: maxexp = 1 + exp = str(randrange(maxexp-2*(abs(maxexp)), maxexp)) + return ''.join((sign(), d, 'E', exp)) + + +def ndigits(n): + if n < 1: return 0 + return randrange(10**(n-1), 10**n) + +def randtuple(maxprec, maxexp): + n = randrange(100) + sign = randrange(2) + coeff = ndigits(maxprec) + if n >= 95: + coeff = () + exp = 'F' + elif n >= 85: + coeff = tuple(map(int, str(ndigits(maxprec)))) + exp = "nN"[randrange(2)] + else: + coeff = tuple(map(int, str(ndigits(maxprec)))) + exp = randrange(-maxexp, maxexp) + return (sign, coeff, exp) + +def from_triple(sign, coeff, exp): + return ''.join((str(sign*coeff), indicator(), str(exp))) + + +# Close to 10**n +def un_close_to_pow10(prec, maxexp, itr=None): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + nines = [10**n - 1 for n in lst] + pow10 = [10**n for n in lst] + for coeff in nines: + yield coeff + yield -coeff + yield from_triple(1, coeff, randrange(2*maxexp)) + yield from_triple(-1, coeff, randrange(2*maxexp)) + for coeff in pow10: + yield coeff + yield -coeff + +# Close to 10**n +def bin_close_to_pow10(prec, maxexp, itr=None): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + nines = [10**n - 1 for n in lst] + pow10 = [10**n for n in lst] + for coeff in nines: + yield coeff, 1 + yield -coeff, -1 + yield 1, coeff + yield -1, -coeff + yield from_triple(1, coeff, randrange(2*maxexp)), 1 + yield from_triple(-1, coeff, randrange(2*maxexp)), -1 + yield 1, from_triple(1, coeff, -randrange(2*maxexp)) + yield -1, from_triple(-1, coeff, -randrange(2*maxexp)) + for coeff in pow10: + yield coeff, -1 + yield -coeff, 1 + yield 1, -coeff + yield -coeff, 1 + +# Close to 1: +def close_to_one_greater(prec, emax, emin): + rprec = 10**prec + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)))) + +def close_to_one_less(prec, emax, emin): + rprec = 10**prec + return ''.join(("0.9", '9'*randrange(prec), + str(randrange(rprec)))) + +# Close to 0: +def close_to_zero_greater(prec, emax, emin): + rprec = 10**prec + return ''.join(("0.", '0'*randrange(prec), + str(randrange(rprec)))) + +def close_to_zero_less(prec, emax, emin): + rprec = 10**prec + return ''.join(("-0.", '0'*randrange(prec), + str(randrange(rprec)))) + +# Close to emax: +def close_to_emax_less(prec, emax, emin): + rprec = 10**prec + return ''.join(("9.", '9'*randrange(prec), + str(randrange(rprec)), "E", str(emax))) + +def close_to_emax_greater(prec, emax, emin): + rprec = 10**prec + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)), "E", str(emax+1))) + +# Close to emin: +def close_to_emin_greater(prec, emax, emin): + rprec = 10**prec + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)), "E", str(emin))) + +def close_to_emin_less(prec, emax, emin): + rprec = 10**prec + return ''.join(("9.", '9'*randrange(prec), + str(randrange(rprec)), "E", str(emin-1))) + +# Close to etiny: +def close_to_etiny_greater(prec, emax, emin): + rprec = 10**prec + etiny = emin - (prec - 1) + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)), "E", str(etiny))) + +def close_to_etiny_less(prec, emax, emin): + rprec = 10**prec + etiny = emin - (prec - 1) + return ''.join(("9.", '9'*randrange(prec), + str(randrange(rprec)), "E", str(etiny-1))) + + +def close_to_min_etiny_greater(prec, max_prec, min_emin): + rprec = 10**prec + etiny = min_emin - (max_prec - 1) + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)), "E", str(etiny))) + +def close_to_min_etiny_less(prec, max_prec, min_emin): + rprec = 10**prec + etiny = min_emin - (max_prec - 1) + return ''.join(("9.", '9'*randrange(prec), + str(randrange(rprec)), "E", str(etiny-1))) + + +close_funcs = [ + close_to_one_greater, close_to_one_less, close_to_zero_greater, + close_to_zero_less, close_to_emax_less, close_to_emax_greater, + close_to_emin_greater, close_to_emin_less, close_to_etiny_greater, + close_to_etiny_less, close_to_min_etiny_greater, close_to_min_etiny_less +] + + +def un_close_numbers(prec, emax, emin, itr=None): + if itr is None: + itr = 1000 + for _ in range(itr): + for func in close_funcs: + yield func(prec, emax, emin) + +def bin_close_numbers(prec, emax, emin, itr=None): + if itr is None: + itr = 1000 + for _ in range(itr): + for func1 in close_funcs: + for func2 in close_funcs: + yield func1(prec, emax, emin), func2(prec, emax, emin) + for func in close_funcs: + yield randdec(prec, emax), func(prec, emax, emin) + yield func(prec, emax, emin), randdec(prec, emax) + +def tern_close_numbers(prec, emax, emin, itr): + if itr is None: + itr = 1000 + for _ in range(itr): + for func1 in close_funcs: + for func2 in close_funcs: + for func3 in close_funcs: + yield (func1(prec, emax, emin), func2(prec, emax, emin), + func3(prec, emax, emin)) + for func in close_funcs: + yield (randdec(prec, emax), func(prec, emax, emin), + func(prec, emax, emin)) + yield (func(prec, emax, emin), randdec(prec, emax), + func(prec, emax, emin)) + yield (func(prec, emax, emin), func(prec, emax, emin), + randdec(prec, emax)) + for func in close_funcs: + yield (randdec(prec, emax), randdec(prec, emax), + func(prec, emax, emin)) + yield (randdec(prec, emax), func(prec, emax, emin), + randdec(prec, emax)) + yield (func(prec, emax, emin), randdec(prec, emax), + randdec(prec, emax)) + + +# If itr == None, test all digit lengths up to prec + 30 +def un_incr_digits(prec, maxexp, itr): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + for m in lst: + yield from_triple(1, ndigits(m), 0) + yield from_triple(-1, ndigits(m), 0) + yield from_triple(1, ndigits(m), randrange(maxexp)) + yield from_triple(-1, ndigits(m), randrange(maxexp)) + +# If itr == None, test all digit lengths up to prec + 30 +# Also output decimals im tuple form. +def un_incr_digits_tuple(prec, maxexp, itr): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + for m in lst: + yield from_triple(1, ndigits(m), 0) + yield from_triple(-1, ndigits(m), 0) + yield from_triple(1, ndigits(m), randrange(maxexp)) + yield from_triple(-1, ndigits(m), randrange(maxexp)) + # test from tuple + yield (0, tuple(map(int, str(ndigits(m)))), 0) + yield (1, tuple(map(int, str(ndigits(m)))), 0) + yield (0, tuple(map(int, str(ndigits(m)))), randrange(maxexp)) + yield (1, tuple(map(int, str(ndigits(m)))), randrange(maxexp)) + +# If itr == None, test all combinations of digit lengths up to prec + 30 +def bin_incr_digits(prec, maxexp, itr): + if itr is None: + lst1 = range(prec+30) + lst2 = range(prec+30) + else: + lst1 = sample(range(prec+30), itr) + lst2 = sample(range(prec+30), itr) + for m in lst1: + x = from_triple(1, ndigits(m), 0) + yield x, x + x = from_triple(-1, ndigits(m), 0) + yield x, x + x = from_triple(1, ndigits(m), randrange(maxexp)) + yield x, x + x = from_triple(-1, ndigits(m), randrange(maxexp)) + yield x, x + for m in lst1: + for n in lst2: + x = from_triple(1, ndigits(m), 0) + y = from_triple(1, ndigits(n), 0) + yield x, y + x = from_triple(-1, ndigits(m), 0) + y = from_triple(1, ndigits(n), 0) + yield x, y + x = from_triple(1, ndigits(m), 0) + y = from_triple(-1, ndigits(n), 0) + yield x, y + x = from_triple(-1, ndigits(m), 0) + y = from_triple(-1, ndigits(n), 0) + yield x, y + x = from_triple(1, ndigits(m), randrange(maxexp)) + y = from_triple(1, ndigits(n), randrange(maxexp)) + yield x, y + x = from_triple(-1, ndigits(m), randrange(maxexp)) + y = from_triple(1, ndigits(n), randrange(maxexp)) + yield x, y + x = from_triple(1, ndigits(m), randrange(maxexp)) + y = from_triple(-1, ndigits(n), randrange(maxexp)) + yield x, y + x = from_triple(-1, ndigits(m), randrange(maxexp)) + y = from_triple(-1, ndigits(n), randrange(maxexp)) + yield x, y + + +def randsign(): + return (1, -1)[randrange(2)] + +# If itr == None, test all combinations of digit lengths up to prec + 30 +def tern_incr_digits(prec, maxexp, itr): + if itr is None: + lst1 = range(prec+30) + lst2 = range(prec+30) + lst3 = range(prec+30) + else: + lst1 = sample(range(prec+30), itr) + lst2 = sample(range(prec+30), itr) + lst3 = sample(range(prec+30), itr) + for m in lst1: + for n in lst2: + for p in lst3: + x = from_triple(randsign(), ndigits(m), 0) + y = from_triple(randsign(), ndigits(n), 0) + z = from_triple(randsign(), ndigits(p), 0) + yield x, y, z + + +# Tests for the 'logical' functions +def bindigits(prec): + z = 0 + for i in range(prec): + z += randrange(2) * 10**i + return z + +def logical_un_incr_digits(prec, itr): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + for m in lst: + yield from_triple(1, bindigits(m), 0) + +def logical_bin_incr_digits(prec, itr): + if itr is None: + lst1 = range(prec+30) + lst2 = range(prec+30) + else: + lst1 = sample(range(prec+30), itr) + lst2 = sample(range(prec+30), itr) + for m in lst1: + x = from_triple(1, bindigits(m), 0) + yield x, x + for m in lst1: + for n in lst2: + x = from_triple(1, bindigits(m), 0) + y = from_triple(1, bindigits(n), 0) + yield x, y + + +def randint(): + p = randrange(1, 100) + return ndigits(p) * (1,-1)[randrange(2)] + +def randfloat(): + p = randrange(1, 100) + s = numeric_value(p, 383) + try: + f = float(numeric_value(p, 383)) + except ValueError: + f = 0.0 + return f + +def randcomplex(): + real = randfloat() + if randrange(100) > 30: + imag = 0.0 + else: + imag = randfloat() + return complex(real, imag) + +def randfraction(): + num = randint() + denom = randint() + if denom == 0: + denom = 1 + return Fraction(num, denom) + +number_funcs = [randint, randfloat, randcomplex, randfraction] + +def un_random_mixed_op(itr=None): + if itr is None: + itr = 1000 + for _ in range(itr): + for func in number_funcs: + yield func() + # Test garbage input + for x in (['x'], ('y',), {'z'}, {1:'z'}): + yield x + +def bin_random_mixed_op(prec, emax, emin, itr=None): + if itr is None: + itr = 1000 + for _ in range(itr): + for func in number_funcs: + yield randdec(prec, emax), func() + yield func(), randdec(prec, emax) + for number in number_funcs: + for dec in close_funcs: + yield dec(prec, emax, emin), number() + # Test garbage input + for x in (['x'], ('y',), {'z'}, {1:'z'}): + for y in (['x'], ('y',), {'z'}, {1:'z'}): + yield x, y + +def tern_random_mixed_op(prec, emax, emin, itr): + if itr is None: + itr = 1000 + for _ in range(itr): + for func in number_funcs: + yield randdec(prec, emax), randdec(prec, emax), func() + yield randdec(prec, emax), func(), func() + yield func(), func(), func() + # Test garbage input + for x in (['x'], ('y',), {'z'}, {1:'z'}): + for y in (['x'], ('y',), {'z'}, {1:'z'}): + for z in (['x'], ('y',), {'z'}, {1:'z'}): + yield x, y, z + +def all_unary(prec, exp_range, itr): + for a in un_close_to_pow10(prec, exp_range, itr): + yield (a,) + for a in un_close_numbers(prec, exp_range, -exp_range, itr): + yield (a,) + for a in un_incr_digits_tuple(prec, exp_range, itr): + yield (a,) + for a in un_randfloat(): + yield (a,) + for a in un_random_mixed_op(itr): + yield (a,) + for a in logical_un_incr_digits(prec, itr): + yield (a,) + for _ in range(100): + yield (randdec(prec, exp_range),) + for _ in range(100): + yield (randtuple(prec, exp_range),) + +def all_binary(prec, exp_range, itr): + for a, b in bin_close_to_pow10(prec, exp_range, itr): + yield a, b + for a, b in bin_close_numbers(prec, exp_range, -exp_range, itr): + yield a, b + for a, b in bin_incr_digits(prec, exp_range, itr): + yield a, b + for a, b in bin_randfloat(): + yield a, b + for a, b in bin_random_mixed_op(prec, exp_range, -exp_range, itr): + yield a, b + for a, b in logical_bin_incr_digits(prec, itr): + yield a, b + for _ in range(100): + yield randdec(prec, exp_range), randdec(prec, exp_range) + +def all_ternary(prec, exp_range, itr): + for a, b, c in tern_close_numbers(prec, exp_range, -exp_range, itr): + yield a, b, c + for a, b, c in tern_incr_digits(prec, exp_range, itr): + yield a, b, c + for a, b, c in tern_randfloat(): + yield a, b, c + for a, b, c in tern_random_mixed_op(prec, exp_range, -exp_range, itr): + yield a, b, c + for _ in range(100): + a = randdec(prec, 2*exp_range) + b = randdec(prec, 2*exp_range) + c = randdec(prec, 2*exp_range) + yield a, b, c diff --git a/Modules/_decimal/tests/randfloat.py b/Modules/_decimal/tests/randfloat.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/randfloat.py @@ -0,0 +1,250 @@ +# Copyright (c) 2010 Python Software Foundation. All Rights Reserved. +# Adapted from Python's Lib/test/test_strtod.py (by Mark Dickinson) + +# More test cases for deccheck.py. + +import random + +TEST_SIZE = 2 + + +def test_short_halfway_cases(): + # exact halfway cases with a small number of significant digits + for k in 0, 5, 10, 15, 20: + # upper = smallest integer >= 2**54/5**k + upper = -(-2**54//5**k) + # lower = smallest odd number >= 2**53/5**k + lower = -(-2**53//5**k) + if lower % 2 == 0: + lower += 1 + for i in range(10 * TEST_SIZE): + # Select a random odd n in [2**53/5**k, + # 2**54/5**k). Then n * 10**k gives a halfway case + # with small number of significant digits. + n, e = random.randrange(lower, upper, 2), k + + # Remove any additional powers of 5. + while n % 5 == 0: + n, e = n // 5, e + 1 + assert n % 10 in (1, 3, 7, 9) + + # Try numbers of the form n * 2**p2 * 10**e, p2 >= 0, + # until n * 2**p2 has more than 20 significant digits. + digits, exponent = n, e + while digits < 10**20: + s = '{}e{}'.format(digits, exponent) + yield s + # Same again, but with extra trailing zeros. + s = '{}e{}'.format(digits * 10**40, exponent - 40) + yield s + digits *= 2 + + # Try numbers of the form n * 5**p2 * 10**(e - p5), p5 + # >= 0, with n * 5**p5 < 10**20. + digits, exponent = n, e + while digits < 10**20: + s = '{}e{}'.format(digits, exponent) + yield s + # Same again, but with extra trailing zeros. + s = '{}e{}'.format(digits * 10**40, exponent - 40) + yield s + digits *= 5 + exponent -= 1 + +def test_halfway_cases(): + # test halfway cases for the round-half-to-even rule + for i in range(1000): + for j in range(TEST_SIZE): + # bit pattern for a random finite positive (or +0.0) float + bits = random.randrange(2047*2**52) + + # convert bit pattern to a number of the form m * 2**e + e, m = divmod(bits, 2**52) + if e: + m, e = m + 2**52, e - 1 + e -= 1074 + + # add 0.5 ulps + m, e = 2*m + 1, e - 1 + + # convert to a decimal string + if e >= 0: + digits = m << e + exponent = 0 + else: + # m * 2**e = (m * 5**-e) * 10**e + digits = m * 5**-e + exponent = e + s = '{}e{}'.format(digits, exponent) + yield s + +def test_boundaries(): + # boundaries expressed as triples (n, e, u), where + # n*10**e is an approximation to the boundary value and + # u*10**e is 1ulp + boundaries = [ + (10000000000000000000, -19, 1110), # a power of 2 boundary (1.0) + (17976931348623159077, 289, 1995), # overflow boundary (2.**1024) + (22250738585072013831, -327, 4941), # normal/subnormal (2.**-1022) + (0, -327, 4941), # zero + ] + for n, e, u in boundaries: + for j in range(1000): + for i in range(TEST_SIZE): + digits = n + random.randrange(-3*u, 3*u) + exponent = e + s = '{}e{}'.format(digits, exponent) + yield s + n *= 10 + u *= 10 + e -= 1 + +def test_underflow_boundary(): + # test values close to 2**-1075, the underflow boundary; similar + # to boundary_tests, except that the random error doesn't scale + # with n + for exponent in range(-400, -320): + base = 10**-exponent // 2**1075 + for j in range(TEST_SIZE): + digits = base + random.randrange(-1000, 1000) + s = '{}e{}'.format(digits, exponent) + yield s + +def test_bigcomp(): + for ndigs in 5, 10, 14, 15, 16, 17, 18, 19, 20, 40, 41, 50: + dig10 = 10**ndigs + for i in range(100 * TEST_SIZE): + digits = random.randrange(dig10) + exponent = random.randrange(-400, 400) + s = '{}e{}'.format(digits, exponent) + yield s + +def test_parsing(): + # make '0' more likely to be chosen than other digits + digits = '000000123456789' + signs = ('+', '-', '') + + # put together random short valid strings + # \d*[.\d*]?e + for i in range(1000): + for j in range(TEST_SIZE): + s = random.choice(signs) + intpart_len = random.randrange(5) + s += ''.join(random.choice(digits) for _ in range(intpart_len)) + if random.choice([True, False]): + s += '.' + fracpart_len = random.randrange(5) + s += ''.join(random.choice(digits) + for _ in range(fracpart_len)) + else: + fracpart_len = 0 + if random.choice([True, False]): + s += random.choice(['e', 'E']) + s += random.choice(signs) + exponent_len = random.randrange(1, 4) + s += ''.join(random.choice(digits) + for _ in range(exponent_len)) + + if intpart_len + fracpart_len: + yield s + +test_particular = [ + # squares + '1.00000000100000000025', + '1.0000000000000000000000000100000000000000000000000' #... + '00025', + '1.0000000000000000000000000000000000000000000010000' #... + '0000000000000000000000000000000000000000025', + '1.0000000000000000000000000000000000000000000000000' #... + '000001000000000000000000000000000000000000000000000' #... + '000000000025', + '0.99999999900000000025', + '0.9999999999999999999999999999999999999999999999999' #... + '999000000000000000000000000000000000000000000000000' #... + '000025', + '0.9999999999999999999999999999999999999999999999999' #... + '999999999999999999999999999999999999999999999999999' #... + '999999999999999999999999999999999999999990000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '0000000000000000000000000000025', + + '1.0000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '100000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000001', + '1.0000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '500000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000005', + '1.0000000000000000000000000000000000000000000000000' #... + '000000000100000000000000000000000000000000000000000' #... + '000000000000000000250000000000000002000000000000000' #... + '000000000000000000000000000000000000000000010000000' #... + '000000000000000000000000000000000000000000000000000' #... + '0000000000000000001', + '1.0000000000000000000000000000000000000000000000000' #... + '000000000100000000000000000000000000000000000000000' #... + '000000000000000000249999999999999999999999999999999' #... + '999999999999979999999999999999999999999999999999999' #... + '999999999999999999999900000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '00000000000000000000000001', + + '0.9999999999999999999999999999999999999999999999999' #... + '999999999900000000000000000000000000000000000000000' #... + '000000000000000000249999999999999998000000000000000' #... + '000000000000000000000000000000000000000000010000000' #... + '000000000000000000000000000000000000000000000000000' #... + '0000000000000000001', + '0.9999999999999999999999999999999999999999999999999' #... + '999999999900000000000000000000000000000000000000000' #... + '000000000000000000250000001999999999999999999999999' #... + '999999999999999999999999999999999990000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '1', + + # tough cases for ln etc. + '1.000000000000000000000000000000000000000000000000' #... + '00000000000000000000000000000000000000000000000000' #... + '00100000000000000000000000000000000000000000000000' #... + '00000000000000000000000000000000000000000000000000' #... + '0001', + '0.999999999999999999999999999999999999999999999999' #... + '99999999999999999999999999999999999999999999999999' #... + '99899999999999999999999999999999999999999999999999' #... + '99999999999999999999999999999999999999999999999999' #... + '99999999999999999999999999999999999999999999999999' #... + '9999' + ] + + +TESTCASES = [ + [x for x in test_short_halfway_cases()], + [x for x in test_halfway_cases()], + [x for x in test_boundaries()], + [x for x in test_underflow_boundary()], + [x for x in test_bigcomp()], + [x for x in test_parsing()], + test_particular +] + +def un_randfloat(): + for i in range(1000): + l = random.choice(TESTCASES[:6]) + yield random.choice(l) + for v in test_particular: + yield v + +def bin_randfloat(): + for i in range(1000): + l1 = random.choice(TESTCASES) + l2 = random.choice(TESTCASES) + yield random.choice(l1), random.choice(l2) + +def tern_randfloat(): + for i in range(1000): + l1 = random.choice(TESTCASES) + l2 = random.choice(TESTCASES) + l3 = random.choice(TESTCASES) + yield random.choice(l1), random.choice(l2), random.choice(l3) diff --git a/Modules/_decimal/tests/runall-memorydebugger.sh b/Modules/_decimal/tests/runall-memorydebugger.sh new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/runall-memorydebugger.sh @@ -0,0 +1,175 @@ +#!/bin/sh + +# +# Purpose: test with and without threads, all machine configurations, pydebug, +# refleaks, release build and release build with valgrind. +# +# Synopsis: ./runall-memorydebugger.sh [--all-configs64 | --all-configs32] +# +# Requirements: valgrind +# + +# Set additional CFLAGS for ./configure +ADD_CFLAGS= + + +CONFIGS_64="x64 uint128 ansi64 universal" +CONFIGS_32="ppro ansi32 ansi-legacy universal" + +VALGRIND="valgrind --tool=memcheck --leak-resolution=high \ + --db-attach=yes --suppressions=Misc/valgrind-python.supp" + +# Get args +case $@ in + *--all-configs64*) + CONFIGS=$CONFIGS_64 + ;; + *--all-configs32*) + CONFIGS=$CONFIGS_32 + ;; + *) + CONFIGS="auto" + ;; +esac + +# gmake required +GMAKE=`which gmake` +if [ X"$GMAKE" = X"" ]; then + GMAKE=make +fi + +# Pretty print configurations +print_config () +{ + len=`echo $@ | wc -c` + margin="#%"`expr \( 74 - $len \) / 2`"s" + + echo "" + echo "# ========================================================================" + printf $margin "" + echo $@ + echo "# ========================================================================" + echo "" +} + + +cd .. + +# test_decimal: refleak, regular and Valgrind tests +for args in "--without-threads" ""; do + for config in $CONFIGS; do + + unset PYTHON_DECIMAL_WITH_MACHINE + libmpdec_config=$config + if [ X"$config" != X"auto" ]; then + PYTHON_DECIMAL_WITH_MACHINE=$config + export PYTHON_DECIMAL_WITH_MACHINE + else + libmpdec_config="" + fi + + ############ refleak tests ########### + print_config "refleak tests: config=$config" $args + printf "\nbuilding python ...\n\n" + + cd ../../ + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== refleak tests ===========================\n\n" + ./python -m test -uall -R 2:2 test_decimal + + + ############ regular tests ########### + print_config "regular tests: config=$config" $args + printf "\nbuilding python ...\n\n" + + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== regular tests ===========================\n\n" + ./python -m test -uall test_decimal + + + ########### valgrind tests ########### + valgrind=$VALGRIND + case "$config" in + # Valgrind has no support for 80 bit long double arithmetic. + ppro) valgrind= ;; + auto) case `uname -m` in + i386|i486|i586|i686) valgrind= ;; + esac + esac + + print_config "valgrind tests: config=$config" $args + printf "\nbuilding python ...\n\n" + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== valgrind tests ===========================\n\n" + $valgrind ./python -m test -uall test_decimal + + cd Modules/_decimal + done +done + +# deccheck +cd ../../ +for config in $CONFIGS; do + for args in "--without-threads" ""; do + + unset PYTHON_DECIMAL_WITH_MACHINE + if [ X"$config" != X"auto" ]; then + PYTHON_DECIMAL_WITH_MACHINE=$config + export PYTHON_DECIMAL_WITH_MACHINE + fi + + ############ debug ############ + print_config "deccheck: config=$config --with-pydebug" $args + printf "\nbuilding python ...\n\n" + + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ========================== debug ===========================\n\n" + ./python Modules/_decimal/tests/deccheck.py + + ########### regular ########### + print_config "deccheck: config=$config " $args + printf "\nbuilding python ...\n\n" + + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== regular ===========================\n\n" + ./python Modules/_decimal/tests/deccheck.py + + ########### valgrind ########### + valgrind=$VALGRIND + case "$config" in + # Valgrind has no support for 80 bit long double arithmetic. + ppro) valgrind= ;; + auto) case `uname -m` in + i386|i486|i586|i686) valgrind= ;; + esac + esac + + print_config "valgrind deccheck: config=$config " $args + printf "\nbuilding python ...\n\n" + + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== valgrind ==========================\n\n" + $valgrind ./python Modules/_decimal/tests/deccheck.py + done +done + + + diff --git a/Modules/_decimal/tests/runall.bat b/Modules/_decimal/tests/runall.bat new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/runall.bat @@ -0,0 +1,121 @@ + at ECHO OFF + +rem Test all machine configurations, pydebug, refleaks, release build. + +cd .. + +call vcvarsall x64 +echo. +echo # ====================================================================== +echo # test_decimal: platform=x64 +echo # ====================================================================== +echo. + +cd ..\..\PCbuild +echo # ==================== refleak tests ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Debug|x64" > NUL 2>&1 +amd64\python_d.exe -m test -uall -R 2:2 test_decimal +echo. + +echo # ==================== regular tests ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Release|x64" > NUL 2>&1 +amd64\python.exe -m test -uall test_decimal +echo. +echo. + + +call vcvarsall x86 +echo. +echo # ====================================================================== +echo # test_decimal: platform=x86 +echo # ====================================================================== +echo. + +echo # ==================== refleak tests ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Debug|win32" > NUL 2>&1 +python_d.exe -m test -uall -R 2:2 test_decimal +echo. + +echo # ==================== regular tests ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Release|win32" > NUL 2>&1 +python.exe -m test -uall test_decimal +echo. +echo. + + +call vcvarsall x64 +echo. +echo # ====================================================================== +echo # deccheck: platform=x64 +echo # ====================================================================== +echo. +echo. +echo # ==================== debug build ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Debug|x64" > NUL 2>&1 +amd64\python_d.exe ..\Modules\_decimal\tests\deccheck.py +echo. +echo. + +echo # =================== release build ====================== +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Release|x64" > NUL 2>&1 +amd64\python.exe ..\Modules\_decimal\tests\deccheck.py +echo. +echo. + + +call vcvarsall x86 +echo. +echo # ====================================================================== +echo # deccheck: platform=x86 +echo # ====================================================================== +echo. +echo. +echo # ==================== debug build ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Debug|win32" > NUL 2>&1 +python_d.exe ..\Modules\_decimal\tests\deccheck.py +echo. +echo. + +echo # =================== release build ====================== +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Release|win32" > NUL 2>&1 +python.exe ..\Modules\_decimal\tests\deccheck.py +echo. +echo. + + +cd ..\Modules\_decimal\tests + + + diff --git a/PCbuild/_decimal.vcproj b/PCbuild/_decimal.vcproj new file mode 100644 --- /dev/null +++ b/PCbuild/_decimal.vcproj @@ -0,0 +1,743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -38,6 +38,11 @@ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_decimal", "_decimal.vcproj", "{0E9791DB-593A-465F-98BC-681011311617}" + ProjectSection(ProjectDependencies) = postProject + {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_ctypes", "_ctypes.vcproj", "{0E9791DB-593A-465F-98BC-681011311618}" ProjectSection(ProjectDependencies) = postProject {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} @@ -271,6 +276,22 @@ {28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|Win32.Build.0 = Release|Win32 {28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.ActiveCfg = Release|x64 {28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.Build.0 = Release|x64 + {0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.ActiveCfg = Debug|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.Build.0 = Debug|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.ActiveCfg = Debug|x64 + {0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.Build.0 = Debug|x64 + {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.Build.0 = PGInstrument|x64 + {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.Build.0 = PGUpdate|x64 + {0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.ActiveCfg = Release|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.Build.0 = Release|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.Release|x64.ActiveCfg = Release|x64 + {0E9791DB-593A-465F-98BC-681011311617}.Release|x64.Build.0 = Release|x64 {0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.ActiveCfg = Debug|Win32 {0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.Build.0 = Debug|Win32 {0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6863,6 +6863,13 @@ fi +ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "$ac_includes_default" +if test "x$ac_cv_type___uint128_t" = xyes; then : + +$as_echo "#define HAVE_GCC_UINT128_T 1" >>confdefs.h + +fi + # Sizes of various common basic types # ANSI C requires sizeof(char) == 1, so no need to check it @@ -12034,6 +12041,40 @@ fi +# ************************************** +# * Check for gcc x64 inline assembler * +# ************************************** + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x64 gcc inline assembler" >&5 +$as_echo_n "checking for x64 gcc inline assembler... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + __asm__ __volatile__ ("movq %rcx, %rax"); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_gcc_asm_for_x64=yes +else + have_gcc_asm_for_x64=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x64" >&5 +$as_echo "$have_gcc_asm_for_x64" >&6; } +if test "$have_gcc_asm_for_x64" = yes +then + +$as_echo "#define HAVE_GCC_ASM_FOR_X64 1" >>confdefs.h + +fi + # ************************************************** # * Check for various properties of floating point * # ************************************************** @@ -14228,6 +14269,136 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } +# Availability of -O2: +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -O2" >&5 +$as_echo_n "checking for -O2... " >&6; } +saved_cflags="$CFLAGS" +CFLAGS="-O2" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_O2=yes +else + have_O2=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_O2" >&5 +$as_echo "$have_O2" >&6; } +CFLAGS="$saved_cflags" + +# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: +# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc _FORTIFY_SOURCE/memmove bug" >&5 +$as_echo_n "checking for glibc _FORTIFY_SOURCE/memmove bug... " >&6; } +saved_cflags="$CFLAGS" +CFLAGS="-O2 -D_FORTIFY_SOURCE=2" +if test "$have_O2" = no; then + CFLAGS="" +fi +if test "$cross_compiling" = yes; then : + have_glibc_memmove_bug=undefined +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +void foo(void *p, void *q) { memmove(p, q, 19); } +int main() { + char a[32] = "123456789000000000"; + foo(&a[9], a); + if (strcmp(a, "123456789123456789000000000") != 0) + return 1; + foo(a, &a[9]); + if (strcmp(a, "123456789000000000") != 0) + return 1; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + have_glibc_memmove_bug=no +else + have_glibc_memmove_bug=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +CFLAGS="$saved_cflags" +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_glibc_memmove_bug" >&5 +$as_echo "$have_glibc_memmove_bug" >&6; } +if test "$have_glibc_memmove_bug" = yes; then + +$as_echo "#define HAVE_GLIBC_MEMMOVE_BUG 1" >>confdefs.h + +fi + +if test "$have_gcc_asm_for_x87" = yes; then + # Some versions of gcc miscompile inline asm: + # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 + # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html + case $CC in + *gcc*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc ipa-pure-const bug" >&5 +$as_echo_n "checking for gcc ipa-pure-const bug... " >&6; } + saved_cflags="$CFLAGS" + CFLAGS="-O2" + if test "$cross_compiling" = yes; then : + have_ipa_pure_const_bug=undefined +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + __attribute__((noinline)) int + foo(int *p) { + int r; + asm ( "movl \$6, (%1)\n\t" + "xorl %0, %0\n\t" + : "=r" (r) : "r" (p) : "memory" + ); + return r; + } + int main() { + int p = 8; + if ((foo(&p) ? : p) != 6) + return 1; + return 0; + } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + have_ipa_pure_const_bug=no +else + have_ipa_pure_const_bug=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$saved_cflags" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ipa_pure_const_bug" >&5 +$as_echo "$have_ipa_pure_const_bug" >&6; } + if test "$have_ipa_pure_const_bug" = yes; then + +$as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h + + fi + ;; + esac +fi + # generate output files ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc" diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1483,6 +1483,8 @@ AC_TYPE_INT64_T AC_CHECK_TYPE(ssize_t, AC_DEFINE(HAVE_SSIZE_T, 1, [Define if your compiler provides ssize_t]),,) +AC_CHECK_TYPE(__uint128_t, + AC_DEFINE(HAVE_GCC_UINT128_T, 1, [Define if your compiler provides __uint128_t]),,) # Sizes of various common basic types # ANSI C requires sizeof(char) == 1, so no need to check it @@ -3329,6 +3331,21 @@ fi], [AC_MSG_RESULT(default LIBC="$LIBC")]) +# ************************************** +# * Check for gcc x64 inline assembler * +# ************************************** + +AC_MSG_CHECKING(for x64 gcc inline assembler) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ + __asm__ __volatile__ ("movq %rcx, %rax"); +]])],[have_gcc_asm_for_x64=yes],[have_gcc_asm_for_x64=no]) +AC_MSG_RESULT($have_gcc_asm_for_x64) +if test "$have_gcc_asm_for_x64" = yes +then + AC_DEFINE(HAVE_GCC_ASM_FOR_X64, 1, + [Define if we can use x64 gcc inline assembler]) +fi + # ************************************************** # * Check for various properties of floating point * # ************************************************** @@ -4333,6 +4350,89 @@ done AC_MSG_RESULT(done) +# Availability of -O2: +AC_MSG_CHECKING(for -O2) +saved_cflags="$CFLAGS" +CFLAGS="-O2" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +]])],[have_O2=yes],[have_O2=no]) +AC_MSG_RESULT($have_O2) +CFLAGS="$saved_cflags" + +# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: +# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html +AC_MSG_CHECKING(for glibc _FORTIFY_SOURCE/memmove bug) +saved_cflags="$CFLAGS" +CFLAGS="-O2 -D_FORTIFY_SOURCE=2" +if test "$have_O2" = no; then + CFLAGS="" +fi +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#include +#include +void foo(void *p, void *q) { memmove(p, q, 19); } +int main() { + char a[32] = "123456789000000000"; + foo(&a[9], a); + if (strcmp(a, "123456789123456789000000000") != 0) + return 1; + foo(a, &a[9]); + if (strcmp(a, "123456789000000000") != 0) + return 1; + return 0; +} +]])], +[have_glibc_memmove_bug=no], +[have_glibc_memmove_bug=yes], +[have_glibc_memmove_bug=undefined]) +CFLAGS="$saved_cflags" +AC_MSG_RESULT($have_glibc_memmove_bug) +if test "$have_glibc_memmove_bug" = yes; then + AC_DEFINE(HAVE_GLIBC_MEMMOVE_BUG, 1, + [Define if glibc has incorrect _FORTIFY_SOURCE wrappers + for memmove and bcopy.]) +fi + +if test "$have_gcc_asm_for_x87" = yes; then + # Some versions of gcc miscompile inline asm: + # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 + # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html + case $CC in + *gcc*) + AC_MSG_CHECKING(for gcc ipa-pure-const bug) + saved_cflags="$CFLAGS" + CFLAGS="-O2" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + __attribute__((noinline)) int + foo(int *p) { + int r; + asm ( "movl \$6, (%1)\n\t" + "xorl %0, %0\n\t" + : "=r" (r) : "r" (p) : "memory" + ); + return r; + } + int main() { + int p = 8; + if ((foo(&p) ? : p) != 6) + return 1; + return 0; + } + ]])], + [have_ipa_pure_const_bug=no], + [have_ipa_pure_const_bug=yes], + [have_ipa_pure_const_bug=undefined]) + CFLAGS="$saved_cflags" + AC_MSG_RESULT($have_ipa_pure_const_bug) + if test "$have_ipa_pure_const_bug" = yes; then + AC_DEFINE(HAVE_IPA_PURE_CONST_BUG, 1, + [Define if gcc has the ipa-pure-const bug.]) + fi + ;; + esac +fi + # generate output files AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc) AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix]) diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -304,10 +304,16 @@ /* Define to 1 if you have the `gamma' function. */ #undef HAVE_GAMMA +/* Define if we can use x64 gcc inline assembler */ +#undef HAVE_GCC_ASM_FOR_X64 + /* Define if we can use gcc inline assembler to get and set x87 control word */ #undef HAVE_GCC_ASM_FOR_X87 +/* Define if your compiler provides __uint128_t */ +#undef HAVE_GCC_UINT128_T + /* Define if you have the getaddrinfo function. */ #undef HAVE_GETADDRINFO @@ -392,6 +398,10 @@ /* Define to 1 if you have the `getwd' function. */ #undef HAVE_GETWD +/* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and + bcopy. */ +#undef HAVE_GLIBC_MEMMOVE_BUG + /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H @@ -422,6 +432,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_IO_H +/* Define if gcc has the ipa-pure-const bug. */ +#undef HAVE_IPA_PURE_CONST_BUG + /* Define to 1 if you have the `kill' function. */ #undef HAVE_KILL diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -1342,6 +1342,9 @@ exts.append(Extension('_codecs_%s' % loc, ['cjkcodecs/_codecs_%s.c' % loc])) + # Stefan Krah's _decimal module + exts.append(self._decimal_ext()) + # Thomas Heller's _ctypes module self.detect_ctypes(inc_dirs, lib_dirs) @@ -1792,6 +1795,116 @@ ext.libraries.append(ffi_lib) self.use_system_libffi = True + def _decimal_ext(self): + sources = [ + '_decimal/_decimal.c', + '_decimal/libmpdec/basearith.c', + '_decimal/libmpdec/constants.c', + '_decimal/libmpdec/context.c', + '_decimal/libmpdec/convolute.c', + '_decimal/libmpdec/crt.c', + '_decimal/libmpdec/difradix2.c', + '_decimal/libmpdec/fnt.c', + '_decimal/libmpdec/fourstep.c', + '_decimal/libmpdec/io.c', + '_decimal/libmpdec/memory.c', + '_decimal/libmpdec/mpdecimal.c', + '_decimal/libmpdec/numbertheory.c', + '_decimal/libmpdec/sixstep.c', + '_decimal/libmpdec/transpose.c', + ] + depends = [ + '_decimal/docstrings.h', + '_decimal/libmpdec/basearith.h', + '_decimal/libmpdec/bits.h', + '_decimal/libmpdec/constants.h', + '_decimal/libmpdec/convolute.h', + '_decimal/libmpdec/crt.h', + '_decimal/libmpdec/difradix2.h', + '_decimal/libmpdec/fnt.h', + '_decimal/libmpdec/fourstep.h', + '_decimal/libmpdec/io.h', + '_decimal/libmpdec/memory.h', + '_decimal/libmpdec/mpdecimal.h', + '_decimal/libmpdec/numbertheory.h', + '_decimal/libmpdec/sixstep.h', + '_decimal/libmpdec/transpose.h', + '_decimal/libmpdec/typearith.h', + '_decimal/libmpdec/umodarith.h', + ] + config = { + 'x64': [('CONFIG_64','1'), ('ASM','1')], + 'uint128': [('CONFIG_64','1'), ('ANSI','1'), ('HAVE_UINT128_T','1')], + 'ansi64': [('CONFIG_64','1'), ('ANSI','1')], + 'ppro': [('CONFIG_32','1'), ('PPRO','1'), ('ASM','1')], + 'ansi32': [('CONFIG_32','1'), ('ANSI','1')], + 'ansi-legacy': [('CONFIG_32','1'), ('ANSI','1'), + ('LEGACY_COMPILER','1')], + 'universal': [('UNIVERSAL','1')] + } + + include_dirs = ['./Modules/_decimal/libmpdec'] + extra_compile_args = [] + undef_macros=['NDEBUG'] + + platform = self.get_platform() + cc = sysconfig.get_config_var('CC') + sizeof_size_t = sysconfig.get_config_var('SIZEOF_SIZE_T') + machine = os.environ.get('PYTHON_DECIMAL_WITH_MACHINE') + + if machine: + # Override automatic configuration to facilitate testing. + define_macros = config[machine] + elif platform == 'darwin': + # Universal here means: build with the same options Python + # was built with. + define_macros = config['universal'] + elif sizeof_size_t == 8: + if sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X64'): + define_macros = config['x64'] + elif sysconfig.get_config_var('HAVE_GCC_UINT128_T'): + define_macros = config['uint128'] + else: + define_macros = config['ansi64'] + elif sizeof_size_t == 4: + ppro = sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X87') + if ppro and ('gcc' in cc or 'clang' in cc) and \ + not 'sunos' in platform: + # solaris: problems with register allocation. + # icc >= 11.0 works as well. + define_macros = config['ppro'] + else: + define_macros = config['ansi32'] + else: + raise DistutilsError("_decimal: unsupported architecture") + + # Workarounds for toolchain bugs: + if sysconfig.get_config_var('HAVE_IPA_PURE_CONST_BUG'): + # Some versions of gcc miscompile inline asm: + # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 + # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html + extra_compile_args.append('-fno-ipa-pure-const') + if sysconfig.get_config_var('HAVE_GLIBC_MEMMOVE_BUG'): + # _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: + # http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html + undef_macros.append('_FORTIFY_SOURCE') + + # Faster version without thread local contexts: + if not sysconfig.get_config_var('WITH_THREAD'): + define_macros.append(('WITHOUT_THREADS', 1)) + + # Uncomment for extra functionality: + #define_macros.append(('EXTRA_FUNCTIONALITY', 1)) + ext = Extension ( + '_decimal', + include_dirs=include_dirs, + define_macros=define_macros, + undef_macros=undef_macros, + extra_compile_args=extra_compile_args, + sources=sources, + depends=depends + ) + return ext class PyBuildInstall(install): # Suppress the warning about installation into the lib_dynload -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 18:48:16 2012 From: python-checkins at python.org (stefan.krah) Date: Wed, 21 Mar 2012 18:48:16 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Document_decimal=2EMIN=5FET?= =?utf8?q?INY=2E?= Message-ID: http://hg.python.org/cpython/rev/3d5ef57742d3 changeset: 75851:3d5ef57742d3 user: Stefan Krah date: Wed Mar 21 18:47:20 2012 +0100 summary: Document decimal.MIN_ETINY. files: Doc/library/decimal.rst | 21 ++++++++++++--------- 1 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -1387,15 +1387,18 @@ The constants in this section are only relevant for the C module. They are also included in the pure Python version for compatibility. -+--------------------+---------------------+------------------------------+ -| | 32-bit | 64-bit | -+====================+=====================+==============================+ -| .. data:: MAX_PREC | :const:`425000000` | :const:`999999999999999999` | -+--------------------+---------------------+------------------------------+ -| .. data:: MAX_EMAX | :const:`425000000` | :const:`999999999999999999` | -+--------------------+---------------------+------------------------------+ -| .. data:: MIN_EMIN | :const:`-425000000` | :const:`-999999999999999999` | -+--------------------+---------------------+------------------------------+ ++---------------------+---------------------+-------------------------------+ +| | 32-bit | 64-bit | ++=====================+=====================+===============================+ +| .. data:: MAX_PREC | :const:`425000000` | :const:`999999999999999999` | ++---------------------+---------------------+-------------------------------+ +| .. data:: MAX_EMAX | :const:`425000000` | :const:`999999999999999999` | ++---------------------+---------------------+-------------------------------+ +| .. data:: MIN_EMIN | :const:`-425000000` | :const:`-999999999999999999` | ++---------------------+---------------------+-------------------------------+ +| .. data:: MIN_ETINY | :const:`-849999999` | :const:`-1999999999999999997` | ++---------------------+---------------------+-------------------------------+ + .. data:: HAVE_THREADS -- Repository URL: http://hg.python.org/cpython From andrew.svetlov at gmail.com Wed Mar 21 18:49:18 2012 From: andrew.svetlov at gmail.com (Andrew Svetlov) Date: Wed, 21 Mar 2012 19:49:18 +0200 Subject: [Python-checkins] cpython: Issue #7652: Integrate the decimal floating point libmpdec library to speed In-Reply-To: References: Message-ID: Excellent! On Wed, Mar 21, 2012 at 7:27 PM, stefan.krah wrote: > http://hg.python.org/cpython/rev/7355550d5357 > changeset: ? 75850:7355550d5357 > user: ? ? ? ?Stefan Krah > date: ? ? ? ?Wed Mar 21 18:25:23 2012 +0100 > summary: > ?Issue #7652: Integrate the decimal floating point libmpdec library to speed > up the decimal module. Performance gains of the new C implementation are > between 12x and 80x, depending on the application. > > files: > ?Doc/library/decimal.rst ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? 178 +- > ?Doc/library/numeric.rst ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? 6 +- > ?Doc/whatsnew/3.3.rst ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? ?87 + > ?Include/longintrepr.h ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? 2 +- > ?Lib/decimal.py ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? 196 +- > ?Lib/test/support.py ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? 4 +- > ?Lib/test/test_decimal.py ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ?4550 ++++- > ?Lib/test/test_fractions.py ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? ?12 +- > ?Lib/test/test_numeric_tower.py ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? ? 2 +- > ?Misc/NEWS ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? 4 + > ?Misc/valgrind-python.supp ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ?13 + > ?Modules/_decimal/ISSUES.txt ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ?56 + > ?Modules/_decimal/README.txt ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ?46 + > ?Modules/_decimal/_decimal.c ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ?5512 +++++++ > ?Modules/_decimal/docstrings.h ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? 753 + > ?Modules/_decimal/libmpdec/README.txt ? ? ? ? ? ? ? ? ? ? ?| ? ?90 + > ?Modules/_decimal/libmpdec/basearith.c ? ? ? ? ? ? ? ? ? ? | ? 635 + > ?Modules/_decimal/libmpdec/basearith.h ? ? ? ? ? ? ? ? ? ? | ? 213 + > ?Modules/_decimal/libmpdec/bits.h ? ? ? ? ? ? ? ? ? ? ? ? ?| ? 192 + > ?Modules/_decimal/libmpdec/constants.c ? ? ? ? ? ? ? ? ? ? | ? 132 + > ?Modules/_decimal/libmpdec/constants.h ? ? ? ? ? ? ? ? ? ? | ? ?83 + > ?Modules/_decimal/libmpdec/context.c ? ? ? ? ? ? ? ? ? ? ? | ? 286 + > ?Modules/_decimal/libmpdec/convolute.c ? ? ? ? ? ? ? ? ? ? | ? 174 + > ?Modules/_decimal/libmpdec/convolute.h ? ? ? ? ? ? ? ? ? ? | ? ?43 + > ?Modules/_decimal/libmpdec/crt.c ? ? ? ? ? ? ? ? ? ? ? ? ? | ? 179 + > ?Modules/_decimal/libmpdec/crt.h ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ?40 + > ?Modules/_decimal/libmpdec/difradix2.c ? ? ? ? ? ? ? ? ? ? | ? 173 + > ?Modules/_decimal/libmpdec/difradix2.h ? ? ? ? ? ? ? ? ? ? | ? ?41 + > ?Modules/_decimal/libmpdec/fnt.c ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ?81 + > ?Modules/_decimal/libmpdec/fnt.h ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ?42 + > ?Modules/_decimal/libmpdec/fourstep.c ? ? ? ? ? ? ? ? ? ? ?| ? 255 + > ?Modules/_decimal/libmpdec/fourstep.h ? ? ? ? ? ? ? ? ? ? ?| ? ?41 + > ?Modules/_decimal/libmpdec/io.c ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ?1575 ++ > ?Modules/_decimal/libmpdec/io.h ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? ?59 + > ?Modules/_decimal/libmpdec/literature/REFERENCES.txt ? ? ? | ? ?51 + > ?Modules/_decimal/libmpdec/literature/bignum.txt ? ? ? ? ? | ? ?83 + > ?Modules/_decimal/libmpdec/literature/fnt.py ? ? ? ? ? ? ? | ? 208 + > ?Modules/_decimal/libmpdec/literature/matrix-transform.txt | ? 256 + > ?Modules/_decimal/libmpdec/literature/mulmod-64.txt ? ? ? ?| ? 127 + > ?Modules/_decimal/libmpdec/literature/mulmod-ppro.txt ? ? ?| ? 269 + > ?Modules/_decimal/libmpdec/literature/six-step.txt ? ? ? ? | ? ?63 + > ?Modules/_decimal/libmpdec/literature/umodarith.lisp ? ? ? | ? 692 + > ?Modules/_decimal/libmpdec/memory.c ? ? ? ? ? ? ? ? ? ? ? ?| ? 292 + > ?Modules/_decimal/libmpdec/memory.h ? ? ? ? ? ? ? ? ? ? ? ?| ? ?44 + > ?Modules/_decimal/libmpdec/mpdecimal.c ? ? ? ? ? ? ? ? ? ? | ?7596 ++++++++++ > ?Modules/_decimal/libmpdec/mpdecimal.h ? ? ? ? ? ? ? ? ? ? | ? 800 + > ?Modules/_decimal/libmpdec/numbertheory.c ? ? ? ? ? ? ? ? ?| ? 132 + > ?Modules/_decimal/libmpdec/numbertheory.h ? ? ? ? ? ? ? ? ?| ? ?71 + > ?Modules/_decimal/libmpdec/sixstep.c ? ? ? ? ? ? ? ? ? ? ? | ? 212 + > ?Modules/_decimal/libmpdec/sixstep.h ? ? ? ? ? ? ? ? ? ? ? | ? ?41 + > ?Modules/_decimal/libmpdec/transpose.c ? ? ? ? ? ? ? ? ? ? | ? 276 + > ?Modules/_decimal/libmpdec/transpose.h ? ? ? ? ? ? ? ? ? ? | ? ?55 + > ?Modules/_decimal/libmpdec/typearith.h ? ? ? ? ? ? ? ? ? ? | ? 669 + > ?Modules/_decimal/libmpdec/umodarith.h ? ? ? ? ? ? ? ? ? ? | ? 650 + > ?Modules/_decimal/libmpdec/vccompat.h ? ? ? ? ? ? ? ? ? ? ?| ? ?62 + > ?Modules/_decimal/libmpdec/vcdiv64.asm ? ? ? ? ? ? ? ? ? ? | ? ?48 + > ?Modules/_decimal/libmpdec/vcstdint.h ? ? ? ? ? ? ? ? ? ? ?| ? 232 + > ?Modules/_decimal/tests/README.txt ? ? ? ? ? ? ? ? ? ? ? ? | ? ?15 + > ?Modules/_decimal/tests/bench.py ? ? ? ? ? ? ? ? ? ? ? ? ? | ? 116 + > ?Modules/_decimal/tests/deccheck.py ? ? ? ? ? ? ? ? ? ? ? ?| ?1074 + > ?Modules/_decimal/tests/formathelper.py ? ? ? ? ? ? ? ? ? ?| ? 344 + > ?Modules/_decimal/tests/randdec.py ? ? ? ? ? ? ? ? ? ? ? ? | ? 559 + > ?Modules/_decimal/tests/randfloat.py ? ? ? ? ? ? ? ? ? ? ? | ? 250 + > ?Modules/_decimal/tests/runall-memorydebugger.sh ? ? ? ? ? | ? 175 + > ?Modules/_decimal/tests/runall.bat ? ? ? ? ? ? ? ? ? ? ? ? | ? 121 + > ?PCbuild/_decimal.vcproj ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? 743 + > ?PCbuild/pcbuild.sln ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ?21 + > ?configure ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? 171 + > ?configure.ac ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? 100 + > ?pyconfig.h.in ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ?13 + > ?setup.py ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? 113 + > ?71 files changed, 31440 insertions(+), 1059 deletions(-) > > > diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst > --- a/Doc/library/decimal.rst > +++ b/Doc/library/decimal.rst > @@ -9,6 +9,7 @@ > ?.. moduleauthor:: Raymond Hettinger > ?.. moduleauthor:: Aahz > ?.. moduleauthor:: Tim Peters > +.. moduleauthor:: Stefan Krah > ?.. sectionauthor:: Raymond D. Hettinger > > ?.. import modules for testing inline doctests with the Sphinx doctest builder > @@ -20,8 +21,9 @@ > ? ?# make sure each group gets a fresh context > ? ?setcontext(Context()) > > -The :mod:`decimal` module provides support for decimal floating point > -arithmetic. ?It offers several advantages over the :class:`float` datatype: > +The :mod:`decimal` module provides support for fast correctly-rounded > +decimal floating point arithmetic. It offers several advantages over the > +:class:`float` datatype: > > ?* Decimal "is based on a floating-point model which was designed with people > ? in mind, and necessarily has a paramount guiding principle -- computers must > @@ -92,7 +94,7 @@ > ?considered as informational, or treated as exceptions. The signals in the > ?decimal module are: :const:`Clamped`, :const:`InvalidOperation`, > ?:const:`DivisionByZero`, :const:`Inexact`, :const:`Rounded`, :const:`Subnormal`, > -:const:`Overflow`, and :const:`Underflow`. > +:const:`Overflow`, :const:`Underflow` and :const:`FloatOperation`. > > ?For each signal there is a flag and a trap enabler. ?When a signal is > ?encountered, its flag is set to one, then, if the trap enabler is > @@ -122,7 +124,7 @@ > > ? ?>>> from decimal import * > ? ?>>> getcontext() > - ? Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, > + ? Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, > ? ? ? ? ? ?capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero, > ? ? ? ? ? ?InvalidOperation]) > > @@ -132,7 +134,7 @@ > ?Construction from an integer or a float performs an exact conversion of the > ?value of that integer or float. ?Decimal numbers include special values such as > ?:const:`NaN` which stands for "Not a number", positive and negative > -:const:`Infinity`, and :const:`-0`. > +:const:`Infinity`, and :const:`-0`:: > > ? ?>>> getcontext().prec = 28 > ? ?>>> Decimal(10) > @@ -152,6 +154,25 @@ > ? ?>>> Decimal('-Infinity') > ? ?Decimal('-Infinity') > > +If the :exc:`FloatOperation` signal is trapped, accidental mixing of > +decimals and floats in constructors or ordering comparisons raises > +an exception:: > + > + ? >>> c = getcontext() > + ? >>> c.traps[FloatOperation] = True > + ? >>> Decimal(3.14) > + ? Traceback (most recent call last): > + ? File "", line 1, in > + ? decimal.FloatOperation: [] > + ? >>> Decimal('3.5') < 3.7 > + ? Traceback (most recent call last): > + ? ? File "", line 1, in > + ? decimal.FloatOperation: [] > + ? >>> Decimal('3.5') == 3.5 > + ? True > + > +.. versionadded:: 3.3 > + > ?The significance of a new Decimal is determined solely by the number of digits > ?input. ?Context precision and rounding only come into play during arithmetic > ?operations. > @@ -169,6 +190,16 @@ > ? ?>>> Decimal('3.1415926535') + Decimal('2.7182818285') > ? ?Decimal('5.85988') > > +If the internal limits of the C version are exceeded, constructing > +a decimal raises :class:`InvalidOperation`:: > + > + ? >>> Decimal("1e9999999999999999999") > + ? Traceback (most recent call last): > + ? ? File "", line 1, in > + ? decimal.InvalidOperation: [] > + > +.. versionchanged:: 3.3 > + > ?Decimals interact well with much of the rest of Python. ?Here is a small decimal > ?floating point flying circus: > > @@ -244,7 +275,7 @@ > ? ?Decimal('0.142857142857142857142857142857142857142857142857142857142857') > > ? ?>>> ExtendedContext > - ? Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, > + ? Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, > ? ? ? ? ? ?capitals=1, clamp=0, flags=[], traps=[]) > ? ?>>> setcontext(ExtendedContext) > ? ?>>> Decimal(1) / Decimal(7) > @@ -269,7 +300,7 @@ > ? ?>>> Decimal(355) / Decimal(113) > ? ?Decimal('3.14159292') > ? ?>>> getcontext() > - ? Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, > + ? Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, > ? ? ? ? ? ?capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[]) > > ?The *flags* entry shows that the rational approximation to :const:`Pi` was > @@ -358,6 +389,10 @@ > ? ? ? The argument to the constructor is now permitted to be a :class:`float` > ? ? ? instance. > > + ? .. versionchanged:: 3.3 > + ? ? ?:class:`float` arguments raise an exception if the :exc:`FloatOperation` > + ? ? ?trap is set. By default the trap is off. > + > ? ?Decimal floating point objects share many properties with the other built-in > ? ?numeric types such as :class:`float` and :class:`int`. ?All of the usual math > ? ?operations and special methods apply. ?Likewise, decimal objects can be > @@ -880,39 +915,33 @@ > ? ?In single threaded environments, it is preferable to not use this context at > ? ?all. ?Instead, simply create contexts explicitly as described below. > > - ? The default values are precision=28, rounding=ROUND_HALF_EVEN, and enabled traps > - ? for Overflow, InvalidOperation, and DivisionByZero. > + ? The default values are :attr:`prec`\ =\ :const:`28`, > + ? :attr:`rounding`\ =\ :const:`ROUND_HALF_EVEN`, > + ? and enabled traps for :class:`Overflow`, :class:`InvalidOperation`, and > + ? :class:`DivisionByZero`. > > ?In addition to the three supplied contexts, new contexts can be created with the > ?:class:`Context` constructor. > > > -.. class:: Context(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=None, clamp=None) > +.. class:: Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None) > > ? ?Creates a new context. ?If a field is not specified or is :const:`None`, the > ? ?default values are copied from the :const:`DefaultContext`. ?If the *flags* > ? ?field is not specified or is :const:`None`, all flags are cleared. > > - ? The *prec* field is a positive integer that sets the precision for arithmetic > - ? operations in the context. > - > - ? The *rounding* option is one of: > - > - ? * :const:`ROUND_CEILING` (towards :const:`Infinity`), > - ? * :const:`ROUND_DOWN` (towards zero), > - ? * :const:`ROUND_FLOOR` (towards :const:`-Infinity`), > - ? * :const:`ROUND_HALF_DOWN` (to nearest with ties going towards zero), > - ? * :const:`ROUND_HALF_EVEN` (to nearest with ties going to nearest even integer), > - ? * :const:`ROUND_HALF_UP` (to nearest with ties going away from zero), or > - ? * :const:`ROUND_UP` (away from zero). > - ? * :const:`ROUND_05UP` (away from zero if last digit after rounding towards zero > - ? ? would have been 0 or 5; otherwise towards zero) > + ? *prec* is an integer in the range [:const:`1`, :const:`MAX_PREC`] that sets > + ? the precision for arithmetic operations in the context. > + > + ? The *rounding* option is one of the constants listed in the section > + ? `Rounding Modes`_. > > ? ?The *traps* and *flags* fields list any signals to be set. Generally, new > ? ?contexts should only set traps and leave the flags clear. > > ? ?The *Emin* and *Emax* fields are integers specifying the outer limits allowable > - ? for exponents. > + ? for exponents. *Emin* must be in the range [:const:`MIN_EMIN`, :const:`0`], > + ? *Emax* in the range [:const:`0`, :const:`MAX_EMAX`]. > > ? ?The *capitals* field is either :const:`0` or :const:`1` (the default). If set to > ? ?:const:`1`, exponents are printed with a capital :const:`E`; otherwise, a > @@ -951,6 +980,12 @@ > > ? ? ? Resets all of the flags to :const:`0`. > > + ? .. method:: clear_traps() > + > + ? ? ?Resets all of the traps to :const:`0`. > + > + ? ? ?.. versionadded:: 3.3 > + > ? ?.. method:: copy() > > ? ? ? Return a duplicate of the context. > @@ -1250,8 +1285,13 @@ > ? ? ? With two arguments, compute ``x**y``. ?If ``x`` is negative then ``y`` > ? ? ? must be integral. ?The result will be inexact unless ``y`` is integral and > ? ? ? the result is finite and can be expressed exactly in 'precision' digits. > - ? ? ?The result should always be correctly rounded, using the rounding mode of > - ? ? ?the current thread's context. > + ? ? ?The rounding mode of the context is used. Results are always correctly-rounded > + ? ? ?in the Python version. > + > + ? ? ?.. versionchanged:: 3.3 > + ? ? ? ? The C module computes :meth:`power` in terms of the correctly-rounded > + ? ? ? ? :meth:`exp` and :meth:`ln` functions. The result is well-defined but > + ? ? ? ? only "almost always correctly-rounded". > > ? ? ? With three arguments, compute ``(x**y) % modulo``. ?For the three argument > ? ? ? form, the following restrictions on the arguments hold: > @@ -1339,6 +1379,66 @@ > > ?.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% > > +.. _decimal-rounding-modes: > + > +Constants > +--------- > + > +The constants in this section are only relevant for the C module. They > +are also included in the pure Python version for compatibility. > + > ++--------------------+---------------------+------------------------------+ > +| ? ? ? ? ? ? ? ? ? ?| ? ? ? 32-bit ? ? ? ?| ? ? ? ? ? ?64-bit ? ? ? ? ? ?| > ++====================+=====================+==============================+ > +| .. data:: MAX_PREC | :const:`425000000` ?| :const:`999999999999999999` ?| > ++--------------------+---------------------+------------------------------+ > +| .. data:: MAX_EMAX | :const:`425000000` ?| :const:`999999999999999999` ?| > ++--------------------+---------------------+------------------------------+ > +| .. data:: MIN_EMIN | :const:`-425000000` | :const:`-999999999999999999` | > ++--------------------+---------------------+------------------------------+ > + > +.. data:: HAVE_THREADS > + > + ? The default value is True. If Python is compiled without threads, the > + ? C version automatically disables the expensive thread local context > + ? machinery. In this case, the value is False. > + > +Rounding modes > +-------------- > + > +.. data:: ROUND_CEILING > + > + ? Round towards :const:`Infinity`. > + > +.. data:: ROUND_DOWN > + > + ? Round towards zero. > + > +.. data:: ROUND_FLOOR > + > + ? Round towards :const:`-Infinity`. > + > +.. data:: ROUND_HALF_DOWN > + > + ? Round to nearest with ties going towards zero. > + > +.. data:: ROUND_HALF_EVEN > + > + ? Round to nearest with ties going to nearest even integer. > + > +.. data:: ROUND_HALF_UP > + > + ? Round to nearest with ties going away from zero. > + > +.. data:: ROUND_UP > + > + ? Round away from zero. > + > +.. data:: ROUND_05UP > + > + ? Round away from zero if last digit after rounding towards zero would have > + ? been 0 or 5; otherwise round towards zero. > + > > ?.. _decimal-signals: > > @@ -1403,7 +1503,6 @@ > ? ? ? Infinity / Infinity > ? ? ? x % 0 > ? ? ? Infinity % x > - ? ? ?x._rescale( non-integer ) > ? ? ? sqrt(-x) and x > 0 > ? ? ? 0 ** 0 > ? ? ? x ** (non-integer) > @@ -1446,6 +1545,23 @@ > ? ?Occurs when a subnormal result is pushed to zero by rounding. :class:`Inexact` > ? ?and :class:`Subnormal` are also signaled. > > + > +.. class:: FloatOperation > + > + ? ?Enable stricter semantics for mixing floats and Decimals. > + > + ? ?If the signal is not trapped (default), mixing floats and Decimals is > + ? ?permitted in the :class:`~decimal.Decimal` constructor, > + ? ?:meth:`~decimal.Context.create_decimal` and all comparison operators. > + ? ?Both conversion and comparisons are exact. Any occurrence of a mixed > + ? ?operation is silently recorded by setting :exc:`FloatOperation` in the > + ? ?context flags. Explicit conversions with :meth:`~decimal.Decimal.from_float` > + ? ?or :meth:`~decimal.Context.create_decimal_from_float` do not set the flag. > + > + ? ?Otherwise (the signal is trapped), only equality comparisons and explicit > + ? ?conversions are silent. All other mixed operations raise :exc:`FloatOperation`. > + > + > ?The following table summarizes the hierarchy of signals:: > > ? ?exceptions.ArithmeticError(exceptions.Exception) > @@ -1458,10 +1574,12 @@ > ? ? ? ? ? ?InvalidOperation > ? ? ? ? ? ?Rounded > ? ? ? ? ? ?Subnormal > + ? ? ? ? ? FloatOperation > > ?.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% > > > + > ?.. _decimal-notes: > > ?Floating Point Notes > @@ -1571,7 +1689,7 @@ > ?the following calculation returns a value equal to zero: > > ? ?>>> 1 / Decimal('Infinity') > - ? Decimal('0E-1000000026') > + ? Decimal('0E-1000026') > > ?.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% > > @@ -1583,7 +1701,7 @@ > > ?The :func:`getcontext` function accesses a different :class:`Context` object for > ?each thread. ?Having separate thread contexts means that threads may make > -changes (such as ``getcontext.prec=10``) without interfering with other threads. > +changes (such as ``getcontext().prec=10``) without interfering with other threads. > > ?Likewise, the :func:`setcontext` function automatically assigns its target to > ?the current thread. > diff --git a/Doc/library/numeric.rst b/Doc/library/numeric.rst > --- a/Doc/library/numeric.rst > +++ b/Doc/library/numeric.rst > @@ -8,9 +8,9 @@ > ?The modules described in this chapter provide numeric and math-related functions > ?and data types. The :mod:`numbers` module defines an abstract hierarchy of > ?numeric types. The :mod:`math` and :mod:`cmath` modules contain various > -mathematical functions for floating-point and complex numbers. For users more > -interested in decimal accuracy than in speed, the :mod:`decimal` module supports > -exact representations of decimal numbers. > +mathematical functions for floating-point and complex numbers. The :mod:`decimal` > +module supports exact representations of decimal numbers, using arbitrary precision > +arithmetic. > > ?The following modules are documented in this chapter: > > diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst > --- a/Doc/whatsnew/3.3.rst > +++ b/Doc/whatsnew/3.3.rst > @@ -596,6 +596,93 @@ > > ?(Contributed by I?igo Serna in :issue:`6755`) > > +decimal > +------- > + > +:issue:`7652` - integrate fast native decimal arithmetic. > + ? C-module and libmpdec written by Stefan Krah. > + > +The new C version of the decimal module integrates the high speed libmpdec > +library for arbitrary precision correctly-rounded decimal arithmetic. > +libmpdec conforms to IBM's General Decimal Arithmetic Specification. > + > +Performance gains range from 12x for database applications to 80x for > +numerically intensive applications: > + > + ? +---------+-------------+--------------+-------------+ > + ? | ? ? ? ? | ?decimal.py | ? _decimal ? | ? speedup ? | > + ? +=========+=============+==============+=============+ > + ? | ? pi ? ?| ? ?42.75s ? | ? ?0.58s ? ? | ? ? 74x ? ? | > + ? +---------+-------------+--------------+-------------+ > + ? | telco ? | ? 172.19s ? | ? ?5.68s ? ? | ? ? 30x ? ? | > + ? +---------+-------------+--------------+-------------+ > + ? | psycopg | ? ? 3.57s ? | ? ?0.29s ? ? | ? ? 12x ? ? | > + ? +---------+-------------+--------------+-------------+ > + > +Features > +~~~~~~~~ > + > +* The :exc:`~decimal.FloatOperation` signal optionally enables stricter > + ?semantics for mixing floats and Decimals. > + > +* If Python is compiled without threads, the C version automatically > + ?disables the expensive thread local context machinery. In this case, > + ?the variable :data:`~decimal.HAVE_THREADS` is set to False. > + > +API changes > +~~~~~~~~~~~ > + > +* The C module has the following context limits, depending on the machine > + ?architecture: > + > + ? +-------------------+---------------------+------------------------------+ > + ? | ? ? ? ? ? ? ? ? ? | ? ? ? 32-bit ? ? ? ?| ? ? ? ? ? ?64-bit ? ? ? ? ? ?| > + ? +===================+=====================+==============================+ > + ? | :const:`MAX_PREC` | :const:`425000000` ?| :const:`999999999999999999` ?| > + ? +-------------------+---------------------+------------------------------+ > + ? | :const:`MAX_EMAX` | :const:`425000000` ?| :const:`999999999999999999` ?| > + ? +-------------------+---------------------+------------------------------+ > + ? | :const:`MIN_EMIN` | :const:`-425000000` | :const:`-999999999999999999` | > + ? +-------------------+---------------------+------------------------------+ > + > +* In the context templates (:class:`~decimal.DefaultContext`, > + ?:class:`~decimal.BasicContext` and :class:`~decimal.ExtendedContext`) > + ?the magnitude of :attr:`~decimal.Context.Emax` and > + ?:attr:`~decimal.Context.Emin` has changed to :const:`999999`. > + > +* The :class:`~decimal.Decimal` constructor in decimal.py does not observe > + ?the context limits and converts values with arbitrary exponents or precision > + ?exactly. Since the C version has internal limits, the following scheme is > + ?used: If possible, values are converted exactly, otherwise > + ?:exc:`~decimal.InvalidOperation` is raised and the result is NaN. In the > + ?latter case it is always possible to use :meth:`~decimal.Context.create_decimal` > + ?in order to obtain a rounded or inexact value. > + > + > +* The power function in decimal.py is always correctly-rounded. In the > + ?C version, it is defined in terms of the correctly-rounded > + ?:meth:`~decimal.Decimal.exp` and :meth:`~decimal.Decimal.ln` functions, > + ?but the final result is only "almost always correctly rounded". > + > + > +* In the C version, the context dictionary containing the signals is a > + ?:class:`~collections.abc.MutableMapping`. ?For speed reasons, > + ?:attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps` always > + ?refer to the same :class:`~collections.abc.MutableMapping` that the context > + ?was initialized with. If a new signal dictionary is assigned, > + ?:attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps` > + ?are updated with the new values, but they do not reference the RHS > + ?dictionary. > + > + > +* Pickling a :class:`~decimal.Context` produces a different output in order > + ?to have a common interchange format for the Python and C versions. > + > + > +* The order of arguments in the :class:`~decimal.Context` constructor has been > + ?changed to match the order displayed by :func:`repr`. > + > + > ?faulthandler > ?------------ > > diff --git a/Include/longintrepr.h b/Include/longintrepr.h > --- a/Include/longintrepr.h > +++ b/Include/longintrepr.h > @@ -6,7 +6,7 @@ > ?#endif > > > -/* This is published for the benefit of "friend" marshal.c only. */ > +/* This is published for the benefit of "friends" marshal.c and _decimal.c. */ > > ?/* Parameters of the long integer representation. ?There are two different > ? ?sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit > diff --git a/Lib/decimal.py b/Lib/decimal.py > --- a/Lib/decimal.py > +++ b/Lib/decimal.py > @@ -46,8 +46,8 @@ > ?Decimal('-0.0123') > ?>>> Decimal(123456) > ?Decimal('123456') > ->>> Decimal('123.45e12345678901234567890') > -Decimal('1.2345E+12345678901234567892') > +>>> Decimal('123.45e12345678') > +Decimal('1.2345E+12345680') > ?>>> Decimal('1.33') + Decimal('1.27') > ?Decimal('2.60') > ?>>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41') > @@ -122,13 +122,20 @@ > ? ? # Exceptions > ? ? 'DecimalException', 'Clamped', 'InvalidOperation', 'DivisionByZero', > ? ? 'Inexact', 'Rounded', 'Subnormal', 'Overflow', 'Underflow', > + ? ?'FloatOperation', > > ? ? # Constants for use in setting up contexts > ? ? 'ROUND_DOWN', 'ROUND_HALF_UP', 'ROUND_HALF_EVEN', 'ROUND_CEILING', > ? ? 'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN', 'ROUND_05UP', > > ? ? # Functions for manipulating contexts > - ? ?'setcontext', 'getcontext', 'localcontext' > + ? ?'setcontext', 'getcontext', 'localcontext', > + > + ? ?# Limits for the C version for compatibility > + ? ?'MAX_PREC', ?'MAX_EMAX', 'MIN_EMIN', 'MIN_ETINY', > + > + ? ?# C version: compile time choice that enables the thread local context > + ? ?'HAVE_THREADS' > ?] > > ?__version__ = '1.70' ? ?# Highest version of the spec this complies with > @@ -137,6 +144,7 @@ > ?import copy as _copy > ?import math as _math > ?import numbers as _numbers > +import sys > > ?try: > ? ? from collections import namedtuple as _namedtuple > @@ -154,6 +162,19 @@ > ?ROUND_HALF_DOWN = 'ROUND_HALF_DOWN' > ?ROUND_05UP = 'ROUND_05UP' > > +# Compatibility with the C version > +HAVE_THREADS = True > +if sys.maxsize == 2**63-1: > + ? ?MAX_PREC = 999999999999999999 > + ? ?MAX_EMAX = 999999999999999999 > + ? ?MIN_EMIN = -999999999999999999 > +else: > + ? ?MAX_PREC = 425000000 > + ? ?MAX_EMAX = 425000000 > + ? ?MIN_EMIN = -425000000 > + > +MIN_ETINY = MIN_EMIN - (MAX_PREC-1) > + > ?# Errors > > ?class DecimalException(ArithmeticError): > @@ -370,9 +391,24 @@ > ? ? In all cases, Inexact, Rounded, and Subnormal will also be raised. > ? ? """ > > +class FloatOperation(DecimalException): > + ? ?"""Enable stricter semantics for mixing floats and Decimals. > + > + ? ?If the signal is not trapped (default), mixing floats and Decimals is > + ? ?permitted in the Decimal() constructor, context.create_decimal() and > + ? ?all comparison operators. Both conversion and comparisons are exact. > + ? ?Any occurrence of a mixed operation is silently recorded by setting > + ? ?FloatOperation in the context flags. ?Explicit conversions with > + ? ?Decimal.from_float() or context.create_decimal_from_float() do not > + ? ?set the flag. > + > + ? ?Otherwise (the signal is trapped), only equality comparisons and explicit > + ? ?conversions are silent. All other mixed operations raise FloatOperation. > + ? ?""" > + > ?# List of public traps and flags > ?_signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded, > - ? ? ? ? ? Underflow, InvalidOperation, Subnormal] > + ? ? ? ? ? ?Underflow, InvalidOperation, Subnormal, FloatOperation] > > ?# Map conditions (per the spec) to signals > ?_condition_map = {ConversionSyntax:InvalidOperation, > @@ -380,6 +416,10 @@ > ? ? ? ? ? ? ? ? ? DivisionUndefined:InvalidOperation, > ? ? ? ? ? ? ? ? ? InvalidContext:InvalidOperation} > > +# Valid rounding modes > +_rounding_modes = (ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_CEILING, > + ? ? ? ? ? ? ? ? ? ROUND_FLOOR, ROUND_UP, ROUND_HALF_DOWN, ROUND_05UP) > + > ?##### Context Functions ################################################## > > ?# The getcontext() and setcontext() function manage access to a thread-local > @@ -392,12 +432,11 @@ > ? ? import threading > ?except ImportError: > ? ? # Python was compiled without threads; create a mock object instead > - ? ?import sys > ? ? class MockThreading(object): > ? ? ? ? def local(self, sys=sys): > ? ? ? ? ? ? return sys.modules[__name__] > ? ? threading = MockThreading() > - ? ?del sys, MockThreading > + ? ?del MockThreading > > ?try: > ? ? threading.local > @@ -650,6 +689,11 @@ > ? ? ? ? ? ? return self > > ? ? ? ? if isinstance(value, float): > + ? ? ? ? ? ?if context is None: > + ? ? ? ? ? ? ? ?context = getcontext() > + ? ? ? ? ? ?context._raise_error(FloatOperation, > + ? ? ? ? ? ? ? ?"strict semantics for mixing floats and Decimals are " > + ? ? ? ? ? ? ? ?"enabled") > ? ? ? ? ? ? value = Decimal.from_float(value) > ? ? ? ? ? ? self._exp ?= value._exp > ? ? ? ? ? ? self._sign = value._sign > @@ -684,7 +728,9 @@ > ? ? ? ? """ > ? ? ? ? if isinstance(f, int): ? ? ? ? ? ? ? ?# handle integer inputs > ? ? ? ? ? ? return cls(f) > - ? ? ? ?if _math.isinf(f) or _math.isnan(f): ?# raises TypeError if not a float > + ? ? ? ?if not isinstance(f, float): > + ? ? ? ? ? ?raise TypeError("argument must be int or float.") > + ? ? ? ?if _math.isinf(f) or _math.isnan(f): > ? ? ? ? ? ? return cls(repr(f)) > ? ? ? ? if _math.copysign(1.0, f) == 1.0: > ? ? ? ? ? ? sign = 0 > @@ -1906,11 +1952,12 @@ > ? ? def _power_modulo(self, other, modulo, context=None): > ? ? ? ? """Three argument version of __pow__""" > > - ? ? ? ?# if can't convert other and modulo to Decimal, raise > - ? ? ? ?# TypeError; there's no point returning NotImplemented (no > - ? ? ? ?# equivalent of __rpow__ for three argument pow) > - ? ? ? ?other = _convert_other(other, raiseit=True) > - ? ? ? ?modulo = _convert_other(modulo, raiseit=True) > + ? ? ? ?other = _convert_other(other) > + ? ? ? ?if other is NotImplemented: > + ? ? ? ? ? ?return other > + ? ? ? ?modulo = _convert_other(modulo) > + ? ? ? ?if modulo is NotImplemented: > + ? ? ? ? ? ?return modulo > > ? ? ? ? if context is None: > ? ? ? ? ? ? context = getcontext() > @@ -3832,11 +3879,9 @@ > ? ? clamp - ?If 1, change exponents if too high (Default 0) > ? ? """ > > - ? ?def __init__(self, prec=None, rounding=None, > - ? ? ? ? ? ? ? ? traps=None, flags=None, > - ? ? ? ? ? ? ? ? Emin=None, Emax=None, > - ? ? ? ? ? ? ? ? capitals=None, clamp=None, > - ? ? ? ? ? ? ? ? _ignored_flags=None): > + ? ?def __init__(self, prec=None, rounding=None, Emin=None, Emax=None, > + ? ? ? ? ? ? ? ? ? ? ? capitals=None, clamp=None, flags=None, traps=None, > + ? ? ? ? ? ? ? ? ? ? ? _ignored_flags=None): > ? ? ? ? # Set defaults; for everything except flags and _ignored_flags, > ? ? ? ? # inherit from DefaultContext. > ? ? ? ? try: > @@ -3859,17 +3904,78 @@ > ? ? ? ? if traps is None: > ? ? ? ? ? ? self.traps = dc.traps.copy() > ? ? ? ? elif not isinstance(traps, dict): > - ? ? ? ? ? ?self.traps = dict((s, int(s in traps)) for s in _signals) > + ? ? ? ? ? ?self.traps = dict((s, int(s in traps)) for s in _signals + traps) > ? ? ? ? else: > ? ? ? ? ? ? self.traps = traps > > ? ? ? ? if flags is None: > ? ? ? ? ? ? self.flags = dict.fromkeys(_signals, 0) > ? ? ? ? elif not isinstance(flags, dict): > - ? ? ? ? ? ?self.flags = dict((s, int(s in flags)) for s in _signals) > + ? ? ? ? ? ?self.flags = dict((s, int(s in flags)) for s in _signals + flags) > ? ? ? ? else: > ? ? ? ? ? ? self.flags = flags > > + ? ?def _set_integer_check(self, name, value, vmin, vmax): > + ? ? ? ?if not isinstance(value, int): > + ? ? ? ? ? ?raise TypeError("%s must be an integer" % name) > + ? ? ? ?if vmin == '-inf': > + ? ? ? ? ? ?if value > vmax: > + ? ? ? ? ? ? ? ?raise ValueError("%s must be in [%s, %d]. got: %s" % (name, vmin, vmax, value)) > + ? ? ? ?elif vmax == 'inf': > + ? ? ? ? ? ?if value < vmin: > + ? ? ? ? ? ? ? ?raise ValueError("%s must be in [%d, %s]. got: %s" % (name, vmin, vmax, value)) > + ? ? ? ?else: > + ? ? ? ? ? ?if value < vmin or value > vmax: > + ? ? ? ? ? ? ? ?raise ValueError("%s must be in [%d, %d]. got %s" % (name, vmin, vmax, value)) > + ? ? ? ?return object.__setattr__(self, name, value) > + > + ? ?def _set_signal_dict(self, name, d): > + ? ? ? ?if not isinstance(d, dict): > + ? ? ? ? ? ?raise TypeError("%s must be a signal dict" % d) > + ? ? ? ?for key in d: > + ? ? ? ? ? ?if not key in _signals: > + ? ? ? ? ? ? ? ?raise KeyError("%s is not a valid signal dict" % d) > + ? ? ? ?for key in _signals: > + ? ? ? ? ? ?if not key in d: > + ? ? ? ? ? ? ? ?raise KeyError("%s is not a valid signal dict" % d) > + ? ? ? ?return object.__setattr__(self, name, d) > + > + ? ?def __setattr__(self, name, value): > + ? ? ? ?if name == 'prec': > + ? ? ? ? ? ?return self._set_integer_check(name, value, 1, 'inf') > + ? ? ? ?elif name == 'Emin': > + ? ? ? ? ? ?return self._set_integer_check(name, value, '-inf', 0) > + ? ? ? ?elif name == 'Emax': > + ? ? ? ? ? ?return self._set_integer_check(name, value, 0, 'inf') > + ? ? ? ?elif name == 'capitals': > + ? ? ? ? ? ?return self._set_integer_check(name, value, 0, 1) > + ? ? ? ?elif name == 'clamp': > + ? ? ? ? ? ?return self._set_integer_check(name, value, 0, 1) > + ? ? ? ?elif name == 'rounding': > + ? ? ? ? ? ?if not value in _rounding_modes: > + ? ? ? ? ? ? ? ?# raise TypeError even for strings to have consistency > + ? ? ? ? ? ? ? ?# among various implementations. > + ? ? ? ? ? ? ? ?raise TypeError("%s: invalid rounding mode" % value) > + ? ? ? ? ? ?return object.__setattr__(self, name, value) > + ? ? ? ?elif name == 'flags' or name == 'traps': > + ? ? ? ? ? ?return self._set_signal_dict(name, value) > + ? ? ? ?elif name == '_ignored_flags': > + ? ? ? ? ? ?return object.__setattr__(self, name, value) > + ? ? ? ?else: > + ? ? ? ? ? ?raise AttributeError( > + ? ? ? ? ? ? ? ?"'decimal.Context' object has no attribute '%s'" % name) > + > + ? ?def __delattr__(self, name): > + ? ? ? ?raise AttributeError("%s cannot be deleted" % name) > + > + ? ?# Support for pickling, copy, and deepcopy > + ? ?def __reduce__(self): > + ? ? ? ?flags = [sig for sig, v in self.flags.items() if v] > + ? ? ? ?traps = [sig for sig, v in self.traps.items() if v] > + ? ? ? ?return (self.__class__, > + ? ? ? ? ? ? ? ?(self.prec, self.rounding, self.Emin, self.Emax, > + ? ? ? ? ? ? ? ? self.capitals, self.clamp, flags, traps)) > + > ? ? def __repr__(self): > ? ? ? ? """Show the current context.""" > ? ? ? ? s = [] > @@ -3888,18 +3994,24 @@ > ? ? ? ? for flag in self.flags: > ? ? ? ? ? ? self.flags[flag] = 0 > > + ? ?def clear_traps(self): > + ? ? ? ?"""Reset all traps to zero""" > + ? ? ? ?for flag in self.traps: > + ? ? ? ? ? ?self.traps[flag] = 0 > + > ? ? def _shallow_copy(self): > ? ? ? ? """Returns a shallow copy from self.""" > - ? ? ? ?nc = Context(self.prec, self.rounding, self.traps, > - ? ? ? ? ? ? ? ? ? ? self.flags, self.Emin, self.Emax, > - ? ? ? ? ? ? ? ? ? ? self.capitals, self.clamp, self._ignored_flags) > + ? ? ? ?nc = Context(self.prec, self.rounding, self.Emin, self.Emax, > + ? ? ? ? ? ? ? ? ? ? self.capitals, self.clamp, self.flags, self.traps, > + ? ? ? ? ? ? ? ? ? ? self._ignored_flags) > ? ? ? ? return nc > > ? ? def copy(self): > ? ? ? ? """Returns a deep copy from self.""" > - ? ? ? ?nc = Context(self.prec, self.rounding, self.traps.copy(), > - ? ? ? ? ? ? ? ? ? ? self.flags.copy(), self.Emin, self.Emax, > - ? ? ? ? ? ? ? ? ? ? self.capitals, self.clamp, self._ignored_flags) > + ? ? ? ?nc = Context(self.prec, self.rounding, self.Emin, self.Emax, > + ? ? ? ? ? ? ? ? ? ? self.capitals, self.clamp, > + ? ? ? ? ? ? ? ? ? ? self.flags.copy(), self.traps.copy(), > + ? ? ? ? ? ? ? ? ? ? self._ignored_flags) > ? ? ? ? return nc > ? ? __copy__ = copy > > @@ -4062,6 +4174,8 @@ > ? ? ? ? >>> ExtendedContext.canonical(Decimal('2.50')) > ? ? ? ? Decimal('2.50') > ? ? ? ? """ > + ? ? ? ?if not isinstance(a, Decimal): > + ? ? ? ? ? ?raise TypeError("canonical requires a Decimal as an argument.") > ? ? ? ? return a.canonical(context=self) > > ? ? def compare(self, a, b): > @@ -4372,6 +4486,8 @@ > ? ? ? ? >>> ExtendedContext.is_canonical(Decimal('2.50')) > ? ? ? ? True > ? ? ? ? """ > + ? ? ? ?if not isinstance(a, Decimal): > + ? ? ? ? ? ?raise TypeError("is_canonical requires a Decimal as an argument.") > ? ? ? ? return a.is_canonical() > > ? ? def is_finite(self, a): > @@ -4964,7 +5080,7 @@ > ? ? ? ? ? +Normal > ? ? ? ? ? +Infinity > > - ? ? ? ?>>> c = Context(ExtendedContext) > + ? ? ? ?>>> c = ExtendedContext.copy() > ? ? ? ? >>> c.Emin = -999 > ? ? ? ? >>> c.Emax = 999 > ? ? ? ? >>> c.number_class(Decimal('Infinity')) > @@ -5916,6 +6032,12 @@ > ? ? if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0: > ? ? ? ? other = other.real > ? ? if isinstance(other, float): > + ? ? ? ?context = getcontext() > + ? ? ? ?if equality_op: > + ? ? ? ? ? ?context.flags[FloatOperation] = 1 > + ? ? ? ?else: > + ? ? ? ? ? ?context._raise_error(FloatOperation, > + ? ? ? ? ? ? ? ?"strict semantics for mixing floats and Decimals are enabled") > ? ? ? ? return self, Decimal.from_float(other) > ? ? return NotImplemented, NotImplemented > > @@ -5929,8 +6051,8 @@ > ? ? ? ? prec=28, rounding=ROUND_HALF_EVEN, > ? ? ? ? traps=[DivisionByZero, Overflow, InvalidOperation], > ? ? ? ? flags=[], > - ? ? ? ?Emax=999999999, > - ? ? ? ?Emin=-999999999, > + ? ? ? ?Emax=999999, > + ? ? ? ?Emin=-999999, > ? ? ? ? capitals=1, > ? ? ? ? clamp=0 > ?) > @@ -6080,7 +6202,7 @@ > ? ? # if format type is 'g' or 'G' then a precision of 0 makes little > ? ? # sense; convert it to 1. ?Same if format type is unspecified. > ? ? if format_dict['precision'] == 0: > - ? ? ? ?if format_dict['type'] is None or format_dict['type'] in 'gG': > + ? ? ? ?if format_dict['type'] is None or format_dict['type'] in 'gGn': > ? ? ? ? ? ? format_dict['precision'] = 1 > > ? ? # determine thousands separator, grouping, and decimal separator, and > @@ -6254,16 +6376,26 @@ > > ?# Constants related to the hash implementation; ?hash(x) is based > ?# on the reduction of x modulo _PyHASH_MODULUS > -import sys > ?_PyHASH_MODULUS = sys.hash_info.modulus > ?# hash values to use for positive and negative infinities, and nans > ?_PyHASH_INF = sys.hash_info.inf > ?_PyHASH_NAN = sys.hash_info.nan > -del sys > > ?# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS > ?_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS) > - > +del sys > + > +try: > + ? ?import _decimal > +except ImportError: > + ? ?pass > +else: > + ? ?s1 = set(dir()) > + ? ?s2 = set(dir(_decimal)) > + ? ?for name in s1 - s2: > + ? ? ? ?del globals()[name] > + ? ?del s1, s2, name > + ? ?from _decimal import * > > ?if __name__ == '__main__': > ? ? import doctest, decimal > diff --git a/Lib/test/support.py b/Lib/test/support.py > --- a/Lib/test/support.py > +++ b/Lib/test/support.py > @@ -1416,7 +1416,7 @@ > ?#======================================================================= > ?# doctest driver. > > -def run_doctest(module, verbosity=None): > +def run_doctest(module, verbosity=None, optionflags=0): > ? ? """Run doctest on the given module. ?Return (#failures, #tests). > > ? ? If optional argument verbosity is not specified (or is None), pass > @@ -1431,7 +1431,7 @@ > ? ? else: > ? ? ? ? verbosity = None > > - ? ?f, t = doctest.testmod(module, verbose=verbosity) > + ? ?f, t = doctest.testmod(module, verbose=verbosity, optionflags=optionflags) > ? ? if f: > ? ? ? ? raise TestFailed("%d of %d doctests failed" % (f, t)) > ? ? if verbose: > diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py > --- a/Lib/test/test_decimal.py > +++ b/Lib/test/test_decimal.py > @@ -16,7 +16,7 @@ > > ?Cowlishaw's tests can be downloaded from: > > - ? www2.hursley.ibm.com/decimal/dectest.zip > + ? http://speleotrove.com/decimal/dectest.zip > > ?This test module can be called from command line with one parameter (Arithmetic > ?or Behaviour) to test each part, or without parameter to test both parts. If > @@ -30,37 +30,74 @@ > ?import warnings > ?import pickle, copy > ?import unittest > -from decimal import * > ?import numbers > +import locale > ?from test.support import (run_unittest, run_doctest, is_resource_enabled, > ? ? ? ? ? ? ? ? ? ? ? ? ? requires_IEEE_754) > -from test.support import check_warnings > +from test.support import check_warnings, import_fresh_module, TestFailed > ?import random > +import time > +import warnings > ?try: > ? ? import threading > ?except ImportError: > ? ? threading = None > > + > +C = import_fresh_module('decimal', fresh=['_decimal']) > +P = import_fresh_module('decimal', blocked=['_decimal']) > +orig_sys_decimal = sys.modules['decimal'] > + > +# fractions module must import the correct decimal module. > +cfractions = import_fresh_module('fractions', fresh=['fractions']) > +sys.modules['decimal'] = P > +pfractions = import_fresh_module('fractions', fresh=['fractions']) > +sys.modules['decimal'] = C > +fractions = {C:cfractions, P:pfractions} > +sys.modules['decimal'] = orig_sys_decimal > + > + > ?# Useful Test Constant > -Signals = tuple(getcontext().flags.keys()) > - > +Signals = { > + ?C: tuple(C.getcontext().flags.keys()) if C else None, > + ?P: tuple(P.getcontext().flags.keys()) > +} > ?# Signals ordered with respect to precedence: when an operation > ?# produces multiple signals, signals occurring later in the list > ?# should be handled before those occurring earlier in the list. > -OrderedSignals = (Clamped, Rounded, Inexact, Subnormal, > - ? ? ? ? ? ? ? ? ?Underflow, Overflow, DivisionByZero, InvalidOperation) > +OrderedSignals = { > + ?C: [C.Clamped, C.Rounded, C.Inexact, C.Subnormal, C.Underflow, > + ? ? ?C.Overflow, C.DivisionByZero, C.InvalidOperation, > + ? ? ?C.FloatOperation] if C else None, > + ?P: [P.Clamped, P.Rounded, P.Inexact, P.Subnormal, P.Underflow, > + ? ? ?P.Overflow, P.DivisionByZero, P.InvalidOperation, > + ? ? ?P.FloatOperation] > +} > +def assert_signals(cls, context, attr, expected): > + ? ?d = getattr(context, attr) > + ? ?cls.assertTrue(all(d[s] if s in expected else not d[s] for s in d)) > + > +RoundingModes = { > + ?C: (C.ROUND_UP, C.ROUND_DOWN, C.ROUND_CEILING, C.ROUND_FLOOR, > + ? ? ?C.ROUND_HALF_UP, C.ROUND_HALF_DOWN, C.ROUND_HALF_EVEN, > + ? ? ?C.ROUND_05UP) if C else None, > + ?P: (P.ROUND_UP, P.ROUND_DOWN, P.ROUND_CEILING, P.ROUND_FLOOR, > + ? ? ?P.ROUND_HALF_UP, P.ROUND_HALF_DOWN, P.ROUND_HALF_EVEN, > + ? ? ?P.ROUND_05UP) > +} > > ?# Tests are built around these assumed context defaults. > ?# test_main() restores the original context. > -def init(): > - ? ?global ORIGINAL_CONTEXT > - ? ?ORIGINAL_CONTEXT = getcontext().copy() > - ? ?DefaultTestContext = Context( > - ? ? ? ?prec = 9, > - ? ? ? ?rounding = ROUND_HALF_EVEN, > - ? ? ? ?traps = dict.fromkeys(Signals, 0) > - ? ? ? ?) > - ? ?setcontext(DefaultTestContext) > +ORIGINAL_CONTEXT = { > + ?C: C.getcontext().copy() if C else None, > + ?P: P.getcontext().copy() > +} > +def init(m): > + ? ?if not m: return > + ? ?DefaultTestContext = m.Context( > + ? ? ? prec=9, rounding=m.ROUND_HALF_EVEN, traps=dict.fromkeys(Signals[m], 0) > + ? ?) > + ? ?m.setcontext(DefaultTestContext) > > ?TESTDATADIR = 'decimaltestdata' > ?if __name__ == '__main__': > @@ -72,149 +109,175 @@ > > ?skip_expected = not os.path.isdir(directory) > > -# list of individual .decTest test ids that correspond to tests that > -# we're skipping for one reason or another. > -skipped_test_ids = set([ > - ? ?# Skip implementation-specific scaleb tests. > - ? ?'scbx164', > - ? ?'scbx165', > - > - ? ?# For some operations (currently exp, ln, log10, power), the decNumber > - ? ?# reference implementation imposes additional restrictions on the context > - ? ?# and operands. ?These restrictions are not part of the specification; > - ? ?# however, the effect of these restrictions does show up in some of the > - ? ?# testcases. ?We skip testcases that violate these restrictions, since > - ? ?# Decimal behaves differently from decNumber for these testcases so these > - ? ?# testcases would otherwise fail. > - ? ?'expx901', > - ? ?'expx902', > - ? ?'expx903', > - ? ?'expx905', > - ? ?'lnx901', > - ? ?'lnx902', > - ? ?'lnx903', > - ? ?'lnx905', > - ? ?'logx901', > - ? ?'logx902', > - ? ?'logx903', > - ? ?'logx905', > - ? ?'powx1183', > - ? ?'powx1184', > - ? ?'powx4001', > - ? ?'powx4002', > - ? ?'powx4003', > - ? ?'powx4005', > - ? ?'powx4008', > - ? ?'powx4010', > - ? ?'powx4012', > - ? ?'powx4014', > - ? ?]) > - > ?# Make sure it actually raises errors when not expected and caught in flags > ?# Slower, since it runs some things several times. > ?EXTENDEDERRORTEST = False > > -#Map the test cases' error names to the actual errors > -ErrorNames = {'clamped' : Clamped, > - ? ? ? ? ? ? ?'conversion_syntax' : InvalidOperation, > - ? ? ? ? ? ? ?'division_by_zero' : DivisionByZero, > - ? ? ? ? ? ? ?'division_impossible' : InvalidOperation, > - ? ? ? ? ? ? ?'division_undefined' : InvalidOperation, > - ? ? ? ? ? ? ?'inexact' : Inexact, > - ? ? ? ? ? ? ?'invalid_context' : InvalidOperation, > - ? ? ? ? ? ? ?'invalid_operation' : InvalidOperation, > - ? ? ? ? ? ? ?'overflow' : Overflow, > - ? ? ? ? ? ? ?'rounded' : Rounded, > - ? ? ? ? ? ? ?'subnormal' : Subnormal, > - ? ? ? ? ? ? ?'underflow' : Underflow} > - > - > -def Nonfunction(*args): > - ? ?"""Doesn't do anything.""" > - ? ?return None > - > -RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings. > - ? ? ? ? ? ? ? ?'down' : ROUND_DOWN, > - ? ? ? ? ? ? ? ?'floor' : ROUND_FLOOR, > - ? ? ? ? ? ? ? ?'half_down' : ROUND_HALF_DOWN, > - ? ? ? ? ? ? ? ?'half_even' : ROUND_HALF_EVEN, > - ? ? ? ? ? ? ? ?'half_up' : ROUND_HALF_UP, > - ? ? ? ? ? ? ? ?'up' : ROUND_UP, > - ? ? ? ? ? ? ? ?'05up' : ROUND_05UP} > - > -# Name adapter to be able to change the Decimal and Context > -# interface without changing the test files from Cowlishaw > -nameAdapter = {'and':'logical_and', > - ? ? ? ? ? ? ? 'apply':'_apply', > - ? ? ? ? ? ? ? 'class':'number_class', > - ? ? ? ? ? ? ? 'comparesig':'compare_signal', > - ? ? ? ? ? ? ? 'comparetotal':'compare_total', > - ? ? ? ? ? ? ? 'comparetotmag':'compare_total_mag', > - ? ? ? ? ? ? ? 'copy':'copy_decimal', > - ? ? ? ? ? ? ? 'copyabs':'copy_abs', > - ? ? ? ? ? ? ? 'copynegate':'copy_negate', > - ? ? ? ? ? ? ? 'copysign':'copy_sign', > - ? ? ? ? ? ? ? 'divideint':'divide_int', > - ? ? ? ? ? ? ? 'invert':'logical_invert', > - ? ? ? ? ? ? ? 'iscanonical':'is_canonical', > - ? ? ? ? ? ? ? 'isfinite':'is_finite', > - ? ? ? ? ? ? ? 'isinfinite':'is_infinite', > - ? ? ? ? ? ? ? 'isnan':'is_nan', > - ? ? ? ? ? ? ? 'isnormal':'is_normal', > - ? ? ? ? ? ? ? 'isqnan':'is_qnan', > - ? ? ? ? ? ? ? 'issigned':'is_signed', > - ? ? ? ? ? ? ? 'issnan':'is_snan', > - ? ? ? ? ? ? ? 'issubnormal':'is_subnormal', > - ? ? ? ? ? ? ? 'iszero':'is_zero', > - ? ? ? ? ? ? ? 'maxmag':'max_mag', > - ? ? ? ? ? ? ? 'minmag':'min_mag', > - ? ? ? ? ? ? ? 'nextminus':'next_minus', > - ? ? ? ? ? ? ? 'nextplus':'next_plus', > - ? ? ? ? ? ? ? 'nexttoward':'next_toward', > - ? ? ? ? ? ? ? 'or':'logical_or', > - ? ? ? ? ? ? ? 'reduce':'normalize', > - ? ? ? ? ? ? ? 'remaindernear':'remainder_near', > - ? ? ? ? ? ? ? 'samequantum':'same_quantum', > - ? ? ? ? ? ? ? 'squareroot':'sqrt', > - ? ? ? ? ? ? ? 'toeng':'to_eng_string', > - ? ? ? ? ? ? ? 'tointegral':'to_integral_value', > - ? ? ? ? ? ? ? 'tointegralx':'to_integral_exact', > - ? ? ? ? ? ? ? 'tosci':'to_sci_string', > - ? ? ? ? ? ? ? 'xor':'logical_xor', > - ? ? ? ? ? ? ?} > - > -# The following functions return True/False rather than a Decimal instance > - > -LOGICAL_FUNCTIONS = ( > - ? ?'is_canonical', > - ? ?'is_finite', > - ? ?'is_infinite', > - ? ?'is_nan', > - ? ?'is_normal', > - ? ?'is_qnan', > - ? ?'is_signed', > - ? ?'is_snan', > - ? ?'is_subnormal', > - ? ?'is_zero', > - ? ?'same_quantum', > - ? ?) > - > -class DecimalTest(unittest.TestCase): > - ? ?"""Class which tests the Decimal class against the test cases. > - > - ? ?Changed for unittest. > - ? ?""" > +# Test extra functionality in the C version (-DEXTRA_FUNCTIONALITY). > +EXTRA_FUNCTIONALITY = True if hasattr(C, 'DecClamped') else False > +requires_extra_functionality = unittest.skipUnless( > + ?EXTRA_FUNCTIONALITY, "test requires build with -DEXTRA_FUNCTIONALITY") > +skip_if_extra_functionality = unittest.skipIf( > + ?EXTRA_FUNCTIONALITY, "test requires regular build") > + > + > +class IBMTestCases(unittest.TestCase): > + ? ?"""Class which tests the Decimal class against the IBM test cases.""" > + > ? ? def setUp(self): > - ? ? ? ?self.context = Context() > + ? ? ? ?self.context = self.decimal.Context() > + ? ? ? ?self.readcontext = self.decimal.Context() > ? ? ? ? self.ignore_list = ['#'] > - ? ? ? ?# Basically, a # means return NaN InvalidOperation. > - ? ? ? ?# Different from a sNaN in trim > - > + > + ? ? ? ?# List of individual .decTest test ids that correspond to tests that > + ? ? ? ?# we're skipping for one reason or another. > + ? ? ? ?self.skipped_test_ids = set([ > + ? ? ? ? ? ?# Skip implementation-specific scaleb tests. > + ? ? ? ? ? ?'scbx164', > + ? ? ? ? ? ?'scbx165', > + > + ? ? ? ? ? ?# For some operations (currently exp, ln, log10, power), the decNumber > + ? ? ? ? ? ?# reference implementation imposes additional restrictions on the context > + ? ? ? ? ? ?# and operands. ?These restrictions are not part of the specification; > + ? ? ? ? ? ?# however, the effect of these restrictions does show up in some of the > + ? ? ? ? ? ?# testcases. ?We skip testcases that violate these restrictions, since > + ? ? ? ? ? ?# Decimal behaves differently from decNumber for these testcases so these > + ? ? ? ? ? ?# testcases would otherwise fail. > + ? ? ? ? ? ?'expx901', > + ? ? ? ? ? ?'expx902', > + ? ? ? ? ? ?'expx903', > + ? ? ? ? ? ?'expx905', > + ? ? ? ? ? ?'lnx901', > + ? ? ? ? ? ?'lnx902', > + ? ? ? ? ? ?'lnx903', > + ? ? ? ? ? ?'lnx905', > + ? ? ? ? ? ?'logx901', > + ? ? ? ? ? ?'logx902', > + ? ? ? ? ? ?'logx903', > + ? ? ? ? ? ?'logx905', > + ? ? ? ? ? ?'powx1183', > + ? ? ? ? ? ?'powx1184', > + ? ? ? ? ? ?'powx4001', > + ? ? ? ? ? ?'powx4002', > + ? ? ? ? ? ?'powx4003', > + ? ? ? ? ? ?'powx4005', > + ? ? ? ? ? ?'powx4008', > + ? ? ? ? ? ?'powx4010', > + ? ? ? ? ? ?'powx4012', > + ? ? ? ? ? ?'powx4014', > + ? ? ? ? ? ?]) > + > + ? ? ? ?if self.decimal == C: > + ? ? ? ? ? ?# status has additional Subnormal, Underflow > + ? ? ? ? ? ?self.skipped_test_ids.add('pwsx803') > + ? ? ? ? ? ?self.skipped_test_ids.add('pwsx805') > + ? ? ? ? ? ?# Correct rounding (skipped for decNumber, too) > + ? ? ? ? ? ?self.skipped_test_ids.add('powx4302') > + ? ? ? ? ? ?self.skipped_test_ids.add('powx4303') > + ? ? ? ? ? ?self.skipped_test_ids.add('powx4342') > + ? ? ? ? ? ?self.skipped_test_ids.add('powx4343') > + ? ? ? ? ? ?# http://bugs.python.org/issue7049 > + ? ? ? ? ? ?self.skipped_test_ids.add('pwmx325') > + ? ? ? ? ? ?self.skipped_test_ids.add('pwmx326') > + > + ? ? ? ?# Map test directives to setter functions. > ? ? ? ? self.ChangeDict = {'precision' : self.change_precision, > - ? ? ? ? ? ? ? ? ? ? ?'rounding' : self.change_rounding_method, > - ? ? ? ? ? ? ? ? ? ? ?'maxexponent' : self.change_max_exponent, > - ? ? ? ? ? ? ? ? ? ? ?'minexponent' : self.change_min_exponent, > - ? ? ? ? ? ? ? ? ? ? ?'clamp' : self.change_clamp} > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'rounding' : self.change_rounding_method, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'maxexponent' : self.change_max_exponent, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'minexponent' : self.change_min_exponent, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'clamp' : self.change_clamp} > + > + ? ? ? ?# Name adapter to be able to change the Decimal and Context > + ? ? ? ?# interface without changing the test files from Cowlishaw. > + ? ? ? ?self.NameAdapter = {'and':'logical_and', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'apply':'_apply', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'class':'number_class', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'comparesig':'compare_signal', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'comparetotal':'compare_total', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'comparetotmag':'compare_total_mag', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'copy':'copy_decimal', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'copyabs':'copy_abs', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'copynegate':'copy_negate', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'copysign':'copy_sign', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'divideint':'divide_int', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'invert':'logical_invert', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'iscanonical':'is_canonical', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'isfinite':'is_finite', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'isinfinite':'is_infinite', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'isnan':'is_nan', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'isnormal':'is_normal', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'isqnan':'is_qnan', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'issigned':'is_signed', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'issnan':'is_snan', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'issubnormal':'is_subnormal', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'iszero':'is_zero', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'maxmag':'max_mag', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'minmag':'min_mag', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'nextminus':'next_minus', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'nextplus':'next_plus', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'nexttoward':'next_toward', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'or':'logical_or', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'reduce':'normalize', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'remaindernear':'remainder_near', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'samequantum':'same_quantum', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'squareroot':'sqrt', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'toeng':'to_eng_string', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'tointegral':'to_integral_value', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'tointegralx':'to_integral_exact', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'tosci':'to_sci_string', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?'xor':'logical_xor'} > + > + ? ? ? ?# Map test-case names to roundings. > + ? ? ? ?self.RoundingDict = {'ceiling' : self.decimal.ROUND_CEILING, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'down' : self.decimal.ROUND_DOWN, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'floor' : self.decimal.ROUND_FLOOR, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'half_down' : self.decimal.ROUND_HALF_DOWN, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'half_even' : self.decimal.ROUND_HALF_EVEN, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'half_up' : self.decimal.ROUND_HALF_UP, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'up' : self.decimal.ROUND_UP, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? '05up' : self.decimal.ROUND_05UP} > + > + ? ? ? ?# Map the test cases' error names to the actual errors. > + ? ? ? ?self.ErrorNames = {'clamped' : self.decimal.Clamped, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'conversion_syntax' : self.decimal.InvalidOperation, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'division_by_zero' : self.decimal.DivisionByZero, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'division_impossible' : self.decimal.InvalidOperation, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'division_undefined' : self.decimal.InvalidOperation, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'inexact' : self.decimal.Inexact, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'invalid_context' : self.decimal.InvalidOperation, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'invalid_operation' : self.decimal.InvalidOperation, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'overflow' : self.decimal.Overflow, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'rounded' : self.decimal.Rounded, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'subnormal' : self.decimal.Subnormal, > + ? ? ? ? ? ? ? ? ? ? ? ? ? 'underflow' : self.decimal.Underflow} > + > + ? ? ? ?# The following functions return True/False rather than a > + ? ? ? ?# Decimal instance. > + ? ? ? ?self.LogicalFunctions = ('is_canonical', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'is_finite', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'is_infinite', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'is_nan', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'is_normal', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'is_qnan', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'is_signed', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'is_snan', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'is_subnormal', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'is_zero', > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 'same_quantum') > + > + ? ?def read_unlimited(self, v, context): > + ? ? ? ?"""Work around the limitations of the 32-bit _decimal version. The > + ? ? ? ? ? guaranteed maximum values for prec, Emax etc. are 425000000, > + ? ? ? ? ? but higher values usually work, except for rare corner cases. > + ? ? ? ? ? In particular, all of the IBM tests pass with maximum values > + ? ? ? ? ? of 1070000000.""" > + ? ? ? ?if self.decimal == C and self.decimal.MAX_EMAX == 425000000: > + ? ? ? ? ? ?self.readcontext._unsafe_setprec(1070000000) > + ? ? ? ? ? ?self.readcontext._unsafe_setemax(1070000000) > + ? ? ? ? ? ?self.readcontext._unsafe_setemin(-1070000000) > + ? ? ? ? ? ?return self.readcontext.create_decimal(v) > + ? ? ? ?else: > + ? ? ? ? ? ?return self.decimal.Decimal(v, context) > > ? ? def eval_file(self, file): > ? ? ? ? global skip_expected > @@ -227,7 +290,7 @@ > ? ? ? ? ? ? ? ? #print line > ? ? ? ? ? ? ? ? try: > ? ? ? ? ? ? ? ? ? ? t = self.eval_line(line) > - ? ? ? ? ? ? ? ?except DecimalException as exception: > + ? ? ? ? ? ? ? ?except self.decimal.DecimalException as exception: > ? ? ? ? ? ? ? ? ? ? #Exception raised where there shouldn't have been one. > ? ? ? ? ? ? ? ? ? ? self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line) > > @@ -254,23 +317,23 @@ > ? ? def eval_directive(self, s): > ? ? ? ? funct, value = (x.strip().lower() for x in s.split(':')) > ? ? ? ? if funct == 'rounding': > - ? ? ? ? ? ?value = RoundingDict[value] > + ? ? ? ? ? ?value = self.RoundingDict[value] > ? ? ? ? else: > ? ? ? ? ? ? try: > ? ? ? ? ? ? ? ? value = int(value) > ? ? ? ? ? ? except ValueError: > ? ? ? ? ? ? ? ? pass > > - ? ? ? ?funct = self.ChangeDict.get(funct, Nonfunction) > + ? ? ? ?funct = self.ChangeDict.get(funct, (lambda *args: None)) > ? ? ? ? funct(value) > > ? ? def eval_equation(self, s): > - ? ? ? ?#global DEFAULT_PRECISION > - ? ? ? ?#print DEFAULT_PRECISION > > ? ? ? ? if not TEST_ALL and random.random() < 0.90: > ? ? ? ? ? ? return > > + ? ? ? ?self.context.clear_flags() > + > ? ? ? ? try: > ? ? ? ? ? ? Sides = s.split('->') > ? ? ? ? ? ? L = Sides[0].strip().split() > @@ -283,26 +346,26 @@ > ? ? ? ? ? ? ans = L[0] > ? ? ? ? ? ? exceptions = L[1:] > ? ? ? ? except (TypeError, AttributeError, IndexError): > - ? ? ? ? ? ?raise InvalidOperation > + ? ? ? ? ? ?raise self.decimal.InvalidOperation > ? ? ? ? def FixQuotes(val): > ? ? ? ? ? ? val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote') > ? ? ? ? ? ? val = val.replace("'", '').replace('"', '') > ? ? ? ? ? ? val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"') > ? ? ? ? ? ? return val > > - ? ? ? ?if id in skipped_test_ids: > + ? ? ? ?if id in self.skipped_test_ids: > ? ? ? ? ? ? return > > - ? ? ? ?fname = nameAdapter.get(funct, funct) > + ? ? ? ?fname = self.NameAdapter.get(funct, funct) > ? ? ? ? if fname == 'rescale': > ? ? ? ? ? ? return > ? ? ? ? funct = getattr(self.context, fname) > ? ? ? ? vals = [] > ? ? ? ? conglomerate = '' > ? ? ? ? quote = 0 > - ? ? ? ?theirexceptions = [ErrorNames[x.lower()] for x in exceptions] > - > - ? ? ? ?for exception in Signals: > + ? ? ? ?theirexceptions = [self.ErrorNames[x.lower()] for x in exceptions] > + > + ? ? ? ?for exception in Signals[self.decimal]: > ? ? ? ? ? ? self.context.traps[exception] = 1 #Catch these bugs... > ? ? ? ? for exception in theirexceptions: > ? ? ? ? ? ? self.context.traps[exception] = 0 > @@ -324,7 +387,7 @@ > ? ? ? ? ? ? ? ? ? ? ? ? ? ? funct(self.context.create_decimal(v)) > ? ? ? ? ? ? ? ? ? ? ? ? except error: > ? ? ? ? ? ? ? ? ? ? ? ? ? ? pass > - ? ? ? ? ? ? ? ? ? ? ? ?except Signals as e: > + ? ? ? ? ? ? ? ? ? ? ? ?except Signals[self.decimal] as e: > ? ? ? ? ? ? ? ? ? ? ? ? ? ? self.fail("Raised %s in %s when %s disabled" % \ > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (e, s, error)) > ? ? ? ? ? ? ? ? ? ? ? ? else: > @@ -332,7 +395,7 @@ > ? ? ? ? ? ? ? ? ? ? ? ? self.context.traps[error] = 0 > ? ? ? ? ? ? ? ? v = self.context.create_decimal(v) > ? ? ? ? ? ? else: > - ? ? ? ? ? ? ? ?v = Decimal(v, self.context) > + ? ? ? ? ? ? ? ?v = self.read_unlimited(v, self.context) > ? ? ? ? ? ? vals.append(v) > > ? ? ? ? ans = FixQuotes(ans) > @@ -344,7 +407,7 @@ > ? ? ? ? ? ? ? ? ? ? funct(*vals) > ? ? ? ? ? ? ? ? except error: > ? ? ? ? ? ? ? ? ? ? pass > - ? ? ? ? ? ? ? ?except Signals as e: > + ? ? ? ? ? ? ? ?except Signals[self.decimal] as e: > ? ? ? ? ? ? ? ? ? ? self.fail("Raised %s in %s when %s disabled" % \ > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (e, s, error)) > ? ? ? ? ? ? ? ? else: > @@ -352,14 +415,14 @@ > ? ? ? ? ? ? ? ? self.context.traps[error] = 0 > > ? ? ? ? ? ? # as above, but add traps cumulatively, to check precedence > - ? ? ? ? ? ?ordered_errors = [e for e in OrderedSignals if e in theirexceptions] > + ? ? ? ? ? ?ordered_errors = [e for e in OrderedSignals[self.decimal] if e in theirexceptions] > ? ? ? ? ? ? for error in ordered_errors: > ? ? ? ? ? ? ? ? self.context.traps[error] = 1 > ? ? ? ? ? ? ? ? try: > ? ? ? ? ? ? ? ? ? ? funct(*vals) > ? ? ? ? ? ? ? ? except error: > ? ? ? ? ? ? ? ? ? ? pass > - ? ? ? ? ? ? ? ?except Signals as e: > + ? ? ? ? ? ? ? ?except Signals[self.decimal] as e: > ? ? ? ? ? ? ? ? ? ? self.fail("Raised %s in %s; expected %s" % > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (type(e), s, error)) > ? ? ? ? ? ? ? ? else: > @@ -373,54 +436,69 @@ > ? ? ? ? ? ? print("--", self.context) > ? ? ? ? try: > ? ? ? ? ? ? result = str(funct(*vals)) > - ? ? ? ? ? ?if fname in LOGICAL_FUNCTIONS: > + ? ? ? ? ? ?if fname in self.LogicalFunctions: > ? ? ? ? ? ? ? ? result = str(int(eval(result))) # 'True', 'False' -> '1', '0' > - ? ? ? ?except Signals as error: > + ? ? ? ?except Signals[self.decimal] as error: > ? ? ? ? ? ? self.fail("Raised %s in %s" % (error, s)) > ? ? ? ? except: #Catch any error long enough to state the test case. > ? ? ? ? ? ? print("ERROR:", s) > ? ? ? ? ? ? raise > > ? ? ? ? myexceptions = self.getexceptions() > - ? ? ? ?self.context.clear_flags() > > ? ? ? ? myexceptions.sort(key=repr) > ? ? ? ? theirexceptions.sort(key=repr) > > ? ? ? ? self.assertEqual(result, ans, > ? ? ? ? ? ? ? ? ? ? ? ? ?'Incorrect answer for ' + s + ' -- got ' + result) > + > ? ? ? ? self.assertEqual(myexceptions, theirexceptions, > ? ? ? ? ? ? ? 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions)) > ? ? ? ? return > > ? ? def getexceptions(self): > - ? ? ? ?return [e for e in Signals if self.context.flags[e]] > + ? ? ? ?return [e for e in Signals[self.decimal] if self.context.flags[e]] > > ? ? def change_precision(self, prec): > - ? ? ? ?self.context.prec = prec > + ? ? ? ?if self.decimal == C and self.decimal.MAX_PREC == 425000000: > + ? ? ? ? ? ?self.context._unsafe_setprec(prec) > + ? ? ? ?else: > + ? ? ? ? ? ?self.context.prec = prec > ? ? def change_rounding_method(self, rounding): > ? ? ? ? self.context.rounding = rounding > ? ? def change_min_exponent(self, exp): > - ? ? ? ?self.context.Emin = exp > + ? ? ? ?if self.decimal == C and self.decimal.MAX_PREC == 425000000: > + ? ? ? ? ? ?self.context._unsafe_setemin(exp) > + ? ? ? ?else: > + ? ? ? ? ? ?self.context.Emin = exp > ? ? def change_max_exponent(self, exp): > - ? ? ? ?self.context.Emax = exp > + ? ? ? ?if self.decimal == C and self.decimal.MAX_PREC == 425000000: > + ? ? ? ? ? ?self.context._unsafe_setemax(exp) > + ? ? ? ?else: > + ? ? ? ? ? ?self.context.Emax = exp > ? ? def change_clamp(self, clamp): > ? ? ? ? self.context.clamp = clamp > > - > +class CIBMTestCases(IBMTestCases): > + ? ?decimal = C > +class PyIBMTestCases(IBMTestCases): > + ? ?decimal = P > > ?# The following classes test the behaviour of Decimal according to PEP 327 > > -class DecimalExplicitConstructionTest(unittest.TestCase): > +class ExplicitConstructionTest(unittest.TestCase): > ? ? '''Unit tests for Explicit Construction cases of Decimal.''' > > ? ? def test_explicit_empty(self): > + ? ? ? ?Decimal = self.decimal.Decimal > ? ? ? ? self.assertEqual(Decimal(), Decimal("0")) > > ? ? def test_explicit_from_None(self): > + ? ? ? ?Decimal = self.decimal.Decimal > ? ? ? ? self.assertRaises(TypeError, Decimal, None) > > ? ? def test_explicit_from_int(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? #positive > ? ? ? ? d = Decimal(45) > @@ -438,7 +516,18 @@ > ? ? ? ? d = Decimal(0) > ? ? ? ? self.assertEqual(str(d), '0') > > + ? ? ? ?# single word longs > + ? ? ? ?for n in range(0, 32): > + ? ? ? ? ? ?for sign in (-1, 1): > + ? ? ? ? ? ? ? ?for x in range(-5, 5): > + ? ? ? ? ? ? ? ? ? ?i = sign * (2**n + x) > + ? ? ? ? ? ? ? ? ? ?d = Decimal(i) > + ? ? ? ? ? ? ? ? ? ?self.assertEqual(str(d), str(i)) > + > ? ? def test_explicit_from_string(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?InvalidOperation = self.decimal.InvalidOperation > + ? ? ? ?localcontext = self.decimal.localcontext > > ? ? ? ? #empty > ? ? ? ? self.assertEqual(str(Decimal('')), 'NaN') > @@ -458,8 +547,35 @@ > ? ? ? ? #leading and trailing whitespace permitted > ? ? ? ? self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4') > ? ? ? ? self.assertEqual(str(Decimal(' ?-7.89')), '-7.89') > + ? ? ? ?self.assertEqual(str(Decimal(" ?3.45679 ?")), '3.45679') > + > + ? ? ? ?# unicode whitespace > + ? ? ? ?for lead in ["", ' ', '\u00a0', '\u205f']: > + ? ? ? ? ? ?for trail in ["", ' ', '\u00a0', '\u205f']: > + ? ? ? ? ? ? ? ?self.assertEqual(str(Decimal(lead + '9.311E+28' + trail)), > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? '9.311E+28') > + > + ? ? ? ?with localcontext() as c: > + ? ? ? ? ? ?c.traps[InvalidOperation] = True > + ? ? ? ? ? ?# Invalid string > + ? ? ? ? ? ?self.assertRaises(InvalidOperation, Decimal, "xyz") > + ? ? ? ? ? ?# Two arguments max > + ? ? ? ? ? ?self.assertRaises(TypeError, Decimal, "1234", "x", "y") > + > + ? ? ? ? ? ?# space within the numeric part > + ? ? ? ? ? ?self.assertRaises(InvalidOperation, Decimal, "1\u00a02\u00a03") > + ? ? ? ? ? ?self.assertRaises(InvalidOperation, Decimal, "\u00a01\u00a02\u00a0") > + > + ? ? ? ? ? ?# unicode whitespace > + ? ? ? ? ? ?self.assertRaises(InvalidOperation, Decimal, "\u00a0") > + ? ? ? ? ? ?self.assertRaises(InvalidOperation, Decimal, "\u00a0\u00a0") > + > + ? ? ? ? ? ?# embedded NUL > + ? ? ? ? ? ?self.assertRaises(InvalidOperation, Decimal, "12\u00003") > + > > ? ? def test_explicit_from_tuples(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? #zero > ? ? ? ? d = Decimal( (0, (0,), 0) ) > @@ -477,6 +593,10 @@ > ? ? ? ? d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) > ? ? ? ? self.assertEqual(str(d), '-4.34913534E-17') > > + ? ? ? ?#inf > + ? ? ? ?d = Decimal( (0, (), "F") ) > + ? ? ? ?self.assertEqual(str(d), 'Infinity') > + > ? ? ? ? #wrong number of items > ? ? ? ? self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) ) > > @@ -491,45 +611,63 @@ > ? ? ? ? self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') ) > > ? ? ? ? #bad coefficients > + ? ? ? ?self.assertRaises(ValueError, Decimal, (1, "xyz", 2) ) > ? ? ? ? self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) ) > ? ? ? ? self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) ) > ? ? ? ? self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) ) > ? ? ? ? self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) ) > > + ? ?def test_explicit_from_list(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?d = Decimal([0, [0], 0]) > + ? ? ? ?self.assertEqual(str(d), '0') > + > + ? ? ? ?d = Decimal([1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25]) > + ? ? ? ?self.assertEqual(str(d), '-4.34913534E-17') > + > + ? ? ? ?d = Decimal([1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25]) > + ? ? ? ?self.assertEqual(str(d), '-4.34913534E-17') > + > + ? ? ? ?d = Decimal((1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25)) > + ? ? ? ?self.assertEqual(str(d), '-4.34913534E-17') > + > ? ? def test_explicit_from_bool(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? self.assertIs(bool(Decimal(0)), False) > ? ? ? ? self.assertIs(bool(Decimal(1)), True) > ? ? ? ? self.assertEqual(Decimal(False), Decimal(0)) > ? ? ? ? self.assertEqual(Decimal(True), Decimal(1)) > > ? ? def test_explicit_from_Decimal(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? #positive > ? ? ? ? d = Decimal(45) > ? ? ? ? e = Decimal(d) > ? ? ? ? self.assertEqual(str(e), '45') > - ? ? ? ?self.assertNotEqual(id(d), id(e)) > > ? ? ? ? #very large positive > ? ? ? ? d = Decimal(500000123) > ? ? ? ? e = Decimal(d) > ? ? ? ? self.assertEqual(str(e), '500000123') > - ? ? ? ?self.assertNotEqual(id(d), id(e)) > > ? ? ? ? #negative > ? ? ? ? d = Decimal(-45) > ? ? ? ? e = Decimal(d) > ? ? ? ? self.assertEqual(str(e), '-45') > - ? ? ? ?self.assertNotEqual(id(d), id(e)) > > ? ? ? ? #zero > ? ? ? ? d = Decimal(0) > ? ? ? ? e = Decimal(d) > ? ? ? ? self.assertEqual(str(e), '0') > - ? ? ? ?self.assertNotEqual(id(d), id(e)) > > ? ? @requires_IEEE_754 > ? ? def test_explicit_from_float(self): > + > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? r = Decimal(0.1) > ? ? ? ? self.assertEqual(type(r), Decimal) > ? ? ? ? self.assertEqual(str(r), > @@ -550,8 +688,11 @@ > ? ? ? ? ? ? self.assertEqual(x, float(Decimal(x))) # roundtrip > > ? ? def test_explicit_context_create_decimal(self): > - > - ? ? ? ?nc = copy.copy(getcontext()) > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?InvalidOperation = self.decimal.InvalidOperation > + ? ? ? ?Rounded = self.decimal.Rounded > + > + ? ? ? ?nc = copy.copy(self.decimal.getcontext()) > ? ? ? ? nc.prec = 3 > > ? ? ? ? # empty > @@ -592,7 +733,73 @@ > ? ? ? ? d = nc.create_decimal(prevdec) > ? ? ? ? self.assertEqual(str(d), '5.00E+8') > > + ? ? ? ?# more integers > + ? ? ? ?nc.prec = 28 > + ? ? ? ?nc.traps[InvalidOperation] = True > + > + ? ? ? ?for v in [-2**63-1, -2**63, -2**31-1, -2**31, 0, > + ? ? ? ? ? ? ? ? ? 2**31-1, 2**31, 2**63-1, 2**63]: > + ? ? ? ? ? ?d = nc.create_decimal(v) > + ? ? ? ? ? ?self.assertTrue(isinstance(d, Decimal)) > + ? ? ? ? ? ?self.assertEqual(int(d), v) > + > + ? ? ? ?nc.prec = 3 > + ? ? ? ?nc.traps[Rounded] = True > + ? ? ? ?self.assertRaises(Rounded, nc.create_decimal, 1234) > + > + ? ? ? ?# from string > + ? ? ? ?nc.prec = 28 > + ? ? ? ?self.assertEqual(str(nc.create_decimal('0E-017')), '0E-17') > + ? ? ? ?self.assertEqual(str(nc.create_decimal('45')), '45') > + ? ? ? ?self.assertEqual(str(nc.create_decimal('-Inf')), '-Infinity') > + ? ? ? ?self.assertEqual(str(nc.create_decimal('NaN123')), 'NaN123') > + > + ? ? ? ?# invalid arguments > + ? ? ? ?self.assertRaises(InvalidOperation, nc.create_decimal, "xyz") > + ? ? ? ?self.assertRaises(ValueError, nc.create_decimal, (1, "xyz", -25)) > + ? ? ? ?self.assertRaises(TypeError, nc.create_decimal, "1234", "5678") > + > + ? ? ? ?# too many NaN payload digits > + ? ? ? ?nc.prec = 3 > + ? ? ? ?self.assertRaises(InvalidOperation, nc.create_decimal, 'NaN12345') > + ? ? ? ?self.assertRaises(InvalidOperation, nc.create_decimal, > + ? ? ? ? ? ? ? ? ? ? ? ? ?Decimal('NaN12345')) > + > + ? ? ? ?nc.traps[InvalidOperation] = False > + ? ? ? ?self.assertEqual(str(nc.create_decimal('NaN12345')), 'NaN') > + ? ? ? ?self.assertTrue(nc.flags[InvalidOperation]) > + > + ? ? ? ?nc.flags[InvalidOperation] = False > + ? ? ? ?self.assertEqual(str(nc.create_decimal(Decimal('NaN12345'))), 'NaN') > + ? ? ? ?self.assertTrue(nc.flags[InvalidOperation]) > + > + ? ?def test_explicit_context_create_from_float(self): > + > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?nc = self.decimal.Context() > + ? ? ? ?r = nc.create_decimal(0.1) > + ? ? ? ?self.assertEqual(type(r), Decimal) > + ? ? ? ?self.assertEqual(str(r), '0.1000000000000000055511151231') > + ? ? ? ?self.assertTrue(nc.create_decimal(float('nan')).is_qnan()) > + ? ? ? ?self.assertTrue(nc.create_decimal(float('inf')).is_infinite()) > + ? ? ? ?self.assertTrue(nc.create_decimal(float('-inf')).is_infinite()) > + ? ? ? ?self.assertEqual(str(nc.create_decimal(float('nan'))), > + ? ? ? ? ? ? ? ? ? ? ? ? str(nc.create_decimal('NaN'))) > + ? ? ? ?self.assertEqual(str(nc.create_decimal(float('inf'))), > + ? ? ? ? ? ? ? ? ? ? ? ? str(nc.create_decimal('Infinity'))) > + ? ? ? ?self.assertEqual(str(nc.create_decimal(float('-inf'))), > + ? ? ? ? ? ? ? ? ? ? ? ? str(nc.create_decimal('-Infinity'))) > + ? ? ? ?self.assertEqual(str(nc.create_decimal(float('-0.0'))), > + ? ? ? ? ? ? ? ? ? ? ? ? str(nc.create_decimal('-0'))) > + ? ? ? ?nc.prec = 100 > + ? ? ? ?for i in range(200): > + ? ? ? ? ? ?x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) > + ? ? ? ? ? ?self.assertEqual(x, float(nc.create_decimal(x))) # roundtrip > + > ? ? def test_unicode_digits(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? test_values = { > ? ? ? ? ? ? '\uff11': '1', > ? ? ? ? ? ? '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372', > @@ -601,29 +808,41 @@ > ? ? ? ? for input, expected in test_values.items(): > ? ? ? ? ? ? self.assertEqual(str(Decimal(input)), expected) > > - > -class DecimalImplicitConstructionTest(unittest.TestCase): > +class CExplicitConstructionTest(ExplicitConstructionTest): > + ? ?decimal = C > +class PyExplicitConstructionTest(ExplicitConstructionTest): > + ? ?decimal = P > + > +class ImplicitConstructionTest(unittest.TestCase): > ? ? '''Unit tests for Implicit Construction cases of Decimal.''' > > ? ? def test_implicit_from_None(self): > - ? ? ? ?self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals()) > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?self.assertRaises(TypeError, eval, 'Decimal(5) + None', locals()) > > ? ? def test_implicit_from_int(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? #normal > ? ? ? ? self.assertEqual(str(Decimal(5) + 45), '50') > ? ? ? ? #exceeding precision > ? ? ? ? self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000)) > > ? ? def test_implicit_from_string(self): > - ? ? ? ?self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals()) > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', locals()) > > ? ? def test_implicit_from_float(self): > - ? ? ? ?self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals()) > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', locals()) > > ? ? def test_implicit_from_Decimal(self): > + ? ? ? ?Decimal = self.decimal.Decimal > ? ? ? ? self.assertEqual(Decimal(5) + Decimal(45), Decimal(50)) > > ? ? def test_rop(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? # Allow other classes to be trained to interact with Decimals > ? ? ? ? class E: > ? ? ? ? ? ? def __divmod__(self, other): > @@ -671,10 +890,16 @@ > ? ? ? ? ? ? self.assertEqual(eval('Decimal(10)' + sym + 'E()'), > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'10' + rop + 'str') > > - > -class DecimalFormatTest(unittest.TestCase): > +class CImplicitConstructionTest(ImplicitConstructionTest): > + ? ?decimal = C > +class PyImplicitConstructionTest(ImplicitConstructionTest): > + ? ?decimal = P > + > +class FormatTest(unittest.TestCase): > ? ? '''Unit tests for the format function.''' > ? ? def test_formatting(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? # triples giving a format, a Decimal, and the expected result > ? ? ? ? test_values = [ > ? ? ? ? ? ? ('e', '0E-15', '0e-15'), > @@ -730,6 +955,7 @@ > ? ? ? ? ? ? ('g', '0E-7', '0e-7'), > ? ? ? ? ? ? ('g', '-0E2', '-0e+2'), > ? ? ? ? ? ? ('.0g', '3.14159265', '3'), ?# 0 sig fig -> 1 sig fig > + ? ? ? ? ? ?('.0n', '3.14159265', '3'), ?# same for 'n' > ? ? ? ? ? ? ('.1g', '3.14159265', '3'), > ? ? ? ? ? ? ('.2g', '3.14159265', '3.1'), > ? ? ? ? ? ? ('.5g', '3.14159265', '3.1416'), > @@ -814,56 +1040,60 @@ > > ? ? ? ? ? ? # issue 6850 > ? ? ? ? ? ? ('a=-7.0', '0.12345', 'aaaa0.1'), > - > - ? ? ? ? ? ?# Issue 7094: Alternate formatting (specified by #) > - ? ? ? ? ? ?('.0e', '1.0', '1e+0'), > - ? ? ? ? ? ?('#.0e', '1.0', '1.e+0'), > - ? ? ? ? ? ?('.0f', '1.0', '1'), > - ? ? ? ? ? ?('#.0f', '1.0', '1.'), > - ? ? ? ? ? ?('g', '1.1', '1.1'), > - ? ? ? ? ? ?('#g', '1.1', '1.1'), > - ? ? ? ? ? ?('.0g', '1', '1'), > - ? ? ? ? ? ?('#.0g', '1', '1.'), > - ? ? ? ? ? ?('.0%', '1.0', '100%'), > - ? ? ? ? ? ?('#.0%', '1.0', '100.%'), > ? ? ? ? ? ? ] > ? ? ? ? for fmt, d, result in test_values: > ? ? ? ? ? ? self.assertEqual(format(Decimal(d), fmt), result) > > + ? ? ? ?# bytes format argument > + ? ? ? ?self.assertRaises(TypeError, Decimal(1).__format__, b'-020') > + > ? ? def test_n_format(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? try: > ? ? ? ? ? ? from locale import CHAR_MAX > ? ? ? ? except ImportError: > ? ? ? ? ? ? return > > + ? ? ? ?def make_grouping(lst): > + ? ? ? ? ? ?return ''.join([chr(x) for x in lst]) if self.decimal == C else lst > + > + ? ? ? ?def get_fmt(x, override=None, fmt='n'): > + ? ? ? ? ? ?if self.decimal == C: > + ? ? ? ? ? ? ? ?return Decimal(x).__format__(fmt, override) > + ? ? ? ? ? ?else: > + ? ? ? ? ? ? ? ?return Decimal(x).__format__(fmt, _localeconv=override) > + > ? ? ? ? # Set up some localeconv-like dictionaries > ? ? ? ? en_US = { > ? ? ? ? ? ? 'decimal_point' : '.', > - ? ? ? ? ? ?'grouping' : [3, 3, 0], > - ? ? ? ? ? ?'thousands_sep': ',' > + ? ? ? ? ? ?'grouping' : make_grouping([3, 3, 0]), > + ? ? ? ? ? ?'thousands_sep' : ',' > ? ? ? ? ? ? } > > ? ? ? ? fr_FR = { > ? ? ? ? ? ? 'decimal_point' : ',', > - ? ? ? ? ? ?'grouping' : [CHAR_MAX], > + ? ? ? ? ? ?'grouping' : make_grouping([CHAR_MAX]), > ? ? ? ? ? ? 'thousands_sep' : '' > ? ? ? ? ? ? } > > ? ? ? ? ru_RU = { > ? ? ? ? ? ? 'decimal_point' : ',', > - ? ? ? ? ? ?'grouping' : [3, 3, 0], > + ? ? ? ? ? ?'grouping': make_grouping([3, 3, 0]), > ? ? ? ? ? ? 'thousands_sep' : ' ' > ? ? ? ? ? ? } > > ? ? ? ? crazy = { > ? ? ? ? ? ? 'decimal_point' : '&', > - ? ? ? ? ? ?'grouping' : [1, 4, 2, CHAR_MAX], > + ? ? ? ? ? ?'grouping': make_grouping([1, 4, 2, CHAR_MAX]), > ? ? ? ? ? ? 'thousands_sep' : '-' > ? ? ? ? ? ? } > > - > - ? ? ? ?def get_fmt(x, locale, fmt='n'): > - ? ? ? ? ? ?return Decimal.__format__(Decimal(x), fmt, _localeconv=locale) > + ? ? ? ?dotsep_wide = { > + ? ? ? ? ? ?'decimal_point' : b'\xc2\xbf'.decode('utf-8'), > + ? ? ? ? ? ?'grouping': make_grouping([3, 3, 0]), > + ? ? ? ? ? ?'thousands_sep' : b'\xc2\xb4'.decode('utf-8') > + ? ? ? ? ? ?} > > ? ? ? ? self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7') > ? ? ? ? self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7') > @@ -902,11 +1132,33 @@ > ? ? ? ? self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6') > ? ? ? ? self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6') > > - > -class DecimalArithmeticOperatorsTest(unittest.TestCase): > + ? ? ? ?# wide char separator and decimal point > + ? ? ? ?self.assertEqual(get_fmt(Decimal('-1.5'), dotsep_wide, '020n'), > + ? ? ? ? ? ? ? ? ? ? ? ? '-0\u00b4000\u00b4000\u00b4000\u00b4001\u00bf5') > + > + ? ?def test_wide_char_separator_decimal_point(self): > + ? ? ? ?# locale with wide char separator and decimal point > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?try: > + ? ? ? ? ? ?locale.setlocale(locale.LC_ALL, 'ps_AF') > + ? ? ? ?except locale.Error: > + ? ? ? ? ? ?return > + > + ? ? ? ?self.assertEqual(format(Decimal('100000000.123'), 'n'), > + ? ? ? ? ? ? ? ? ? ? ? ? '100\u066c000\u066c000\u066b123') > + ? ? ? ?locale.resetlocale() > + > +class CFormatTest(FormatTest): > + ? ?decimal = C > +class PyFormatTest(FormatTest): > + ? ?decimal = P > + > +class ArithmeticOperatorsTest(unittest.TestCase): > ? ? '''Unit tests for all arithmetic operators, binary and unary.''' > > ? ? def test_addition(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('-11.1') > ? ? ? ? d2 = Decimal('22.2') > @@ -934,6 +1186,7 @@ > ? ? ? ? self.assertEqual(d1, Decimal('16.1')) > > ? ? def test_subtraction(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('-11.1') > ? ? ? ? d2 = Decimal('22.2') > @@ -961,6 +1214,7 @@ > ? ? ? ? self.assertEqual(d1, Decimal('-38.3')) > > ? ? def test_multiplication(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('-5') > ? ? ? ? d2 = Decimal('3') > @@ -988,6 +1242,7 @@ > ? ? ? ? self.assertEqual(d1, Decimal('-75')) > > ? ? def test_division(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('-5') > ? ? ? ? d2 = Decimal('2') > @@ -1015,6 +1270,7 @@ > ? ? ? ? self.assertEqual(d1, Decimal('-0.625')) > > ? ? def test_floor_division(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('5') > ? ? ? ? d2 = Decimal('2') > @@ -1042,6 +1298,7 @@ > ? ? ? ? self.assertEqual(d1, Decimal('1')) > > ? ? def test_powering(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('5') > ? ? ? ? d2 = Decimal('2') > @@ -1069,6 +1326,7 @@ > ? ? ? ? self.assertEqual(d1, Decimal('390625')) > > ? ? def test_module(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('5') > ? ? ? ? d2 = Decimal('2') > @@ -1096,6 +1354,7 @@ > ? ? ? ? self.assertEqual(d1, Decimal('1')) > > ? ? def test_floor_div_module(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('5') > ? ? ? ? d2 = Decimal('2') > @@ -1122,6 +1381,8 @@ > ? ? ? ? self.assertEqual(type(q), type(d1)) > > ? ? def test_unary_operators(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? self.assertEqual(+Decimal(45), Decimal(+45)) ? ? ? ? ? # ?+ > ? ? ? ? self.assertEqual(-Decimal(45), Decimal(-45)) ? ? ? ? ? # ?- > ? ? ? ? self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) ?# abs > @@ -1134,6 +1395,9 @@ > > ? ? ? ? # equality comparisons (==, !=) involving only quiet nans > ? ? ? ? # don't signal, but return False or True respectively. > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?InvalidOperation = self.decimal.InvalidOperation > + ? ? ? ?localcontext = self.decimal.localcontext > > ? ? ? ? n = Decimal('NaN') > ? ? ? ? s = Decimal('sNaN') > @@ -1179,53 +1443,124 @@ > ? ? ? ? ? ? ? ? ? ? self.assertRaises(InvalidOperation, op, x, y) > > ? ? def test_copy_sign(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? d = Decimal(1).copy_sign(Decimal(-2)) > - > ? ? ? ? self.assertEqual(Decimal(1).copy_sign(-2), d) > ? ? ? ? self.assertRaises(TypeError, Decimal(1).copy_sign, '-2') > > +class CArithmeticOperatorsTest(ArithmeticOperatorsTest): > + ? ?decimal = C > +class PyArithmeticOperatorsTest(ArithmeticOperatorsTest): > + ? ?decimal = P > + > ?# The following are two functions used to test threading in the next class > > ?def thfunc1(cls): > + ? ?Decimal = cls.decimal.Decimal > + ? ?InvalidOperation = cls.decimal.InvalidOperation > + ? ?DivisionByZero = cls.decimal.DivisionByZero > + ? ?Overflow = cls.decimal.Overflow > + ? ?Underflow = cls.decimal.Underflow > + ? ?Inexact = cls.decimal.Inexact > + ? ?getcontext = cls.decimal.getcontext > + ? ?localcontext = cls.decimal.localcontext > + > ? ? d1 = Decimal(1) > ? ? d3 = Decimal(3) > ? ? test1 = d1/d3 > + > + ? ?cls.finish1.set() > ? ? cls.synchro.wait() > + > ? ? test2 = d1/d3 > - ? ?cls.finish1.set() > - > - ? ?cls.assertEqual(test1, Decimal('0.3333333333333333333333333333')) > - ? ?cls.assertEqual(test2, Decimal('0.3333333333333333333333333333')) > + ? ?with localcontext() as c2: > + ? ? ? ?cls.assertTrue(c2.flags[Inexact]) > + ? ? ? ?cls.assertRaises(DivisionByZero, c2.divide, d1, 0) > + ? ? ? ?cls.assertTrue(c2.flags[DivisionByZero]) > + ? ? ? ?with localcontext() as c3: > + ? ? ? ? ? ?cls.assertTrue(c3.flags[Inexact]) > + ? ? ? ? ? ?cls.assertTrue(c3.flags[DivisionByZero]) > + ? ? ? ? ? ?cls.assertRaises(InvalidOperation, c3.compare, d1, Decimal('sNaN')) > + ? ? ? ? ? ?cls.assertTrue(c3.flags[InvalidOperation]) > + ? ? ? ? ? ?del c3 > + ? ? ? ?cls.assertFalse(c2.flags[InvalidOperation]) > + ? ? ? ?del c2 > + > + ? ?cls.assertEqual(test1, Decimal('0.333333333333333333333333')) > + ? ?cls.assertEqual(test2, Decimal('0.333333333333333333333333')) > + > + ? ?c1 = getcontext() > + ? ?cls.assertTrue(c1.flags[Inexact]) > + ? ?for sig in Overflow, Underflow, DivisionByZero, InvalidOperation: > + ? ? ? ?cls.assertFalse(c1.flags[sig]) > ? ? return > > ?def thfunc2(cls): > + ? ?Decimal = cls.decimal.Decimal > + ? ?InvalidOperation = cls.decimal.InvalidOperation > + ? ?DivisionByZero = cls.decimal.DivisionByZero > + ? ?Overflow = cls.decimal.Overflow > + ? ?Underflow = cls.decimal.Underflow > + ? ?Inexact = cls.decimal.Inexact > + ? ?getcontext = cls.decimal.getcontext > + ? ?localcontext = cls.decimal.localcontext > + > ? ? d1 = Decimal(1) > ? ? d3 = Decimal(3) > ? ? test1 = d1/d3 > + > ? ? thiscontext = getcontext() > ? ? thiscontext.prec = 18 > ? ? test2 = d1/d3 > + > + ? ?with localcontext() as c2: > + ? ? ? ?cls.assertTrue(c2.flags[Inexact]) > + ? ? ? ?cls.assertRaises(Overflow, c2.multiply, Decimal('1e425000000'), 999) > + ? ? ? ?cls.assertTrue(c2.flags[Overflow]) > + ? ? ? ?with localcontext(thiscontext) as c3: > + ? ? ? ? ? ?cls.assertTrue(c3.flags[Inexact]) > + ? ? ? ? ? ?cls.assertFalse(c3.flags[Overflow]) > + ? ? ? ? ? ?c3.traps[Underflow] = True > + ? ? ? ? ? ?cls.assertRaises(Underflow, c3.divide, Decimal('1e-425000000'), 999) > + ? ? ? ? ? ?cls.assertTrue(c3.flags[Underflow]) > + ? ? ? ? ? ?del c3 > + ? ? ? ?cls.assertFalse(c2.flags[Underflow]) > + ? ? ? ?cls.assertFalse(c2.traps[Underflow]) > + ? ? ? ?del c2 > + > ? ? cls.synchro.set() > ? ? cls.finish2.set() > > - ? ?cls.assertEqual(test1, Decimal('0.3333333333333333333333333333')) > + ? ?cls.assertEqual(test1, Decimal('0.333333333333333333333333')) > ? ? cls.assertEqual(test2, Decimal('0.333333333333333333')) > + > + ? ?cls.assertFalse(thiscontext.traps[Underflow]) > + ? ?cls.assertTrue(thiscontext.flags[Inexact]) > + ? ?for sig in Overflow, Underflow, DivisionByZero, InvalidOperation: > + ? ? ? ?cls.assertFalse(thiscontext.flags[sig]) > ? ? return > > - > -class DecimalUseOfContextTest(unittest.TestCase): > - ? ?'''Unit tests for Use of Context cases in Decimal.''' > - > - ? ?try: > - ? ? ? ?import threading > - ? ?except ImportError: > - ? ? ? ?threading = None > +class ThreadingTest(unittest.TestCase): > + ? ?'''Unit tests for thread local contexts in Decimal.''' > > ? ? # Take care executing this test from IDLE, there's an issue in threading > ? ? # that hangs IDLE and I couldn't find it > > ? ? def test_threading(self): > - ? ? ? ?#Test the "threading isolation" of a Context. > + ? ? ? ?DefaultContext = self.decimal.DefaultContext > + > + ? ? ? ?if self.decimal == C and not self.decimal.HAVE_THREADS: > + ? ? ? ? ? ?self.skipTest("compiled without threading") > + ? ? ? ?# Test the "threading isolation" of a Context. Also test changing > + ? ? ? ?# the DefaultContext, which acts as a template for the thread-local > + ? ? ? ?# contexts. > + ? ? ? ?save_prec = DefaultContext.prec > + ? ? ? ?save_emax = DefaultContext.Emax > + ? ? ? ?save_emin = DefaultContext.Emin > + ? ? ? ?DefaultContext.prec = 24 > + ? ? ? ?DefaultContext.Emax = 425000000 > + ? ? ? ?DefaultContext.Emin = -425000000 > > ? ? ? ? self.synchro = threading.Event() > ? ? ? ? self.finish1 = threading.Event() > @@ -1239,17 +1574,29 @@ > > ? ? ? ? self.finish1.wait() > ? ? ? ? self.finish2.wait() > + > + ? ? ? ?for sig in Signals[self.decimal]: > + ? ? ? ? ? ?self.assertFalse(DefaultContext.flags[sig]) > + > + ? ? ? ?DefaultContext.prec = save_prec > + ? ? ? ?DefaultContext.Emax = save_emax > + ? ? ? ?DefaultContext.Emin = save_emin > ? ? ? ? return > > - ? ?if threading is None: > - ? ? ? ?del test_threading > - > - > -class DecimalUsabilityTest(unittest.TestCase): > + at unittest.skipUnless(threading, 'threading required') > +class CThreadingTest(ThreadingTest): > + ? ?decimal = C > + at unittest.skipUnless(threading, 'threading required') > +class PyThreadingTest(ThreadingTest): > + ? ?decimal = P > + > +class UsabilityTest(unittest.TestCase): > ? ? '''Unit tests for Usability cases of Decimal.''' > > ? ? def test_comparison_operators(self): > > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? da = Decimal('23.42') > ? ? ? ? db = Decimal('23.42') > ? ? ? ? dc = Decimal('45') > @@ -1283,6 +1630,8 @@ > ? ? ? ? self.assertEqual(a, b) > > ? ? def test_decimal_float_comparison(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? da = Decimal('0.25') > ? ? ? ? db = Decimal('3.0') > ? ? ? ? self.assertLess(da, 3.0) > @@ -1299,7 +1648,71 @@ > ? ? ? ? self.assertEqual(3.0, db) > ? ? ? ? self.assertNotEqual(0.1, Decimal('0.1')) > > + ? ?def test_decimal_complex_comparison(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?da = Decimal('0.25') > + ? ? ? ?db = Decimal('3.0') > + ? ? ? ?self.assertNotEqual(da, (1.5+0j)) > + ? ? ? ?self.assertNotEqual((1.5+0j), da) > + ? ? ? ?self.assertEqual(da, (0.25+0j)) > + ? ? ? ?self.assertEqual((0.25+0j), da) > + ? ? ? ?self.assertEqual((3.0+0j), db) > + ? ? ? ?self.assertEqual(db, (3.0+0j)) > + > + ? ? ? ?self.assertNotEqual(db, (3.0+1j)) > + ? ? ? ?self.assertNotEqual((3.0+1j), db) > + > + ? ? ? ?self.assertIs(db.__lt__(3.0+0j), NotImplemented) > + ? ? ? ?self.assertIs(db.__le__(3.0+0j), NotImplemented) > + ? ? ? ?self.assertIs(db.__gt__(3.0+0j), NotImplemented) > + ? ? ? ?self.assertIs(db.__le__(3.0+0j), NotImplemented) > + > + ? ?def test_decimal_fraction_comparison(self): > + ? ? ? ?D = self.decimal.Decimal > + ? ? ? ?F = fractions[self.decimal].Fraction > + ? ? ? ?Context = self.decimal.Context > + ? ? ? ?localcontext = self.decimal.localcontext > + ? ? ? ?InvalidOperation = self.decimal.InvalidOperation > + > + > + ? ? ? ?emax = C.MAX_EMAX if C else 999999999 > + ? ? ? ?emin = C.MIN_EMIN if C else -999999999 > + ? ? ? ?etiny = C.MIN_ETINY if C else -1999999997 > + ? ? ? ?c = Context(Emax=emax, Emin=emin) > + > + ? ? ? ?with localcontext(c): > + ? ? ? ? ? ?c.prec = emax > + ? ? ? ? ? ?self.assertLess(D(0), F(1,9999999999999999999999999999999999999)) > + ? ? ? ? ? ?self.assertLess(F(-1,9999999999999999999999999999999999999), D(0)) > + ? ? ? ? ? ?self.assertLess(F(0,1), D("1e" + str(etiny))) > + ? ? ? ? ? ?self.assertLess(D("-1e" + str(etiny)), F(0,1)) > + ? ? ? ? ? ?self.assertLess(F(0,9999999999999999999999999), D("1e" + str(etiny))) > + ? ? ? ? ? ?self.assertLess(D("-1e" + str(etiny)), F(0,9999999999999999999999999)) > + > + ? ? ? ? ? ?self.assertEqual(D("0.1"), F(1,10)) > + ? ? ? ? ? ?self.assertEqual(F(1,10), D("0.1")) > + > + ? ? ? ? ? ?c.prec = 300 > + ? ? ? ? ? ?self.assertNotEqual(D(1)/3, F(1,3)) > + ? ? ? ? ? ?self.assertNotEqual(F(1,3), D(1)/3) > + > + ? ? ? ? ? ?self.assertLessEqual(F(120984237, 9999999999), D("9e" + str(emax))) > + ? ? ? ? ? ?self.assertGreaterEqual(D("9e" + str(emax)), F(120984237, 9999999999)) > + > + ? ? ? ? ? ?self.assertGreater(D('inf'), F(99999999999,123)) > + ? ? ? ? ? ?self.assertGreater(D('inf'), F(-99999999999,123)) > + ? ? ? ? ? ?self.assertLess(D('-inf'), F(99999999999,123)) > + ? ? ? ? ? ?self.assertLess(D('-inf'), F(-99999999999,123)) > + > + ? ? ? ? ? ?self.assertRaises(InvalidOperation, D('nan').__gt__, F(-9,123)) > + ? ? ? ? ? ?self.assertIs(NotImplemented, F(-9,123).__lt__(D('nan'))) > + ? ? ? ? ? ?self.assertNotEqual(D('nan'), F(-9,123)) > + ? ? ? ? ? ?self.assertNotEqual(F(-9,123), D('nan')) > + > ? ? def test_copy_and_deepcopy_methods(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? d = Decimal('43.24') > ? ? ? ? c = copy.copy(d) > ? ? ? ? self.assertEqual(id(c), id(d)) > @@ -1307,6 +1720,10 @@ > ? ? ? ? self.assertEqual(id(dc), id(d)) > > ? ? def test_hash_method(self): > + > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?localcontext = self.decimal.localcontext > + > ? ? ? ? def hashit(d): > ? ? ? ? ? ? a = hash(d) > ? ? ? ? ? ? b = d.__hash__() > @@ -1367,24 +1784,27 @@ > ? ? ? ? ? ? d = Decimal(s) > ? ? ? ? ? ? self.assertEqual(hashit(f), hashit(d)) > > - ? ? ? ?# check that the value of the hash doesn't depend on the > - ? ? ? ?# current context (issue #1757) > - ? ? ? ?c = getcontext() > - ? ? ? ?old_precision = c.prec > - ? ? ? ?x = Decimal("123456789.1") > - > - ? ? ? ?c.prec = 6 > - ? ? ? ?h1 = hashit(x) > - ? ? ? ?c.prec = 10 > - ? ? ? ?h2 = hashit(x) > - ? ? ? ?c.prec = 16 > - ? ? ? ?h3 = hashit(x) > - > - ? ? ? ?self.assertEqual(h1, h2) > - ? ? ? ?self.assertEqual(h1, h3) > - ? ? ? ?c.prec = old_precision > + ? ? ? ?with localcontext() as c: > + ? ? ? ? ? ?# check that the value of the hash doesn't depend on the > + ? ? ? ? ? ?# current context (issue #1757) > + ? ? ? ? ? ?x = Decimal("123456789.1") > + > + ? ? ? ? ? ?c.prec = 6 > + ? ? ? ? ? ?h1 = hashit(x) > + ? ? ? ? ? ?c.prec = 10 > + ? ? ? ? ? ?h2 = hashit(x) > + ? ? ? ? ? ?c.prec = 16 > + ? ? ? ? ? ?h3 = hashit(x) > + > + ? ? ? ? ? ?self.assertEqual(h1, h2) > + ? ? ? ? ? ?self.assertEqual(h1, h3) > + > + ? ? ? ? ? ?c.prec = 10000 > + ? ? ? ? ? ?x = 1100 ** 1248 > + ? ? ? ? ? ?self.assertEqual(hashit(Decimal(x)), hashit(x)) > > ? ? def test_min_and_max_methods(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('15.32') > ? ? ? ? d2 = Decimal('28.5') > @@ -1404,6 +1824,8 @@ > ? ? ? ? self.assertIs(max(d2,l1), d2) > > ? ? def test_as_nonzero(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > ? ? ? ? #as false > ? ? ? ? self.assertFalse(Decimal(0)) > ? ? ? ? #as true > @@ -1411,6 +1833,7 @@ > > ? ? def test_tostring_methods(self): > ? ? ? ? #Test str and repr methods. > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d = Decimal('15.32') > ? ? ? ? self.assertEqual(str(d), '15.32') ? ? ? ? ? ? ? # str > @@ -1418,6 +1841,7 @@ > > ? ? def test_tonum_methods(self): > ? ? ? ? #Test float and int methods. > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? d1 = Decimal('66') > ? ? ? ? d2 = Decimal('15.32') > @@ -1440,6 +1864,7 @@ > ? ? ? ? ? ? ('-11.0', -11), > ? ? ? ? ? ? ('0.0', 0), > ? ? ? ? ? ? ('-0E3', 0), > + ? ? ? ? ? ?('89891211712379812736.1', 89891211712379812736), > ? ? ? ? ? ? ] > ? ? ? ? for d, i in test_pairs: > ? ? ? ? ? ? self.assertEqual(math.floor(Decimal(d)), i) > @@ -1459,6 +1884,7 @@ > ? ? ? ? ? ? ('-11.0', -11), > ? ? ? ? ? ? ('0.0', 0), > ? ? ? ? ? ? ('-0E3', 0), > + ? ? ? ? ? ?('89891211712379812736.1', 89891211712379812737), > ? ? ? ? ? ? ] > ? ? ? ? for d, i in test_pairs: > ? ? ? ? ? ? self.assertEqual(math.ceil(Decimal(d)), i) > @@ -1516,9 +1942,8 @@ > ? ? ? ? for d, n, r in test_triples: > ? ? ? ? ? ? self.assertEqual(str(round(Decimal(d), n)), r) > > - > - > ? ? def test_eval_round_trip(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? #with zero > ? ? ? ? d = Decimal( (0, (0,), 0) ) > @@ -1537,6 +1962,7 @@ > ? ? ? ? self.assertEqual(d, eval(repr(d))) > > ? ? def test_as_tuple(self): > + ? ? ? ?Decimal = self.decimal.Decimal > > ? ? ? ? #with zero > ? ? ? ? d = Decimal(0) > @@ -1550,7 +1976,7 @@ > ? ? ? ? d = Decimal("-4.34913534E-17") > ? ? ? ? self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) > > - ? ? ? ?#inf > + ? ? ? ?# XXX non-compliant infinity payload. > ? ? ? ? d = Decimal("Infinity") > ? ? ? ? self.assertEqual(d.as_tuple(), (0, (0,), 'F') ) > > @@ -1570,14 +1996,2158 @@ > ? ? ? ? d = Decimal( (1, (), 'n') ) > ? ? ? ? self.assertEqual(d.as_tuple(), (1, (), 'n') ) > > - ? ? ? ?#coefficient in infinity should be ignored > - ? ? ? ?d = Decimal( (0, (4, 5, 3, 4), 'F') ) > - ? ? ? ?self.assertEqual(d.as_tuple(), (0, (0,), 'F')) > - ? ? ? ?d = Decimal( (1, (0, 2, 7, 1), 'F') ) > - ? ? ? ?self.assertEqual(d.as_tuple(), (1, (0,), 'F')) > - > - ? ?def test_immutability_operations(self): > + ? ? ? ?# XXX coefficient in infinity should raise an error > + ? ? ? ?if self.decimal == P: > + ? ? ? ? ? ?d = Decimal( (0, (4, 5, 3, 4), 'F') ) > + ? ? ? ? ? ?self.assertEqual(d.as_tuple(), (0, (0,), 'F')) > + ? ? ? ? ? ?d = Decimal( (1, (0, 2, 7, 1), 'F') ) > + ? ? ? ? ? ?self.assertEqual(d.as_tuple(), (1, (0,), 'F')) > + > + ? ?def test_subclassing(self): > + ? ? ? ?# Different behaviours when subclassing Decimal > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?class MyDecimal(Decimal): > + ? ? ? ? ? ?pass > + > + ? ? ? ?d1 = MyDecimal(1) > + ? ? ? ?d2 = MyDecimal(2) > + ? ? ? ?d = d1 + d2 > + ? ? ? ?self.assertIs(type(d), Decimal) > + > + ? ? ? ?d = d1.max(d2) > + ? ? ? ?self.assertIs(type(d), Decimal) > + > + ? ? ? ?d = copy.copy(d1) > + ? ? ? ?self.assertIs(type(d), MyDecimal) > + ? ? ? ?self.assertEqual(d, d1) > + > + ? ? ? ?d = copy.deepcopy(d1) > + ? ? ? ?self.assertIs(type(d), MyDecimal) > + ? ? ? ?self.assertEqual(d, d1) > + > + ? ?def test_implicit_context(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?getcontext = self.decimal.getcontext > + > + ? ? ? ?# Check results when context given implicitly. ?(Issue 2478) > + ? ? ? ?c = getcontext() > + ? ? ? ?self.assertEqual(str(Decimal(0).sqrt()), > + ? ? ? ? ? ? ? ? ? ? ? ? str(c.sqrt(Decimal(0)))) > + > + ? ?def test_conversions_from_int(self): > + ? ? ? ?# Check that methods taking a second Decimal argument will > + ? ? ? ?# always accept an integer in place of a Decimal. > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?self.assertEqual(Decimal(4).compare(3), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(4).compare(Decimal(3))) > + ? ? ? ?self.assertEqual(Decimal(4).compare_signal(3), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(4).compare_signal(Decimal(3))) > + ? ? ? ?self.assertEqual(Decimal(4).compare_total(3), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(4).compare_total(Decimal(3))) > + ? ? ? ?self.assertEqual(Decimal(4).compare_total_mag(3), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(4).compare_total_mag(Decimal(3))) > + ? ? ? ?self.assertEqual(Decimal(10101).logical_and(1001), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(10101).logical_and(Decimal(1001))) > + ? ? ? ?self.assertEqual(Decimal(10101).logical_or(1001), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(10101).logical_or(Decimal(1001))) > + ? ? ? ?self.assertEqual(Decimal(10101).logical_xor(1001), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(10101).logical_xor(Decimal(1001))) > + ? ? ? ?self.assertEqual(Decimal(567).max(123), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(567).max(Decimal(123))) > + ? ? ? ?self.assertEqual(Decimal(567).max_mag(123), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(567).max_mag(Decimal(123))) > + ? ? ? ?self.assertEqual(Decimal(567).min(123), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(567).min(Decimal(123))) > + ? ? ? ?self.assertEqual(Decimal(567).min_mag(123), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(567).min_mag(Decimal(123))) > + ? ? ? ?self.assertEqual(Decimal(567).next_toward(123), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(567).next_toward(Decimal(123))) > + ? ? ? ?self.assertEqual(Decimal(1234).quantize(100), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(1234).quantize(Decimal(100))) > + ? ? ? ?self.assertEqual(Decimal(768).remainder_near(1234), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(768).remainder_near(Decimal(1234))) > + ? ? ? ?self.assertEqual(Decimal(123).rotate(1), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(123).rotate(Decimal(1))) > + ? ? ? ?self.assertEqual(Decimal(1234).same_quantum(1000), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(1234).same_quantum(Decimal(1000))) > + ? ? ? ?self.assertEqual(Decimal('9.123').scaleb(-100), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal('9.123').scaleb(Decimal(-100))) > + ? ? ? ?self.assertEqual(Decimal(456).shift(-1), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(456).shift(Decimal(-1))) > + > + ? ? ? ?self.assertEqual(Decimal(-12).fma(Decimal(45), 67), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(-12).fma(Decimal(45), Decimal(67))) > + ? ? ? ?self.assertEqual(Decimal(-12).fma(45, 67), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(-12).fma(Decimal(45), Decimal(67))) > + ? ? ? ?self.assertEqual(Decimal(-12).fma(45, Decimal(67)), > + ? ? ? ? ? ? ? ? ? ? ? ? Decimal(-12).fma(Decimal(45), Decimal(67))) > + > +class CUsabilityTest(UsabilityTest): > + ? ?decimal = C > +class PyUsabilityTest(UsabilityTest): > + ? ?decimal = P > + > +class PythonAPItests(unittest.TestCase): > + > + ? ?def test_abc(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?self.assertTrue(issubclass(Decimal, numbers.Number)) > + ? ? ? ?self.assertFalse(issubclass(Decimal, numbers.Real)) > + ? ? ? ?self.assertIsInstance(Decimal(0), numbers.Number) > + ? ? ? ?self.assertNotIsInstance(Decimal(0), numbers.Real) > + > + ? ?def test_pickle(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?savedecimal = sys.modules['decimal'] > + > + ? ? ? ?# Round trip > + ? ? ? ?sys.modules['decimal'] = self.decimal > + ? ? ? ?d = Decimal('-3.141590000') > + ? ? ? ?p = pickle.dumps(d) > + ? ? ? ?e = pickle.loads(p) > + ? ? ? ?self.assertEqual(d, e) > + > + ? ? ? ?if C: > + ? ? ? ? ? ?# Test interchangeability > + ? ? ? ? ? ?x = C.Decimal('-3.123e81723') > + ? ? ? ? ? ?y = P.Decimal('-3.123e81723') > + > + ? ? ? ? ? ?sys.modules['decimal'] = C > + ? ? ? ? ? ?sx = pickle.dumps(x) > + ? ? ? ? ? ?sys.modules['decimal'] = P > + ? ? ? ? ? ?r = pickle.loads(sx) > + ? ? ? ? ? ?self.assertIsInstance(r, P.Decimal) > + ? ? ? ? ? ?self.assertEqual(r, y) > + > + ? ? ? ? ? ?sys.modules['decimal'] = P > + ? ? ? ? ? ?sy = pickle.dumps(y) > + ? ? ? ? ? ?sys.modules['decimal'] = C > + ? ? ? ? ? ?r = pickle.loads(sy) > + ? ? ? ? ? ?self.assertIsInstance(r, C.Decimal) > + ? ? ? ? ? ?self.assertEqual(r, x) > + > + ? ? ? ?sys.modules['decimal'] = savedecimal > + > + ? ?def test_int(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?ROUND_DOWN = self.decimal.ROUND_DOWN > + > + ? ? ? ?for x in range(-250, 250): > + ? ? ? ? ? ?s = '%0.2f' % (x / 100.0) > + ? ? ? ? ? ?# should work the same as for floats > + ? ? ? ? ? ?self.assertEqual(int(Decimal(s)), int(float(s))) > + ? ? ? ? ? ?# should work the same as to_integral in the ROUND_DOWN mode > + ? ? ? ? ? ?d = Decimal(s) > + ? ? ? ? ? ?r = d.to_integral(ROUND_DOWN) > + ? ? ? ? ? ?self.assertEqual(Decimal(int(d)), r) > + > + ? ? ? ?self.assertRaises(ValueError, int, Decimal('-nan')) > + ? ? ? ?self.assertRaises(ValueError, int, Decimal('snan')) > + ? ? ? ?self.assertRaises(OverflowError, int, Decimal('inf')) > + ? ? ? ?self.assertRaises(OverflowError, int, Decimal('-inf')) > + > + ? ?def test_trunc(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?ROUND_DOWN = self.decimal.ROUND_DOWN > + > + ? ? ? ?for x in range(-250, 250): > + ? ? ? ? ? ?s = '%0.2f' % (x / 100.0) > + ? ? ? ? ? ?# should work the same as for floats > + ? ? ? ? ? ?self.assertEqual(int(Decimal(s)), int(float(s))) > + ? ? ? ? ? ?# should work the same as to_integral in the ROUND_DOWN mode > + ? ? ? ? ? ?d = Decimal(s) > + ? ? ? ? ? ?r = d.to_integral(ROUND_DOWN) > + ? ? ? ? ? ?self.assertEqual(Decimal(math.trunc(d)), r) > + > + ? ?def test_from_float(self): > + > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?class MyDecimal(Decimal): > + ? ? ? ? ? ?pass > + > + ? ? ? ?self.assertTrue(issubclass(MyDecimal, Decimal)) > + > + ? ? ? ?r = MyDecimal.from_float(0.1) > + ? ? ? ?self.assertEqual(type(r), MyDecimal) > + ? ? ? ?self.assertEqual(str(r), > + ? ? ? ? ? ? ? ?'0.1000000000000000055511151231257827021181583404541015625') > + ? ? ? ?bigint = 12345678901234567890123456789 > + ? ? ? ?self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint)) > + ? ? ? ?self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan()) > + ? ? ? ?self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite()) > + ? ? ? ?self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite()) > + ? ? ? ?self.assertEqual(str(MyDecimal.from_float(float('nan'))), > + ? ? ? ? ? ? ? ? ? ? ? ? str(Decimal('NaN'))) > + ? ? ? ?self.assertEqual(str(MyDecimal.from_float(float('inf'))), > + ? ? ? ? ? ? ? ? ? ? ? ? str(Decimal('Infinity'))) > + ? ? ? ?self.assertEqual(str(MyDecimal.from_float(float('-inf'))), > + ? ? ? ? ? ? ? ? ? ? ? ? str(Decimal('-Infinity'))) > + ? ? ? ?self.assertRaises(TypeError, MyDecimal.from_float, 'abc') > + ? ? ? ?for i in range(200): > + ? ? ? ? ? ?x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) > + ? ? ? ? ? ?self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip > + > + ? ?def test_create_decimal_from_float(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?Context = self.decimal.Context > + ? ? ? ?ROUND_DOWN = self.decimal.ROUND_DOWN > + ? ? ? ?ROUND_UP = self.decimal.ROUND_UP > + ? ? ? ?Inexact = self.decimal.Inexact > + > + ? ? ? ?context = Context(prec=5, rounding=ROUND_DOWN) > + ? ? ? ?self.assertEqual( > + ? ? ? ? ? ?context.create_decimal_from_float(math.pi), > + ? ? ? ? ? ?Decimal('3.1415') > + ? ? ? ?) > + ? ? ? ?context = Context(prec=5, rounding=ROUND_UP) > + ? ? ? ?self.assertEqual( > + ? ? ? ? ? ?context.create_decimal_from_float(math.pi), > + ? ? ? ? ? ?Decimal('3.1416') > + ? ? ? ?) > + ? ? ? ?context = Context(prec=5, traps=[Inexact]) > + ? ? ? ?self.assertRaises( > + ? ? ? ? ? ?Inexact, > + ? ? ? ? ? ?context.create_decimal_from_float, > + ? ? ? ? ? ?math.pi > + ? ? ? ?) > + ? ? ? ?self.assertEqual(repr(context.create_decimal_from_float(-0.0)), > + ? ? ? ? ? ? ? ? ? ? ? ? "Decimal('-0')") > + ? ? ? ?self.assertEqual(repr(context.create_decimal_from_float(1.0)), > + ? ? ? ? ? ? ? ? ? ? ? ? "Decimal('1')") > + ? ? ? ?self.assertEqual(repr(context.create_decimal_from_float(10)), > + ? ? ? ? ? ? ? ? ? ? ? ? "Decimal('10')") > + > + ? ?def test_quantize(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + ? ? ? ?Context = self.decimal.Context > + ? ? ? ?InvalidOperation = self.decimal.InvalidOperation > + ? ? ? ?ROUND_DOWN = self.decimal.ROUND_DOWN > + > + ? ? ? ?c = Context(Emax=99999, Emin=-99999) > + ? ? ? ?self.assertEqual( > + ? ? ? ? ? ?Decimal('7.335').quantize(Decimal('.01')), > + ? ? ? ? ? ?Decimal('7.34') > + ? ? ? ?) > + ? ? ? ?self.assertEqual( > + ? ? ? ? ? ?Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN), > + ? ? ? ? ? ?Decimal('7.33') > + ? ? ? ?) > + ? ? ? ?self.assertRaises( > + ? ? ? ? ? ?InvalidOperation, > + ? ? ? ? ? ?Decimal("10e99999").quantize, Decimal('1e100000'), context=c > + ? ? ? ?) > + > + ? ? ? ?c = Context() > + ? ? ? ?d = Decimal("0.871831e800") > + ? ? ? ?x = d.quantize(context=c, exp=Decimal("1e797"), rounding=ROUND_DOWN) > + ? ? ? ?self.assertEqual(x, Decimal('8.71E+799')) > + > + ? ?def test_complex(self): > + ? ? ? ?Decimal = self.decimal.Decimal > + > + ? ? ? ?x = Decimal("9.8182731e181273") > + ? ? ? ?self.assertEqual(x.real, x) > + ? ? ? ?self.assertEqual(x.imag, 0) > + ? ? ? ?self.assertEqual(x.conjugate(), x) > + > + ? ? ? ?x = Decimal("1") > + ? ? ? ?self.assertEqual(complex(x), complex(float(1))) > + > + ? ? ? ?self.assertRaises(AttributeError, setattr, x, 'real', 100) > + ? ? ? ?self.assertRaises(AttributeError, setattr, x, 'imag', 100) > + ? ? ? ?self.assertRaises(AttributeError, setattr, x, 'conjugate', 100) > + ? ? ? ?self.assertRaises(AttributeError, setattr, x, '__complex__', 100) > + > + ? ?def test_named_parameters(self): > + ? ? ? ?D = self.decimal.Decimal > + ? ? ? ?Context = self.decimal.Context > + ? ? ? ?localcontext = self.decimal.localcontext > + ... > > [Message clipped] > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > -- Thanks, Andrew Svetlov From python-checkins at python.org Wed Mar 21 19:26:21 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 21 Mar 2012 19:26:21 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_use_identifier_api?= Message-ID: http://hg.python.org/cpython/rev/5fae5be91849 changeset: 75852:5fae5be91849 parent: 75843:f1e1b32d6301 user: Benjamin Peterson date: Tue Mar 20 23:17:04 2012 -0400 summary: use identifier api files: Python/ceval.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1837,10 +1837,11 @@ if (PyGen_CheckExact(x)) { retval = _PyGen_Send((PyGenObject *)x, u); } else { + _Py_IDENTIFIER(send); if (u == Py_None) retval = PyIter_Next(x); else - retval = PyObject_CallMethod(x, "send", "O", u); + retval = _PyObject_CallMethodId(x, &PyId_send, "O", u); } Py_DECREF(u); if (!retval) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 19:26:22 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 21 Mar 2012 19:26:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_some_more_identifier_goodne?= =?utf8?q?ss?= Message-ID: http://hg.python.org/cpython/rev/e704451ecab2 changeset: 75853:e704451ecab2 user: Benjamin Peterson date: Tue Mar 20 23:26:41 2012 -0400 summary: some more identifier goodness files: Objects/abstract.c | 35 +++++++-------------------------- 1 files changed, 8 insertions(+), 27 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1325,16 +1325,10 @@ PyNumber_Long(PyObject *o) { PyNumberMethods *m; - static PyObject *trunc_name = NULL; PyObject *trunc_func; const char *buffer; Py_ssize_t buffer_len; - - if (trunc_name == NULL) { - trunc_name = PyUnicode_InternFromString("__trunc__"); - if (trunc_name == NULL) - return NULL; - } + _Py_IDENTIFIER(__trunc__); if (o == NULL) return null_error(); @@ -1356,7 +1350,7 @@ } if (PyLong_Check(o)) /* An int subclass without nb_int */ return _PyLong_Copy((PyLongObject *)o); - trunc_func = PyObject_GetAttr(o, trunc_name); + trunc_func = _PyObject_GetAttrId(o, &PyId___trunc__); if (trunc_func) { PyObject *truncated = PyEval_CallObject(trunc_func, NULL); PyObject *int_instance; @@ -2411,10 +2405,8 @@ /* isinstance(), issubclass() */ -/* abstract_get_bases() has logically 4 return states, with a sort of 0th - * state that will almost never happen. +/* abstract_get_bases() has logically 4 return states: * - * 0. creating the __bases__ static string could get a MemoryError * 1. getattr(cls, '__bases__') could raise an AttributeError * 2. getattr(cls, '__bases__') could raise some other exception * 3. getattr(cls, '__bases__') could return a tuple @@ -2440,16 +2432,11 @@ static PyObject * abstract_get_bases(PyObject *cls) { - static PyObject *__bases__ = NULL; + _Py_IDENTIFIER(__bases__); PyObject *bases; - if (__bases__ == NULL) { - __bases__ = PyUnicode_InternFromString("__bases__"); - if (__bases__ == NULL) - return NULL; - } Py_ALLOW_RECURSION - bases = PyObject_GetAttr(cls, __bases__); + bases = _PyObject_GetAttrId(cls, &PyId___bases__); Py_END_ALLOW_RECURSION if (bases == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) @@ -2519,19 +2506,13 @@ recursive_isinstance(PyObject *inst, PyObject *cls) { PyObject *icls; - static PyObject *__class__ = NULL; int retval = 0; - - if (__class__ == NULL) { - __class__ = PyUnicode_InternFromString("__class__"); - if (__class__ == NULL) - return -1; - } + _Py_IDENTIFIER(__class__); if (PyType_Check(cls)) { retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls); if (retval == 0) { - PyObject *c = PyObject_GetAttr(inst, __class__); + PyObject *c = _PyObject_GetAttrId(inst, &PyId___class__); if (c == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) PyErr_Clear(); @@ -2552,7 +2533,7 @@ if (!check_class(cls, "isinstance() arg 2 must be a type or tuple of types")) return -1; - icls = PyObject_GetAttr(inst, __class__); + icls = _PyObject_GetAttrId(inst, &PyId___class__); if (icls == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) PyErr_Clear(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 19:26:23 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 21 Mar 2012 19:26:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_correctly_lookup_=5F=5Ftrun?= =?utf8?q?c=5F=5F_in_int=28=29_constructor?= Message-ID: http://hg.python.org/cpython/rev/5a3af70180a2 changeset: 75854:5a3af70180a2 user: Benjamin Peterson date: Tue Mar 20 23:48:11 2012 -0400 summary: correctly lookup __trunc__ in int() constructor files: Lib/test/test_descr.py | 1 + Objects/abstract.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1770,6 +1770,7 @@ ("__format__", format, format_impl, set(), {}), ("__floor__", math.floor, zero, set(), {}), ("__trunc__", math.trunc, zero, set(), {}), + ("__trunc__", int, zero, set(), {}), ("__ceil__", math.ceil, zero, set(), {}), ("__dir__", dir, empty_seq, set(), {}), ] diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1350,7 +1350,7 @@ } if (PyLong_Check(o)) /* An int subclass without nb_int */ return _PyLong_Copy((PyLongObject *)o); - trunc_func = _PyObject_GetAttrId(o, &PyId___trunc__); + trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__); if (trunc_func) { PyObject *truncated = PyEval_CallObject(trunc_func, NULL); PyObject *int_instance; @@ -1362,7 +1362,8 @@ "__trunc__ returned non-Integral (type %.200s)"); return int_instance; } - PyErr_Clear(); /* It's not an error if o.__trunc__ doesn't exist. */ + if (PyErr_Occurred()) + return NULL; if (PyBytes_Check(o)) /* need to do extra error checking that PyLong_FromString() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 19:26:24 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 21 Mar 2012 19:26:24 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/4aa3369e4d60 changeset: 75855:4aa3369e4d60 parent: 75854:5a3af70180a2 parent: 75851:3d5ef57742d3 user: Benjamin Peterson date: Wed Mar 21 14:26:09 2012 -0400 summary: merge heads files: Doc/library/decimal.rst | 181 +- Doc/library/numeric.rst | 6 +- Doc/whatsnew/3.3.rst | 87 + Include/longintrepr.h | 2 +- Lib/decimal.py | 196 +- Lib/idlelib/NEWS.txt | 7 + Lib/idlelib/PyShell.py | 6 +- Lib/smtpd.py | 12 + Lib/test/support.py | 4 +- Lib/test/test_decimal.py | 4550 ++++- Lib/test/test_fractions.py | 12 +- Lib/test/test_numeric_tower.py | 2 +- Lib/test/test_smtpd.py | 48 +- Misc/ACKS | 1 + Misc/NEWS | 10 + Misc/valgrind-python.supp | 13 + Modules/_decimal/ISSUES.txt | 56 + Modules/_decimal/README.txt | 46 + Modules/_decimal/_decimal.c | 5512 +++++++ Modules/_decimal/docstrings.h | 753 + Modules/_decimal/libmpdec/README.txt | 90 + Modules/_decimal/libmpdec/basearith.c | 635 + Modules/_decimal/libmpdec/basearith.h | 213 + Modules/_decimal/libmpdec/bits.h | 192 + Modules/_decimal/libmpdec/constants.c | 132 + Modules/_decimal/libmpdec/constants.h | 83 + Modules/_decimal/libmpdec/context.c | 286 + Modules/_decimal/libmpdec/convolute.c | 174 + Modules/_decimal/libmpdec/convolute.h | 43 + Modules/_decimal/libmpdec/crt.c | 179 + Modules/_decimal/libmpdec/crt.h | 40 + Modules/_decimal/libmpdec/difradix2.c | 173 + Modules/_decimal/libmpdec/difradix2.h | 41 + Modules/_decimal/libmpdec/fnt.c | 81 + Modules/_decimal/libmpdec/fnt.h | 42 + Modules/_decimal/libmpdec/fourstep.c | 255 + Modules/_decimal/libmpdec/fourstep.h | 41 + Modules/_decimal/libmpdec/io.c | 1575 ++ Modules/_decimal/libmpdec/io.h | 59 + Modules/_decimal/libmpdec/literature/REFERENCES.txt | 51 + Modules/_decimal/libmpdec/literature/bignum.txt | 83 + Modules/_decimal/libmpdec/literature/fnt.py | 208 + Modules/_decimal/libmpdec/literature/matrix-transform.txt | 256 + Modules/_decimal/libmpdec/literature/mulmod-64.txt | 127 + Modules/_decimal/libmpdec/literature/mulmod-ppro.txt | 269 + Modules/_decimal/libmpdec/literature/six-step.txt | 63 + Modules/_decimal/libmpdec/literature/umodarith.lisp | 692 + Modules/_decimal/libmpdec/memory.c | 292 + Modules/_decimal/libmpdec/memory.h | 44 + Modules/_decimal/libmpdec/mpdecimal.c | 7596 ++++++++++ Modules/_decimal/libmpdec/mpdecimal.h | 800 + Modules/_decimal/libmpdec/numbertheory.c | 132 + Modules/_decimal/libmpdec/numbertheory.h | 71 + Modules/_decimal/libmpdec/sixstep.c | 212 + Modules/_decimal/libmpdec/sixstep.h | 41 + Modules/_decimal/libmpdec/transpose.c | 276 + Modules/_decimal/libmpdec/transpose.h | 55 + Modules/_decimal/libmpdec/typearith.h | 669 + Modules/_decimal/libmpdec/umodarith.h | 650 + Modules/_decimal/libmpdec/vccompat.h | 62 + Modules/_decimal/libmpdec/vcdiv64.asm | 48 + Modules/_decimal/libmpdec/vcstdint.h | 232 + Modules/_decimal/tests/README.txt | 15 + Modules/_decimal/tests/bench.py | 116 + Modules/_decimal/tests/deccheck.py | 1074 + Modules/_decimal/tests/formathelper.py | 344 + Modules/_decimal/tests/randdec.py | 559 + Modules/_decimal/tests/randfloat.py | 250 + Modules/_decimal/tests/runall-memorydebugger.sh | 175 + Modules/_decimal/tests/runall.bat | 121 + PCbuild/_decimal.vcproj | 743 + PCbuild/pcbuild.sln | 21 + PCbuild/pythoncore.vcproj | 4 - configure | 171 + configure.ac | 100 + pyconfig.h.in | 13 + setup.py | 113 + 77 files changed, 31520 insertions(+), 1066 deletions(-) diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -9,6 +9,7 @@ .. moduleauthor:: Raymond Hettinger .. moduleauthor:: Aahz .. moduleauthor:: Tim Peters +.. moduleauthor:: Stefan Krah .. sectionauthor:: Raymond D. Hettinger .. import modules for testing inline doctests with the Sphinx doctest builder @@ -20,8 +21,9 @@ # make sure each group gets a fresh context setcontext(Context()) -The :mod:`decimal` module provides support for decimal floating point -arithmetic. It offers several advantages over the :class:`float` datatype: +The :mod:`decimal` module provides support for fast correctly-rounded +decimal floating point arithmetic. It offers several advantages over the +:class:`float` datatype: * Decimal "is based on a floating-point model which was designed with people in mind, and necessarily has a paramount guiding principle -- computers must @@ -92,7 +94,7 @@ considered as informational, or treated as exceptions. The signals in the decimal module are: :const:`Clamped`, :const:`InvalidOperation`, :const:`DivisionByZero`, :const:`Inexact`, :const:`Rounded`, :const:`Subnormal`, -:const:`Overflow`, and :const:`Underflow`. +:const:`Overflow`, :const:`Underflow` and :const:`FloatOperation`. For each signal there is a flag and a trap enabler. When a signal is encountered, its flag is set to one, then, if the trap enabler is @@ -122,7 +124,7 @@ >>> from decimal import * >>> getcontext() - Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, + Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero, InvalidOperation]) @@ -132,7 +134,7 @@ Construction from an integer or a float performs an exact conversion of the value of that integer or float. Decimal numbers include special values such as :const:`NaN` which stands for "Not a number", positive and negative -:const:`Infinity`, and :const:`-0`. +:const:`Infinity`, and :const:`-0`:: >>> getcontext().prec = 28 >>> Decimal(10) @@ -152,6 +154,25 @@ >>> Decimal('-Infinity') Decimal('-Infinity') +If the :exc:`FloatOperation` signal is trapped, accidental mixing of +decimals and floats in constructors or ordering comparisons raises +an exception:: + + >>> c = getcontext() + >>> c.traps[FloatOperation] = True + >>> Decimal(3.14) + Traceback (most recent call last): + File "", line 1, in + decimal.FloatOperation: [] + >>> Decimal('3.5') < 3.7 + Traceback (most recent call last): + File "", line 1, in + decimal.FloatOperation: [] + >>> Decimal('3.5') == 3.5 + True + +.. versionadded:: 3.3 + The significance of a new Decimal is determined solely by the number of digits input. Context precision and rounding only come into play during arithmetic operations. @@ -169,6 +190,16 @@ >>> Decimal('3.1415926535') + Decimal('2.7182818285') Decimal('5.85988') +If the internal limits of the C version are exceeded, constructing +a decimal raises :class:`InvalidOperation`:: + + >>> Decimal("1e9999999999999999999") + Traceback (most recent call last): + File "", line 1, in + decimal.InvalidOperation: [] + +.. versionchanged:: 3.3 + Decimals interact well with much of the rest of Python. Here is a small decimal floating point flying circus: @@ -244,7 +275,7 @@ Decimal('0.142857142857142857142857142857142857142857142857142857142857') >>> ExtendedContext - Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, + Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[]) >>> setcontext(ExtendedContext) >>> Decimal(1) / Decimal(7) @@ -269,7 +300,7 @@ >>> Decimal(355) / Decimal(113) Decimal('3.14159292') >>> getcontext() - Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, + Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[]) The *flags* entry shows that the rational approximation to :const:`Pi` was @@ -358,6 +389,10 @@ The argument to the constructor is now permitted to be a :class:`float` instance. + .. versionchanged:: 3.3 + :class:`float` arguments raise an exception if the :exc:`FloatOperation` + trap is set. By default the trap is off. + Decimal floating point objects share many properties with the other built-in numeric types such as :class:`float` and :class:`int`. All of the usual math operations and special methods apply. Likewise, decimal objects can be @@ -880,39 +915,33 @@ In single threaded environments, it is preferable to not use this context at all. Instead, simply create contexts explicitly as described below. - The default values are precision=28, rounding=ROUND_HALF_EVEN, and enabled traps - for Overflow, InvalidOperation, and DivisionByZero. + The default values are :attr:`prec`\ =\ :const:`28`, + :attr:`rounding`\ =\ :const:`ROUND_HALF_EVEN`, + and enabled traps for :class:`Overflow`, :class:`InvalidOperation`, and + :class:`DivisionByZero`. In addition to the three supplied contexts, new contexts can be created with the :class:`Context` constructor. -.. class:: Context(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=None, clamp=None) +.. class:: Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None) Creates a new context. If a field is not specified or is :const:`None`, the default values are copied from the :const:`DefaultContext`. If the *flags* field is not specified or is :const:`None`, all flags are cleared. - The *prec* field is a positive integer that sets the precision for arithmetic - operations in the context. - - The *rounding* option is one of: - - * :const:`ROUND_CEILING` (towards :const:`Infinity`), - * :const:`ROUND_DOWN` (towards zero), - * :const:`ROUND_FLOOR` (towards :const:`-Infinity`), - * :const:`ROUND_HALF_DOWN` (to nearest with ties going towards zero), - * :const:`ROUND_HALF_EVEN` (to nearest with ties going to nearest even integer), - * :const:`ROUND_HALF_UP` (to nearest with ties going away from zero), or - * :const:`ROUND_UP` (away from zero). - * :const:`ROUND_05UP` (away from zero if last digit after rounding towards zero - would have been 0 or 5; otherwise towards zero) + *prec* is an integer in the range [:const:`1`, :const:`MAX_PREC`] that sets + the precision for arithmetic operations in the context. + + The *rounding* option is one of the constants listed in the section + `Rounding Modes`_. The *traps* and *flags* fields list any signals to be set. Generally, new contexts should only set traps and leave the flags clear. The *Emin* and *Emax* fields are integers specifying the outer limits allowable - for exponents. + for exponents. *Emin* must be in the range [:const:`MIN_EMIN`, :const:`0`], + *Emax* in the range [:const:`0`, :const:`MAX_EMAX`]. The *capitals* field is either :const:`0` or :const:`1` (the default). If set to :const:`1`, exponents are printed with a capital :const:`E`; otherwise, a @@ -951,6 +980,12 @@ Resets all of the flags to :const:`0`. + .. method:: clear_traps() + + Resets all of the traps to :const:`0`. + + .. versionadded:: 3.3 + .. method:: copy() Return a duplicate of the context. @@ -1250,8 +1285,13 @@ With two arguments, compute ``x**y``. If ``x`` is negative then ``y`` must be integral. The result will be inexact unless ``y`` is integral and the result is finite and can be expressed exactly in 'precision' digits. - The result should always be correctly rounded, using the rounding mode of - the current thread's context. + The rounding mode of the context is used. Results are always correctly-rounded + in the Python version. + + .. versionchanged:: 3.3 + The C module computes :meth:`power` in terms of the correctly-rounded + :meth:`exp` and :meth:`ln` functions. The result is well-defined but + only "almost always correctly-rounded". With three arguments, compute ``(x**y) % modulo``. For the three argument form, the following restrictions on the arguments hold: @@ -1339,6 +1379,69 @@ .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +.. _decimal-rounding-modes: + +Constants +--------- + +The constants in this section are only relevant for the C module. They +are also included in the pure Python version for compatibility. + ++---------------------+---------------------+-------------------------------+ +| | 32-bit | 64-bit | ++=====================+=====================+===============================+ +| .. data:: MAX_PREC | :const:`425000000` | :const:`999999999999999999` | ++---------------------+---------------------+-------------------------------+ +| .. data:: MAX_EMAX | :const:`425000000` | :const:`999999999999999999` | ++---------------------+---------------------+-------------------------------+ +| .. data:: MIN_EMIN | :const:`-425000000` | :const:`-999999999999999999` | ++---------------------+---------------------+-------------------------------+ +| .. data:: MIN_ETINY | :const:`-849999999` | :const:`-1999999999999999997` | ++---------------------+---------------------+-------------------------------+ + + +.. data:: HAVE_THREADS + + The default value is True. If Python is compiled without threads, the + C version automatically disables the expensive thread local context + machinery. In this case, the value is False. + +Rounding modes +-------------- + +.. data:: ROUND_CEILING + + Round towards :const:`Infinity`. + +.. data:: ROUND_DOWN + + Round towards zero. + +.. data:: ROUND_FLOOR + + Round towards :const:`-Infinity`. + +.. data:: ROUND_HALF_DOWN + + Round to nearest with ties going towards zero. + +.. data:: ROUND_HALF_EVEN + + Round to nearest with ties going to nearest even integer. + +.. data:: ROUND_HALF_UP + + Round to nearest with ties going away from zero. + +.. data:: ROUND_UP + + Round away from zero. + +.. data:: ROUND_05UP + + Round away from zero if last digit after rounding towards zero would have + been 0 or 5; otherwise round towards zero. + .. _decimal-signals: @@ -1403,7 +1506,6 @@ Infinity / Infinity x % 0 Infinity % x - x._rescale( non-integer ) sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) @@ -1446,6 +1548,23 @@ Occurs when a subnormal result is pushed to zero by rounding. :class:`Inexact` and :class:`Subnormal` are also signaled. + +.. class:: FloatOperation + + Enable stricter semantics for mixing floats and Decimals. + + If the signal is not trapped (default), mixing floats and Decimals is + permitted in the :class:`~decimal.Decimal` constructor, + :meth:`~decimal.Context.create_decimal` and all comparison operators. + Both conversion and comparisons are exact. Any occurrence of a mixed + operation is silently recorded by setting :exc:`FloatOperation` in the + context flags. Explicit conversions with :meth:`~decimal.Decimal.from_float` + or :meth:`~decimal.Context.create_decimal_from_float` do not set the flag. + + Otherwise (the signal is trapped), only equality comparisons and explicit + conversions are silent. All other mixed operations raise :exc:`FloatOperation`. + + The following table summarizes the hierarchy of signals:: exceptions.ArithmeticError(exceptions.Exception) @@ -1458,10 +1577,12 @@ InvalidOperation Rounded Subnormal + FloatOperation .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + .. _decimal-notes: Floating Point Notes @@ -1571,7 +1692,7 @@ the following calculation returns a value equal to zero: >>> 1 / Decimal('Infinity') - Decimal('0E-1000000026') + Decimal('0E-1000026') .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1583,7 +1704,7 @@ The :func:`getcontext` function accesses a different :class:`Context` object for each thread. Having separate thread contexts means that threads may make -changes (such as ``getcontext.prec=10``) without interfering with other threads. +changes (such as ``getcontext().prec=10``) without interfering with other threads. Likewise, the :func:`setcontext` function automatically assigns its target to the current thread. diff --git a/Doc/library/numeric.rst b/Doc/library/numeric.rst --- a/Doc/library/numeric.rst +++ b/Doc/library/numeric.rst @@ -8,9 +8,9 @@ The modules described in this chapter provide numeric and math-related functions and data types. The :mod:`numbers` module defines an abstract hierarchy of numeric types. The :mod:`math` and :mod:`cmath` modules contain various -mathematical functions for floating-point and complex numbers. For users more -interested in decimal accuracy than in speed, the :mod:`decimal` module supports -exact representations of decimal numbers. +mathematical functions for floating-point and complex numbers. The :mod:`decimal` +module supports exact representations of decimal numbers, using arbitrary precision +arithmetic. The following modules are documented in this chapter: diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -596,6 +596,93 @@ (Contributed by I?igo Serna in :issue:`6755`) +decimal +------- + +:issue:`7652` - integrate fast native decimal arithmetic. + C-module and libmpdec written by Stefan Krah. + +The new C version of the decimal module integrates the high speed libmpdec +library for arbitrary precision correctly-rounded decimal arithmetic. +libmpdec conforms to IBM's General Decimal Arithmetic Specification. + +Performance gains range from 12x for database applications to 80x for +numerically intensive applications: + + +---------+-------------+--------------+-------------+ + | | decimal.py | _decimal | speedup | + +=========+=============+==============+=============+ + | pi | 42.75s | 0.58s | 74x | + +---------+-------------+--------------+-------------+ + | telco | 172.19s | 5.68s | 30x | + +---------+-------------+--------------+-------------+ + | psycopg | 3.57s | 0.29s | 12x | + +---------+-------------+--------------+-------------+ + +Features +~~~~~~~~ + +* The :exc:`~decimal.FloatOperation` signal optionally enables stricter + semantics for mixing floats and Decimals. + +* If Python is compiled without threads, the C version automatically + disables the expensive thread local context machinery. In this case, + the variable :data:`~decimal.HAVE_THREADS` is set to False. + +API changes +~~~~~~~~~~~ + +* The C module has the following context limits, depending on the machine + architecture: + + +-------------------+---------------------+------------------------------+ + | | 32-bit | 64-bit | + +===================+=====================+==============================+ + | :const:`MAX_PREC` | :const:`425000000` | :const:`999999999999999999` | + +-------------------+---------------------+------------------------------+ + | :const:`MAX_EMAX` | :const:`425000000` | :const:`999999999999999999` | + +-------------------+---------------------+------------------------------+ + | :const:`MIN_EMIN` | :const:`-425000000` | :const:`-999999999999999999` | + +-------------------+---------------------+------------------------------+ + +* In the context templates (:class:`~decimal.DefaultContext`, + :class:`~decimal.BasicContext` and :class:`~decimal.ExtendedContext`) + the magnitude of :attr:`~decimal.Context.Emax` and + :attr:`~decimal.Context.Emin` has changed to :const:`999999`. + +* The :class:`~decimal.Decimal` constructor in decimal.py does not observe + the context limits and converts values with arbitrary exponents or precision + exactly. Since the C version has internal limits, the following scheme is + used: If possible, values are converted exactly, otherwise + :exc:`~decimal.InvalidOperation` is raised and the result is NaN. In the + latter case it is always possible to use :meth:`~decimal.Context.create_decimal` + in order to obtain a rounded or inexact value. + + +* The power function in decimal.py is always correctly-rounded. In the + C version, it is defined in terms of the correctly-rounded + :meth:`~decimal.Decimal.exp` and :meth:`~decimal.Decimal.ln` functions, + but the final result is only "almost always correctly rounded". + + +* In the C version, the context dictionary containing the signals is a + :class:`~collections.abc.MutableMapping`. For speed reasons, + :attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps` always + refer to the same :class:`~collections.abc.MutableMapping` that the context + was initialized with. If a new signal dictionary is assigned, + :attr:`~decimal.Context.flags` and :attr:`~decimal.Context.traps` + are updated with the new values, but they do not reference the RHS + dictionary. + + +* Pickling a :class:`~decimal.Context` produces a different output in order + to have a common interchange format for the Python and C versions. + + +* The order of arguments in the :class:`~decimal.Context` constructor has been + changed to match the order displayed by :func:`repr`. + + faulthandler ------------ diff --git a/Include/longintrepr.h b/Include/longintrepr.h --- a/Include/longintrepr.h +++ b/Include/longintrepr.h @@ -6,7 +6,7 @@ #endif -/* This is published for the benefit of "friend" marshal.c only. */ +/* This is published for the benefit of "friends" marshal.c and _decimal.c. */ /* Parameters of the long integer representation. There are two different sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -46,8 +46,8 @@ Decimal('-0.0123') >>> Decimal(123456) Decimal('123456') ->>> Decimal('123.45e12345678901234567890') -Decimal('1.2345E+12345678901234567892') +>>> Decimal('123.45e12345678') +Decimal('1.2345E+12345680') >>> Decimal('1.33') + Decimal('1.27') Decimal('2.60') >>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41') @@ -122,13 +122,20 @@ # Exceptions 'DecimalException', 'Clamped', 'InvalidOperation', 'DivisionByZero', 'Inexact', 'Rounded', 'Subnormal', 'Overflow', 'Underflow', + 'FloatOperation', # Constants for use in setting up contexts 'ROUND_DOWN', 'ROUND_HALF_UP', 'ROUND_HALF_EVEN', 'ROUND_CEILING', 'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN', 'ROUND_05UP', # Functions for manipulating contexts - 'setcontext', 'getcontext', 'localcontext' + 'setcontext', 'getcontext', 'localcontext', + + # Limits for the C version for compatibility + 'MAX_PREC', 'MAX_EMAX', 'MIN_EMIN', 'MIN_ETINY', + + # C version: compile time choice that enables the thread local context + 'HAVE_THREADS' ] __version__ = '1.70' # Highest version of the spec this complies with @@ -137,6 +144,7 @@ import copy as _copy import math as _math import numbers as _numbers +import sys try: from collections import namedtuple as _namedtuple @@ -154,6 +162,19 @@ ROUND_HALF_DOWN = 'ROUND_HALF_DOWN' ROUND_05UP = 'ROUND_05UP' +# Compatibility with the C version +HAVE_THREADS = True +if sys.maxsize == 2**63-1: + MAX_PREC = 999999999999999999 + MAX_EMAX = 999999999999999999 + MIN_EMIN = -999999999999999999 +else: + MAX_PREC = 425000000 + MAX_EMAX = 425000000 + MIN_EMIN = -425000000 + +MIN_ETINY = MIN_EMIN - (MAX_PREC-1) + # Errors class DecimalException(ArithmeticError): @@ -370,9 +391,24 @@ In all cases, Inexact, Rounded, and Subnormal will also be raised. """ +class FloatOperation(DecimalException): + """Enable stricter semantics for mixing floats and Decimals. + + If the signal is not trapped (default), mixing floats and Decimals is + permitted in the Decimal() constructor, context.create_decimal() and + all comparison operators. Both conversion and comparisons are exact. + Any occurrence of a mixed operation is silently recorded by setting + FloatOperation in the context flags. Explicit conversions with + Decimal.from_float() or context.create_decimal_from_float() do not + set the flag. + + Otherwise (the signal is trapped), only equality comparisons and explicit + conversions are silent. All other mixed operations raise FloatOperation. + """ + # List of public traps and flags _signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded, - Underflow, InvalidOperation, Subnormal] + Underflow, InvalidOperation, Subnormal, FloatOperation] # Map conditions (per the spec) to signals _condition_map = {ConversionSyntax:InvalidOperation, @@ -380,6 +416,10 @@ DivisionUndefined:InvalidOperation, InvalidContext:InvalidOperation} +# Valid rounding modes +_rounding_modes = (ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_CEILING, + ROUND_FLOOR, ROUND_UP, ROUND_HALF_DOWN, ROUND_05UP) + ##### Context Functions ################################################## # The getcontext() and setcontext() function manage access to a thread-local @@ -392,12 +432,11 @@ import threading except ImportError: # Python was compiled without threads; create a mock object instead - import sys class MockThreading(object): def local(self, sys=sys): return sys.modules[__name__] threading = MockThreading() - del sys, MockThreading + del MockThreading try: threading.local @@ -650,6 +689,11 @@ return self if isinstance(value, float): + if context is None: + context = getcontext() + context._raise_error(FloatOperation, + "strict semantics for mixing floats and Decimals are " + "enabled") value = Decimal.from_float(value) self._exp = value._exp self._sign = value._sign @@ -684,7 +728,9 @@ """ if isinstance(f, int): # handle integer inputs return cls(f) - if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float + if not isinstance(f, float): + raise TypeError("argument must be int or float.") + if _math.isinf(f) or _math.isnan(f): return cls(repr(f)) if _math.copysign(1.0, f) == 1.0: sign = 0 @@ -1906,11 +1952,12 @@ def _power_modulo(self, other, modulo, context=None): """Three argument version of __pow__""" - # if can't convert other and modulo to Decimal, raise - # TypeError; there's no point returning NotImplemented (no - # equivalent of __rpow__ for three argument pow) - other = _convert_other(other, raiseit=True) - modulo = _convert_other(modulo, raiseit=True) + other = _convert_other(other) + if other is NotImplemented: + return other + modulo = _convert_other(modulo) + if modulo is NotImplemented: + return modulo if context is None: context = getcontext() @@ -3832,11 +3879,9 @@ clamp - If 1, change exponents if too high (Default 0) """ - def __init__(self, prec=None, rounding=None, - traps=None, flags=None, - Emin=None, Emax=None, - capitals=None, clamp=None, - _ignored_flags=None): + def __init__(self, prec=None, rounding=None, Emin=None, Emax=None, + capitals=None, clamp=None, flags=None, traps=None, + _ignored_flags=None): # Set defaults; for everything except flags and _ignored_flags, # inherit from DefaultContext. try: @@ -3859,17 +3904,78 @@ if traps is None: self.traps = dc.traps.copy() elif not isinstance(traps, dict): - self.traps = dict((s, int(s in traps)) for s in _signals) + self.traps = dict((s, int(s in traps)) for s in _signals + traps) else: self.traps = traps if flags is None: self.flags = dict.fromkeys(_signals, 0) elif not isinstance(flags, dict): - self.flags = dict((s, int(s in flags)) for s in _signals) + self.flags = dict((s, int(s in flags)) for s in _signals + flags) else: self.flags = flags + def _set_integer_check(self, name, value, vmin, vmax): + if not isinstance(value, int): + raise TypeError("%s must be an integer" % name) + if vmin == '-inf': + if value > vmax: + raise ValueError("%s must be in [%s, %d]. got: %s" % (name, vmin, vmax, value)) + elif vmax == 'inf': + if value < vmin: + raise ValueError("%s must be in [%d, %s]. got: %s" % (name, vmin, vmax, value)) + else: + if value < vmin or value > vmax: + raise ValueError("%s must be in [%d, %d]. got %s" % (name, vmin, vmax, value)) + return object.__setattr__(self, name, value) + + def _set_signal_dict(self, name, d): + if not isinstance(d, dict): + raise TypeError("%s must be a signal dict" % d) + for key in d: + if not key in _signals: + raise KeyError("%s is not a valid signal dict" % d) + for key in _signals: + if not key in d: + raise KeyError("%s is not a valid signal dict" % d) + return object.__setattr__(self, name, d) + + def __setattr__(self, name, value): + if name == 'prec': + return self._set_integer_check(name, value, 1, 'inf') + elif name == 'Emin': + return self._set_integer_check(name, value, '-inf', 0) + elif name == 'Emax': + return self._set_integer_check(name, value, 0, 'inf') + elif name == 'capitals': + return self._set_integer_check(name, value, 0, 1) + elif name == 'clamp': + return self._set_integer_check(name, value, 0, 1) + elif name == 'rounding': + if not value in _rounding_modes: + # raise TypeError even for strings to have consistency + # among various implementations. + raise TypeError("%s: invalid rounding mode" % value) + return object.__setattr__(self, name, value) + elif name == 'flags' or name == 'traps': + return self._set_signal_dict(name, value) + elif name == '_ignored_flags': + return object.__setattr__(self, name, value) + else: + raise AttributeError( + "'decimal.Context' object has no attribute '%s'" % name) + + def __delattr__(self, name): + raise AttributeError("%s cannot be deleted" % name) + + # Support for pickling, copy, and deepcopy + def __reduce__(self): + flags = [sig for sig, v in self.flags.items() if v] + traps = [sig for sig, v in self.traps.items() if v] + return (self.__class__, + (self.prec, self.rounding, self.Emin, self.Emax, + self.capitals, self.clamp, flags, traps)) + def __repr__(self): """Show the current context.""" s = [] @@ -3888,18 +3994,24 @@ for flag in self.flags: self.flags[flag] = 0 + def clear_traps(self): + """Reset all traps to zero""" + for flag in self.traps: + self.traps[flag] = 0 + def _shallow_copy(self): """Returns a shallow copy from self.""" - nc = Context(self.prec, self.rounding, self.traps, - self.flags, self.Emin, self.Emax, - self.capitals, self.clamp, self._ignored_flags) + nc = Context(self.prec, self.rounding, self.Emin, self.Emax, + self.capitals, self.clamp, self.flags, self.traps, + self._ignored_flags) return nc def copy(self): """Returns a deep copy from self.""" - nc = Context(self.prec, self.rounding, self.traps.copy(), - self.flags.copy(), self.Emin, self.Emax, - self.capitals, self.clamp, self._ignored_flags) + nc = Context(self.prec, self.rounding, self.Emin, self.Emax, + self.capitals, self.clamp, + self.flags.copy(), self.traps.copy(), + self._ignored_flags) return nc __copy__ = copy @@ -4062,6 +4174,8 @@ >>> ExtendedContext.canonical(Decimal('2.50')) Decimal('2.50') """ + if not isinstance(a, Decimal): + raise TypeError("canonical requires a Decimal as an argument.") return a.canonical(context=self) def compare(self, a, b): @@ -4372,6 +4486,8 @@ >>> ExtendedContext.is_canonical(Decimal('2.50')) True """ + if not isinstance(a, Decimal): + raise TypeError("is_canonical requires a Decimal as an argument.") return a.is_canonical() def is_finite(self, a): @@ -4964,7 +5080,7 @@ +Normal +Infinity - >>> c = Context(ExtendedContext) + >>> c = ExtendedContext.copy() >>> c.Emin = -999 >>> c.Emax = 999 >>> c.number_class(Decimal('Infinity')) @@ -5916,6 +6032,12 @@ if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0: other = other.real if isinstance(other, float): + context = getcontext() + if equality_op: + context.flags[FloatOperation] = 1 + else: + context._raise_error(FloatOperation, + "strict semantics for mixing floats and Decimals are enabled") return self, Decimal.from_float(other) return NotImplemented, NotImplemented @@ -5929,8 +6051,8 @@ prec=28, rounding=ROUND_HALF_EVEN, traps=[DivisionByZero, Overflow, InvalidOperation], flags=[], - Emax=999999999, - Emin=-999999999, + Emax=999999, + Emin=-999999, capitals=1, clamp=0 ) @@ -6080,7 +6202,7 @@ # if format type is 'g' or 'G' then a precision of 0 makes little # sense; convert it to 1. Same if format type is unspecified. if format_dict['precision'] == 0: - if format_dict['type'] is None or format_dict['type'] in 'gG': + if format_dict['type'] is None or format_dict['type'] in 'gGn': format_dict['precision'] = 1 # determine thousands separator, grouping, and decimal separator, and @@ -6254,16 +6376,26 @@ # Constants related to the hash implementation; hash(x) is based # on the reduction of x modulo _PyHASH_MODULUS -import sys _PyHASH_MODULUS = sys.hash_info.modulus # hash values to use for positive and negative infinities, and nans _PyHASH_INF = sys.hash_info.inf _PyHASH_NAN = sys.hash_info.nan -del sys # _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS _PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS) - +del sys + +try: + import _decimal +except ImportError: + pass +else: + s1 = set(dir()) + s2 = set(dir(_decimal)) + for name in s1 - s2: + del globals()[name] + del s1, s2, name + from _decimal import * if __name__ == '__main__': import doctest, decimal diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,3 +1,10 @@ +What's New in IDLE 3.2.3? +========================= + +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)). + + What's New in IDLE 3.2.1? ========================= diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1403,8 +1403,10 @@ if enable_edit: if not (cmd or script): - for filename in args: - flist.open(filename) + for filename in args[:]: + if flist.open(filename) is None: + # filename is a directory actually, disconsider it + args.remove(filename) if not args: flist.new() if enable_shell: diff --git a/Lib/smtpd.py b/Lib/smtpd.py --- a/Lib/smtpd.py +++ b/Lib/smtpd.py @@ -374,6 +374,10 @@ return address def smtp_MAIL(self, arg): + if not self.seen_greeting: + self.push('503 Error: send HELO first'); + return + print('===> MAIL', arg, file=DEBUGSTREAM) address = self.__getaddr('FROM:', arg) if arg else None if not address: @@ -387,6 +391,10 @@ self.push('250 Ok') def smtp_RCPT(self, arg): + if not self.seen_greeting: + self.push('503 Error: send HELO first'); + return + print('===> RCPT', arg, file=DEBUGSTREAM) if not self.mailfrom: self.push('503 Error: need MAIL command') @@ -411,6 +419,10 @@ self.push('250 Ok') def smtp_DATA(self, arg): + if not self.seen_greeting: + self.push('503 Error: send HELO first'); + return + if not self.rcpttos: self.push('503 Error: need RCPT command') return diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -1416,7 +1416,7 @@ #======================================================================= # doctest driver. -def run_doctest(module, verbosity=None): +def run_doctest(module, verbosity=None, optionflags=0): """Run doctest on the given module. Return (#failures, #tests). If optional argument verbosity is not specified (or is None), pass @@ -1431,7 +1431,7 @@ else: verbosity = None - f, t = doctest.testmod(module, verbose=verbosity) + f, t = doctest.testmod(module, verbose=verbosity, optionflags=optionflags) if f: raise TestFailed("%d of %d doctests failed" % (f, t)) if verbose: diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -16,7 +16,7 @@ Cowlishaw's tests can be downloaded from: - www2.hursley.ibm.com/decimal/dectest.zip + http://speleotrove.com/decimal/dectest.zip This test module can be called from command line with one parameter (Arithmetic or Behaviour) to test each part, or without parameter to test both parts. If @@ -30,37 +30,74 @@ import warnings import pickle, copy import unittest -from decimal import * import numbers +import locale from test.support import (run_unittest, run_doctest, is_resource_enabled, requires_IEEE_754) -from test.support import check_warnings +from test.support import check_warnings, import_fresh_module, TestFailed import random +import time +import warnings try: import threading except ImportError: threading = None + +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) +orig_sys_decimal = sys.modules['decimal'] + +# fractions module must import the correct decimal module. +cfractions = import_fresh_module('fractions', fresh=['fractions']) +sys.modules['decimal'] = P +pfractions = import_fresh_module('fractions', fresh=['fractions']) +sys.modules['decimal'] = C +fractions = {C:cfractions, P:pfractions} +sys.modules['decimal'] = orig_sys_decimal + + # Useful Test Constant -Signals = tuple(getcontext().flags.keys()) - +Signals = { + C: tuple(C.getcontext().flags.keys()) if C else None, + P: tuple(P.getcontext().flags.keys()) +} # Signals ordered with respect to precedence: when an operation # produces multiple signals, signals occurring later in the list # should be handled before those occurring earlier in the list. -OrderedSignals = (Clamped, Rounded, Inexact, Subnormal, - Underflow, Overflow, DivisionByZero, InvalidOperation) +OrderedSignals = { + C: [C.Clamped, C.Rounded, C.Inexact, C.Subnormal, C.Underflow, + C.Overflow, C.DivisionByZero, C.InvalidOperation, + C.FloatOperation] if C else None, + P: [P.Clamped, P.Rounded, P.Inexact, P.Subnormal, P.Underflow, + P.Overflow, P.DivisionByZero, P.InvalidOperation, + P.FloatOperation] +} +def assert_signals(cls, context, attr, expected): + d = getattr(context, attr) + cls.assertTrue(all(d[s] if s in expected else not d[s] for s in d)) + +RoundingModes = { + C: (C.ROUND_UP, C.ROUND_DOWN, C.ROUND_CEILING, C.ROUND_FLOOR, + C.ROUND_HALF_UP, C.ROUND_HALF_DOWN, C.ROUND_HALF_EVEN, + C.ROUND_05UP) if C else None, + P: (P.ROUND_UP, P.ROUND_DOWN, P.ROUND_CEILING, P.ROUND_FLOOR, + P.ROUND_HALF_UP, P.ROUND_HALF_DOWN, P.ROUND_HALF_EVEN, + P.ROUND_05UP) +} # Tests are built around these assumed context defaults. # test_main() restores the original context. -def init(): - global ORIGINAL_CONTEXT - ORIGINAL_CONTEXT = getcontext().copy() - DefaultTestContext = Context( - prec = 9, - rounding = ROUND_HALF_EVEN, - traps = dict.fromkeys(Signals, 0) - ) - setcontext(DefaultTestContext) +ORIGINAL_CONTEXT = { + C: C.getcontext().copy() if C else None, + P: P.getcontext().copy() +} +def init(m): + if not m: return + DefaultTestContext = m.Context( + prec=9, rounding=m.ROUND_HALF_EVEN, traps=dict.fromkeys(Signals[m], 0) + ) + m.setcontext(DefaultTestContext) TESTDATADIR = 'decimaltestdata' if __name__ == '__main__': @@ -72,149 +109,175 @@ skip_expected = not os.path.isdir(directory) -# list of individual .decTest test ids that correspond to tests that -# we're skipping for one reason or another. -skipped_test_ids = set([ - # Skip implementation-specific scaleb tests. - 'scbx164', - 'scbx165', - - # For some operations (currently exp, ln, log10, power), the decNumber - # reference implementation imposes additional restrictions on the context - # and operands. These restrictions are not part of the specification; - # however, the effect of these restrictions does show up in some of the - # testcases. We skip testcases that violate these restrictions, since - # Decimal behaves differently from decNumber for these testcases so these - # testcases would otherwise fail. - 'expx901', - 'expx902', - 'expx903', - 'expx905', - 'lnx901', - 'lnx902', - 'lnx903', - 'lnx905', - 'logx901', - 'logx902', - 'logx903', - 'logx905', - 'powx1183', - 'powx1184', - 'powx4001', - 'powx4002', - 'powx4003', - 'powx4005', - 'powx4008', - 'powx4010', - 'powx4012', - 'powx4014', - ]) - # Make sure it actually raises errors when not expected and caught in flags # Slower, since it runs some things several times. EXTENDEDERRORTEST = False -#Map the test cases' error names to the actual errors -ErrorNames = {'clamped' : Clamped, - 'conversion_syntax' : InvalidOperation, - 'division_by_zero' : DivisionByZero, - 'division_impossible' : InvalidOperation, - 'division_undefined' : InvalidOperation, - 'inexact' : Inexact, - 'invalid_context' : InvalidOperation, - 'invalid_operation' : InvalidOperation, - 'overflow' : Overflow, - 'rounded' : Rounded, - 'subnormal' : Subnormal, - 'underflow' : Underflow} - - -def Nonfunction(*args): - """Doesn't do anything.""" - return None - -RoundingDict = {'ceiling' : ROUND_CEILING, #Maps test-case names to roundings. - 'down' : ROUND_DOWN, - 'floor' : ROUND_FLOOR, - 'half_down' : ROUND_HALF_DOWN, - 'half_even' : ROUND_HALF_EVEN, - 'half_up' : ROUND_HALF_UP, - 'up' : ROUND_UP, - '05up' : ROUND_05UP} - -# Name adapter to be able to change the Decimal and Context -# interface without changing the test files from Cowlishaw -nameAdapter = {'and':'logical_and', - 'apply':'_apply', - 'class':'number_class', - 'comparesig':'compare_signal', - 'comparetotal':'compare_total', - 'comparetotmag':'compare_total_mag', - 'copy':'copy_decimal', - 'copyabs':'copy_abs', - 'copynegate':'copy_negate', - 'copysign':'copy_sign', - 'divideint':'divide_int', - 'invert':'logical_invert', - 'iscanonical':'is_canonical', - 'isfinite':'is_finite', - 'isinfinite':'is_infinite', - 'isnan':'is_nan', - 'isnormal':'is_normal', - 'isqnan':'is_qnan', - 'issigned':'is_signed', - 'issnan':'is_snan', - 'issubnormal':'is_subnormal', - 'iszero':'is_zero', - 'maxmag':'max_mag', - 'minmag':'min_mag', - 'nextminus':'next_minus', - 'nextplus':'next_plus', - 'nexttoward':'next_toward', - 'or':'logical_or', - 'reduce':'normalize', - 'remaindernear':'remainder_near', - 'samequantum':'same_quantum', - 'squareroot':'sqrt', - 'toeng':'to_eng_string', - 'tointegral':'to_integral_value', - 'tointegralx':'to_integral_exact', - 'tosci':'to_sci_string', - 'xor':'logical_xor', - } - -# The following functions return True/False rather than a Decimal instance - -LOGICAL_FUNCTIONS = ( - 'is_canonical', - 'is_finite', - 'is_infinite', - 'is_nan', - 'is_normal', - 'is_qnan', - 'is_signed', - 'is_snan', - 'is_subnormal', - 'is_zero', - 'same_quantum', - ) - -class DecimalTest(unittest.TestCase): - """Class which tests the Decimal class against the test cases. - - Changed for unittest. - """ +# Test extra functionality in the C version (-DEXTRA_FUNCTIONALITY). +EXTRA_FUNCTIONALITY = True if hasattr(C, 'DecClamped') else False +requires_extra_functionality = unittest.skipUnless( + EXTRA_FUNCTIONALITY, "test requires build with -DEXTRA_FUNCTIONALITY") +skip_if_extra_functionality = unittest.skipIf( + EXTRA_FUNCTIONALITY, "test requires regular build") + + +class IBMTestCases(unittest.TestCase): + """Class which tests the Decimal class against the IBM test cases.""" + def setUp(self): - self.context = Context() + self.context = self.decimal.Context() + self.readcontext = self.decimal.Context() self.ignore_list = ['#'] - # Basically, a # means return NaN InvalidOperation. - # Different from a sNaN in trim - + + # List of individual .decTest test ids that correspond to tests that + # we're skipping for one reason or another. + self.skipped_test_ids = set([ + # Skip implementation-specific scaleb tests. + 'scbx164', + 'scbx165', + + # For some operations (currently exp, ln, log10, power), the decNumber + # reference implementation imposes additional restrictions on the context + # and operands. These restrictions are not part of the specification; + # however, the effect of these restrictions does show up in some of the + # testcases. We skip testcases that violate these restrictions, since + # Decimal behaves differently from decNumber for these testcases so these + # testcases would otherwise fail. + 'expx901', + 'expx902', + 'expx903', + 'expx905', + 'lnx901', + 'lnx902', + 'lnx903', + 'lnx905', + 'logx901', + 'logx902', + 'logx903', + 'logx905', + 'powx1183', + 'powx1184', + 'powx4001', + 'powx4002', + 'powx4003', + 'powx4005', + 'powx4008', + 'powx4010', + 'powx4012', + 'powx4014', + ]) + + if self.decimal == C: + # status has additional Subnormal, Underflow + self.skipped_test_ids.add('pwsx803') + self.skipped_test_ids.add('pwsx805') + # Correct rounding (skipped for decNumber, too) + self.skipped_test_ids.add('powx4302') + self.skipped_test_ids.add('powx4303') + self.skipped_test_ids.add('powx4342') + self.skipped_test_ids.add('powx4343') + # http://bugs.python.org/issue7049 + self.skipped_test_ids.add('pwmx325') + self.skipped_test_ids.add('pwmx326') + + # Map test directives to setter functions. self.ChangeDict = {'precision' : self.change_precision, - 'rounding' : self.change_rounding_method, - 'maxexponent' : self.change_max_exponent, - 'minexponent' : self.change_min_exponent, - 'clamp' : self.change_clamp} + 'rounding' : self.change_rounding_method, + 'maxexponent' : self.change_max_exponent, + 'minexponent' : self.change_min_exponent, + 'clamp' : self.change_clamp} + + # Name adapter to be able to change the Decimal and Context + # interface without changing the test files from Cowlishaw. + self.NameAdapter = {'and':'logical_and', + 'apply':'_apply', + 'class':'number_class', + 'comparesig':'compare_signal', + 'comparetotal':'compare_total', + 'comparetotmag':'compare_total_mag', + 'copy':'copy_decimal', + 'copyabs':'copy_abs', + 'copynegate':'copy_negate', + 'copysign':'copy_sign', + 'divideint':'divide_int', + 'invert':'logical_invert', + 'iscanonical':'is_canonical', + 'isfinite':'is_finite', + 'isinfinite':'is_infinite', + 'isnan':'is_nan', + 'isnormal':'is_normal', + 'isqnan':'is_qnan', + 'issigned':'is_signed', + 'issnan':'is_snan', + 'issubnormal':'is_subnormal', + 'iszero':'is_zero', + 'maxmag':'max_mag', + 'minmag':'min_mag', + 'nextminus':'next_minus', + 'nextplus':'next_plus', + 'nexttoward':'next_toward', + 'or':'logical_or', + 'reduce':'normalize', + 'remaindernear':'remainder_near', + 'samequantum':'same_quantum', + 'squareroot':'sqrt', + 'toeng':'to_eng_string', + 'tointegral':'to_integral_value', + 'tointegralx':'to_integral_exact', + 'tosci':'to_sci_string', + 'xor':'logical_xor'} + + # Map test-case names to roundings. + self.RoundingDict = {'ceiling' : self.decimal.ROUND_CEILING, + 'down' : self.decimal.ROUND_DOWN, + 'floor' : self.decimal.ROUND_FLOOR, + 'half_down' : self.decimal.ROUND_HALF_DOWN, + 'half_even' : self.decimal.ROUND_HALF_EVEN, + 'half_up' : self.decimal.ROUND_HALF_UP, + 'up' : self.decimal.ROUND_UP, + '05up' : self.decimal.ROUND_05UP} + + # Map the test cases' error names to the actual errors. + self.ErrorNames = {'clamped' : self.decimal.Clamped, + 'conversion_syntax' : self.decimal.InvalidOperation, + 'division_by_zero' : self.decimal.DivisionByZero, + 'division_impossible' : self.decimal.InvalidOperation, + 'division_undefined' : self.decimal.InvalidOperation, + 'inexact' : self.decimal.Inexact, + 'invalid_context' : self.decimal.InvalidOperation, + 'invalid_operation' : self.decimal.InvalidOperation, + 'overflow' : self.decimal.Overflow, + 'rounded' : self.decimal.Rounded, + 'subnormal' : self.decimal.Subnormal, + 'underflow' : self.decimal.Underflow} + + # The following functions return True/False rather than a + # Decimal instance. + self.LogicalFunctions = ('is_canonical', + 'is_finite', + 'is_infinite', + 'is_nan', + 'is_normal', + 'is_qnan', + 'is_signed', + 'is_snan', + 'is_subnormal', + 'is_zero', + 'same_quantum') + + def read_unlimited(self, v, context): + """Work around the limitations of the 32-bit _decimal version. The + guaranteed maximum values for prec, Emax etc. are 425000000, + but higher values usually work, except for rare corner cases. + In particular, all of the IBM tests pass with maximum values + of 1070000000.""" + if self.decimal == C and self.decimal.MAX_EMAX == 425000000: + self.readcontext._unsafe_setprec(1070000000) + self.readcontext._unsafe_setemax(1070000000) + self.readcontext._unsafe_setemin(-1070000000) + return self.readcontext.create_decimal(v) + else: + return self.decimal.Decimal(v, context) def eval_file(self, file): global skip_expected @@ -227,7 +290,7 @@ #print line try: t = self.eval_line(line) - except DecimalException as exception: + except self.decimal.DecimalException as exception: #Exception raised where there shouldn't have been one. self.fail('Exception "'+exception.__class__.__name__ + '" raised on line '+line) @@ -254,23 +317,23 @@ def eval_directive(self, s): funct, value = (x.strip().lower() for x in s.split(':')) if funct == 'rounding': - value = RoundingDict[value] + value = self.RoundingDict[value] else: try: value = int(value) except ValueError: pass - funct = self.ChangeDict.get(funct, Nonfunction) + funct = self.ChangeDict.get(funct, (lambda *args: None)) funct(value) def eval_equation(self, s): - #global DEFAULT_PRECISION - #print DEFAULT_PRECISION if not TEST_ALL and random.random() < 0.90: return + self.context.clear_flags() + try: Sides = s.split('->') L = Sides[0].strip().split() @@ -283,26 +346,26 @@ ans = L[0] exceptions = L[1:] except (TypeError, AttributeError, IndexError): - raise InvalidOperation + raise self.decimal.InvalidOperation def FixQuotes(val): val = val.replace("''", 'SingleQuote').replace('""', 'DoubleQuote') val = val.replace("'", '').replace('"', '') val = val.replace('SingleQuote', "'").replace('DoubleQuote', '"') return val - if id in skipped_test_ids: + if id in self.skipped_test_ids: return - fname = nameAdapter.get(funct, funct) + fname = self.NameAdapter.get(funct, funct) if fname == 'rescale': return funct = getattr(self.context, fname) vals = [] conglomerate = '' quote = 0 - theirexceptions = [ErrorNames[x.lower()] for x in exceptions] - - for exception in Signals: + theirexceptions = [self.ErrorNames[x.lower()] for x in exceptions] + + for exception in Signals[self.decimal]: self.context.traps[exception] = 1 #Catch these bugs... for exception in theirexceptions: self.context.traps[exception] = 0 @@ -324,7 +387,7 @@ funct(self.context.create_decimal(v)) except error: pass - except Signals as e: + except Signals[self.decimal] as e: self.fail("Raised %s in %s when %s disabled" % \ (e, s, error)) else: @@ -332,7 +395,7 @@ self.context.traps[error] = 0 v = self.context.create_decimal(v) else: - v = Decimal(v, self.context) + v = self.read_unlimited(v, self.context) vals.append(v) ans = FixQuotes(ans) @@ -344,7 +407,7 @@ funct(*vals) except error: pass - except Signals as e: + except Signals[self.decimal] as e: self.fail("Raised %s in %s when %s disabled" % \ (e, s, error)) else: @@ -352,14 +415,14 @@ self.context.traps[error] = 0 # as above, but add traps cumulatively, to check precedence - ordered_errors = [e for e in OrderedSignals if e in theirexceptions] + ordered_errors = [e for e in OrderedSignals[self.decimal] if e in theirexceptions] for error in ordered_errors: self.context.traps[error] = 1 try: funct(*vals) except error: pass - except Signals as e: + except Signals[self.decimal] as e: self.fail("Raised %s in %s; expected %s" % (type(e), s, error)) else: @@ -373,54 +436,69 @@ print("--", self.context) try: result = str(funct(*vals)) - if fname in LOGICAL_FUNCTIONS: + if fname in self.LogicalFunctions: result = str(int(eval(result))) # 'True', 'False' -> '1', '0' - except Signals as error: + except Signals[self.decimal] as error: self.fail("Raised %s in %s" % (error, s)) except: #Catch any error long enough to state the test case. print("ERROR:", s) raise myexceptions = self.getexceptions() - self.context.clear_flags() myexceptions.sort(key=repr) theirexceptions.sort(key=repr) self.assertEqual(result, ans, 'Incorrect answer for ' + s + ' -- got ' + result) + self.assertEqual(myexceptions, theirexceptions, 'Incorrect flags set in ' + s + ' -- got ' + str(myexceptions)) return def getexceptions(self): - return [e for e in Signals if self.context.flags[e]] + return [e for e in Signals[self.decimal] if self.context.flags[e]] def change_precision(self, prec): - self.context.prec = prec + if self.decimal == C and self.decimal.MAX_PREC == 425000000: + self.context._unsafe_setprec(prec) + else: + self.context.prec = prec def change_rounding_method(self, rounding): self.context.rounding = rounding def change_min_exponent(self, exp): - self.context.Emin = exp + if self.decimal == C and self.decimal.MAX_PREC == 425000000: + self.context._unsafe_setemin(exp) + else: + self.context.Emin = exp def change_max_exponent(self, exp): - self.context.Emax = exp + if self.decimal == C and self.decimal.MAX_PREC == 425000000: + self.context._unsafe_setemax(exp) + else: + self.context.Emax = exp def change_clamp(self, clamp): self.context.clamp = clamp - +class CIBMTestCases(IBMTestCases): + decimal = C +class PyIBMTestCases(IBMTestCases): + decimal = P # The following classes test the behaviour of Decimal according to PEP 327 -class DecimalExplicitConstructionTest(unittest.TestCase): +class ExplicitConstructionTest(unittest.TestCase): '''Unit tests for Explicit Construction cases of Decimal.''' def test_explicit_empty(self): + Decimal = self.decimal.Decimal self.assertEqual(Decimal(), Decimal("0")) def test_explicit_from_None(self): + Decimal = self.decimal.Decimal self.assertRaises(TypeError, Decimal, None) def test_explicit_from_int(self): + Decimal = self.decimal.Decimal #positive d = Decimal(45) @@ -438,7 +516,18 @@ d = Decimal(0) self.assertEqual(str(d), '0') + # single word longs + for n in range(0, 32): + for sign in (-1, 1): + for x in range(-5, 5): + i = sign * (2**n + x) + d = Decimal(i) + self.assertEqual(str(d), str(i)) + def test_explicit_from_string(self): + Decimal = self.decimal.Decimal + InvalidOperation = self.decimal.InvalidOperation + localcontext = self.decimal.localcontext #empty self.assertEqual(str(Decimal('')), 'NaN') @@ -458,8 +547,35 @@ #leading and trailing whitespace permitted self.assertEqual(str(Decimal('1.3E4 \n')), '1.3E+4') self.assertEqual(str(Decimal(' -7.89')), '-7.89') + self.assertEqual(str(Decimal(" 3.45679 ")), '3.45679') + + # unicode whitespace + for lead in ["", ' ', '\u00a0', '\u205f']: + for trail in ["", ' ', '\u00a0', '\u205f']: + self.assertEqual(str(Decimal(lead + '9.311E+28' + trail)), + '9.311E+28') + + with localcontext() as c: + c.traps[InvalidOperation] = True + # Invalid string + self.assertRaises(InvalidOperation, Decimal, "xyz") + # Two arguments max + self.assertRaises(TypeError, Decimal, "1234", "x", "y") + + # space within the numeric part + self.assertRaises(InvalidOperation, Decimal, "1\u00a02\u00a03") + self.assertRaises(InvalidOperation, Decimal, "\u00a01\u00a02\u00a0") + + # unicode whitespace + self.assertRaises(InvalidOperation, Decimal, "\u00a0") + self.assertRaises(InvalidOperation, Decimal, "\u00a0\u00a0") + + # embedded NUL + self.assertRaises(InvalidOperation, Decimal, "12\u00003") + def test_explicit_from_tuples(self): + Decimal = self.decimal.Decimal #zero d = Decimal( (0, (0,), 0) ) @@ -477,6 +593,10 @@ d = Decimal( (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) self.assertEqual(str(d), '-4.34913534E-17') + #inf + d = Decimal( (0, (), "F") ) + self.assertEqual(str(d), 'Infinity') + #wrong number of items self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1)) ) @@ -491,45 +611,63 @@ self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 9, 1), '1') ) #bad coefficients + self.assertRaises(ValueError, Decimal, (1, "xyz", 2) ) self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) ) self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) ) self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) ) self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) ) + def test_explicit_from_list(self): + Decimal = self.decimal.Decimal + + d = Decimal([0, [0], 0]) + self.assertEqual(str(d), '0') + + d = Decimal([1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25]) + self.assertEqual(str(d), '-4.34913534E-17') + + d = Decimal([1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25]) + self.assertEqual(str(d), '-4.34913534E-17') + + d = Decimal((1, [4, 3, 4, 9, 1, 3, 5, 3, 4], -25)) + self.assertEqual(str(d), '-4.34913534E-17') + def test_explicit_from_bool(self): + Decimal = self.decimal.Decimal + self.assertIs(bool(Decimal(0)), False) self.assertIs(bool(Decimal(1)), True) self.assertEqual(Decimal(False), Decimal(0)) self.assertEqual(Decimal(True), Decimal(1)) def test_explicit_from_Decimal(self): + Decimal = self.decimal.Decimal #positive d = Decimal(45) e = Decimal(d) self.assertEqual(str(e), '45') - self.assertNotEqual(id(d), id(e)) #very large positive d = Decimal(500000123) e = Decimal(d) self.assertEqual(str(e), '500000123') - self.assertNotEqual(id(d), id(e)) #negative d = Decimal(-45) e = Decimal(d) self.assertEqual(str(e), '-45') - self.assertNotEqual(id(d), id(e)) #zero d = Decimal(0) e = Decimal(d) self.assertEqual(str(e), '0') - self.assertNotEqual(id(d), id(e)) @requires_IEEE_754 def test_explicit_from_float(self): + + Decimal = self.decimal.Decimal + r = Decimal(0.1) self.assertEqual(type(r), Decimal) self.assertEqual(str(r), @@ -550,8 +688,11 @@ self.assertEqual(x, float(Decimal(x))) # roundtrip def test_explicit_context_create_decimal(self): - - nc = copy.copy(getcontext()) + Decimal = self.decimal.Decimal + InvalidOperation = self.decimal.InvalidOperation + Rounded = self.decimal.Rounded + + nc = copy.copy(self.decimal.getcontext()) nc.prec = 3 # empty @@ -592,7 +733,73 @@ d = nc.create_decimal(prevdec) self.assertEqual(str(d), '5.00E+8') + # more integers + nc.prec = 28 + nc.traps[InvalidOperation] = True + + for v in [-2**63-1, -2**63, -2**31-1, -2**31, 0, + 2**31-1, 2**31, 2**63-1, 2**63]: + d = nc.create_decimal(v) + self.assertTrue(isinstance(d, Decimal)) + self.assertEqual(int(d), v) + + nc.prec = 3 + nc.traps[Rounded] = True + self.assertRaises(Rounded, nc.create_decimal, 1234) + + # from string + nc.prec = 28 + self.assertEqual(str(nc.create_decimal('0E-017')), '0E-17') + self.assertEqual(str(nc.create_decimal('45')), '45') + self.assertEqual(str(nc.create_decimal('-Inf')), '-Infinity') + self.assertEqual(str(nc.create_decimal('NaN123')), 'NaN123') + + # invalid arguments + self.assertRaises(InvalidOperation, nc.create_decimal, "xyz") + self.assertRaises(ValueError, nc.create_decimal, (1, "xyz", -25)) + self.assertRaises(TypeError, nc.create_decimal, "1234", "5678") + + # too many NaN payload digits + nc.prec = 3 + self.assertRaises(InvalidOperation, nc.create_decimal, 'NaN12345') + self.assertRaises(InvalidOperation, nc.create_decimal, + Decimal('NaN12345')) + + nc.traps[InvalidOperation] = False + self.assertEqual(str(nc.create_decimal('NaN12345')), 'NaN') + self.assertTrue(nc.flags[InvalidOperation]) + + nc.flags[InvalidOperation] = False + self.assertEqual(str(nc.create_decimal(Decimal('NaN12345'))), 'NaN') + self.assertTrue(nc.flags[InvalidOperation]) + + def test_explicit_context_create_from_float(self): + + Decimal = self.decimal.Decimal + + nc = self.decimal.Context() + r = nc.create_decimal(0.1) + self.assertEqual(type(r), Decimal) + self.assertEqual(str(r), '0.1000000000000000055511151231') + self.assertTrue(nc.create_decimal(float('nan')).is_qnan()) + self.assertTrue(nc.create_decimal(float('inf')).is_infinite()) + self.assertTrue(nc.create_decimal(float('-inf')).is_infinite()) + self.assertEqual(str(nc.create_decimal(float('nan'))), + str(nc.create_decimal('NaN'))) + self.assertEqual(str(nc.create_decimal(float('inf'))), + str(nc.create_decimal('Infinity'))) + self.assertEqual(str(nc.create_decimal(float('-inf'))), + str(nc.create_decimal('-Infinity'))) + self.assertEqual(str(nc.create_decimal(float('-0.0'))), + str(nc.create_decimal('-0'))) + nc.prec = 100 + for i in range(200): + x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) + self.assertEqual(x, float(nc.create_decimal(x))) # roundtrip + def test_unicode_digits(self): + Decimal = self.decimal.Decimal + test_values = { '\uff11': '1', '\u0660.\u0660\u0663\u0667\u0662e-\u0663' : '0.0000372', @@ -601,29 +808,41 @@ for input, expected in test_values.items(): self.assertEqual(str(Decimal(input)), expected) - -class DecimalImplicitConstructionTest(unittest.TestCase): +class CExplicitConstructionTest(ExplicitConstructionTest): + decimal = C +class PyExplicitConstructionTest(ExplicitConstructionTest): + decimal = P + +class ImplicitConstructionTest(unittest.TestCase): '''Unit tests for Implicit Construction cases of Decimal.''' def test_implicit_from_None(self): - self.assertRaises(TypeError, eval, 'Decimal(5) + None', globals()) + Decimal = self.decimal.Decimal + self.assertRaises(TypeError, eval, 'Decimal(5) + None', locals()) def test_implicit_from_int(self): + Decimal = self.decimal.Decimal + #normal self.assertEqual(str(Decimal(5) + 45), '50') #exceeding precision self.assertEqual(Decimal(5) + 123456789000, Decimal(123456789000)) def test_implicit_from_string(self): - self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', globals()) + Decimal = self.decimal.Decimal + self.assertRaises(TypeError, eval, 'Decimal(5) + "3"', locals()) def test_implicit_from_float(self): - self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', globals()) + Decimal = self.decimal.Decimal + self.assertRaises(TypeError, eval, 'Decimal(5) + 2.2', locals()) def test_implicit_from_Decimal(self): + Decimal = self.decimal.Decimal self.assertEqual(Decimal(5) + Decimal(45), Decimal(50)) def test_rop(self): + Decimal = self.decimal.Decimal + # Allow other classes to be trained to interact with Decimals class E: def __divmod__(self, other): @@ -671,10 +890,16 @@ self.assertEqual(eval('Decimal(10)' + sym + 'E()'), '10' + rop + 'str') - -class DecimalFormatTest(unittest.TestCase): +class CImplicitConstructionTest(ImplicitConstructionTest): + decimal = C +class PyImplicitConstructionTest(ImplicitConstructionTest): + decimal = P + +class FormatTest(unittest.TestCase): '''Unit tests for the format function.''' def test_formatting(self): + Decimal = self.decimal.Decimal + # triples giving a format, a Decimal, and the expected result test_values = [ ('e', '0E-15', '0e-15'), @@ -730,6 +955,7 @@ ('g', '0E-7', '0e-7'), ('g', '-0E2', '-0e+2'), ('.0g', '3.14159265', '3'), # 0 sig fig -> 1 sig fig + ('.0n', '3.14159265', '3'), # same for 'n' ('.1g', '3.14159265', '3'), ('.2g', '3.14159265', '3.1'), ('.5g', '3.14159265', '3.1416'), @@ -814,56 +1040,60 @@ # issue 6850 ('a=-7.0', '0.12345', 'aaaa0.1'), - - # Issue 7094: Alternate formatting (specified by #) - ('.0e', '1.0', '1e+0'), - ('#.0e', '1.0', '1.e+0'), - ('.0f', '1.0', '1'), - ('#.0f', '1.0', '1.'), - ('g', '1.1', '1.1'), - ('#g', '1.1', '1.1'), - ('.0g', '1', '1'), - ('#.0g', '1', '1.'), - ('.0%', '1.0', '100%'), - ('#.0%', '1.0', '100.%'), ] for fmt, d, result in test_values: self.assertEqual(format(Decimal(d), fmt), result) + # bytes format argument + self.assertRaises(TypeError, Decimal(1).__format__, b'-020') + def test_n_format(self): + Decimal = self.decimal.Decimal + try: from locale import CHAR_MAX except ImportError: return + def make_grouping(lst): + return ''.join([chr(x) for x in lst]) if self.decimal == C else lst + + def get_fmt(x, override=None, fmt='n'): + if self.decimal == C: + return Decimal(x).__format__(fmt, override) + else: + return Decimal(x).__format__(fmt, _localeconv=override) + # Set up some localeconv-like dictionaries en_US = { 'decimal_point' : '.', - 'grouping' : [3, 3, 0], - 'thousands_sep': ',' + 'grouping' : make_grouping([3, 3, 0]), + 'thousands_sep' : ',' } fr_FR = { 'decimal_point' : ',', - 'grouping' : [CHAR_MAX], + 'grouping' : make_grouping([CHAR_MAX]), 'thousands_sep' : '' } ru_RU = { 'decimal_point' : ',', - 'grouping' : [3, 3, 0], + 'grouping': make_grouping([3, 3, 0]), 'thousands_sep' : ' ' } crazy = { 'decimal_point' : '&', - 'grouping' : [1, 4, 2, CHAR_MAX], + 'grouping': make_grouping([1, 4, 2, CHAR_MAX]), 'thousands_sep' : '-' } - - def get_fmt(x, locale, fmt='n'): - return Decimal.__format__(Decimal(x), fmt, _localeconv=locale) + dotsep_wide = { + 'decimal_point' : b'\xc2\xbf'.decode('utf-8'), + 'grouping': make_grouping([3, 3, 0]), + 'thousands_sep' : b'\xc2\xb4'.decode('utf-8') + } self.assertEqual(get_fmt(Decimal('12.7'), en_US), '12.7') self.assertEqual(get_fmt(Decimal('12.7'), fr_FR), '12,7') @@ -902,11 +1132,33 @@ self.assertEqual(get_fmt(123456, crazy, '012n'), '00-01-2345-6') self.assertEqual(get_fmt(123456, crazy, '013n'), '000-01-2345-6') - -class DecimalArithmeticOperatorsTest(unittest.TestCase): + # wide char separator and decimal point + self.assertEqual(get_fmt(Decimal('-1.5'), dotsep_wide, '020n'), + '-0\u00b4000\u00b4000\u00b4000\u00b4001\u00bf5') + + def test_wide_char_separator_decimal_point(self): + # locale with wide char separator and decimal point + Decimal = self.decimal.Decimal + + try: + locale.setlocale(locale.LC_ALL, 'ps_AF') + except locale.Error: + return + + self.assertEqual(format(Decimal('100000000.123'), 'n'), + '100\u066c000\u066c000\u066b123') + locale.resetlocale() + +class CFormatTest(FormatTest): + decimal = C +class PyFormatTest(FormatTest): + decimal = P + +class ArithmeticOperatorsTest(unittest.TestCase): '''Unit tests for all arithmetic operators, binary and unary.''' def test_addition(self): + Decimal = self.decimal.Decimal d1 = Decimal('-11.1') d2 = Decimal('22.2') @@ -934,6 +1186,7 @@ self.assertEqual(d1, Decimal('16.1')) def test_subtraction(self): + Decimal = self.decimal.Decimal d1 = Decimal('-11.1') d2 = Decimal('22.2') @@ -961,6 +1214,7 @@ self.assertEqual(d1, Decimal('-38.3')) def test_multiplication(self): + Decimal = self.decimal.Decimal d1 = Decimal('-5') d2 = Decimal('3') @@ -988,6 +1242,7 @@ self.assertEqual(d1, Decimal('-75')) def test_division(self): + Decimal = self.decimal.Decimal d1 = Decimal('-5') d2 = Decimal('2') @@ -1015,6 +1270,7 @@ self.assertEqual(d1, Decimal('-0.625')) def test_floor_division(self): + Decimal = self.decimal.Decimal d1 = Decimal('5') d2 = Decimal('2') @@ -1042,6 +1298,7 @@ self.assertEqual(d1, Decimal('1')) def test_powering(self): + Decimal = self.decimal.Decimal d1 = Decimal('5') d2 = Decimal('2') @@ -1069,6 +1326,7 @@ self.assertEqual(d1, Decimal('390625')) def test_module(self): + Decimal = self.decimal.Decimal d1 = Decimal('5') d2 = Decimal('2') @@ -1096,6 +1354,7 @@ self.assertEqual(d1, Decimal('1')) def test_floor_div_module(self): + Decimal = self.decimal.Decimal d1 = Decimal('5') d2 = Decimal('2') @@ -1122,6 +1381,8 @@ self.assertEqual(type(q), type(d1)) def test_unary_operators(self): + Decimal = self.decimal.Decimal + self.assertEqual(+Decimal(45), Decimal(+45)) # + self.assertEqual(-Decimal(45), Decimal(-45)) # - self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs @@ -1134,6 +1395,9 @@ # equality comparisons (==, !=) involving only quiet nans # don't signal, but return False or True respectively. + Decimal = self.decimal.Decimal + InvalidOperation = self.decimal.InvalidOperation + localcontext = self.decimal.localcontext n = Decimal('NaN') s = Decimal('sNaN') @@ -1179,53 +1443,124 @@ self.assertRaises(InvalidOperation, op, x, y) def test_copy_sign(self): + Decimal = self.decimal.Decimal + d = Decimal(1).copy_sign(Decimal(-2)) - self.assertEqual(Decimal(1).copy_sign(-2), d) self.assertRaises(TypeError, Decimal(1).copy_sign, '-2') +class CArithmeticOperatorsTest(ArithmeticOperatorsTest): + decimal = C +class PyArithmeticOperatorsTest(ArithmeticOperatorsTest): + decimal = P + # The following are two functions used to test threading in the next class def thfunc1(cls): + Decimal = cls.decimal.Decimal + InvalidOperation = cls.decimal.InvalidOperation + DivisionByZero = cls.decimal.DivisionByZero + Overflow = cls.decimal.Overflow + Underflow = cls.decimal.Underflow + Inexact = cls.decimal.Inexact + getcontext = cls.decimal.getcontext + localcontext = cls.decimal.localcontext + d1 = Decimal(1) d3 = Decimal(3) test1 = d1/d3 + + cls.finish1.set() cls.synchro.wait() + test2 = d1/d3 - cls.finish1.set() - - cls.assertEqual(test1, Decimal('0.3333333333333333333333333333')) - cls.assertEqual(test2, Decimal('0.3333333333333333333333333333')) + with localcontext() as c2: + cls.assertTrue(c2.flags[Inexact]) + cls.assertRaises(DivisionByZero, c2.divide, d1, 0) + cls.assertTrue(c2.flags[DivisionByZero]) + with localcontext() as c3: + cls.assertTrue(c3.flags[Inexact]) + cls.assertTrue(c3.flags[DivisionByZero]) + cls.assertRaises(InvalidOperation, c3.compare, d1, Decimal('sNaN')) + cls.assertTrue(c3.flags[InvalidOperation]) + del c3 + cls.assertFalse(c2.flags[InvalidOperation]) + del c2 + + cls.assertEqual(test1, Decimal('0.333333333333333333333333')) + cls.assertEqual(test2, Decimal('0.333333333333333333333333')) + + c1 = getcontext() + cls.assertTrue(c1.flags[Inexact]) + for sig in Overflow, Underflow, DivisionByZero, InvalidOperation: + cls.assertFalse(c1.flags[sig]) return def thfunc2(cls): + Decimal = cls.decimal.Decimal + InvalidOperation = cls.decimal.InvalidOperation + DivisionByZero = cls.decimal.DivisionByZero + Overflow = cls.decimal.Overflow + Underflow = cls.decimal.Underflow + Inexact = cls.decimal.Inexact + getcontext = cls.decimal.getcontext + localcontext = cls.decimal.localcontext + d1 = Decimal(1) d3 = Decimal(3) test1 = d1/d3 + thiscontext = getcontext() thiscontext.prec = 18 test2 = d1/d3 + + with localcontext() as c2: + cls.assertTrue(c2.flags[Inexact]) + cls.assertRaises(Overflow, c2.multiply, Decimal('1e425000000'), 999) + cls.assertTrue(c2.flags[Overflow]) + with localcontext(thiscontext) as c3: + cls.assertTrue(c3.flags[Inexact]) + cls.assertFalse(c3.flags[Overflow]) + c3.traps[Underflow] = True + cls.assertRaises(Underflow, c3.divide, Decimal('1e-425000000'), 999) + cls.assertTrue(c3.flags[Underflow]) + del c3 + cls.assertFalse(c2.flags[Underflow]) + cls.assertFalse(c2.traps[Underflow]) + del c2 + cls.synchro.set() cls.finish2.set() - cls.assertEqual(test1, Decimal('0.3333333333333333333333333333')) + cls.assertEqual(test1, Decimal('0.333333333333333333333333')) cls.assertEqual(test2, Decimal('0.333333333333333333')) + + cls.assertFalse(thiscontext.traps[Underflow]) + cls.assertTrue(thiscontext.flags[Inexact]) + for sig in Overflow, Underflow, DivisionByZero, InvalidOperation: + cls.assertFalse(thiscontext.flags[sig]) return - -class DecimalUseOfContextTest(unittest.TestCase): - '''Unit tests for Use of Context cases in Decimal.''' - - try: - import threading - except ImportError: - threading = None +class ThreadingTest(unittest.TestCase): + '''Unit tests for thread local contexts in Decimal.''' # Take care executing this test from IDLE, there's an issue in threading # that hangs IDLE and I couldn't find it def test_threading(self): - #Test the "threading isolation" of a Context. + DefaultContext = self.decimal.DefaultContext + + if self.decimal == C and not self.decimal.HAVE_THREADS: + self.skipTest("compiled without threading") + # Test the "threading isolation" of a Context. Also test changing + # the DefaultContext, which acts as a template for the thread-local + # contexts. + save_prec = DefaultContext.prec + save_emax = DefaultContext.Emax + save_emin = DefaultContext.Emin + DefaultContext.prec = 24 + DefaultContext.Emax = 425000000 + DefaultContext.Emin = -425000000 self.synchro = threading.Event() self.finish1 = threading.Event() @@ -1239,17 +1574,29 @@ self.finish1.wait() self.finish2.wait() + + for sig in Signals[self.decimal]: + self.assertFalse(DefaultContext.flags[sig]) + + DefaultContext.prec = save_prec + DefaultContext.Emax = save_emax + DefaultContext.Emin = save_emin return - if threading is None: - del test_threading - - -class DecimalUsabilityTest(unittest.TestCase): + at unittest.skipUnless(threading, 'threading required') +class CThreadingTest(ThreadingTest): + decimal = C + at unittest.skipUnless(threading, 'threading required') +class PyThreadingTest(ThreadingTest): + decimal = P + +class UsabilityTest(unittest.TestCase): '''Unit tests for Usability cases of Decimal.''' def test_comparison_operators(self): + Decimal = self.decimal.Decimal + da = Decimal('23.42') db = Decimal('23.42') dc = Decimal('45') @@ -1283,6 +1630,8 @@ self.assertEqual(a, b) def test_decimal_float_comparison(self): + Decimal = self.decimal.Decimal + da = Decimal('0.25') db = Decimal('3.0') self.assertLess(da, 3.0) @@ -1299,7 +1648,71 @@ self.assertEqual(3.0, db) self.assertNotEqual(0.1, Decimal('0.1')) + def test_decimal_complex_comparison(self): + Decimal = self.decimal.Decimal + + da = Decimal('0.25') + db = Decimal('3.0') + self.assertNotEqual(da, (1.5+0j)) + self.assertNotEqual((1.5+0j), da) + self.assertEqual(da, (0.25+0j)) + self.assertEqual((0.25+0j), da) + self.assertEqual((3.0+0j), db) + self.assertEqual(db, (3.0+0j)) + + self.assertNotEqual(db, (3.0+1j)) + self.assertNotEqual((3.0+1j), db) + + self.assertIs(db.__lt__(3.0+0j), NotImplemented) + self.assertIs(db.__le__(3.0+0j), NotImplemented) + self.assertIs(db.__gt__(3.0+0j), NotImplemented) + self.assertIs(db.__le__(3.0+0j), NotImplemented) + + def test_decimal_fraction_comparison(self): + D = self.decimal.Decimal + F = fractions[self.decimal].Fraction + Context = self.decimal.Context + localcontext = self.decimal.localcontext + InvalidOperation = self.decimal.InvalidOperation + + + emax = C.MAX_EMAX if C else 999999999 + emin = C.MIN_EMIN if C else -999999999 + etiny = C.MIN_ETINY if C else -1999999997 + c = Context(Emax=emax, Emin=emin) + + with localcontext(c): + c.prec = emax + self.assertLess(D(0), F(1,9999999999999999999999999999999999999)) + self.assertLess(F(-1,9999999999999999999999999999999999999), D(0)) + self.assertLess(F(0,1), D("1e" + str(etiny))) + self.assertLess(D("-1e" + str(etiny)), F(0,1)) + self.assertLess(F(0,9999999999999999999999999), D("1e" + str(etiny))) + self.assertLess(D("-1e" + str(etiny)), F(0,9999999999999999999999999)) + + self.assertEqual(D("0.1"), F(1,10)) + self.assertEqual(F(1,10), D("0.1")) + + c.prec = 300 + self.assertNotEqual(D(1)/3, F(1,3)) + self.assertNotEqual(F(1,3), D(1)/3) + + self.assertLessEqual(F(120984237, 9999999999), D("9e" + str(emax))) + self.assertGreaterEqual(D("9e" + str(emax)), F(120984237, 9999999999)) + + self.assertGreater(D('inf'), F(99999999999,123)) + self.assertGreater(D('inf'), F(-99999999999,123)) + self.assertLess(D('-inf'), F(99999999999,123)) + self.assertLess(D('-inf'), F(-99999999999,123)) + + self.assertRaises(InvalidOperation, D('nan').__gt__, F(-9,123)) + self.assertIs(NotImplemented, F(-9,123).__lt__(D('nan'))) + self.assertNotEqual(D('nan'), F(-9,123)) + self.assertNotEqual(F(-9,123), D('nan')) + def test_copy_and_deepcopy_methods(self): + Decimal = self.decimal.Decimal + d = Decimal('43.24') c = copy.copy(d) self.assertEqual(id(c), id(d)) @@ -1307,6 +1720,10 @@ self.assertEqual(id(dc), id(d)) def test_hash_method(self): + + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + def hashit(d): a = hash(d) b = d.__hash__() @@ -1367,24 +1784,27 @@ d = Decimal(s) self.assertEqual(hashit(f), hashit(d)) - # check that the value of the hash doesn't depend on the - # current context (issue #1757) - c = getcontext() - old_precision = c.prec - x = Decimal("123456789.1") - - c.prec = 6 - h1 = hashit(x) - c.prec = 10 - h2 = hashit(x) - c.prec = 16 - h3 = hashit(x) - - self.assertEqual(h1, h2) - self.assertEqual(h1, h3) - c.prec = old_precision + with localcontext() as c: + # check that the value of the hash doesn't depend on the + # current context (issue #1757) + x = Decimal("123456789.1") + + c.prec = 6 + h1 = hashit(x) + c.prec = 10 + h2 = hashit(x) + c.prec = 16 + h3 = hashit(x) + + self.assertEqual(h1, h2) + self.assertEqual(h1, h3) + + c.prec = 10000 + x = 1100 ** 1248 + self.assertEqual(hashit(Decimal(x)), hashit(x)) def test_min_and_max_methods(self): + Decimal = self.decimal.Decimal d1 = Decimal('15.32') d2 = Decimal('28.5') @@ -1404,6 +1824,8 @@ self.assertIs(max(d2,l1), d2) def test_as_nonzero(self): + Decimal = self.decimal.Decimal + #as false self.assertFalse(Decimal(0)) #as true @@ -1411,6 +1833,7 @@ def test_tostring_methods(self): #Test str and repr methods. + Decimal = self.decimal.Decimal d = Decimal('15.32') self.assertEqual(str(d), '15.32') # str @@ -1418,6 +1841,7 @@ def test_tonum_methods(self): #Test float and int methods. + Decimal = self.decimal.Decimal d1 = Decimal('66') d2 = Decimal('15.32') @@ -1440,6 +1864,7 @@ ('-11.0', -11), ('0.0', 0), ('-0E3', 0), + ('89891211712379812736.1', 89891211712379812736), ] for d, i in test_pairs: self.assertEqual(math.floor(Decimal(d)), i) @@ -1459,6 +1884,7 @@ ('-11.0', -11), ('0.0', 0), ('-0E3', 0), + ('89891211712379812736.1', 89891211712379812737), ] for d, i in test_pairs: self.assertEqual(math.ceil(Decimal(d)), i) @@ -1516,9 +1942,8 @@ for d, n, r in test_triples: self.assertEqual(str(round(Decimal(d), n)), r) - - def test_eval_round_trip(self): + Decimal = self.decimal.Decimal #with zero d = Decimal( (0, (0,), 0) ) @@ -1537,6 +1962,7 @@ self.assertEqual(d, eval(repr(d))) def test_as_tuple(self): + Decimal = self.decimal.Decimal #with zero d = Decimal(0) @@ -1550,7 +1976,7 @@ d = Decimal("-4.34913534E-17") self.assertEqual(d.as_tuple(), (1, (4, 3, 4, 9, 1, 3, 5, 3, 4), -25) ) - #inf + # XXX non-compliant infinity payload. d = Decimal("Infinity") self.assertEqual(d.as_tuple(), (0, (0,), 'F') ) @@ -1570,14 +1996,2158 @@ d = Decimal( (1, (), 'n') ) self.assertEqual(d.as_tuple(), (1, (), 'n') ) - #coefficient in infinity should be ignored - d = Decimal( (0, (4, 5, 3, 4), 'F') ) - self.assertEqual(d.as_tuple(), (0, (0,), 'F')) - d = Decimal( (1, (0, 2, 7, 1), 'F') ) - self.assertEqual(d.as_tuple(), (1, (0,), 'F')) - - def test_immutability_operations(self): + # XXX coefficient in infinity should raise an error + if self.decimal == P: + d = Decimal( (0, (4, 5, 3, 4), 'F') ) + self.assertEqual(d.as_tuple(), (0, (0,), 'F')) + d = Decimal( (1, (0, 2, 7, 1), 'F') ) + self.assertEqual(d.as_tuple(), (1, (0,), 'F')) + + def test_subclassing(self): + # Different behaviours when subclassing Decimal + Decimal = self.decimal.Decimal + + class MyDecimal(Decimal): + pass + + d1 = MyDecimal(1) + d2 = MyDecimal(2) + d = d1 + d2 + self.assertIs(type(d), Decimal) + + d = d1.max(d2) + self.assertIs(type(d), Decimal) + + d = copy.copy(d1) + self.assertIs(type(d), MyDecimal) + self.assertEqual(d, d1) + + d = copy.deepcopy(d1) + self.assertIs(type(d), MyDecimal) + self.assertEqual(d, d1) + + def test_implicit_context(self): + Decimal = self.decimal.Decimal + getcontext = self.decimal.getcontext + + # Check results when context given implicitly. (Issue 2478) + c = getcontext() + self.assertEqual(str(Decimal(0).sqrt()), + str(c.sqrt(Decimal(0)))) + + def test_conversions_from_int(self): + # Check that methods taking a second Decimal argument will + # always accept an integer in place of a Decimal. + Decimal = self.decimal.Decimal + + self.assertEqual(Decimal(4).compare(3), + Decimal(4).compare(Decimal(3))) + self.assertEqual(Decimal(4).compare_signal(3), + Decimal(4).compare_signal(Decimal(3))) + self.assertEqual(Decimal(4).compare_total(3), + Decimal(4).compare_total(Decimal(3))) + self.assertEqual(Decimal(4).compare_total_mag(3), + Decimal(4).compare_total_mag(Decimal(3))) + self.assertEqual(Decimal(10101).logical_and(1001), + Decimal(10101).logical_and(Decimal(1001))) + self.assertEqual(Decimal(10101).logical_or(1001), + Decimal(10101).logical_or(Decimal(1001))) + self.assertEqual(Decimal(10101).logical_xor(1001), + Decimal(10101).logical_xor(Decimal(1001))) + self.assertEqual(Decimal(567).max(123), + Decimal(567).max(Decimal(123))) + self.assertEqual(Decimal(567).max_mag(123), + Decimal(567).max_mag(Decimal(123))) + self.assertEqual(Decimal(567).min(123), + Decimal(567).min(Decimal(123))) + self.assertEqual(Decimal(567).min_mag(123), + Decimal(567).min_mag(Decimal(123))) + self.assertEqual(Decimal(567).next_toward(123), + Decimal(567).next_toward(Decimal(123))) + self.assertEqual(Decimal(1234).quantize(100), + Decimal(1234).quantize(Decimal(100))) + self.assertEqual(Decimal(768).remainder_near(1234), + Decimal(768).remainder_near(Decimal(1234))) + self.assertEqual(Decimal(123).rotate(1), + Decimal(123).rotate(Decimal(1))) + self.assertEqual(Decimal(1234).same_quantum(1000), + Decimal(1234).same_quantum(Decimal(1000))) + self.assertEqual(Decimal('9.123').scaleb(-100), + Decimal('9.123').scaleb(Decimal(-100))) + self.assertEqual(Decimal(456).shift(-1), + Decimal(456).shift(Decimal(-1))) + + self.assertEqual(Decimal(-12).fma(Decimal(45), 67), + Decimal(-12).fma(Decimal(45), Decimal(67))) + self.assertEqual(Decimal(-12).fma(45, 67), + Decimal(-12).fma(Decimal(45), Decimal(67))) + self.assertEqual(Decimal(-12).fma(45, Decimal(67)), + Decimal(-12).fma(Decimal(45), Decimal(67))) + +class CUsabilityTest(UsabilityTest): + decimal = C +class PyUsabilityTest(UsabilityTest): + decimal = P + +class PythonAPItests(unittest.TestCase): + + def test_abc(self): + Decimal = self.decimal.Decimal + + self.assertTrue(issubclass(Decimal, numbers.Number)) + self.assertFalse(issubclass(Decimal, numbers.Real)) + self.assertIsInstance(Decimal(0), numbers.Number) + self.assertNotIsInstance(Decimal(0), numbers.Real) + + def test_pickle(self): + Decimal = self.decimal.Decimal + + savedecimal = sys.modules['decimal'] + + # Round trip + sys.modules['decimal'] = self.decimal + d = Decimal('-3.141590000') + p = pickle.dumps(d) + e = pickle.loads(p) + self.assertEqual(d, e) + + if C: + # Test interchangeability + x = C.Decimal('-3.123e81723') + y = P.Decimal('-3.123e81723') + + sys.modules['decimal'] = C + sx = pickle.dumps(x) + sys.modules['decimal'] = P + r = pickle.loads(sx) + self.assertIsInstance(r, P.Decimal) + self.assertEqual(r, y) + + sys.modules['decimal'] = P + sy = pickle.dumps(y) + sys.modules['decimal'] = C + r = pickle.loads(sy) + self.assertIsInstance(r, C.Decimal) + self.assertEqual(r, x) + + sys.modules['decimal'] = savedecimal + + def test_int(self): + Decimal = self.decimal.Decimal + ROUND_DOWN = self.decimal.ROUND_DOWN + + for x in range(-250, 250): + s = '%0.2f' % (x / 100.0) + # should work the same as for floats + self.assertEqual(int(Decimal(s)), int(float(s))) + # should work the same as to_integral in the ROUND_DOWN mode + d = Decimal(s) + r = d.to_integral(ROUND_DOWN) + self.assertEqual(Decimal(int(d)), r) + + self.assertRaises(ValueError, int, Decimal('-nan')) + self.assertRaises(ValueError, int, Decimal('snan')) + self.assertRaises(OverflowError, int, Decimal('inf')) + self.assertRaises(OverflowError, int, Decimal('-inf')) + + def test_trunc(self): + Decimal = self.decimal.Decimal + ROUND_DOWN = self.decimal.ROUND_DOWN + + for x in range(-250, 250): + s = '%0.2f' % (x / 100.0) + # should work the same as for floats + self.assertEqual(int(Decimal(s)), int(float(s))) + # should work the same as to_integral in the ROUND_DOWN mode + d = Decimal(s) + r = d.to_integral(ROUND_DOWN) + self.assertEqual(Decimal(math.trunc(d)), r) + + def test_from_float(self): + + Decimal = self.decimal.Decimal + + class MyDecimal(Decimal): + pass + + self.assertTrue(issubclass(MyDecimal, Decimal)) + + r = MyDecimal.from_float(0.1) + self.assertEqual(type(r), MyDecimal) + self.assertEqual(str(r), + '0.1000000000000000055511151231257827021181583404541015625') + bigint = 12345678901234567890123456789 + self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint)) + self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan()) + self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite()) + self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite()) + self.assertEqual(str(MyDecimal.from_float(float('nan'))), + str(Decimal('NaN'))) + self.assertEqual(str(MyDecimal.from_float(float('inf'))), + str(Decimal('Infinity'))) + self.assertEqual(str(MyDecimal.from_float(float('-inf'))), + str(Decimal('-Infinity'))) + self.assertRaises(TypeError, MyDecimal.from_float, 'abc') + for i in range(200): + x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) + self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip + + def test_create_decimal_from_float(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + ROUND_DOWN = self.decimal.ROUND_DOWN + ROUND_UP = self.decimal.ROUND_UP + Inexact = self.decimal.Inexact + + context = Context(prec=5, rounding=ROUND_DOWN) + self.assertEqual( + context.create_decimal_from_float(math.pi), + Decimal('3.1415') + ) + context = Context(prec=5, rounding=ROUND_UP) + self.assertEqual( + context.create_decimal_from_float(math.pi), + Decimal('3.1416') + ) + context = Context(prec=5, traps=[Inexact]) + self.assertRaises( + Inexact, + context.create_decimal_from_float, + math.pi + ) + self.assertEqual(repr(context.create_decimal_from_float(-0.0)), + "Decimal('-0')") + self.assertEqual(repr(context.create_decimal_from_float(1.0)), + "Decimal('1')") + self.assertEqual(repr(context.create_decimal_from_float(10)), + "Decimal('10')") + + def test_quantize(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + InvalidOperation = self.decimal.InvalidOperation + ROUND_DOWN = self.decimal.ROUND_DOWN + + c = Context(Emax=99999, Emin=-99999) + self.assertEqual( + Decimal('7.335').quantize(Decimal('.01')), + Decimal('7.34') + ) + self.assertEqual( + Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN), + Decimal('7.33') + ) + self.assertRaises( + InvalidOperation, + Decimal("10e99999").quantize, Decimal('1e100000'), context=c + ) + + c = Context() + d = Decimal("0.871831e800") + x = d.quantize(context=c, exp=Decimal("1e797"), rounding=ROUND_DOWN) + self.assertEqual(x, Decimal('8.71E+799')) + + def test_complex(self): + Decimal = self.decimal.Decimal + + x = Decimal("9.8182731e181273") + self.assertEqual(x.real, x) + self.assertEqual(x.imag, 0) + self.assertEqual(x.conjugate(), x) + + x = Decimal("1") + self.assertEqual(complex(x), complex(float(1))) + + self.assertRaises(AttributeError, setattr, x, 'real', 100) + self.assertRaises(AttributeError, setattr, x, 'imag', 100) + self.assertRaises(AttributeError, setattr, x, 'conjugate', 100) + self.assertRaises(AttributeError, setattr, x, '__complex__', 100) + + def test_named_parameters(self): + D = self.decimal.Decimal + Context = self.decimal.Context + localcontext = self.decimal.localcontext + InvalidOperation = self.decimal.InvalidOperation + Overflow = self.decimal.Overflow + + xc = Context() + xc.prec = 1 + xc.Emax = 1 + xc.Emin = -1 + + with localcontext() as c: + c.clear_flags() + + self.assertEqual(D(9, xc), 9) + self.assertEqual(D(9, context=xc), 9) + self.assertEqual(D(context=xc, value=9), 9) + self.assertEqual(D(context=xc), 0) + xc.clear_flags() + self.assertRaises(InvalidOperation, D, "xyz", context=xc) + self.assertTrue(xc.flags[InvalidOperation]) + self.assertFalse(c.flags[InvalidOperation]) + + xc.clear_flags() + self.assertEqual(D(2).exp(context=xc), 7) + self.assertRaises(Overflow, D(8).exp, context=xc) + self.assertTrue(xc.flags[Overflow]) + self.assertFalse(c.flags[Overflow]) + + xc.clear_flags() + self.assertEqual(D(2).ln(context=xc), D('0.7')) + self.assertRaises(InvalidOperation, D(-1).ln, context=xc) + self.assertTrue(xc.flags[InvalidOperation]) + self.assertFalse(c.flags[InvalidOperation]) + + self.assertEqual(D(0).log10(context=xc), D('-inf')) + self.assertEqual(D(-1).next_minus(context=xc), -2) + self.assertEqual(D(-1).next_plus(context=xc), D('-0.9')) + self.assertEqual(D("9.73").normalize(context=xc), D('1E+1')) + self.assertEqual(D("9999").to_integral(context=xc), 9999) + self.assertEqual(D("-2000").to_integral_exact(context=xc), -2000) + self.assertEqual(D("123").to_integral_value(context=xc), 123) + self.assertEqual(D("0.0625").sqrt(context=xc), D('0.2')) + + self.assertEqual(D("0.0625").compare(context=xc, other=3), -1) + xc.clear_flags() + self.assertRaises(InvalidOperation, + D("0").compare_signal, D('nan'), context=xc) + self.assertTrue(xc.flags[InvalidOperation]) + self.assertFalse(c.flags[InvalidOperation]) + self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0')) + self.assertEqual(D("0.01").max(D('0.0101'), context=xc), D('0.0')) + self.assertEqual(D("0.2").max_mag(D('-0.3'), context=xc), + D('-0.3')) + self.assertEqual(D("0.02").min(D('-0.03'), context=xc), D('-0.0')) + self.assertEqual(D("0.02").min_mag(D('-0.03'), context=xc), + D('0.0')) + self.assertEqual(D("0.2").next_toward(D('-1'), context=xc), D('0.1')) + xc.clear_flags() + self.assertRaises(InvalidOperation, + D("0.2").quantize, D('1e10'), context=xc) + self.assertTrue(xc.flags[InvalidOperation]) + self.assertFalse(c.flags[InvalidOperation]) + self.assertEqual(D("9.99").remainder_near(D('1.5'), context=xc), + D('-0.5')) + + self.assertEqual(D("9.9").fma(third=D('0.9'), context=xc, other=7), + D('7E+1')) + + self.assertRaises(TypeError, D(1).is_canonical, context=xc) + self.assertRaises(TypeError, D(1).is_finite, context=xc) + self.assertRaises(TypeError, D(1).is_infinite, context=xc) + self.assertRaises(TypeError, D(1).is_nan, context=xc) + self.assertRaises(TypeError, D(1).is_qnan, context=xc) + self.assertRaises(TypeError, D(1).is_snan, context=xc) + self.assertRaises(TypeError, D(1).is_signed, context=xc) + self.assertRaises(TypeError, D(1).is_zero, context=xc) + + self.assertFalse(D("0.01").is_normal(context=xc)) + self.assertTrue(D("0.01").is_subnormal(context=xc)) + + self.assertRaises(TypeError, D(1).adjusted, context=xc) + self.assertRaises(TypeError, D(1).conjugate, context=xc) + self.assertRaises(TypeError, D(1).radix, context=xc) + + self.assertEqual(D(-111).logb(context=xc), 2) + self.assertEqual(D(0).logical_invert(context=xc), 1) + self.assertEqual(D('0.01').number_class(context=xc), '+Subnormal') + self.assertEqual(D('0.21').to_eng_string(context=xc), '0.21') + + self.assertEqual(D('11').logical_and(D('10'), context=xc), 0) + self.assertEqual(D('11').logical_or(D('10'), context=xc), 1) + self.assertEqual(D('01').logical_xor(D('10'), context=xc), 1) + self.assertEqual(D('23').rotate(1, context=xc), 3) + self.assertEqual(D('23').rotate(1, context=xc), 3) + xc.clear_flags() + self.assertRaises(Overflow, + D('23').scaleb, 1, context=xc) + self.assertTrue(xc.flags[Overflow]) + self.assertFalse(c.flags[Overflow]) + self.assertEqual(D('23').shift(-1, context=xc), 0) + + self.assertRaises(TypeError, D.from_float, 1.1, context=xc) + self.assertRaises(TypeError, D(0).as_tuple, context=xc) + + if (self.decimal == C): + self.assertRaises(TypeError, D(1).canonical, context=xc) + self.assertEqual(D("-1").copy_abs(context=xc), 1) + self.assertEqual(D("1").copy_negate(context=xc), -1) + else: + self.assertEqual(D(1).canonical(context=xc), 1) + self.assertRaises(TypeError, D("-1").copy_abs, context=xc) + self.assertRaises(TypeError, D("-1").copy_negate, context=xc) + +class CPythonAPItests(PythonAPItests): + decimal = C +class PyPythonAPItests(PythonAPItests): + decimal = P + +class ContextAPItests(unittest.TestCase): + + def test_pickle(self): + + Context = self.decimal.Context + + savedecimal = sys.modules['decimal'] + + # Round trip + sys.modules['decimal'] = self.decimal + c = Context() + e = pickle.loads(pickle.dumps(c)) + + self.assertEqual(c.prec, e.prec) + self.assertEqual(c.Emin, e.Emin) + self.assertEqual(c.Emax, e.Emax) + self.assertEqual(c.rounding, e.rounding) + self.assertEqual(c.capitals, e.capitals) + self.assertEqual(c.clamp, e.clamp) + self.assertEqual(c.flags, e.flags) + self.assertEqual(c.traps, e.traps) + + # Test interchangeability + combinations = [(C, P), (P, C)] if C else [(P, P)] + for dumper, loader in combinations: + for ri, _ in enumerate(RoundingModes[dumper]): + for fi, _ in enumerate(OrderedSignals[dumper]): + for ti, _ in enumerate(OrderedSignals[dumper]): + + prec = random.randrange(1, 100) + emin = random.randrange(-100, 0) + emax = random.randrange(1, 100) + caps = random.randrange(2) + clamp = random.randrange(2) + + # One module dumps + sys.modules['decimal'] = dumper + c = dumper.Context( + prec=prec, Emin=emin, Emax=emax, + rounding=RoundingModes[dumper][ri], + capitals=caps, clamp=clamp, + flags=OrderedSignals[dumper][:fi], + traps=OrderedSignals[dumper][:ti] + ) + s = pickle.dumps(c) + + # The other module loads + sys.modules['decimal'] = loader + d = pickle.loads(s) + self.assertIsInstance(d, loader.Context) + + self.assertEqual(d.prec, prec) + self.assertEqual(d.Emin, emin) + self.assertEqual(d.Emax, emax) + self.assertEqual(d.rounding, RoundingModes[loader][ri]) + self.assertEqual(d.capitals, caps) + self.assertEqual(d.clamp, clamp) + assert_signals(self, d, 'flags', OrderedSignals[loader][:fi]) + assert_signals(self, d, 'traps', OrderedSignals[loader][:ti]) + + sys.modules['decimal'] = savedecimal + + def test_equality_with_other_types(self): + Decimal = self.decimal.Decimal + + self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}]) + self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}]) + + def test_copy(self): + # All copies should be deep + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy() + self.assertNotEqual(id(c), id(d)) + self.assertNotEqual(id(c.flags), id(d.flags)) + self.assertNotEqual(id(c.traps), id(d.traps)) + k1 = set(c.flags.keys()) + k2 = set(d.flags.keys()) + self.assertEqual(k1, k2) + self.assertEqual(c.flags, d.flags) + + def test__clamp(self): + # In Python 3.2, the private attribute `_clamp` was made + # public (issue 8540), with the old `_clamp` becoming a + # property wrapping `clamp`. For the duration of Python 3.2 + # only, the attribute should be gettable/settable via both + # `clamp` and `_clamp`; in Python 3.3, `_clamp` should be + # removed. + Context = self.decimal.Context + c = Context() + self.assertRaises(AttributeError, getattr, c, '_clamp') + + def test_abs(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.abs(Decimal(-1)) + self.assertEqual(c.abs(-1), d) + self.assertRaises(TypeError, c.abs, '-1') + + def test_add(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.add(Decimal(1), Decimal(1)) + self.assertEqual(c.add(1, 1), d) + self.assertEqual(c.add(Decimal(1), 1), d) + self.assertEqual(c.add(1, Decimal(1)), d) + self.assertRaises(TypeError, c.add, '1', 1) + self.assertRaises(TypeError, c.add, 1, '1') + + def test_compare(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.compare(Decimal(1), Decimal(1)) + self.assertEqual(c.compare(1, 1), d) + self.assertEqual(c.compare(Decimal(1), 1), d) + self.assertEqual(c.compare(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare, '1', 1) + self.assertRaises(TypeError, c.compare, 1, '1') + + def test_compare_signal(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.compare_signal(Decimal(1), Decimal(1)) + self.assertEqual(c.compare_signal(1, 1), d) + self.assertEqual(c.compare_signal(Decimal(1), 1), d) + self.assertEqual(c.compare_signal(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare_signal, '1', 1) + self.assertRaises(TypeError, c.compare_signal, 1, '1') + + def test_compare_total(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.compare_total(Decimal(1), Decimal(1)) + self.assertEqual(c.compare_total(1, 1), d) + self.assertEqual(c.compare_total(Decimal(1), 1), d) + self.assertEqual(c.compare_total(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare_total, '1', 1) + self.assertRaises(TypeError, c.compare_total, 1, '1') + + def test_compare_total_mag(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.compare_total_mag(Decimal(1), Decimal(1)) + self.assertEqual(c.compare_total_mag(1, 1), d) + self.assertEqual(c.compare_total_mag(Decimal(1), 1), d) + self.assertEqual(c.compare_total_mag(1, Decimal(1)), d) + self.assertRaises(TypeError, c.compare_total_mag, '1', 1) + self.assertRaises(TypeError, c.compare_total_mag, 1, '1') + + def test_copy_abs(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy_abs(Decimal(-1)) + self.assertEqual(c.copy_abs(-1), d) + self.assertRaises(TypeError, c.copy_abs, '-1') + + def test_copy_decimal(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy_decimal(Decimal(-1)) + self.assertEqual(c.copy_decimal(-1), d) + self.assertRaises(TypeError, c.copy_decimal, '-1') + + def test_copy_negate(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy_negate(Decimal(-1)) + self.assertEqual(c.copy_negate(-1), d) + self.assertRaises(TypeError, c.copy_negate, '-1') + + def test_copy_sign(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.copy_sign(Decimal(1), Decimal(-2)) + self.assertEqual(c.copy_sign(1, -2), d) + self.assertEqual(c.copy_sign(Decimal(1), -2), d) + self.assertEqual(c.copy_sign(1, Decimal(-2)), d) + self.assertRaises(TypeError, c.copy_sign, '1', -2) + self.assertRaises(TypeError, c.copy_sign, 1, '-2') + + def test_divide(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.divide(Decimal(1), Decimal(2)) + self.assertEqual(c.divide(1, 2), d) + self.assertEqual(c.divide(Decimal(1), 2), d) + self.assertEqual(c.divide(1, Decimal(2)), d) + self.assertRaises(TypeError, c.divide, '1', 2) + self.assertRaises(TypeError, c.divide, 1, '2') + + def test_divide_int(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.divide_int(Decimal(1), Decimal(2)) + self.assertEqual(c.divide_int(1, 2), d) + self.assertEqual(c.divide_int(Decimal(1), 2), d) + self.assertEqual(c.divide_int(1, Decimal(2)), d) + self.assertRaises(TypeError, c.divide_int, '1', 2) + self.assertRaises(TypeError, c.divide_int, 1, '2') + + def test_divmod(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.divmod(Decimal(1), Decimal(2)) + self.assertEqual(c.divmod(1, 2), d) + self.assertEqual(c.divmod(Decimal(1), 2), d) + self.assertEqual(c.divmod(1, Decimal(2)), d) + self.assertRaises(TypeError, c.divmod, '1', 2) + self.assertRaises(TypeError, c.divmod, 1, '2') + + def test_exp(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.exp(Decimal(10)) + self.assertEqual(c.exp(10), d) + self.assertRaises(TypeError, c.exp, '10') + + def test_fma(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.fma(Decimal(2), Decimal(3), Decimal(4)) + self.assertEqual(c.fma(2, 3, 4), d) + self.assertEqual(c.fma(Decimal(2), 3, 4), d) + self.assertEqual(c.fma(2, Decimal(3), 4), d) + self.assertEqual(c.fma(2, 3, Decimal(4)), d) + self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d) + self.assertRaises(TypeError, c.fma, '2', 3, 4) + self.assertRaises(TypeError, c.fma, 2, '3', 4) + self.assertRaises(TypeError, c.fma, 2, 3, '4') + + # Issue 12079 for Context.fma ... + self.assertRaises(TypeError, c.fma, + Decimal('Infinity'), Decimal(0), "not a decimal") + self.assertRaises(TypeError, c.fma, + Decimal(1), Decimal('snan'), 1.222) + # ... and for Decimal.fma. + self.assertRaises(TypeError, Decimal('Infinity').fma, + Decimal(0), "not a decimal") + self.assertRaises(TypeError, Decimal(1).fma, + Decimal('snan'), 1.222) + + def test_is_finite(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_finite(Decimal(10)) + self.assertEqual(c.is_finite(10), d) + self.assertRaises(TypeError, c.is_finite, '10') + + def test_is_infinite(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_infinite(Decimal(10)) + self.assertEqual(c.is_infinite(10), d) + self.assertRaises(TypeError, c.is_infinite, '10') + + def test_is_nan(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_nan(Decimal(10)) + self.assertEqual(c.is_nan(10), d) + self.assertRaises(TypeError, c.is_nan, '10') + + def test_is_normal(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_normal(Decimal(10)) + self.assertEqual(c.is_normal(10), d) + self.assertRaises(TypeError, c.is_normal, '10') + + def test_is_qnan(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_qnan(Decimal(10)) + self.assertEqual(c.is_qnan(10), d) + self.assertRaises(TypeError, c.is_qnan, '10') + + def test_is_signed(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_signed(Decimal(10)) + self.assertEqual(c.is_signed(10), d) + self.assertRaises(TypeError, c.is_signed, '10') + + def test_is_snan(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_snan(Decimal(10)) + self.assertEqual(c.is_snan(10), d) + self.assertRaises(TypeError, c.is_snan, '10') + + def test_is_subnormal(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_subnormal(Decimal(10)) + self.assertEqual(c.is_subnormal(10), d) + self.assertRaises(TypeError, c.is_subnormal, '10') + + def test_is_zero(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.is_zero(Decimal(10)) + self.assertEqual(c.is_zero(10), d) + self.assertRaises(TypeError, c.is_zero, '10') + + def test_ln(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.ln(Decimal(10)) + self.assertEqual(c.ln(10), d) + self.assertRaises(TypeError, c.ln, '10') + + def test_log10(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.log10(Decimal(10)) + self.assertEqual(c.log10(10), d) + self.assertRaises(TypeError, c.log10, '10') + + def test_logb(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logb(Decimal(10)) + self.assertEqual(c.logb(10), d) + self.assertRaises(TypeError, c.logb, '10') + + def test_logical_and(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logical_and(Decimal(1), Decimal(1)) + self.assertEqual(c.logical_and(1, 1), d) + self.assertEqual(c.logical_and(Decimal(1), 1), d) + self.assertEqual(c.logical_and(1, Decimal(1)), d) + self.assertRaises(TypeError, c.logical_and, '1', 1) + self.assertRaises(TypeError, c.logical_and, 1, '1') + + def test_logical_invert(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logical_invert(Decimal(1000)) + self.assertEqual(c.logical_invert(1000), d) + self.assertRaises(TypeError, c.logical_invert, '1000') + + def test_logical_or(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logical_or(Decimal(1), Decimal(1)) + self.assertEqual(c.logical_or(1, 1), d) + self.assertEqual(c.logical_or(Decimal(1), 1), d) + self.assertEqual(c.logical_or(1, Decimal(1)), d) + self.assertRaises(TypeError, c.logical_or, '1', 1) + self.assertRaises(TypeError, c.logical_or, 1, '1') + + def test_logical_xor(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.logical_xor(Decimal(1), Decimal(1)) + self.assertEqual(c.logical_xor(1, 1), d) + self.assertEqual(c.logical_xor(Decimal(1), 1), d) + self.assertEqual(c.logical_xor(1, Decimal(1)), d) + self.assertRaises(TypeError, c.logical_xor, '1', 1) + self.assertRaises(TypeError, c.logical_xor, 1, '1') + + def test_max(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.max(Decimal(1), Decimal(2)) + self.assertEqual(c.max(1, 2), d) + self.assertEqual(c.max(Decimal(1), 2), d) + self.assertEqual(c.max(1, Decimal(2)), d) + self.assertRaises(TypeError, c.max, '1', 2) + self.assertRaises(TypeError, c.max, 1, '2') + + def test_max_mag(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.max_mag(Decimal(1), Decimal(2)) + self.assertEqual(c.max_mag(1, 2), d) + self.assertEqual(c.max_mag(Decimal(1), 2), d) + self.assertEqual(c.max_mag(1, Decimal(2)), d) + self.assertRaises(TypeError, c.max_mag, '1', 2) + self.assertRaises(TypeError, c.max_mag, 1, '2') + + def test_min(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.min(Decimal(1), Decimal(2)) + self.assertEqual(c.min(1, 2), d) + self.assertEqual(c.min(Decimal(1), 2), d) + self.assertEqual(c.min(1, Decimal(2)), d) + self.assertRaises(TypeError, c.min, '1', 2) + self.assertRaises(TypeError, c.min, 1, '2') + + def test_min_mag(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.min_mag(Decimal(1), Decimal(2)) + self.assertEqual(c.min_mag(1, 2), d) + self.assertEqual(c.min_mag(Decimal(1), 2), d) + self.assertEqual(c.min_mag(1, Decimal(2)), d) + self.assertRaises(TypeError, c.min_mag, '1', 2) + self.assertRaises(TypeError, c.min_mag, 1, '2') + + def test_minus(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.minus(Decimal(10)) + self.assertEqual(c.minus(10), d) + self.assertRaises(TypeError, c.minus, '10') + + def test_multiply(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.multiply(Decimal(1), Decimal(2)) + self.assertEqual(c.multiply(1, 2), d) + self.assertEqual(c.multiply(Decimal(1), 2), d) + self.assertEqual(c.multiply(1, Decimal(2)), d) + self.assertRaises(TypeError, c.multiply, '1', 2) + self.assertRaises(TypeError, c.multiply, 1, '2') + + def test_next_minus(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.next_minus(Decimal(10)) + self.assertEqual(c.next_minus(10), d) + self.assertRaises(TypeError, c.next_minus, '10') + + def test_next_plus(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.next_plus(Decimal(10)) + self.assertEqual(c.next_plus(10), d) + self.assertRaises(TypeError, c.next_plus, '10') + + def test_next_toward(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.next_toward(Decimal(1), Decimal(2)) + self.assertEqual(c.next_toward(1, 2), d) + self.assertEqual(c.next_toward(Decimal(1), 2), d) + self.assertEqual(c.next_toward(1, Decimal(2)), d) + self.assertRaises(TypeError, c.next_toward, '1', 2) + self.assertRaises(TypeError, c.next_toward, 1, '2') + + def test_normalize(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.normalize(Decimal(10)) + self.assertEqual(c.normalize(10), d) + self.assertRaises(TypeError, c.normalize, '10') + + def test_number_class(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + self.assertEqual(c.number_class(123), c.number_class(Decimal(123))) + self.assertEqual(c.number_class(0), c.number_class(Decimal(0))) + self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45))) + + def test_plus(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.plus(Decimal(10)) + self.assertEqual(c.plus(10), d) + self.assertRaises(TypeError, c.plus, '10') + + def test_power(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.power(Decimal(1), Decimal(4)) + self.assertEqual(c.power(1, 4), d) + self.assertEqual(c.power(Decimal(1), 4), d) + self.assertEqual(c.power(1, Decimal(4)), d) + self.assertEqual(c.power(Decimal(1), Decimal(4)), d) + self.assertRaises(TypeError, c.power, '1', 4) + self.assertRaises(TypeError, c.power, 1, '4') + self.assertEqual(c.power(modulo=5, b=8, a=2), 1) + + def test_quantize(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.quantize(Decimal(1), Decimal(2)) + self.assertEqual(c.quantize(1, 2), d) + self.assertEqual(c.quantize(Decimal(1), 2), d) + self.assertEqual(c.quantize(1, Decimal(2)), d) + self.assertRaises(TypeError, c.quantize, '1', 2) + self.assertRaises(TypeError, c.quantize, 1, '2') + + def test_remainder(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.remainder(Decimal(1), Decimal(2)) + self.assertEqual(c.remainder(1, 2), d) + self.assertEqual(c.remainder(Decimal(1), 2), d) + self.assertEqual(c.remainder(1, Decimal(2)), d) + self.assertRaises(TypeError, c.remainder, '1', 2) + self.assertRaises(TypeError, c.remainder, 1, '2') + + def test_remainder_near(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.remainder_near(Decimal(1), Decimal(2)) + self.assertEqual(c.remainder_near(1, 2), d) + self.assertEqual(c.remainder_near(Decimal(1), 2), d) + self.assertEqual(c.remainder_near(1, Decimal(2)), d) + self.assertRaises(TypeError, c.remainder_near, '1', 2) + self.assertRaises(TypeError, c.remainder_near, 1, '2') + + def test_rotate(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.rotate(Decimal(1), Decimal(2)) + self.assertEqual(c.rotate(1, 2), d) + self.assertEqual(c.rotate(Decimal(1), 2), d) + self.assertEqual(c.rotate(1, Decimal(2)), d) + self.assertRaises(TypeError, c.rotate, '1', 2) + self.assertRaises(TypeError, c.rotate, 1, '2') + + def test_sqrt(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.sqrt(Decimal(10)) + self.assertEqual(c.sqrt(10), d) + self.assertRaises(TypeError, c.sqrt, '10') + + def test_same_quantum(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.same_quantum(Decimal(1), Decimal(2)) + self.assertEqual(c.same_quantum(1, 2), d) + self.assertEqual(c.same_quantum(Decimal(1), 2), d) + self.assertEqual(c.same_quantum(1, Decimal(2)), d) + self.assertRaises(TypeError, c.same_quantum, '1', 2) + self.assertRaises(TypeError, c.same_quantum, 1, '2') + + def test_scaleb(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.scaleb(Decimal(1), Decimal(2)) + self.assertEqual(c.scaleb(1, 2), d) + self.assertEqual(c.scaleb(Decimal(1), 2), d) + self.assertEqual(c.scaleb(1, Decimal(2)), d) + self.assertRaises(TypeError, c.scaleb, '1', 2) + self.assertRaises(TypeError, c.scaleb, 1, '2') + + def test_shift(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.shift(Decimal(1), Decimal(2)) + self.assertEqual(c.shift(1, 2), d) + self.assertEqual(c.shift(Decimal(1), 2), d) + self.assertEqual(c.shift(1, Decimal(2)), d) + self.assertRaises(TypeError, c.shift, '1', 2) + self.assertRaises(TypeError, c.shift, 1, '2') + + def test_subtract(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.subtract(Decimal(1), Decimal(2)) + self.assertEqual(c.subtract(1, 2), d) + self.assertEqual(c.subtract(Decimal(1), 2), d) + self.assertEqual(c.subtract(1, Decimal(2)), d) + self.assertRaises(TypeError, c.subtract, '1', 2) + self.assertRaises(TypeError, c.subtract, 1, '2') + + def test_to_eng_string(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.to_eng_string(Decimal(10)) + self.assertEqual(c.to_eng_string(10), d) + self.assertRaises(TypeError, c.to_eng_string, '10') + + def test_to_sci_string(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.to_sci_string(Decimal(10)) + self.assertEqual(c.to_sci_string(10), d) + self.assertRaises(TypeError, c.to_sci_string, '10') + + def test_to_integral_exact(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.to_integral_exact(Decimal(10)) + self.assertEqual(c.to_integral_exact(10), d) + self.assertRaises(TypeError, c.to_integral_exact, '10') + + def test_to_integral_value(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + + c = Context() + d = c.to_integral_value(Decimal(10)) + self.assertEqual(c.to_integral_value(10), d) + self.assertRaises(TypeError, c.to_integral_value, '10') + self.assertRaises(TypeError, c.to_integral_value, 10, 'x') + +class CContextAPItests(ContextAPItests): + decimal = C +class PyContextAPItests(ContextAPItests): + decimal = P + +class ContextWithStatement(unittest.TestCase): + # Can't do these as docstrings until Python 2.6 + # as doctest can't handle __future__ statements + + def test_localcontext(self): + # Use a copy of the current context in the block + getcontext = self.decimal.getcontext + localcontext = self.decimal.localcontext + + orig_ctx = getcontext() + with localcontext() as enter_ctx: + set_ctx = getcontext() + final_ctx = getcontext() + self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly') + self.assertIsNot(orig_ctx, set_ctx, 'did not copy the context') + self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context') + + def test_localcontextarg(self): + # Use a copy of the supplied context in the block + Context = self.decimal.Context + getcontext = self.decimal.getcontext + localcontext = self.decimal.localcontext + + localcontext = self.decimal.localcontext + orig_ctx = getcontext() + new_ctx = Context(prec=42) + with localcontext(new_ctx) as enter_ctx: + set_ctx = getcontext() + final_ctx = getcontext() + self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly') + self.assertEqual(set_ctx.prec, new_ctx.prec, 'did not set correct context') + self.assertIsNot(new_ctx, set_ctx, 'did not copy the context') + self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context') + + def test_nested_with_statements(self): + # Use a copy of the supplied context in the block + Decimal = self.decimal.Decimal + Context = self.decimal.Context + getcontext = self.decimal.getcontext + localcontext = self.decimal.localcontext + Clamped = self.decimal.Clamped + Overflow = self.decimal.Overflow + + orig_ctx = getcontext() + orig_ctx.clear_flags() + new_ctx = Context(Emax=384) + with localcontext() as c1: + self.assertEqual(c1.flags, orig_ctx.flags) + self.assertEqual(c1.traps, orig_ctx.traps) + c1.traps[Clamped] = True + c1.Emin = -383 + self.assertNotEqual(orig_ctx.Emin, -383) + self.assertRaises(Clamped, c1.create_decimal, '0e-999') + self.assertTrue(c1.flags[Clamped]) + with localcontext(new_ctx) as c2: + self.assertEqual(c2.flags, new_ctx.flags) + self.assertEqual(c2.traps, new_ctx.traps) + self.assertRaises(Overflow, c2.power, Decimal('3.4e200'), 2) + self.assertFalse(c2.flags[Clamped]) + self.assertTrue(c2.flags[Overflow]) + del c2 + self.assertFalse(c1.flags[Overflow]) + del c1 + self.assertNotEqual(orig_ctx.Emin, -383) + self.assertFalse(orig_ctx.flags[Clamped]) + self.assertFalse(orig_ctx.flags[Overflow]) + self.assertFalse(new_ctx.flags[Clamped]) + self.assertFalse(new_ctx.flags[Overflow]) + + def test_with_statements_gc1(self): + localcontext = self.decimal.localcontext + + with localcontext() as c1: + del c1 + with localcontext() as c2: + del c2 + with localcontext() as c3: + del c3 + with localcontext() as c4: + del c4 + + def test_with_statements_gc2(self): + localcontext = self.decimal.localcontext + + with localcontext() as c1: + with localcontext(c1) as c2: + del c1 + with localcontext(c2) as c3: + del c2 + with localcontext(c3) as c4: + del c3 + del c4 + + def test_with_statements_gc3(self): + Context = self.decimal.Context + localcontext = self.decimal.localcontext + getcontext = self.decimal.getcontext + setcontext = self.decimal.setcontext + + with localcontext() as c1: + del c1 + n1 = Context(prec=1) + setcontext(n1) + with localcontext(n1) as c2: + del n1 + self.assertEqual(c2.prec, 1) + del c2 + n2 = Context(prec=2) + setcontext(n2) + del n2 + self.assertEqual(getcontext().prec, 2) + n3 = Context(prec=3) + setcontext(n3) + self.assertEqual(getcontext().prec, 3) + with localcontext(n3) as c3: + del n3 + self.assertEqual(c3.prec, 3) + del c3 + n4 = Context(prec=4) + setcontext(n4) + del n4 + self.assertEqual(getcontext().prec, 4) + with localcontext() as c4: + self.assertEqual(c4.prec, 4) + del c4 + +class CContextWithStatement(ContextWithStatement): + decimal = C +class PyContextWithStatement(ContextWithStatement): + decimal = P + +class ContextFlags(unittest.TestCase): + + def test_flags_irrelevant(self): + # check that the result (numeric result + flags raised) of an + # arithmetic operation doesn't depend on the current flags + Decimal = self.decimal.Decimal + Context = self.decimal.Context + Inexact = self.decimal.Inexact + Rounded = self.decimal.Rounded + Underflow = self.decimal.Underflow + Clamped = self.decimal.Clamped + Subnormal = self.decimal.Subnormal + ROUND_HALF_EVEN = self.decimal.ROUND_HALF_EVEN + + def raise_error(context, flag): + if self.decimal == C: + context.flags[flag] = True + if context.traps[flag]: + raise flag + else: + context._raise_error(flag) + + context = Context(prec=9, Emin = -425000000, Emax = 425000000, + rounding=ROUND_HALF_EVEN, traps=[], flags=[]) + + # operations that raise various flags, in the form (function, arglist) + operations = [ + (context._apply, [Decimal("100E-425000010")]), + (context.sqrt, [Decimal(2)]), + (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]), + (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]), + (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]), + ] + + # try various flags individually, then a whole lot at once + flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal], + [Inexact, Rounded, Underflow, Clamped, Subnormal]] + + for fn, args in operations: + # find answer and flags raised using a clean context + context.clear_flags() + ans = fn(*args) + flags = [k for k, v in context.flags.items() if v] + + for extra_flags in flagsets: + # set flags, before calling operation + context.clear_flags() + for flag in extra_flags: + raise_error(context, flag) + new_ans = fn(*args) + + # flags that we expect to be set after the operation + expected_flags = list(flags) + for flag in extra_flags: + if flag not in expected_flags: + expected_flags.append(flag) + expected_flags.sort(key=id) + + # flags we actually got + new_flags = [k for k,v in context.flags.items() if v] + new_flags.sort(key=id) + + self.assertEqual(ans, new_ans, + "operation produces different answers depending on flags set: " + + "expected %s, got %s." % (ans, new_ans)) + self.assertEqual(new_flags, expected_flags, + "operation raises different flags depending on flags set: " + + "expected %s, got %s" % (expected_flags, new_flags)) + + def test_flag_comparisons(self): + Context = self.decimal.Context + Inexact = self.decimal.Inexact + Rounded = self.decimal.Rounded + + c = Context() + + # Valid SignalDict + self.assertNotEqual(c.flags, c.traps) + self.assertNotEqual(c.traps, c.flags) + + c.flags = c.traps + self.assertEqual(c.flags, c.traps) + self.assertEqual(c.traps, c.flags) + + c.flags[Rounded] = True + c.traps = c.flags + self.assertEqual(c.flags, c.traps) + self.assertEqual(c.traps, c.flags) + + d = {} + d.update(c.flags) + self.assertEqual(d, c.flags) + self.assertEqual(c.flags, d) + + d[Inexact] = True + self.assertNotEqual(d, c.flags) + self.assertNotEqual(c.flags, d) + + # Invalid SignalDict + d = {Inexact:False} + self.assertNotEqual(d, c.flags) + self.assertNotEqual(c.flags, d) + + d = ["xyz"] + self.assertNotEqual(d, c.flags) + self.assertNotEqual(c.flags, d) + + @requires_IEEE_754 + def test_float_operation(self): + Decimal = self.decimal.Decimal + FloatOperation = self.decimal.FloatOperation + localcontext = self.decimal.localcontext + + with localcontext() as c: + ##### trap is off by default + self.assertFalse(c.traps[FloatOperation]) + + # implicit conversion sets the flag + c.clear_flags() + self.assertEqual(Decimal(7.5), 7.5) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + self.assertEqual(c.create_decimal(7.5), 7.5) + self.assertTrue(c.flags[FloatOperation]) + + # explicit conversion does not set the flag + c.clear_flags() + x = Decimal.from_float(7.5) + self.assertFalse(c.flags[FloatOperation]) + # comparison sets the flag + self.assertEqual(x, 7.5) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + x = c.create_decimal_from_float(7.5) + self.assertFalse(c.flags[FloatOperation]) + self.assertEqual(x, 7.5) + self.assertTrue(c.flags[FloatOperation]) + + ##### set the trap + c.traps[FloatOperation] = True + + # implicit conversion raises + c.clear_flags() + self.assertRaises(FloatOperation, Decimal, 7.5) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + self.assertRaises(FloatOperation, c.create_decimal, 7.5) + self.assertTrue(c.flags[FloatOperation]) + + # explicit conversion is silent + c.clear_flags() + x = Decimal.from_float(7.5) + self.assertFalse(c.flags[FloatOperation]) + + c.clear_flags() + x = c.create_decimal_from_float(7.5) + self.assertFalse(c.flags[FloatOperation]) + + def test_float_comparison(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + FloatOperation = self.decimal.FloatOperation + localcontext = self.decimal.localcontext + + def assert_attr(a, b, attr, context, signal=None): + context.clear_flags() + f = getattr(a, attr) + if signal == FloatOperation: + self.assertRaises(signal, f, b) + else: + self.assertIs(f(b), True) + self.assertTrue(context.flags[FloatOperation]) + + small_d = Decimal('0.25') + big_d = Decimal('3.0') + small_f = 0.25 + big_f = 3.0 + + zero_d = Decimal('0.0') + neg_zero_d = Decimal('-0.0') + zero_f = 0.0 + neg_zero_f = -0.0 + + inf_d = Decimal('Infinity') + neg_inf_d = Decimal('-Infinity') + inf_f = float('inf') + neg_inf_f = float('-inf') + + def doit(c, signal=None): + # Order + for attr in '__lt__', '__le__': + assert_attr(small_d, big_f, attr, c, signal) + + for attr in '__gt__', '__ge__': + assert_attr(big_d, small_f, attr, c, signal) + + # Equality + assert_attr(small_d, small_f, '__eq__', c, None) + + assert_attr(neg_zero_d, neg_zero_f, '__eq__', c, None) + assert_attr(neg_zero_d, zero_f, '__eq__', c, None) + + assert_attr(zero_d, neg_zero_f, '__eq__', c, None) + assert_attr(zero_d, zero_f, '__eq__', c, None) + + assert_attr(neg_inf_d, neg_inf_f, '__eq__', c, None) + assert_attr(inf_d, inf_f, '__eq__', c, None) + + # Inequality + assert_attr(small_d, big_f, '__ne__', c, None) + + assert_attr(Decimal('0.1'), 0.1, '__ne__', c, None) + + assert_attr(neg_inf_d, inf_f, '__ne__', c, None) + assert_attr(inf_d, neg_inf_f, '__ne__', c, None) + + assert_attr(Decimal('NaN'), float('nan'), '__ne__', c, None) + + def test_containers(c, signal=None): + c.clear_flags() + s = set([100.0, Decimal('100.0')]) + self.assertEqual(len(s), 1) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + if signal: + self.assertRaises(signal, sorted, [1.0, Decimal('10.0')]) + else: + s = sorted([10.0, Decimal('10.0')]) + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + b = 10.0 in [Decimal('10.0'), 1.0] + self.assertTrue(c.flags[FloatOperation]) + + c.clear_flags() + b = 10.0 in {Decimal('10.0'):'a', 1.0:'b'} + self.assertTrue(c.flags[FloatOperation]) + + nc = Context() + with localcontext(nc) as c: + self.assertFalse(c.traps[FloatOperation]) + doit(c, signal=None) + test_containers(c, signal=None) + + c.traps[FloatOperation] = True + doit(c, signal=FloatOperation) + test_containers(c, signal=FloatOperation) + + def test_float_operation_default(self): + Decimal = self.decimal.Decimal + Context = self.decimal.Context + Inexact = self.decimal.Inexact + FloatOperation= self.decimal.FloatOperation + + context = Context() + self.assertFalse(context.flags[FloatOperation]) + self.assertFalse(context.traps[FloatOperation]) + + context.clear_traps() + context.traps[Inexact] = True + context.traps[FloatOperation] = True + self.assertTrue(context.traps[FloatOperation]) + self.assertTrue(context.traps[Inexact]) + +class CContextFlags(ContextFlags): + decimal = C +class PyContextFlags(ContextFlags): + decimal = P + +class SpecialContexts(unittest.TestCase): + """Test the context templates.""" + + def test_context_templates(self): + BasicContext = self.decimal.BasicContext + ExtendedContext = self.decimal.ExtendedContext + getcontext = self.decimal.getcontext + setcontext = self.decimal.setcontext + InvalidOperation = self.decimal.InvalidOperation + DivisionByZero = self.decimal.DivisionByZero + Overflow = self.decimal.Overflow + Underflow = self.decimal.Underflow + Clamped = self.decimal.Clamped + + assert_signals(self, BasicContext, 'traps', + [InvalidOperation, DivisionByZero, Overflow, Underflow, Clamped] + ) + + savecontext = getcontext().copy() + basic_context_prec = BasicContext.prec + extended_context_prec = ExtendedContext.prec + + ex = None + try: + BasicContext.prec = ExtendedContext.prec = 441 + for template in BasicContext, ExtendedContext: + setcontext(template) + c = getcontext() + self.assertIsNot(c, template) + self.assertEqual(c.prec, 441) + except Exception as e: + ex = e.__class__ + finally: + BasicContext.prec = basic_context_prec + ExtendedContext.prec = extended_context_prec + setcontext(savecontext) + if ex: + raise ex + + def test_default_context(self): + DefaultContext = self.decimal.DefaultContext + BasicContext = self.decimal.BasicContext + ExtendedContext = self.decimal.ExtendedContext + getcontext = self.decimal.getcontext + setcontext = self.decimal.setcontext + InvalidOperation = self.decimal.InvalidOperation + DivisionByZero = self.decimal.DivisionByZero + Overflow = self.decimal.Overflow + + self.assertEqual(BasicContext.prec, 9) + self.assertEqual(ExtendedContext.prec, 9) + + assert_signals(self, DefaultContext, 'traps', + [InvalidOperation, DivisionByZero, Overflow] + ) + + savecontext = getcontext().copy() + default_context_prec = DefaultContext.prec + + ex = None + try: + c = getcontext() + saveprec = c.prec + + DefaultContext.prec = 961 + c = getcontext() + self.assertEqual(c.prec, saveprec) + + setcontext(DefaultContext) + c = getcontext() + self.assertIsNot(c, DefaultContext) + self.assertEqual(c.prec, 961) + except Exception as e: + ex = e.__class__ + finally: + DefaultContext.prec = default_context_prec + setcontext(savecontext) + if ex: + raise ex + +class CSpecialContexts(SpecialContexts): + decimal = C +class PySpecialContexts(SpecialContexts): + decimal = P + +class ContextInputValidation(unittest.TestCase): + + def test_invalid_context(self): + Context = self.decimal.Context + DefaultContext = self.decimal.DefaultContext + + c = DefaultContext.copy() + + # prec, Emax + for attr in ['prec', 'Emax']: + setattr(c, attr, 999999) + self.assertEqual(getattr(c, attr), 999999) + self.assertRaises(ValueError, setattr, c, attr, -1) + self.assertRaises(TypeError, setattr, c, attr, 'xyz') + + # Emin + setattr(c, 'Emin', -999999) + self.assertEqual(getattr(c, 'Emin'), -999999) + self.assertRaises(ValueError, setattr, c, 'Emin', 1) + self.assertRaises(TypeError, setattr, c, 'Emin', (1,2,3)) + + # rounding: always raise TypeError in order to get consistent + # exceptions across implementations. In decimal, rounding + # modes are strings, in _decimal they are integers. The idea + # is to view rounding as an abstract type and not mind the + # implementation details. + # Hence, a user should view the rounding modes as if they + # had been defined in a language that supports abstract + # data types, e.g. ocaml: + # + # type rounding = ROUND_DOWN | ROUND_HALF_UP | ... ;; + # + self.assertRaises(TypeError, setattr, c, 'rounding', -1) + self.assertRaises(TypeError, setattr, c, 'rounding', 9) + self.assertRaises(TypeError, setattr, c, 'rounding', 1.0) + self.assertRaises(TypeError, setattr, c, 'rounding', 'xyz') + + # capitals, clamp + for attr in ['capitals', 'clamp']: + self.assertRaises(ValueError, setattr, c, attr, -1) + self.assertRaises(ValueError, setattr, c, attr, 2) + self.assertRaises(TypeError, setattr, c, attr, [1,2,3]) + + # Invalid attribute + self.assertRaises(AttributeError, setattr, c, 'emax', 100) + + # Invalid signal dict + self.assertRaises(TypeError, setattr, c, 'flags', []) + self.assertRaises(KeyError, setattr, c, 'flags', {}) + self.assertRaises(KeyError, setattr, c, 'traps', + {'InvalidOperation':0}) + + # Attributes cannot be deleted + for attr in ['prec', 'Emax', 'Emin', 'rounding', 'capitals', 'clamp', + 'flags', 'traps']: + self.assertRaises(AttributeError, c.__delattr__, attr) + + # Invalid attributes + self.assertRaises(TypeError, getattr, c, 9) + self.assertRaises(TypeError, setattr, c, 9) + + # Invalid values in constructor + self.assertRaises(TypeError, Context, rounding=999999) + self.assertRaises(TypeError, Context, rounding='xyz') + self.assertRaises(ValueError, Context, clamp=2) + self.assertRaises(ValueError, Context, capitals=-1) + self.assertRaises(KeyError, Context, flags=["P"]) + self.assertRaises(KeyError, Context, traps=["Q"]) + + # Type error in conversion + self.assertRaises(TypeError, Context, flags=(0,1)) + self.assertRaises(TypeError, Context, traps=(1,0)) + +class CContextInputValidation(ContextInputValidation): + decimal = C +class PyContextInputValidation(ContextInputValidation): + decimal = P + +class ContextSubclassing(unittest.TestCase): + + def test_context_subclassing(self): + decimal = self.decimal + Decimal = decimal.Decimal + Context = decimal.Context + ROUND_HALF_EVEN = decimal.ROUND_HALF_EVEN + ROUND_DOWN = decimal.ROUND_DOWN + Clamped = decimal.Clamped + DivisionByZero = decimal.DivisionByZero + Inexact = decimal.Inexact + Overflow = decimal.Overflow + Rounded = decimal.Rounded + Subnormal = decimal.Subnormal + Underflow = decimal.Underflow + InvalidOperation = decimal.InvalidOperation + + class MyContext(Context): + def __init__(self, prec=None, rounding=None, Emin=None, Emax=None, + capitals=None, clamp=None, flags=None, + traps=None): + Context.__init__(self) + if prec is not None: + self.prec = prec + if rounding is not None: + self.rounding = rounding + if Emin is not None: + self.Emin = Emin + if Emax is not None: + self.Emax = Emax + if capitals is not None: + self.capitals = capitals + if clamp is not None: + self.clamp = clamp + if flags is not None: + if isinstance(flags, list): + flags = {v:(v in flags) for v in OrderedSignals[decimal] + flags} + self.flags = flags + if traps is not None: + if isinstance(traps, list): + traps = {v:(v in traps) for v in OrderedSignals[decimal] + traps} + self.traps = traps + + c = Context() + d = MyContext() + for attr in ('prec', 'rounding', 'Emin', 'Emax', 'capitals', 'clamp', + 'flags', 'traps'): + self.assertEqual(getattr(c, attr), getattr(d, attr)) + + # prec + self.assertRaises(ValueError, MyContext, **{'prec':-1}) + c = MyContext(prec=1) + self.assertEqual(c.prec, 1) + self.assertRaises(InvalidOperation, c.quantize, Decimal('9e2'), 0) + + # rounding + self.assertRaises(TypeError, MyContext, **{'rounding':'XYZ'}) + c = MyContext(rounding=ROUND_DOWN, prec=1) + self.assertEqual(c.rounding, ROUND_DOWN) + self.assertEqual(c.plus(Decimal('9.9')), 9) + + # Emin + self.assertRaises(ValueError, MyContext, **{'Emin':5}) + c = MyContext(Emin=-1, prec=1) + self.assertEqual(c.Emin, -1) + x = c.add(Decimal('1e-99'), Decimal('2.234e-2000')) + self.assertEqual(x, Decimal('0.0')) + for signal in (Inexact, Underflow, Subnormal, Rounded, Clamped): + self.assertTrue(c.flags[signal]) + + # Emax + self.assertRaises(ValueError, MyContext, **{'Emax':-1}) + c = MyContext(Emax=1, prec=1) + self.assertEqual(c.Emax, 1) + self.assertRaises(Overflow, c.add, Decimal('1e99'), Decimal('2.234e2000')) + if self.decimal == C: + for signal in (Inexact, Overflow, Rounded): + self.assertTrue(c.flags[signal]) + + # capitals + self.assertRaises(ValueError, MyContext, **{'capitals':-1}) + c = MyContext(capitals=0) + self.assertEqual(c.capitals, 0) + x = c.create_decimal('1E222') + self.assertEqual(c.to_sci_string(x), '1e+222') + + # clamp + self.assertRaises(ValueError, MyContext, **{'clamp':2}) + c = MyContext(clamp=1, Emax=99) + self.assertEqual(c.clamp, 1) + x = c.plus(Decimal('1e99')) + self.assertEqual(str(x), '1.000000000000000000000000000E+99') + + # flags + self.assertRaises(TypeError, MyContext, **{'flags':'XYZ'}) + c = MyContext(flags=[Rounded, DivisionByZero]) + for signal in (Rounded, DivisionByZero): + self.assertTrue(c.flags[signal]) + c.clear_flags() + for signal in OrderedSignals[decimal]: + self.assertFalse(c.flags[signal]) + + # traps + self.assertRaises(TypeError, MyContext, **{'traps':'XYZ'}) + c = MyContext(traps=[Rounded, DivisionByZero]) + for signal in (Rounded, DivisionByZero): + self.assertTrue(c.traps[signal]) + c.clear_traps() + for signal in OrderedSignals[decimal]: + self.assertFalse(c.traps[signal]) + +class CContextSubclassing(ContextSubclassing): + decimal = C +class PyContextSubclassing(ContextSubclassing): + decimal = P + + at skip_if_extra_functionality +class CheckAttributes(unittest.TestCase): + + def test_module_attributes(self): + + # Architecture dependent context limits + self.assertEqual(C.MAX_PREC, P.MAX_PREC) + self.assertEqual(C.MAX_EMAX, P.MAX_EMAX) + self.assertEqual(C.MIN_EMIN, P.MIN_EMIN) + self.assertEqual(C.MIN_ETINY, P.MIN_ETINY) + + self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False) + self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False) + + self.assertEqual(C.__version__, P.__version__) + + x = dir(C) + y = [s for s in dir(P) if '__' in s or not s.startswith('_')] + self.assertEqual(set(x) - set(y), {'MallocError'}) + + def test_context_attributes(self): + + x = [s for s in dir(C.Context()) if '__' in s or not s.startswith('_')] + y = [s for s in dir(P.Context()) if '__' in s or not s.startswith('_')] + self.assertEqual(set(x) - set(y), set()) + + def test_decimal_attributes(self): + + x = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')] + y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')] + self.assertEqual(set(x) - set(y), set()) + +class Coverage(unittest.TestCase): + + def test_adjusted(self): + Decimal = self.decimal.Decimal + + self.assertEqual(Decimal('1234e9999').adjusted(), 10002) + # XXX raise? + self.assertEqual(Decimal('nan').adjusted(), 0) + self.assertEqual(Decimal('inf').adjusted(), 0) + + def test_canonical(self): + Decimal = self.decimal.Decimal + getcontext = self.decimal.getcontext + + x = Decimal(9).canonical() + self.assertEqual(x, 9) + + c = getcontext() + x = c.canonical(Decimal(9)) + self.assertEqual(x, 9) + + def test_context_repr(self): + c = self.decimal.DefaultContext.copy() + + c.prec = 425000000 + c.Emax = 425000000 + c.Emin = -425000000 + c.rounding = self.decimal.ROUND_HALF_DOWN + c.capitals = 0 + c.clamp = 1 + for sig in OrderedSignals[self.decimal]: + c.flags[sig] = False + c.traps[sig] = False + + s = c.__repr__() + t = "Context(prec=425000000, rounding=ROUND_HALF_DOWN, " \ + "Emin=-425000000, Emax=425000000, capitals=0, clamp=1, " \ + "flags=[], traps=[])" + self.assertEqual(s, t) + + def test_implicit_context(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + + with localcontext() as c: + c.prec = 1 + c.Emax = 1 + c.Emin = -1 + + # abs + self.assertEqual(abs(Decimal("-10")), 10) + # add + self.assertEqual(Decimal("7") + 1, 8) + # divide + self.assertEqual(Decimal("10") / 5, 2) + # divide_int + self.assertEqual(Decimal("10") // 7, 1) + # fma + self.assertEqual(Decimal("1.2").fma(Decimal("0.01"), 1), 1) + self.assertIs(Decimal("NaN").fma(7, 1).is_nan(), True) + # three arg power + self.assertEqual(pow(Decimal(10), 2, 7), 2) + # exp + self.assertEqual(Decimal("1.01").exp(), 3) + # is_normal + self.assertIs(Decimal("0.01").is_normal(), False) + # is_subnormal + self.assertIs(Decimal("0.01").is_subnormal(), True) + # ln + self.assertEqual(Decimal("20").ln(), 3) + # log10 + self.assertEqual(Decimal("20").log10(), 1) + # logb + self.assertEqual(Decimal("580").logb(), 2) + # logical_invert + self.assertEqual(Decimal("10").logical_invert(), 1) + # minus + self.assertEqual(-Decimal("-10"), 10) + # multiply + self.assertEqual(Decimal("2") * 4, 8) + # next_minus + self.assertEqual(Decimal("10").next_minus(), 9) + # next_plus + self.assertEqual(Decimal("10").next_plus(), Decimal('2E+1')) + # normalize + self.assertEqual(Decimal("-10").normalize(), Decimal('-1E+1')) + # number_class + self.assertEqual(Decimal("10").number_class(), '+Normal') + # plus + self.assertEqual(+Decimal("-1"), -1) + # remainder + self.assertEqual(Decimal("10") % 7, 3) + # subtract + self.assertEqual(Decimal("10") - 7, 3) + # to_integral_exact + self.assertEqual(Decimal("1.12345").to_integral_exact(), 1) + + # Boolean functions + self.assertTrue(Decimal("1").is_canonical()) + self.assertTrue(Decimal("1").is_finite()) + self.assertTrue(Decimal("1").is_finite()) + self.assertTrue(Decimal("snan").is_snan()) + self.assertTrue(Decimal("-1").is_signed()) + self.assertTrue(Decimal("0").is_zero()) + self.assertTrue(Decimal("0").is_zero()) + + # Copy + with localcontext() as c: + c.prec = 10000 + x = 1228 ** 1523 + y = -Decimal(x) + + z = y.copy_abs() + self.assertEqual(z, x) + + z = y.copy_negate() + self.assertEqual(z, x) + + z = y.copy_sign(Decimal(1)) + self.assertEqual(z, x) + + def test_divmod(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + InvalidOperation = self.decimal.InvalidOperation + DivisionByZero = self.decimal.DivisionByZero + + with localcontext() as c: + q, r = divmod(Decimal("10912837129"), 1001) + self.assertEqual(q, Decimal('10901935')) + self.assertEqual(r, Decimal('194')) + + q, r = divmod(Decimal("NaN"), 7) + self.assertTrue(q.is_nan() and r.is_nan()) + + c.traps[InvalidOperation] = False + q, r = divmod(Decimal("NaN"), 7) + self.assertTrue(q.is_nan() and r.is_nan()) + + c.traps[InvalidOperation] = False + c.clear_flags() + q, r = divmod(Decimal("inf"), Decimal("inf")) + self.assertTrue(q.is_nan() and r.is_nan()) + self.assertTrue(c.flags[InvalidOperation]) + + c.clear_flags() + q, r = divmod(Decimal("inf"), 101) + self.assertTrue(q.is_infinite() and r.is_nan()) + self.assertTrue(c.flags[InvalidOperation]) + + c.clear_flags() + q, r = divmod(Decimal(0), 0) + self.assertTrue(q.is_nan() and r.is_nan()) + self.assertTrue(c.flags[InvalidOperation]) + + c.traps[DivisionByZero] = False + c.clear_flags() + q, r = divmod(Decimal(11), 0) + self.assertTrue(q.is_infinite() and r.is_nan()) + self.assertTrue(c.flags[InvalidOperation] and + c.flags[DivisionByZero]) + + def test_power(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + Overflow = self.decimal.Overflow + Rounded = self.decimal.Rounded + + with localcontext() as c: + c.prec = 3 + c.clear_flags() + self.assertEqual(Decimal("1.0") ** 100, Decimal('1.00')) + self.assertTrue(c.flags[Rounded]) + + c.prec = 1 + c.Emax = 1 + c.Emin = -1 + c.clear_flags() + c.traps[Overflow] = False + self.assertEqual(Decimal(10000) ** Decimal("0.5"), Decimal('inf')) + self.assertTrue(c.flags[Overflow]) + + def test_quantize(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + InvalidOperation = self.decimal.InvalidOperation + + with localcontext() as c: + c.prec = 1 + c.Emax = 1 + c.Emin = -1 + c.traps[InvalidOperation] = False + x = Decimal(99).quantize(Decimal("1e1")) + self.assertTrue(x.is_nan()) + + def test_radix(self): + Decimal = self.decimal.Decimal + getcontext = self.decimal.getcontext + + c = getcontext() + self.assertEqual(Decimal("1").radix(), 10) + self.assertEqual(c.radix(), 10) + + def test_rop(self): + Decimal = self.decimal.Decimal + + for attr in ('__radd__', '__rsub__', '__rmul__', '__rtruediv__', + '__rdivmod__', '__rmod__', '__rfloordiv__', '__rpow__'): + self.assertIs(getattr(Decimal("1"), attr)("xyz"), NotImplemented) + + def test_round(self): + # Python3 behavior: round() returns Decimal + Decimal = self.decimal.Decimal + getcontext = self.decimal.getcontext + + c = getcontext() + c.prec = 28 + + self.assertEqual(str(Decimal("9.99").__round__()), "10") + self.assertEqual(str(Decimal("9.99e-5").__round__()), "0") + self.assertEqual(str(Decimal("1.23456789").__round__(5)), "1.23457") + self.assertEqual(str(Decimal("1.2345").__round__(10)), "1.2345000000") + self.assertEqual(str(Decimal("1.2345").__round__(-10)), "0E+10") + + self.assertRaises(TypeError, Decimal("1.23").__round__, "5") + self.assertRaises(TypeError, Decimal("1.23").__round__, 5, 8) + + def test_create_decimal(self): + c = self.decimal.Context() + self.assertRaises(ValueError, c.create_decimal, ["%"]) + + def test_int(self): + Decimal = self.decimal.Decimal + localcontext = self.decimal.localcontext + + with localcontext() as c: + c.prec = 9999 + x = Decimal(1221**1271) / 10**3923 + self.assertEqual(int(x), 1) + self.assertEqual(x.to_integral(), 2) + + def test_copy(self): + Context = self.decimal.Context + + c = Context() + c.prec = 10000 + x = -(1172 ** 1712) + + y = c.copy_abs(x) + self.assertEqual(y, -x) + + y = c.copy_negate(x) + self.assertEqual(y, -x) + + y = c.copy_sign(x, 1) + self.assertEqual(y, -x) + +class CCoverage(Coverage): + decimal = C +class PyCoverage(Coverage): + decimal = P + +class PyFunctionality(unittest.TestCase): + """Extra functionality in decimal.py""" + + def test_py_quantize_watchexp(self): + # watchexp functionality + Decimal = P.Decimal + localcontext = P.localcontext + + with localcontext() as c: + c.prec = 1 + c.Emax = 1 + c.Emin = -1 + x = Decimal(99999).quantize(Decimal("1e3"), watchexp=False) + self.assertEqual(x, Decimal('1.00E+5')) + + def test_py_alternate_formatting(self): + # triples giving a format, a Decimal, and the expected result + Decimal = P.Decimal + localcontext = P.localcontext + + test_values = [ + # Issue 7094: Alternate formatting (specified by #) + ('.0e', '1.0', '1e+0'), + ('#.0e', '1.0', '1.e+0'), + ('.0f', '1.0', '1'), + ('#.0f', '1.0', '1.'), + ('g', '1.1', '1.1'), + ('#g', '1.1', '1.1'), + ('.0g', '1', '1'), + ('#.0g', '1', '1.'), + ('.0%', '1.0', '100%'), + ('#.0%', '1.0', '100.%'), + ] + for fmt, d, result in test_values: + self.assertEqual(format(Decimal(d), fmt), result) + +class PyWhitebox(unittest.TestCase): + """White box testing for decimal.py""" + + def test_py_exact_power(self): + # Rarely exercised lines in _power_exact. + Decimal = P.Decimal + localcontext = P.localcontext + + with localcontext() as c: + c.prec = 8 + x = Decimal(2**16) ** Decimal("-0.5") + self.assertEqual(x, Decimal('0.00390625')) + + x = Decimal(2**16) ** Decimal("-0.6") + self.assertEqual(x, Decimal('0.0012885819')) + + x = Decimal("256e7") ** Decimal("-0.5") + + x = Decimal(152587890625) ** Decimal('-0.0625') + self.assertEqual(x, Decimal("0.2")) + + x = Decimal("152587890625e7") ** Decimal('-0.0625') + + x = Decimal(5**2659) ** Decimal('-0.0625') + + c.prec = 1 + x = Decimal("152587890625") ** Decimal('-0.5') + c.prec = 201 + x = Decimal(2**578) ** Decimal("-0.5") + + def test_py_immutability_operations(self): # Do operations and check that it didn't change change internal objects. + Decimal = P.Decimal + DefaultContext = P.DefaultContext + setcontext = P.setcontext + + c = DefaultContext.copy() + c.traps = dict((s, 0) for s in OrderedSignals[P]) + setcontext(c) d1 = Decimal('-25e55') b1 = Decimal('-25e55') @@ -1649,715 +4219,727 @@ checkSameDec("to_eng_string") checkSameDec("to_integral") - def test_subclassing(self): - # Different behaviours when subclassing Decimal - - class MyDecimal(Decimal): - pass - - d1 = MyDecimal(1) - d2 = MyDecimal(2) - d = d1 + d2 - self.assertIs(type(d), Decimal) - - d = d1.max(d2) - self.assertIs(type(d), Decimal) - - def test_implicit_context(self): - # Check results when context given implicitly. (Issue 2478) - c = getcontext() - self.assertEqual(str(Decimal(0).sqrt()), - str(c.sqrt(Decimal(0)))) - - def test_conversions_from_int(self): - # Check that methods taking a second Decimal argument will - # always accept an integer in place of a Decimal. - self.assertEqual(Decimal(4).compare(3), - Decimal(4).compare(Decimal(3))) - self.assertEqual(Decimal(4).compare_signal(3), - Decimal(4).compare_signal(Decimal(3))) - self.assertEqual(Decimal(4).compare_total(3), - Decimal(4).compare_total(Decimal(3))) - self.assertEqual(Decimal(4).compare_total_mag(3), - Decimal(4).compare_total_mag(Decimal(3))) - self.assertEqual(Decimal(10101).logical_and(1001), - Decimal(10101).logical_and(Decimal(1001))) - self.assertEqual(Decimal(10101).logical_or(1001), - Decimal(10101).logical_or(Decimal(1001))) - self.assertEqual(Decimal(10101).logical_xor(1001), - Decimal(10101).logical_xor(Decimal(1001))) - self.assertEqual(Decimal(567).max(123), - Decimal(567).max(Decimal(123))) - self.assertEqual(Decimal(567).max_mag(123), - Decimal(567).max_mag(Decimal(123))) - self.assertEqual(Decimal(567).min(123), - Decimal(567).min(Decimal(123))) - self.assertEqual(Decimal(567).min_mag(123), - Decimal(567).min_mag(Decimal(123))) - self.assertEqual(Decimal(567).next_toward(123), - Decimal(567).next_toward(Decimal(123))) - self.assertEqual(Decimal(1234).quantize(100), - Decimal(1234).quantize(Decimal(100))) - self.assertEqual(Decimal(768).remainder_near(1234), - Decimal(768).remainder_near(Decimal(1234))) - self.assertEqual(Decimal(123).rotate(1), - Decimal(123).rotate(Decimal(1))) - self.assertEqual(Decimal(1234).same_quantum(1000), - Decimal(1234).same_quantum(Decimal(1000))) - self.assertEqual(Decimal('9.123').scaleb(-100), - Decimal('9.123').scaleb(Decimal(-100))) - self.assertEqual(Decimal(456).shift(-1), - Decimal(456).shift(Decimal(-1))) - - self.assertEqual(Decimal(-12).fma(Decimal(45), 67), - Decimal(-12).fma(Decimal(45), Decimal(67))) - self.assertEqual(Decimal(-12).fma(45, 67), - Decimal(-12).fma(Decimal(45), Decimal(67))) - self.assertEqual(Decimal(-12).fma(45, Decimal(67)), - Decimal(-12).fma(Decimal(45), Decimal(67))) - - -class DecimalPythonAPItests(unittest.TestCase): - - def test_abc(self): - self.assertTrue(issubclass(Decimal, numbers.Number)) - self.assertFalse(issubclass(Decimal, numbers.Real)) - self.assertIsInstance(Decimal(0), numbers.Number) - self.assertNotIsInstance(Decimal(0), numbers.Real) - - def test_pickle(self): - d = Decimal('-3.141590000') - p = pickle.dumps(d) - e = pickle.loads(p) - self.assertEqual(d, e) - - def test_int(self): - for x in range(-250, 250): - s = '%0.2f' % (x / 100.0) - # should work the same as for floats - self.assertEqual(int(Decimal(s)), int(float(s))) - # should work the same as to_integral in the ROUND_DOWN mode - d = Decimal(s) - r = d.to_integral(ROUND_DOWN) - self.assertEqual(Decimal(int(d)), r) - - self.assertRaises(ValueError, int, Decimal('-nan')) - self.assertRaises(ValueError, int, Decimal('snan')) - self.assertRaises(OverflowError, int, Decimal('inf')) - self.assertRaises(OverflowError, int, Decimal('-inf')) - - def test_trunc(self): - for x in range(-250, 250): - s = '%0.2f' % (x / 100.0) - # should work the same as for floats - self.assertEqual(int(Decimal(s)), int(float(s))) - # should work the same as to_integral in the ROUND_DOWN mode - d = Decimal(s) - r = d.to_integral(ROUND_DOWN) - self.assertEqual(Decimal(math.trunc(d)), r) - - def test_from_float(self): - - class MyDecimal(Decimal): - pass - - r = MyDecimal.from_float(0.1) - self.assertEqual(type(r), MyDecimal) - self.assertEqual(str(r), - '0.1000000000000000055511151231257827021181583404541015625') - bigint = 12345678901234567890123456789 - self.assertEqual(MyDecimal.from_float(bigint), MyDecimal(bigint)) - self.assertTrue(MyDecimal.from_float(float('nan')).is_qnan()) - self.assertTrue(MyDecimal.from_float(float('inf')).is_infinite()) - self.assertTrue(MyDecimal.from_float(float('-inf')).is_infinite()) - self.assertEqual(str(MyDecimal.from_float(float('nan'))), - str(Decimal('NaN'))) - self.assertEqual(str(MyDecimal.from_float(float('inf'))), - str(Decimal('Infinity'))) - self.assertEqual(str(MyDecimal.from_float(float('-inf'))), - str(Decimal('-Infinity'))) - self.assertRaises(TypeError, MyDecimal.from_float, 'abc') - for i in range(200): - x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) - self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip - - def test_create_decimal_from_float(self): - context = Context(prec=5, rounding=ROUND_DOWN) + def test_py_decimal_id(self): + Decimal = P.Decimal + + d = Decimal(45) + e = Decimal(d) + self.assertEqual(str(e), '45') + self.assertNotEqual(id(d), id(e)) + + def test_py_rescale(self): + # Coverage + Decimal = P.Decimal + ROUND_UP = P.ROUND_UP + localcontext = P.localcontext + + with localcontext() as c: + x = Decimal("NaN")._rescale(3, ROUND_UP) + self.assertTrue(x.is_nan()) + + def test_py__round(self): + # Coverage + Decimal = P.Decimal + ROUND_UP = P.ROUND_UP + + self.assertRaises(ValueError, Decimal("3.1234")._round, 0, ROUND_UP) + +class CFunctionality(unittest.TestCase): + """Extra functionality in _decimal""" + + @requires_extra_functionality + def test_c_ieee_context(self): + # issue 8786: Add support for IEEE 754 contexts to decimal module. + IEEEContext = C.IEEEContext + DECIMAL32 = C.DECIMAL32 + DECIMAL64 = C.DECIMAL64 + DECIMAL128 = C.DECIMAL128 + + def assert_rest(self, context): + self.assertEqual(context.clamp, 1) + assert_signals(self, context, 'traps', []) + assert_signals(self, context, 'flags', []) + + c = IEEEContext(DECIMAL32) + self.assertEqual(c.prec, 7) + self.assertEqual(c.Emax, 96) + self.assertEqual(c.Emin, -95) + assert_rest(self, c) + + c = IEEEContext(DECIMAL64) + self.assertEqual(c.prec, 16) + self.assertEqual(c.Emax, 384) + self.assertEqual(c.Emin, -383) + assert_rest(self, c) + + c = IEEEContext(DECIMAL128) + self.assertEqual(c.prec, 34) + self.assertEqual(c.Emax, 6144) + self.assertEqual(c.Emin, -6143) + assert_rest(self, c) + + # Invalid values + self.assertRaises(OverflowError, IEEEContext, 2**63) + self.assertRaises(ValueError, IEEEContext, -1) + self.assertRaises(ValueError, IEEEContext, 1024) + + @requires_extra_functionality + def test_c_context(self): + Context = C.Context + + c = Context(flags=C.DecClamped, traps=C.DecRounded) + self.assertEqual(c._flags, C.DecClamped) + self.assertEqual(c._traps, C.DecRounded) + + @requires_extra_functionality + def test_constants(self): + # Condition flags + cond = ( + C.DecClamped, C.DecConversionSyntax, C.DecDivisionByZero, + C.DecDivisionImpossible, C.DecDivisionUndefined, + C.DecFpuError, C.DecInexact, C.DecInvalidContext, + C.DecInvalidOperation, C.DecMallocError, + C.DecFloatOperation, C.DecOverflow, C.DecRounded, + C.DecSubnormal, C.DecUnderflow + ) + + # IEEEContext + self.assertEqual(C.DECIMAL32, 32) + self.assertEqual(C.DECIMAL64, 64) + self.assertEqual(C.DECIMAL128, 128) + self.assertEqual(C.IEEE_CONTEXT_MAX_BITS, 512) + + # Rounding modes + for i, v in enumerate(RoundingModes[C]): + self.assertEqual(v, i) + self.assertEqual(C.ROUND_TRUNC, 8) + + # Conditions + for i, v in enumerate(cond): + self.assertEqual(v, 1< 425000000) + + c = Context() + + # SignalDict: input validation + self.assertRaises(KeyError, c.flags.__setitem__, 801, 0) + self.assertRaises(KeyError, c.traps.__setitem__, 801, 0) + self.assertRaises(ValueError, c.flags.__delitem__, Overflow) + self.assertRaises(ValueError, c.traps.__delitem__, InvalidOperation) + self.assertRaises(TypeError, setattr, c, 'flags', ['x']) + self.assertRaises(TypeError, setattr, c,'traps', ['y']) + self.assertRaises(KeyError, setattr, c, 'flags', {0:1}) + self.assertRaises(KeyError, setattr, c, 'traps', {0:1}) + + # Test assignment from a signal dict with the correct length but + # one invalid key. + d = c.flags.copy() + del d[FloatOperation] + d["XYZ"] = 91283719 + self.assertRaises(KeyError, setattr, c, 'flags', d) + self.assertRaises(KeyError, setattr, c, 'traps', d) + + # Input corner cases + int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1 + gt_max_emax = 10**18 if HAVE_CONFIG_64 else 10**9 + + # prec, Emax, Emin + for attr in ['prec', 'Emax']: + self.assertRaises(ValueError, setattr, c, attr, gt_max_emax) + self.assertRaises(ValueError, setattr, c, 'Emin', -gt_max_emax) + + # prec, Emax, Emin in context constructor + self.assertRaises(ValueError, Context, prec=gt_max_emax) + self.assertRaises(ValueError, Context, Emax=gt_max_emax) + self.assertRaises(ValueError, Context, Emin=-gt_max_emax) + + # Overflow in conversion + self.assertRaises(OverflowError, Context, prec=int_max+1) + self.assertRaises(OverflowError, Context, Emax=int_max+1) + self.assertRaises(OverflowError, Context, Emin=-int_max-2) + self.assertRaises(OverflowError, Context, rounding=int_max+1) + self.assertRaises(OverflowError, Context, clamp=int_max+1) + self.assertRaises(OverflowError, Context, capitals=int_max+1) + + # OverflowError, general ValueError + for attr in ('prec', 'Emin', 'Emax', 'capitals', 'clamp'): + self.assertRaises(OverflowError, setattr, c, attr, int_max+1) + self.assertRaises(OverflowError, setattr, c, attr, -int_max-2) + if sys.platform != 'win32': + self.assertRaises(ValueError, setattr, c, attr, int_max) + self.assertRaises(ValueError, setattr, c, attr, -int_max-1) + + # OverflowError, general TypeError + for attr in ('rounding',): + self.assertRaises(OverflowError, setattr, c, attr, int_max+1) + self.assertRaises(OverflowError, setattr, c, attr, -int_max-2) + if sys.platform != 'win32': + self.assertRaises(TypeError, setattr, c, attr, int_max) + self.assertRaises(TypeError, setattr, c, attr, -int_max-1) + + # OverflowError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax + if C.MAX_PREC == 425000000: + self.assertRaises(OverflowError, getattr(c, '_unsafe_setprec'), + int_max+1) + self.assertRaises(OverflowError, getattr(c, '_unsafe_setemax'), + int_max+1) + self.assertRaises(OverflowError, getattr(c, '_unsafe_setemin'), + -int_max-2) + + # ValueError: _unsafe_setprec, _unsafe_setemin, _unsafe_setemax + if C.MAX_PREC == 425000000: + self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'), 0) + self.assertRaises(ValueError, getattr(c, '_unsafe_setprec'), + 1070000001) + self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'), -1) + self.assertRaises(ValueError, getattr(c, '_unsafe_setemax'), + 1070000001) + self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'), + -1070000001) + self.assertRaises(ValueError, getattr(c, '_unsafe_setemin'), 1) + + # capitals, clamp + for attr in ['capitals', 'clamp']: + self.assertRaises(ValueError, setattr, c, attr, -1) + self.assertRaises(ValueError, setattr, c, attr, 2) + self.assertRaises(TypeError, setattr, c, attr, [1,2,3]) + if HAVE_CONFIG_64: + self.assertRaises(ValueError, setattr, c, attr, 2**32) + self.assertRaises(ValueError, setattr, c, attr, 2**32+1) + + # Invalid local context + self.assertRaises(TypeError, exec, 'with localcontext("xyz"): pass', + locals()) + + # setcontext + saved_context = getcontext() + self.assertRaises(TypeError, setcontext, "xyz") + setcontext(saved_context) + + @requires_extra_functionality + def test_c_context_errors_extra(self): + Context = C.Context + InvalidOperation = C.InvalidOperation + Overflow = C.Overflow + localcontext = C.localcontext + getcontext = C.getcontext + setcontext = C.setcontext + HAVE_CONFIG_64 = (C.MAX_PREC > 425000000) + + c = Context() + + # Input corner cases + int_max = 2**63-1 if HAVE_CONFIG_64 else 2**31-1 + + # OverflowError, general ValueError + self.assertRaises(OverflowError, setattr, c, '_allcr', int_max+1) + self.assertRaises(OverflowError, setattr, c, '_allcr', -int_max-2) + if sys.platform != 'win32': + self.assertRaises(ValueError, setattr, c, '_allcr', int_max) + self.assertRaises(ValueError, setattr, c, '_allcr', -int_max-1) + + # OverflowError, general TypeError + for attr in ('_flags', '_traps'): + self.assertRaises(OverflowError, setattr, c, attr, int_max+1) + self.assertRaises(OverflowError, setattr, c, attr, -int_max-2) + if sys.platform != 'win32': + self.assertRaises(TypeError, setattr, c, attr, int_max) + self.assertRaises(TypeError, setattr, c, attr, -int_max-1) + + # _allcr + self.assertRaises(ValueError, setattr, c, '_allcr', -1) + self.assertRaises(ValueError, setattr, c, '_allcr', 2) + self.assertRaises(TypeError, setattr, c, '_allcr', [1,2,3]) + if HAVE_CONFIG_64: + self.assertRaises(ValueError, setattr, c, '_allcr', 2**32) + self.assertRaises(ValueError, setattr, c, '_allcr', 2**32+1) + + # _flags, _traps + for attr in ['_flags', '_traps']: + self.assertRaises(TypeError, setattr, c, attr, 999999) + self.assertRaises(TypeError, setattr, c, attr, 'x') + + def test_c_valid_context(self): + # These tests are for code coverage in _decimal. + DefaultContext = C.DefaultContext + ROUND_HALF_UP = C.ROUND_HALF_UP + Clamped = C.Clamped + Underflow = C.Underflow + Inexact = C.Inexact + Rounded = C.Rounded + Subnormal = C.Subnormal + + c = DefaultContext.copy() + + # Exercise all getters and setters + c.prec = 34 + c.rounding = ROUND_HALF_UP + c.Emax = 3000 + c.Emin = -3000 + c.capitals = 1 + c.clamp = 0 + + self.assertEqual(c.prec, 34) + self.assertEqual(c.rounding, ROUND_HALF_UP) + self.assertEqual(c.Emin, -3000) + self.assertEqual(c.Emax, 3000) + self.assertEqual(c.capitals, 1) + self.assertEqual(c.clamp, 0) + + self.assertEqual(c.Etiny(), -3033) + self.assertEqual(c.Etop(), 2967) + + # Exercise all unsafe setters + if C.MAX_PREC == 425000000: + c._unsafe_setprec(999999999) + c._unsafe_setemax(999999999) + c._unsafe_setemin(-999999999) + self.assertEqual(c.prec, 999999999) + self.assertEqual(c.Emax, 999999999) + self.assertEqual(c.Emin, -999999999) + + @requires_extra_functionality + def test_c_valid_context_extra(self): + DefaultContext = C.DefaultContext + + c = DefaultContext.copy() + self.assertEqual(c._allcr, 1) + c._allcr = 0 + self.assertEqual(c._allcr, 0) + + def test_c_round(self): + # Restricted input. + Decimal = C.Decimal + InvalidOperation = C.InvalidOperation + localcontext = C.localcontext + MAX_EMAX = C.MAX_EMAX + MIN_ETINY = C.MIN_ETINY + int_max = 2**63-1 if C.MAX_PREC > 425000000 else 2**31-1 + + with localcontext() as c: + c.traps[InvalidOperation] = True + self.assertRaises(InvalidOperation, Decimal("1.23").__round__, + -int_max-1) + self.assertRaises(InvalidOperation, Decimal("1.23").__round__, + int_max) + self.assertRaises(InvalidOperation, Decimal("1").__round__, + int(MAX_EMAX+1)) + self.assertRaises(C.InvalidOperation, Decimal("1").__round__, + -int(MIN_ETINY-1)) + self.assertRaises(OverflowError, Decimal("1.23").__round__, + -int_max-2) + self.assertRaises(OverflowError, Decimal("1.23").__round__, + int_max+1) + + def test_c_format(self): + # Restricted input + Decimal = C.Decimal + InvalidOperation = C.InvalidOperation + Rounded = C.Rounded + localcontext = C.localcontext + HAVE_CONFIG_64 = (C.MAX_PREC > 425000000) + + self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", [], 9) + self.assertRaises(TypeError, Decimal(1).__format__, "=10.10", 9) + self.assertRaises(TypeError, Decimal(1).__format__, []) + + with localcontext() as c: + c.traps[InvalidOperation] = True + c.traps[Rounded] = True + self.assertRaises(ValueError, Decimal(1).__format__, "<>=10.10") + maxsize = 2**63-1 if HAVE_CONFIG_64 else 2**31-1 + self.assertRaises(InvalidOperation, Decimal("1.23456789").__format__, + "=%d.1" % maxsize) + + def test_c_integral(self): + Decimal = C.Decimal + Inexact = C.Inexact + ROUND_UP = C.ROUND_UP + localcontext = C.localcontext + + x = Decimal(10) + self.assertEqual(x.to_integral(), 10) + self.assertRaises(TypeError, x.to_integral, '10') + self.assertRaises(TypeError, x.to_integral, 10, 'x') + self.assertRaises(TypeError, x.to_integral, 10) + + self.assertEqual(x.to_integral_value(), 10) + self.assertRaises(TypeError, x.to_integral_value, '10') + self.assertRaises(TypeError, x.to_integral_value, 10, 'x') + self.assertRaises(TypeError, x.to_integral_value, 10) + + self.assertEqual(x.to_integral_exact(), 10) + self.assertRaises(TypeError, x.to_integral_exact, '10') + self.assertRaises(TypeError, x.to_integral_exact, 10, 'x') + self.assertRaises(TypeError, x.to_integral_exact, 10) + + with localcontext() as c: + x = Decimal("99999999999999999999999999.9").to_integral_value(ROUND_UP) + self.assertEqual(x, Decimal('100000000000000000000000000')) + + x = Decimal("99999999999999999999999999.9").to_integral_exact(ROUND_UP) + self.assertEqual(x, Decimal('100000000000000000000000000')) + + c.traps[Inexact] = True + self.assertRaises(Inexact, Decimal("999.9").to_integral_exact, ROUND_UP) + + def test_c_funcs(self): + # Invalid arguments + Decimal = C.Decimal + InvalidOperation = C.InvalidOperation + DivisionByZero = C.DivisionByZero + ROUND_UP = C.ROUND_UP + getcontext = C.getcontext + localcontext = C.localcontext + + self.assertEqual(Decimal('9.99e10').to_eng_string(), '99.9E+9') + + self.assertRaises(TypeError, pow, Decimal(1), 2, "3") + self.assertRaises(TypeError, Decimal(9).number_class, "x", "y") + self.assertRaises(TypeError, Decimal(9).same_quantum, 3, "x", "y") + + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), [] + ) + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), getcontext() + ) + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), 10 + ) + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), ROUND_UP, 1000 + ) + + with localcontext() as c: + c.clear_traps() + + # Invalid arguments + self.assertRaises(TypeError, c.copy_sign, Decimal(1), "x", "y") + self.assertRaises(TypeError, c.canonical, 200) + self.assertRaises(TypeError, c.is_canonical, 200) + self.assertRaises(TypeError, c.divmod, 9, 8, "x", "y") + self.assertRaises(TypeError, c.same_quantum, 9, 3, "x", "y") + + self.assertEqual(str(c.canonical(Decimal(200))), '200') + self.assertEqual(c.radix(), 10) + + c.traps[DivisionByZero] = True + self.assertRaises(DivisionByZero, Decimal(9).__divmod__, 0) + self.assertRaises(DivisionByZero, c.divmod, 9, 0) + self.assertTrue(c.flags[InvalidOperation]) + + c.clear_flags() + c.traps[InvalidOperation] = True + self.assertRaises(InvalidOperation, Decimal(9).__divmod__, 0) + self.assertRaises(InvalidOperation, c.divmod, 9, 0) + self.assertTrue(c.flags[DivisionByZero]) + + c.traps[InvalidOperation] = True + c.prec = 2 + self.assertRaises(InvalidOperation, pow, Decimal(1000), 1, 501) + + @requires_extra_functionality + def test_c_context_templates(self): self.assertEqual( - context.create_decimal_from_float(math.pi), - Decimal('3.1415') + C.BasicContext._traps, + C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow| + C.DecUnderflow|C.DecClamped ) - context = Context(prec=5, rounding=ROUND_UP) self.assertEqual( - context.create_decimal_from_float(math.pi), - Decimal('3.1416') + C.DefaultContext._traps, + C.DecIEEEInvalidOperation|C.DecDivisionByZero|C.DecOverflow ) - context = Context(prec=5, traps=[Inexact]) - self.assertRaises( - Inexact, - context.create_decimal_from_float, - math.pi - ) - self.assertEqual(repr(context.create_decimal_from_float(-0.0)), - "Decimal('-0')") - self.assertEqual(repr(context.create_decimal_from_float(1.0)), - "Decimal('1')") - self.assertEqual(repr(context.create_decimal_from_float(10)), - "Decimal('10')") - -class ContextAPItests(unittest.TestCase): - - def test_pickle(self): - c = Context() - e = pickle.loads(pickle.dumps(c)) - for k in vars(c): - v1 = vars(c)[k] - v2 = vars(e)[k] - self.assertEqual(v1, v2) - - def test_equality_with_other_types(self): - self.assertIn(Decimal(10), ['a', 1.0, Decimal(10), (1,2), {}]) - self.assertNotIn(Decimal(10), ['a', 1.0, (1,2), {}]) - - def test_copy(self): - # All copies should be deep - c = Context() - d = c.copy() - self.assertNotEqual(id(c), id(d)) - self.assertNotEqual(id(c.flags), id(d.flags)) - self.assertNotEqual(id(c.traps), id(d.traps)) - - def test__clamp(self): - # In Python 3.2, the private attribute `_clamp` was made - # public (issue 8540), with the old `_clamp` becoming a - # property wrapping `clamp`. For the duration of Python 3.2 - # only, the attribute should be gettable/settable via both - # `clamp` and `_clamp`; in Python 3.3, `_clamp` should be - # removed. - c = Context() - with self.assertRaises(AttributeError): - clamp_value = c._clamp - - def test_abs(self): - c = Context() - d = c.abs(Decimal(-1)) - self.assertEqual(c.abs(-1), d) - self.assertRaises(TypeError, c.abs, '-1') - - def test_add(self): - c = Context() - d = c.add(Decimal(1), Decimal(1)) - self.assertEqual(c.add(1, 1), d) - self.assertEqual(c.add(Decimal(1), 1), d) - self.assertEqual(c.add(1, Decimal(1)), d) - self.assertRaises(TypeError, c.add, '1', 1) - self.assertRaises(TypeError, c.add, 1, '1') - - def test_compare(self): - c = Context() - d = c.compare(Decimal(1), Decimal(1)) - self.assertEqual(c.compare(1, 1), d) - self.assertEqual(c.compare(Decimal(1), 1), d) - self.assertEqual(c.compare(1, Decimal(1)), d) - self.assertRaises(TypeError, c.compare, '1', 1) - self.assertRaises(TypeError, c.compare, 1, '1') - - def test_compare_signal(self): - c = Context() - d = c.compare_signal(Decimal(1), Decimal(1)) - self.assertEqual(c.compare_signal(1, 1), d) - self.assertEqual(c.compare_signal(Decimal(1), 1), d) - self.assertEqual(c.compare_signal(1, Decimal(1)), d) - self.assertRaises(TypeError, c.compare_signal, '1', 1) - self.assertRaises(TypeError, c.compare_signal, 1, '1') - - def test_compare_total(self): - c = Context() - d = c.compare_total(Decimal(1), Decimal(1)) - self.assertEqual(c.compare_total(1, 1), d) - self.assertEqual(c.compare_total(Decimal(1), 1), d) - self.assertEqual(c.compare_total(1, Decimal(1)), d) - self.assertRaises(TypeError, c.compare_total, '1', 1) - self.assertRaises(TypeError, c.compare_total, 1, '1') - - def test_compare_total_mag(self): - c = Context() - d = c.compare_total_mag(Decimal(1), Decimal(1)) - self.assertEqual(c.compare_total_mag(1, 1), d) - self.assertEqual(c.compare_total_mag(Decimal(1), 1), d) - self.assertEqual(c.compare_total_mag(1, Decimal(1)), d) - self.assertRaises(TypeError, c.compare_total_mag, '1', 1) - self.assertRaises(TypeError, c.compare_total_mag, 1, '1') - - def test_copy_abs(self): - c = Context() - d = c.copy_abs(Decimal(-1)) - self.assertEqual(c.copy_abs(-1), d) - self.assertRaises(TypeError, c.copy_abs, '-1') - - def test_copy_decimal(self): - c = Context() - d = c.copy_decimal(Decimal(-1)) - self.assertEqual(c.copy_decimal(-1), d) - self.assertRaises(TypeError, c.copy_decimal, '-1') - - def test_copy_negate(self): - c = Context() - d = c.copy_negate(Decimal(-1)) - self.assertEqual(c.copy_negate(-1), d) - self.assertRaises(TypeError, c.copy_negate, '-1') - - def test_copy_sign(self): - c = Context() - d = c.copy_sign(Decimal(1), Decimal(-2)) - self.assertEqual(c.copy_sign(1, -2), d) - self.assertEqual(c.copy_sign(Decimal(1), -2), d) - self.assertEqual(c.copy_sign(1, Decimal(-2)), d) - self.assertRaises(TypeError, c.copy_sign, '1', -2) - self.assertRaises(TypeError, c.copy_sign, 1, '-2') - - def test_divide(self): - c = Context() - d = c.divide(Decimal(1), Decimal(2)) - self.assertEqual(c.divide(1, 2), d) - self.assertEqual(c.divide(Decimal(1), 2), d) - self.assertEqual(c.divide(1, Decimal(2)), d) - self.assertRaises(TypeError, c.divide, '1', 2) - self.assertRaises(TypeError, c.divide, 1, '2') - - def test_divide_int(self): - c = Context() - d = c.divide_int(Decimal(1), Decimal(2)) - self.assertEqual(c.divide_int(1, 2), d) - self.assertEqual(c.divide_int(Decimal(1), 2), d) - self.assertEqual(c.divide_int(1, Decimal(2)), d) - self.assertRaises(TypeError, c.divide_int, '1', 2) - self.assertRaises(TypeError, c.divide_int, 1, '2') - - def test_divmod(self): - c = Context() - d = c.divmod(Decimal(1), Decimal(2)) - self.assertEqual(c.divmod(1, 2), d) - self.assertEqual(c.divmod(Decimal(1), 2), d) - self.assertEqual(c.divmod(1, Decimal(2)), d) - self.assertRaises(TypeError, c.divmod, '1', 2) - self.assertRaises(TypeError, c.divmod, 1, '2') - - def test_exp(self): - c = Context() - d = c.exp(Decimal(10)) - self.assertEqual(c.exp(10), d) - self.assertRaises(TypeError, c.exp, '10') - - def test_fma(self): - c = Context() - d = c.fma(Decimal(2), Decimal(3), Decimal(4)) - self.assertEqual(c.fma(2, 3, 4), d) - self.assertEqual(c.fma(Decimal(2), 3, 4), d) - self.assertEqual(c.fma(2, Decimal(3), 4), d) - self.assertEqual(c.fma(2, 3, Decimal(4)), d) - self.assertEqual(c.fma(Decimal(2), Decimal(3), 4), d) - self.assertRaises(TypeError, c.fma, '2', 3, 4) - self.assertRaises(TypeError, c.fma, 2, '3', 4) - self.assertRaises(TypeError, c.fma, 2, 3, '4') - - # Issue 12079 for Context.fma ... - self.assertRaises(TypeError, c.fma, - Decimal('Infinity'), Decimal(0), "not a decimal") - self.assertRaises(TypeError, c.fma, - Decimal(1), Decimal('snan'), 1.222) - # ... and for Decimal.fma. - self.assertRaises(TypeError, Decimal('Infinity').fma, - Decimal(0), "not a decimal") - self.assertRaises(TypeError, Decimal(1).fma, - Decimal('snan'), 1.222) - - def test_is_finite(self): - c = Context() - d = c.is_finite(Decimal(10)) - self.assertEqual(c.is_finite(10), d) - self.assertRaises(TypeError, c.is_finite, '10') - - def test_is_infinite(self): - c = Context() - d = c.is_infinite(Decimal(10)) - self.assertEqual(c.is_infinite(10), d) - self.assertRaises(TypeError, c.is_infinite, '10') - - def test_is_nan(self): - c = Context() - d = c.is_nan(Decimal(10)) - self.assertEqual(c.is_nan(10), d) - self.assertRaises(TypeError, c.is_nan, '10') - - def test_is_normal(self): - c = Context() - d = c.is_normal(Decimal(10)) - self.assertEqual(c.is_normal(10), d) - self.assertRaises(TypeError, c.is_normal, '10') - - def test_is_qnan(self): - c = Context() - d = c.is_qnan(Decimal(10)) - self.assertEqual(c.is_qnan(10), d) - self.assertRaises(TypeError, c.is_qnan, '10') - - def test_is_signed(self): - c = Context() - d = c.is_signed(Decimal(10)) - self.assertEqual(c.is_signed(10), d) - self.assertRaises(TypeError, c.is_signed, '10') - - def test_is_snan(self): - c = Context() - d = c.is_snan(Decimal(10)) - self.assertEqual(c.is_snan(10), d) - self.assertRaises(TypeError, c.is_snan, '10') - - def test_is_subnormal(self): - c = Context() - d = c.is_subnormal(Decimal(10)) - self.assertEqual(c.is_subnormal(10), d) - self.assertRaises(TypeError, c.is_subnormal, '10') - - def test_is_zero(self): - c = Context() - d = c.is_zero(Decimal(10)) - self.assertEqual(c.is_zero(10), d) - self.assertRaises(TypeError, c.is_zero, '10') - - def test_ln(self): - c = Context() - d = c.ln(Decimal(10)) - self.assertEqual(c.ln(10), d) - self.assertRaises(TypeError, c.ln, '10') - - def test_log10(self): - c = Context() - d = c.log10(Decimal(10)) - self.assertEqual(c.log10(10), d) - self.assertRaises(TypeError, c.log10, '10') - - def test_logb(self): - c = Context() - d = c.logb(Decimal(10)) - self.assertEqual(c.logb(10), d) - self.assertRaises(TypeError, c.logb, '10') - - def test_logical_and(self): - c = Context() - d = c.logical_and(Decimal(1), Decimal(1)) - self.assertEqual(c.logical_and(1, 1), d) - self.assertEqual(c.logical_and(Decimal(1), 1), d) - self.assertEqual(c.logical_and(1, Decimal(1)), d) - self.assertRaises(TypeError, c.logical_and, '1', 1) - self.assertRaises(TypeError, c.logical_and, 1, '1') - - def test_logical_invert(self): - c = Context() - d = c.logical_invert(Decimal(1000)) - self.assertEqual(c.logical_invert(1000), d) - self.assertRaises(TypeError, c.logical_invert, '1000') - - def test_logical_or(self): - c = Context() - d = c.logical_or(Decimal(1), Decimal(1)) - self.assertEqual(c.logical_or(1, 1), d) - self.assertEqual(c.logical_or(Decimal(1), 1), d) - self.assertEqual(c.logical_or(1, Decimal(1)), d) - self.assertRaises(TypeError, c.logical_or, '1', 1) - self.assertRaises(TypeError, c.logical_or, 1, '1') - - def test_logical_xor(self): - c = Context() - d = c.logical_xor(Decimal(1), Decimal(1)) - self.assertEqual(c.logical_xor(1, 1), d) - self.assertEqual(c.logical_xor(Decimal(1), 1), d) - self.assertEqual(c.logical_xor(1, Decimal(1)), d) - self.assertRaises(TypeError, c.logical_xor, '1', 1) - self.assertRaises(TypeError, c.logical_xor, 1, '1') - - def test_max(self): - c = Context() - d = c.max(Decimal(1), Decimal(2)) - self.assertEqual(c.max(1, 2), d) - self.assertEqual(c.max(Decimal(1), 2), d) - self.assertEqual(c.max(1, Decimal(2)), d) - self.assertRaises(TypeError, c.max, '1', 2) - self.assertRaises(TypeError, c.max, 1, '2') - - def test_max_mag(self): - c = Context() - d = c.max_mag(Decimal(1), Decimal(2)) - self.assertEqual(c.max_mag(1, 2), d) - self.assertEqual(c.max_mag(Decimal(1), 2), d) - self.assertEqual(c.max_mag(1, Decimal(2)), d) - self.assertRaises(TypeError, c.max_mag, '1', 2) - self.assertRaises(TypeError, c.max_mag, 1, '2') - - def test_min(self): - c = Context() - d = c.min(Decimal(1), Decimal(2)) - self.assertEqual(c.min(1, 2), d) - self.assertEqual(c.min(Decimal(1), 2), d) - self.assertEqual(c.min(1, Decimal(2)), d) - self.assertRaises(TypeError, c.min, '1', 2) - self.assertRaises(TypeError, c.min, 1, '2') - - def test_min_mag(self): - c = Context() - d = c.min_mag(Decimal(1), Decimal(2)) - self.assertEqual(c.min_mag(1, 2), d) - self.assertEqual(c.min_mag(Decimal(1), 2), d) - self.assertEqual(c.min_mag(1, Decimal(2)), d) - self.assertRaises(TypeError, c.min_mag, '1', 2) - self.assertRaises(TypeError, c.min_mag, 1, '2') - - def test_minus(self): - c = Context() - d = c.minus(Decimal(10)) - self.assertEqual(c.minus(10), d) - self.assertRaises(TypeError, c.minus, '10') - - def test_multiply(self): - c = Context() - d = c.multiply(Decimal(1), Decimal(2)) - self.assertEqual(c.multiply(1, 2), d) - self.assertEqual(c.multiply(Decimal(1), 2), d) - self.assertEqual(c.multiply(1, Decimal(2)), d) - self.assertRaises(TypeError, c.multiply, '1', 2) - self.assertRaises(TypeError, c.multiply, 1, '2') - - def test_next_minus(self): - c = Context() - d = c.next_minus(Decimal(10)) - self.assertEqual(c.next_minus(10), d) - self.assertRaises(TypeError, c.next_minus, '10') - - def test_next_plus(self): - c = Context() - d = c.next_plus(Decimal(10)) - self.assertEqual(c.next_plus(10), d) - self.assertRaises(TypeError, c.next_plus, '10') - - def test_next_toward(self): - c = Context() - d = c.next_toward(Decimal(1), Decimal(2)) - self.assertEqual(c.next_toward(1, 2), d) - self.assertEqual(c.next_toward(Decimal(1), 2), d) - self.assertEqual(c.next_toward(1, Decimal(2)), d) - self.assertRaises(TypeError, c.next_toward, '1', 2) - self.assertRaises(TypeError, c.next_toward, 1, '2') - - def test_normalize(self): - c = Context() - d = c.normalize(Decimal(10)) - self.assertEqual(c.normalize(10), d) - self.assertRaises(TypeError, c.normalize, '10') - - def test_number_class(self): - c = Context() - self.assertEqual(c.number_class(123), c.number_class(Decimal(123))) - self.assertEqual(c.number_class(0), c.number_class(Decimal(0))) - self.assertEqual(c.number_class(-45), c.number_class(Decimal(-45))) - - def test_power(self): - c = Context() - d = c.power(Decimal(1), Decimal(4), Decimal(2)) - self.assertEqual(c.power(1, 4, 2), d) - self.assertEqual(c.power(Decimal(1), 4, 2), d) - self.assertEqual(c.power(1, Decimal(4), 2), d) - self.assertEqual(c.power(1, 4, Decimal(2)), d) - self.assertEqual(c.power(Decimal(1), Decimal(4), 2), d) - self.assertRaises(TypeError, c.power, '1', 4, 2) - self.assertRaises(TypeError, c.power, 1, '4', 2) - self.assertRaises(TypeError, c.power, 1, 4, '2') - - def test_plus(self): - c = Context() - d = c.plus(Decimal(10)) - self.assertEqual(c.plus(10), d) - self.assertRaises(TypeError, c.plus, '10') - - def test_quantize(self): - c = Context() - d = c.quantize(Decimal(1), Decimal(2)) - self.assertEqual(c.quantize(1, 2), d) - self.assertEqual(c.quantize(Decimal(1), 2), d) - self.assertEqual(c.quantize(1, Decimal(2)), d) - self.assertRaises(TypeError, c.quantize, '1', 2) - self.assertRaises(TypeError, c.quantize, 1, '2') - - def test_remainder(self): - c = Context() - d = c.remainder(Decimal(1), Decimal(2)) - self.assertEqual(c.remainder(1, 2), d) - self.assertEqual(c.remainder(Decimal(1), 2), d) - self.assertEqual(c.remainder(1, Decimal(2)), d) - self.assertRaises(TypeError, c.remainder, '1', 2) - self.assertRaises(TypeError, c.remainder, 1, '2') - - def test_remainder_near(self): - c = Context() - d = c.remainder_near(Decimal(1), Decimal(2)) - self.assertEqual(c.remainder_near(1, 2), d) - self.assertEqual(c.remainder_near(Decimal(1), 2), d) - self.assertEqual(c.remainder_near(1, Decimal(2)), d) - self.assertRaises(TypeError, c.remainder_near, '1', 2) - self.assertRaises(TypeError, c.remainder_near, 1, '2') - - def test_rotate(self): - c = Context() - d = c.rotate(Decimal(1), Decimal(2)) - self.assertEqual(c.rotate(1, 2), d) - self.assertEqual(c.rotate(Decimal(1), 2), d) - self.assertEqual(c.rotate(1, Decimal(2)), d) - self.assertRaises(TypeError, c.rotate, '1', 2) - self.assertRaises(TypeError, c.rotate, 1, '2') - - def test_sqrt(self): - c = Context() - d = c.sqrt(Decimal(10)) - self.assertEqual(c.sqrt(10), d) - self.assertRaises(TypeError, c.sqrt, '10') - - def test_same_quantum(self): - c = Context() - d = c.same_quantum(Decimal(1), Decimal(2)) - self.assertEqual(c.same_quantum(1, 2), d) - self.assertEqual(c.same_quantum(Decimal(1), 2), d) - self.assertEqual(c.same_quantum(1, Decimal(2)), d) - self.assertRaises(TypeError, c.same_quantum, '1', 2) - self.assertRaises(TypeError, c.same_quantum, 1, '2') - - def test_scaleb(self): - c = Context() - d = c.scaleb(Decimal(1), Decimal(2)) - self.assertEqual(c.scaleb(1, 2), d) - self.assertEqual(c.scaleb(Decimal(1), 2), d) - self.assertEqual(c.scaleb(1, Decimal(2)), d) - self.assertRaises(TypeError, c.scaleb, '1', 2) - self.assertRaises(TypeError, c.scaleb, 1, '2') - - def test_shift(self): - c = Context() - d = c.shift(Decimal(1), Decimal(2)) - self.assertEqual(c.shift(1, 2), d) - self.assertEqual(c.shift(Decimal(1), 2), d) - self.assertEqual(c.shift(1, Decimal(2)), d) - self.assertRaises(TypeError, c.shift, '1', 2) - self.assertRaises(TypeError, c.shift, 1, '2') - - def test_subtract(self): - c = Context() - d = c.subtract(Decimal(1), Decimal(2)) - self.assertEqual(c.subtract(1, 2), d) - self.assertEqual(c.subtract(Decimal(1), 2), d) - self.assertEqual(c.subtract(1, Decimal(2)), d) - self.assertRaises(TypeError, c.subtract, '1', 2) - self.assertRaises(TypeError, c.subtract, 1, '2') - - def test_to_eng_string(self): - c = Context() - d = c.to_eng_string(Decimal(10)) - self.assertEqual(c.to_eng_string(10), d) - self.assertRaises(TypeError, c.to_eng_string, '10') - - def test_to_sci_string(self): - c = Context() - d = c.to_sci_string(Decimal(10)) - self.assertEqual(c.to_sci_string(10), d) - self.assertRaises(TypeError, c.to_sci_string, '10') - - def test_to_integral_exact(self): - c = Context() - d = c.to_integral_exact(Decimal(10)) - self.assertEqual(c.to_integral_exact(10), d) - self.assertRaises(TypeError, c.to_integral_exact, '10') - - def test_to_integral_value(self): - c = Context() - d = c.to_integral_value(Decimal(10)) - self.assertEqual(c.to_integral_value(10), d) - self.assertRaises(TypeError, c.to_integral_value, '10') - -class WithStatementTest(unittest.TestCase): - # Can't do these as docstrings until Python 2.6 - # as doctest can't handle __future__ statements - - def test_localcontext(self): - # Use a copy of the current context in the block - orig_ctx = getcontext() - with localcontext() as enter_ctx: - set_ctx = getcontext() - final_ctx = getcontext() - self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly') - self.assertIsNot(orig_ctx, set_ctx, 'did not copy the context') - self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context') - - def test_localcontextarg(self): - # Use a copy of the supplied context in the block - orig_ctx = getcontext() - new_ctx = Context(prec=42) - with localcontext(new_ctx) as enter_ctx: - set_ctx = getcontext() - final_ctx = getcontext() - self.assertIs(orig_ctx, final_ctx, 'did not restore context correctly') - self.assertEqual(set_ctx.prec, new_ctx.prec, 'did not set correct context') - self.assertIsNot(new_ctx, set_ctx, 'did not copy the context') - self.assertIs(set_ctx, enter_ctx, '__enter__ returned wrong context') - -class ContextFlags(unittest.TestCase): - def test_flags_irrelevant(self): - # check that the result (numeric result + flags raised) of an - # arithmetic operation doesn't depend on the current flags - - context = Context(prec=9, Emin = -999999999, Emax = 999999999, - rounding=ROUND_HALF_EVEN, traps=[], flags=[]) - - # operations that raise various flags, in the form (function, arglist) - operations = [ - (context._apply, [Decimal("100E-1000000009")]), - (context.sqrt, [Decimal(2)]), - (context.add, [Decimal("1.23456789"), Decimal("9.87654321")]), - (context.multiply, [Decimal("1.23456789"), Decimal("9.87654321")]), - (context.subtract, [Decimal("1.23456789"), Decimal("9.87654321")]), - ] - - # try various flags individually, then a whole lot at once - flagsets = [[Inexact], [Rounded], [Underflow], [Clamped], [Subnormal], - [Inexact, Rounded, Underflow, Clamped, Subnormal]] - - for fn, args in operations: - # find answer and flags raised using a clean context - context.clear_flags() - ans = fn(*args) - flags = [k for k, v in context.flags.items() if v] - - for extra_flags in flagsets: - # set flags, before calling operation - context.clear_flags() - for flag in extra_flags: - context._raise_error(flag) - new_ans = fn(*args) - - # flags that we expect to be set after the operation - expected_flags = list(flags) - for flag in extra_flags: - if flag not in expected_flags: - expected_flags.append(flag) - expected_flags.sort(key=id) - - # flags we actually got - new_flags = [k for k,v in context.flags.items() if v] - new_flags.sort(key=id) - - self.assertEqual(ans, new_ans, - "operation produces different answers depending on flags set: " + - "expected %s, got %s." % (ans, new_ans)) - self.assertEqual(new_flags, expected_flags, - "operation raises different flags depending on flags set: " + - "expected %s, got %s" % (expected_flags, new_flags)) + + @requires_extra_functionality + def test_c_signal_dict(self): + + # SignalDict coverage + Context = C.Context + DefaultContext = C.DefaultContext + + InvalidOperation = C.InvalidOperation + DivisionByZero = C.DivisionByZero + Overflow = C.Overflow + Subnormal = C.Subnormal + Underflow = C.Underflow + Rounded = C.Rounded + Inexact = C.Inexact + Clamped = C.Clamped + + DecClamped = C.DecClamped + DecInvalidOperation = C.DecInvalidOperation + DecIEEEInvalidOperation = C.DecIEEEInvalidOperation + + def assertIsExclusivelySet(signal, signal_dict): + for sig in signal_dict: + if sig == signal: + self.assertTrue(signal_dict[sig]) + else: + self.assertFalse(signal_dict[sig]) + + c = DefaultContext.copy() + + # Signal dict methods + self.assertTrue(Overflow in c.traps) + c.clear_traps() + for k in c.traps.keys(): + c.traps[k] = True + for v in c.traps.values(): + self.assertTrue(v) + c.clear_traps() + for k, v in c.traps.items(): + self.assertFalse(v) + + self.assertFalse(c.flags.get(Overflow)) + self.assertIs(c.flags.get("x"), None) + self.assertEqual(c.flags.get("x", "y"), "y") + self.assertRaises(TypeError, c.flags.get, "x", "y", "z") + + self.assertEqual(len(c.flags), len(c.traps)) + s = sys.getsizeof(c.flags) + s = sys.getsizeof(c.traps) + s = c.flags.__repr__() + + # Set flags/traps. + c.clear_flags() + c._flags = DecClamped + self.assertTrue(c.flags[Clamped]) + + c.clear_traps() + c._traps = DecInvalidOperation + self.assertTrue(c.traps[InvalidOperation]) + + # Set flags/traps from dictionary. + c.clear_flags() + d = c.flags.copy() + d[DivisionByZero] = True + c.flags = d + assertIsExclusivelySet(DivisionByZero, c.flags) + + c.clear_traps() + d = c.traps.copy() + d[Underflow] = True + c.traps = d + assertIsExclusivelySet(Underflow, c.traps) + + # Random constructors + IntSignals = { + Clamped: C.DecClamped, + Rounded: C.DecRounded, + Inexact: C.DecInexact, + Subnormal: C.DecSubnormal, + Underflow: C.DecUnderflow, + Overflow: C.DecOverflow, + DivisionByZero: C.DecDivisionByZero, + InvalidOperation: C.DecIEEEInvalidOperation + } + IntCond = [ + C.DecDivisionImpossible, C.DecDivisionUndefined, C.DecFpuError, + C.DecInvalidContext, C.DecInvalidOperation, C.DecMallocError, + C.DecConversionSyntax, + ] + + lim = len(OrderedSignals[C]) + for r in range(lim): + for t in range(lim): + for round in RoundingModes[C]: + flags = random.sample(OrderedSignals[C], r) + traps = random.sample(OrderedSignals[C], t) + prec = random.randrange(1, 10000) + emin = random.randrange(-10000, 0) + emax = random.randrange(0, 10000) + clamp = random.randrange(0, 2) + caps = random.randrange(0, 2) + cr = random.randrange(0, 2) + c = Context(prec=prec, rounding=round, Emin=emin, Emax=emax, + capitals=caps, clamp=clamp, flags=list(flags), + traps=list(traps)) + + self.assertEqual(c.prec, prec) + self.assertEqual(c.rounding, round) + self.assertEqual(c.Emin, emin) + self.assertEqual(c.Emax, emax) + self.assertEqual(c.capitals, caps) + self.assertEqual(c.clamp, clamp) + + f = 0 + for x in flags: + f |= IntSignals[x] + self.assertEqual(c._flags, f) + + f = 0 + for x in traps: + f |= IntSignals[x] + self.assertEqual(c._traps, f) + + for cond in IntCond: + c._flags = cond + self.assertTrue(c._flags&DecIEEEInvalidOperation) + assertIsExclusivelySet(InvalidOperation, c.flags) + + for cond in IntCond: + c._traps = cond + self.assertTrue(c._traps&DecIEEEInvalidOperation) + assertIsExclusivelySet(InvalidOperation, c.traps) + + def test_invalid_override(self): + Decimal = C.Decimal + + try: + from locale import CHAR_MAX + except ImportError: + return + + def make_grouping(lst): + return ''.join([chr(x) for x in lst]) + + def get_fmt(x, override=None, fmt='n'): + return Decimal(x).__format__(fmt, override) + + invalid_grouping = { + 'decimal_point' : ',', + 'grouping' : make_grouping([255, 255, 0]), + 'thousands_sep' : ',' + } + invalid_dot = { + 'decimal_point' : 'xxxxx', + 'grouping' : make_grouping([3, 3, 0]), + 'thousands_sep' : ',' + } + invalid_sep = { + 'decimal_point' : '.', + 'grouping' : make_grouping([3, 3, 0]), + 'thousands_sep' : 'yyyyy' + } + + if CHAR_MAX == 127: # negative grouping in override + self.assertRaises(ValueError, get_fmt, 12345, + invalid_grouping, 'g') + + self.assertRaises(ValueError, get_fmt, 12345, invalid_dot, 'g') + self.assertRaises(ValueError, get_fmt, 12345, invalid_sep, 'g') + + +all_tests = [ + CExplicitConstructionTest, PyExplicitConstructionTest, + CImplicitConstructionTest, PyImplicitConstructionTest, + CFormatTest, PyFormatTest, + CArithmeticOperatorsTest, PyArithmeticOperatorsTest, + CThreadingTest, PyThreadingTest, + CUsabilityTest, PyUsabilityTest, + CPythonAPItests, PyPythonAPItests, + CContextAPItests, PyContextAPItests, + CContextWithStatement, PyContextWithStatement, + CContextFlags, PyContextFlags, + CSpecialContexts, PySpecialContexts, + CContextInputValidation, PyContextInputValidation, + CContextSubclassing, PyContextSubclassing, + CCoverage, PyCoverage, + CFunctionality, PyFunctionality, + CWhitebox, PyWhitebox, + CIBMTestCases, PyIBMTestCases, +] + +# Delete C tests if _decimal.so is not present. +if not C: + all_tests = all_tests[1::2] +else: + all_tests.insert(0, CheckAttributes) + def test_main(arith=False, verbose=None, todo_tests=None, debug=None): """ Execute the tests. @@ -2366,27 +4948,16 @@ is enabled in regrtest.py """ - init() + init(C) + init(P) global TEST_ALL, DEBUG TEST_ALL = arith or is_resource_enabled('decimal') DEBUG = debug if todo_tests is None: - test_classes = [ - DecimalExplicitConstructionTest, - DecimalImplicitConstructionTest, - DecimalArithmeticOperatorsTest, - DecimalFormatTest, - DecimalUseOfContextTest, - DecimalUsabilityTest, - DecimalPythonAPItests, - ContextAPItests, - DecimalTest, - WithStatementTest, - ContextFlags - ] + test_classes = all_tests else: - test_classes = [DecimalTest] + test_classes = [CIBMTestCases, PyIBMTestCases] # Dynamically build custom test definition for each file in the test # directory and add the definitions to the DecimalTest class. This @@ -2398,17 +4969,32 @@ if todo_tests is not None and head not in todo_tests: continue tester = lambda self, f=filename: self.eval_file(directory + f) - setattr(DecimalTest, 'test_' + head, tester) + setattr(CIBMTestCases, 'test_' + head, tester) + setattr(PyIBMTestCases, 'test_' + head, tester) del filename, head, tail, tester try: run_unittest(*test_classes) if todo_tests is None: - import decimal as DecimalModule - run_doctest(DecimalModule, verbose) + from doctest import IGNORE_EXCEPTION_DETAIL + savedecimal = sys.modules['decimal'] + if C: + sys.modules['decimal'] = C + run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL) + sys.modules['decimal'] = P + run_doctest(P, verbose) + sys.modules['decimal'] = savedecimal finally: - setcontext(ORIGINAL_CONTEXT) + if C: C.setcontext(ORIGINAL_CONTEXT[C]) + P.setcontext(ORIGINAL_CONTEXT[P]) + if not C: + warnings.warn('C tests skipped: no module named _decimal.', + UserWarning) + if not orig_sys_decimal is sys.modules['decimal']: + raise TestFailed("Internal error: unbalanced number of changes to " + "sys.modules['decimal'].") + if __name__ == '__main__': import optparse diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -401,14 +401,10 @@ def testMixingWithDecimal(self): # Decimal refuses mixed arithmetic (but not mixed comparisons) - self.assertRaisesMessage( - TypeError, - "unsupported operand type(s) for +: 'Fraction' and 'Decimal'", - operator.add, F(3,11), Decimal('3.1415926')) - self.assertRaisesMessage( - TypeError, - "unsupported operand type(s) for +: 'Decimal' and 'Fraction'", - operator.add, Decimal('3.1415926'), F(3,11)) + self.assertRaises(TypeError, operator.add, + F(3,11), Decimal('3.1415926')) + self.assertRaises(TypeError, operator.add, + Decimal('3.1415926'), F(3,11)) def testComparisons(self): self.assertTrue(F(1, 2) < F(2, 3)) diff --git a/Lib/test/test_numeric_tower.py b/Lib/test/test_numeric_tower.py --- a/Lib/test/test_numeric_tower.py +++ b/Lib/test/test_numeric_tower.py @@ -150,7 +150,7 @@ # int, float, Fraction, Decimal test_values = [ float('-inf'), - D('-1e999999999'), + D('-1e425000000'), -1e308, F(-22, 7), -3.14, diff --git a/Lib/test/test_smtpd.py b/Lib/test/test_smtpd.py --- a/Lib/test/test_smtpd.py +++ b/Lib/test/test_smtpd.py @@ -39,6 +39,7 @@ channel.socket.queue_recv(line) channel.handle_read() + write_line(b'HELO test.example') write_line(b'MAIL From:eggs at example') write_line(b'RCPT To:spam at example') write_line(b'DATA') @@ -104,6 +105,11 @@ self.write_line(b'NOOP') self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') + def test_HELO_NOOP(self): + self.write_line(b'HELO example') + self.write_line(b'NOOP') + self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') + def test_NOOP_bad_syntax(self): self.write_line(b'NOOP hi') self.assertEqual(self.channel.socket.last, @@ -113,17 +119,23 @@ self.write_line(b'QUIT') self.assertEqual(self.channel.socket.last, b'221 Bye\r\n') + def test_HELO_QUIT(self): + self.write_line(b'HELO example') + self.write_line(b'QUIT') + self.assertEqual(self.channel.socket.last, b'221 Bye\r\n') + def test_QUIT_arg_ignored(self): self.write_line(b'QUIT bye bye') self.assertEqual(self.channel.socket.last, b'221 Bye\r\n') def test_bad_state(self): self.channel.smtp_state = 'BAD STATE' - self.write_line(b'HELO') + self.write_line(b'HELO example') self.assertEqual(self.channel.socket.last, b'451 Internal confusion\r\n') def test_command_too_long(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from ' + b'a' * self.channel.command_size_limit + b'@example') @@ -133,6 +145,7 @@ def test_data_too_long(self): # Small hack. Setting limit to 2K octets here will save us some time. self.channel.data_size_limit = 2048 + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'DATA') @@ -142,43 +155,61 @@ b'552 Error: Too much mail data\r\n') def test_need_MAIL(self): + self.write_line(b'HELO example') self.write_line(b'RCPT to:spam at example') self.assertEqual(self.channel.socket.last, b'503 Error: need MAIL command\r\n') def test_MAIL_syntax(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from eggs at example') self.assertEqual(self.channel.socket.last, b'501 Syntax: MAIL FROM:
\r\n') def test_MAIL_missing_from(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from:') self.assertEqual(self.channel.socket.last, b'501 Syntax: MAIL FROM:
\r\n') def test_MAIL_chevrons(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from:') self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') def test_nested_MAIL(self): + self.write_line(b'HELO example') self.write_line(b'MAIL from:eggs at example') self.write_line(b'MAIL from:spam at example') self.assertEqual(self.channel.socket.last, b'503 Error: nested MAIL command\r\n') + def test_no_HELO_MAIL(self): + self.write_line(b'MAIL from:') + self.assertEqual(self.channel.socket.last, + b'503 Error: send HELO first\r\n') + def test_need_RCPT(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'DATA') self.assertEqual(self.channel.socket.last, b'503 Error: need RCPT command\r\n') def test_RCPT_syntax(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT to eggs at example') self.assertEqual(self.channel.socket.last, b'501 Syntax: RCPT TO:
\r\n') + def test_no_HELO_RCPT(self): + self.write_line(b'RCPT to eggs at example') + self.assertEqual(self.channel.socket.last, + b'503 Error: send HELO first\r\n') + def test_data_dialog(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') self.write_line(b'RCPT To:spam at example') @@ -193,12 +224,19 @@ [('peer', 'eggs at example', ['spam at example'], 'data\nmore')]) def test_DATA_syntax(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'DATA spam') self.assertEqual(self.channel.socket.last, b'501 Syntax: DATA\r\n') + def test_no_HELO_DATA(self): + self.write_line(b'DATA spam') + self.assertEqual(self.channel.socket.last, + b'503 Error: send HELO first\r\n') + def test_data_transparency_section_4_5_2(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'DATA') @@ -206,6 +244,7 @@ self.assertEqual(self.channel.received_data, '.') def test_multiple_RCPT(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'RCPT To:ham at example') @@ -216,6 +255,7 @@ def test_manual_status(self): # checks that the Channel is able to return a custom status message + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'DATA') @@ -223,6 +263,7 @@ self.assertEqual(self.channel.socket.last, b'250 Okish\r\n') def test_RSET(self): + self.write_line(b'HELO example') self.write_line(b'MAIL From:eggs at example') self.write_line(b'RCPT To:spam at example') self.write_line(b'RSET') @@ -234,6 +275,11 @@ self.assertEqual(self.server.messages, [('peer', 'foo at example', ['eggs at example'], 'data')]) + def test_HELO_RSET(self): + self.write_line(b'HELO example') + self.write_line(b'RSET') + self.assertEqual(self.channel.socket.last, b'250 Ok\r\n') + def test_RSET_syntax(self): self.write_line(b'RSET hi') self.assertEqual(self.channel.socket.last, b'501 Syntax: RSET\r\n') diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -531,6 +531,7 @@ Lawrence Kesteloot Vivek Khera Mads Kiilerich +Jason Killen Taek Joo Kim W. Trevor King Paul Kippes diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,16 @@ Library ------- +- Issue #7652: Integrate the decimal floating point libmpdec library to speed + up the decimal module. Performance gains of the new C implementation are + between 12x and 80x, depending on the application. + +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)) (Patch by Guilherme Polo) + +- Issue #14269: SMTPD now conforms to the RFC and requires a HELO command + before MAIL, RCPT, or DATA. + - Issue #13694: asynchronous connect in asyncore.dispatcher does not set addr attribute. diff --git a/Misc/valgrind-python.supp b/Misc/valgrind-python.supp --- a/Misc/valgrind-python.supp +++ b/Misc/valgrind-python.supp @@ -456,3 +456,16 @@ fun:PyUnicode_FSConverter } +# Additional suppressions for the unified decimal tests: +{ + test_decimal + Memcheck:Addr4 + fun:PyUnicodeUCS2_FSConverter +} + +{ + test_decimal2 + Memcheck:Addr4 + fun:PyUnicode_FSConverter +} + diff --git a/Modules/_decimal/ISSUES.txt b/Modules/_decimal/ISSUES.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/ISSUES.txt @@ -0,0 +1,56 @@ + + +Normal priority: +---------------- + +1) Add C-API importable as capsule. + +2) Add --with-system-libmpdec to ./configure. + +3) Use same default emin/emax on 32-bit (MAX_EMAX=425000000) and 64-bit + (MAX_EMAX=10**18-1). + +4) Order of arguments in Context(). + +5) Documentation. + +6) quantize() + - exp argument is misleading: + Decimal('0.321000e+2').quantize(exp=9) -> user might expect + that the result will have exp=9. + - watchexp + +7) Match the exception hierarchy of decimal.py: + + exceptions.ArithmeticError(exceptions.Exception) + DecimalException + Clamped + DivisionByZero(DecimalException, exceptions.ZeroDivisionError) + Inexact + Overflow(Inexact, Rounded) + Underflow(Inexact, Rounded, Subnormal) + InvalidOperation + Rounded + Subnormal + FloatOperation + + +Low priority: +------------- + +1) Convert tabs (wait until commit). + +2) Pre-ANSI compilers require '#' in the first column (should be done + for the whole Python source tree if we support such compilers). (?) + +3) FETCH_CURRENT_CONTEXT vs. CURRENT_CONTEXT? + +4) Justify remaining uses of exit on overflow in bignum arith. Short + answer: with correct context values the coefficients never get big + enough for that to happen. + +5) Justify remaining uses of abort() in mpdecimal: These uses are + for debug purposes and can't be reached when the library is used + correctly. + + diff --git a/Modules/_decimal/README.txt b/Modules/_decimal/README.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/README.txt @@ -0,0 +1,46 @@ + + +About +===== + +_decimal.c is a wrapper for the libmpdec library. libmpdec is a fast C +library for correctly-rounded arbitrary precision decimal floating point +arithmetic. It is a complete implementation of Mike Cowlishaw/IBM's +General Decimal Arithmetic Specification. + + +Build process for the module +============================ + +As usual, the build process for _decimal.so is driven by setup.py in the top +level directory. setup.py autodetects the following build configurations: + + 1) x64 - 64-bit Python, x86_64 processor (AMD, Intel) + + 2) uint128 - 64-bit Python, compiler provides __uint128_t (gcc) + + 3) ansi64 - 64-bit Python, ANSI C + + 4) ppro - 32-bit Python, x86 CPU, PentiumPro or later + + 5) ansi32 - 32-bit Python, ANSI C + + 6) ansi-legacy - 32-bit Python, compiler without uint64_t + + 7) universal - Mac OS only (multi-arch) + + +It is possible to override autodetection by exporting: + + PYTHON_DECIMAL_WITH_MACHINE=value, where value is one of the above options. + + +NOTE +==== + +decimal.so is not built from a static libmpdec.a since doing so led to +failures on AIX (user report) and Windows (mixing static and dynamic CRTs +causes locale problems and more). + + + diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/_decimal.c @@ -0,0 +1,5512 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include +#include "longintrepr.h" +#include "pythread.h" +#include "structmember.h" +#include "complexobject.h" +#include "mpdecimal.h" + +#include + +#include "docstrings.h" +#include "memory.h" + + +/* + * Type sizes with assertions in mpdecimal.h and pyport.h: + * sizeof(size_t) == sizeof(Py_ssize_t) + * sizeof(size_t) == sizeof(mpd_uint_t) == sizeof(mpd_ssize_t) + */ + +#ifdef TEST_COVERAGE + #undef Py_LOCAL_INLINE + #define Py_LOCAL_INLINE Py_LOCAL +#endif + +#define MPD_Float_operation MPD_Not_implemented + +#define BOUNDS_CHECK(x, MIN, MAX) x = (x < MIN || MAX < x) ? MAX : x + + +typedef struct { + PyObject_HEAD + mpd_t *dec; +} PyDecObject; + +typedef struct { + PyObject_HEAD + uint32_t *flags; +} PyDecSignalDictObject; + +typedef struct { + PyObject_HEAD + mpd_context_t ctx; + PyObject *traps; + PyObject *flags; + int capitals; +} PyDecContextObject; + +typedef struct { + PyObject_HEAD + PyObject *local; + PyObject *global; +} PyDecContextManagerObject; + + +#undef MPD +#undef CTX +static PyTypeObject PyDec_Type; +static PyTypeObject *PyDecSignalDict_Type; +static PyTypeObject PyDecContext_Type; +static PyTypeObject PyDecContextManager_Type; +#define PyDec_CheckExact(v) (Py_TYPE(v) == &PyDec_Type) +#define PyDec_Check(v) PyObject_TypeCheck(v, &PyDec_Type) +#define PyDecSignalDict_Check(v) (Py_TYPE(v) == PyDecSignalDict_Type) +#define PyDecContext_Check(v) PyObject_TypeCheck(v, &PyDecContext_Type) +#define MPD(v) (((PyDecObject *)v)->dec) +#define SdFlagAddr(v) (((PyDecSignalDictObject *)v)->flags) +#define SdFlags(v) (*((PyDecSignalDictObject *)v)->flags) +#define CTX(v) (&((PyDecContextObject *)v)->ctx) +#define CtxCaps(v) (((PyDecContextObject *)v)->capitals) + + +Py_LOCAL_INLINE(PyObject *) +incr_true(void) +{ + Py_INCREF(Py_True); + return Py_True; +} + +Py_LOCAL_INLINE(PyObject *) +incr_false(void) +{ + Py_INCREF(Py_False); + return Py_False; +} + + +#ifdef WITHOUT_THREADS +/* Default module context */ +static PyObject *module_context = NULL; +#else +/* Key for thread state dictionary */ +static PyObject *tls_context_key = NULL; +#endif + +/* Template for creating new thread contexts, calling Context() without + * arguments and initializing the module_context on first access. */ +static PyObject *default_context_template = NULL; +/* Basic and extended context templates */ +static PyObject *basic_context_template = NULL; +static PyObject *extended_context_template = NULL; + + +/* Error codes for functions that return signals or conditions */ +#define DEC_INVALID_SIGNALS (MPD_Max_status+1U) +#define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1) +#define DEC_ERRORS (DEC_INVALID_SIGNALS|DEC_ERR_OCCURRED) + +typedef struct { + const char *name; /* condition or signal name */ + const char *fqname; /* fully qualified name */ + uint32_t flag; /* libmpdec flag */ + PyObject *ex; /* corresponding exception */ +} DecCondMap; + +/* Top level Exception; inherits from ArithmeticError */ +static PyObject *DecimalException = NULL; + +/* Exceptions that correspond to IEEE signals; inherit from DecimalException */ +#define SIGNAL_MAP_LEN 9 +static DecCondMap signal_map[] = { + {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, + {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL}, + {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL}, + {"Overflow", "decimal.Overflow", MPD_Overflow, NULL}, + {"Underflow", "decimal.Underflow", MPD_Underflow, NULL}, + {"Subnormal", "decimal.Subnormal", MPD_Subnormal, NULL}, + {"Inexact", "decimal.Inexact", MPD_Inexact, NULL}, + {"Rounded", "decimal.Rounded", MPD_Rounded, NULL}, + {"Clamped", "decimal.Clamped", MPD_Clamped, NULL}, + {NULL} +}; + +/* Exceptions that inherit from InvalidOperation */ +static DecCondMap cond_map[] = { + {"InvalidOperation", "decimal.InvalidOperation", MPD_Invalid_operation, NULL}, + {"ConversionSyntax", "decimal.ConversionSyntax", MPD_Conversion_syntax, NULL}, + {"DivisionImpossible", "decimal.DivisionImpossible", MPD_Division_impossible, NULL}, + {"DivisionUndefined", "decimal.DivisionUndefined", MPD_Division_undefined, NULL}, + {"InvalidContext", "decimal.InvalidContext", MPD_Invalid_context, NULL}, + {"MallocError", "decimal.MallocError", MPD_Malloc_error, NULL}, + {NULL} +}; + +static const char *dec_signal_string[MPD_NUM_FLAGS] = { + "Clamped", + "InvalidOperation", + "DivisionByZero", + "InvalidOperation", + "InvalidOperation", + "InvalidOperation", + "Inexact", + "InvalidOperation", + "InvalidOperation", + "InvalidOperation", + "FloatOperation", + "Overflow", + "Rounded", + "Subnormal", + "Underflow", +}; + +static const char *invalid_rounding_err = +"valid values for rounding are:\n\ + [ROUND_CEILING, ROUND_FLOOR, ROUND_UP, ROUND_DOWN,\n\ + ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN,\n\ + ROUND_05UP]"; + +static const char *invalid_signals_err = +"valid values for signals are:\n\ + [InvalidOperation, FloatOperation, DivisionByZero,\n\ + Overflow, Underflow, Subnormal, Inexact, Rounded,\n\ + Clamped]"; + +#ifdef EXTRA_FUNCTIONALITY +static const char *invalid_flags_err = +"valid values for _flags or _traps are:\n\ + signals:\n\ + [DecIEEEInvalidOperation, DecFloatOperation, DecDivisionByZero,\n\ + DecOverflow, DecUnderflow, DecSubnormal, DecInexact, DecRounded,\n\ + DecClamped]\n\ + conditions which trigger DecIEEEInvalidOperation:\n\ + [DecInvalidOperation, DecConversionSyntax, DecDivisionImpossible,\n\ + DecDivisionUndefined, DecFpuError, DecInvalidContext, DecMallocError]"; +#endif + +static int +value_error_int(const char *mesg) +{ + PyErr_SetString(PyExc_ValueError, mesg); + return -1; +} + +#ifdef CONFIG_32 +static PyObject * +value_error_ptr(const char *mesg) +{ + PyErr_SetString(PyExc_ValueError, mesg); + return NULL; +} +#endif + +static int +type_error_int(const char *mesg) +{ + PyErr_SetString(PyExc_TypeError, mesg); + return -1; +} + +static PyObject * +type_error_ptr(const char *mesg) +{ + PyErr_SetString(PyExc_TypeError, mesg); + return NULL; +} + +static int +runtime_error_int(const char *mesg) +{ + PyErr_SetString(PyExc_RuntimeError, mesg); + return -1; +} +#define INTERNAL_ERROR_INT(funcname) \ + return runtime_error_int("internal error in " funcname) + +static PyObject * +runtime_error_ptr(const char *mesg) +{ + PyErr_SetString(PyExc_RuntimeError, mesg); + return NULL; +} +#define INTERNAL_ERROR_PTR(funcname) \ + return runtime_error_ptr("internal error in " funcname) + +static void +dec_traphandler(mpd_context_t *ctx UNUSED) /* GCOV_NOT_REACHED */ +{ /* GCOV_NOT_REACHED */ + return; /* GCOV_NOT_REACHED */ +} + +static PyObject * +flags_as_exception(uint32_t flags) +{ + DecCondMap *cm; + + for (cm = signal_map; cm->name != NULL; cm++) { + if (flags&cm->flag) { + return cm->ex; + } + } + + INTERNAL_ERROR_PTR("flags_as_exception"); /* GCOV_NOT_REACHED */ +} + +Py_LOCAL_INLINE(uint32_t) +exception_as_flag(PyObject *ex) +{ + DecCondMap *cm; + + for (cm = signal_map; cm->name != NULL; cm++) { + if (cm->ex == ex) { + return cm->flag; + } + } + + PyErr_SetString(PyExc_KeyError, invalid_signals_err); + return DEC_INVALID_SIGNALS; +} + +static PyObject * +flags_as_list(uint32_t flags) +{ + PyObject *list; + DecCondMap *cm; + + list = PyList_New(0); + if (list == NULL) { + return NULL; + } + + for (cm = cond_map; cm->name != NULL; cm++) { + if (flags&cm->flag) { + if (PyList_Append(list, cm->ex) < 0) { + goto error; + } + } + } + for (cm = signal_map+1; cm->name != NULL; cm++) { + if (flags&cm->flag) { + if (PyList_Append(list, cm->ex) < 0) { + goto error; + } + } + } + + return list; + +error: + Py_DECREF(list); + return NULL; +} + +static PyObject * +signals_as_list(uint32_t flags) +{ + PyObject *list; + DecCondMap *cm; + + list = PyList_New(0); + if (list == NULL) { + return NULL; + } + + for (cm = signal_map; cm->name != NULL; cm++) { + if (flags&cm->flag) { + if (PyList_Append(list, cm->ex) < 0) { + Py_DECREF(list); + return NULL; + } + } + } + + return list; +} + +static uint32_t +list_as_flags(PyObject *list) +{ + PyObject *item; + uint32_t flags, x; + Py_ssize_t n, j; + + assert(PyList_Check(list)); + + n = PyList_Size(list); + flags = 0; + for (j = 0; j < n; j++) { + item = PyList_GetItem(list, j); + x = exception_as_flag(item); + if (x & DEC_ERRORS) { + return x; + } + flags |= x; + } + + return flags; +} + +static PyObject * +flags_as_dict(uint32_t flags) +{ + DecCondMap *cm; + PyObject *dict; + + dict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + + for (cm = signal_map; cm->name != NULL; cm++) { + PyObject *b = flags&cm->flag ? Py_True : Py_False; + if (PyDict_SetItem(dict, cm->ex, b) < 0) { + Py_DECREF(dict); + return NULL; + } + } + + return dict; +} + +static uint32_t +dict_as_flags(PyObject *val) +{ + PyObject *b; + DecCondMap *cm; + uint32_t flags = 0; + int x; + + if (!PyDict_Check(val)) { + PyErr_SetString(PyExc_TypeError, + "argument must be a signal dict"); + return DEC_INVALID_SIGNALS; + } + + if (PyDict_Size(val) != SIGNAL_MAP_LEN) { + PyErr_SetString(PyExc_KeyError, + "invalid signal dict"); + return DEC_INVALID_SIGNALS; + } + + for (cm = signal_map; cm->name != NULL; cm++) { + b = PyDict_GetItemWithError(val, cm->ex); + if (b == NULL) { + if (PyErr_Occurred()) { + return DEC_ERR_OCCURRED; + } + PyErr_SetString(PyExc_KeyError, + "invalid signal dict"); + return DEC_INVALID_SIGNALS; + } + + x = PyObject_IsTrue(b); + if (x < 0) { + return DEC_ERR_OCCURRED; + } + if (x == 1) { + flags |= cm->flag; + } + } + + return flags; +} + +#ifdef EXTRA_FUNCTIONALITY +static uint32_t +long_as_flags(PyObject *v) +{ + long x; + + x = PyLong_AsLong(v); + if (x == -1 && PyErr_Occurred()) { + return DEC_ERR_OCCURRED; + } + if (x < 0 || x > (long)MPD_Max_status) { + PyErr_SetString(PyExc_TypeError, invalid_flags_err); + return DEC_INVALID_SIGNALS; + } + + return x; +} +#endif + +static int +dec_addstatus(PyObject *context, uint32_t status) +{ + mpd_context_t *ctx = CTX(context); + + ctx->status |= status; + if (ctx->traps&status) { + PyObject *ex, *siglist; + + ex = flags_as_exception(ctx->traps&status); + if (ex == NULL) { + return 1; /* GCOV_NOT_REACHED */ + } + siglist = flags_as_list(ctx->traps&status); + if (siglist == NULL) { + return 1; + } + + PyErr_SetObject(ex, siglist); + Py_DECREF(siglist); + return 1; + } + return 0; +} + + +/******************************************************************************/ +/* SignalDict Object */ +/******************************************************************************/ + +/* The SignalDict is a MutableMapping that provides access to the + mpd_context_t flags, which reside in the context object. When a + new context is created, context.traps and context.flags are + initialized to new SignalDicts. Once a SignalDict is tied to + a context, it cannot be deleted. */ + +static int +signaldict_init(PyObject *self, PyObject *args UNUSED, PyObject *kwds UNUSED) +{ + SdFlagAddr(self) = NULL; + return 0; +} + +static Py_ssize_t +signaldict_len(PyObject *self UNUSED) +{ + return SIGNAL_MAP_LEN; +} + +static PyObject *SignalTuple; +static PyObject * +signaldict_iter(PyObject *self UNUSED) +{ + return PyTuple_Type.tp_iter(SignalTuple); +} + +static PyObject * +signaldict_getitem(PyObject *self, PyObject *key) +{ + uint32_t flag; + + flag = exception_as_flag(key); + if (flag & DEC_ERRORS) { + return NULL; + } + + return SdFlags(self)&flag ? incr_true() : incr_false(); +} + +static int +signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) +{ + uint32_t flag; + int x; + + if (value == NULL) { + return value_error_int("signal keys cannot be deleted"); + } + + flag = exception_as_flag(key); + if (flag & DEC_ERRORS) { + return -1; + } + + x = PyObject_IsTrue(value); + if (x < 0) { + return -1; + } + + if (x == 1) { + SdFlags(self) |= flag; + } + else { + SdFlags(self) &= ~flag; + } + + return 0; +} + +static PyObject * +signaldict_repr(PyObject *self) +{ + DecCondMap *cm; + const char *n[SIGNAL_MAP_LEN]; /* name */ + const char *b[SIGNAL_MAP_LEN]; /* bool */ + int i; + + assert(SIGNAL_MAP_LEN == 9); + + for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { + n[i] = cm->fqname; + b[i] = SdFlags(self)&cm->flag ? "True" : "False"; + } + return PyUnicode_FromFormat( + "{:%s, :%s, :%s, " + ":%s, :%s, :%s, " + ":%s, :%s, :%s}", + n[0], b[0], n[1], b[1], n[2], b[2], + n[3], b[3], n[4], b[4], n[5], b[5], + n[6], b[6], n[7], b[7], n[8], b[8]); +} + +static PyObject * +signaldict_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *res = Py_NotImplemented; + + assert(PyDecSignalDict_Check(v)); + + if (op == Py_EQ || op == Py_NE) { + if (PyDecSignalDict_Check(w)) { + res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False; + } + else if (PyDict_Check(w)) { + uint32_t flags = dict_as_flags(w); + if (flags & DEC_ERRORS) { + if (flags & DEC_INVALID_SIGNALS) { + /* non-comparable: Py_NotImplemented */ + PyErr_Clear(); + } + else { + return NULL; + } + } + else { + res = (SdFlags(v)==flags) ^ (op==Py_NE) ? Py_True : Py_False; + } + } + } + + Py_INCREF(res); + return res; +} + +static PyObject * +signaldict_copy(PyObject *self) +{ + return flags_as_dict(SdFlags(self)); +} + + +static PyMappingMethods signaldict_as_mapping = { + (lenfunc)signaldict_len, /* mp_length */ + (binaryfunc)signaldict_getitem, /* mp_subscript */ + (objobjargproc)signaldict_setitem /* mp_ass_subscript */ +}; + +static PyMethodDef signaldict_methods[] = { + { "copy", (PyCFunction)signaldict_copy, METH_NOARGS, NULL}, + {NULL, NULL} +}; + + +static PyTypeObject PyDecSignalDictMixin_Type = +{ + PyVarObject_HEAD_INIT(0, 0) + "decimal.SignalDictMixin", /* tp_name */ + sizeof(PyDecSignalDictObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc) signaldict_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &signaldict_as_mapping, /* tp_as_mapping */ + PyObject_HashNotImplemented, /* tp_hash */ + 0, /* tp_call */ + (reprfunc) 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + (PyBufferProcs *) 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE| + Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + signaldict_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)signaldict_iter, /* tp_iter */ + 0, /* tp_iternext */ + signaldict_methods, /* 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 */ + (initproc)signaldict_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ +}; + + +/******************************************************************************/ +/* Context Object, Part 1 */ +/******************************************************************************/ + +#define Dec_CONTEXT_GET_SSIZE(mem) \ +static PyObject * \ +context_get##mem(PyObject *self, void *closure UNUSED) \ +{ \ + return PyLong_FromSsize_t(mpd_get##mem(CTX(self))); \ +} + +#define Dec_CONTEXT_GET_ULONG(mem) \ +static PyObject * \ +context_get##mem(PyObject *self, void *closure UNUSED) \ +{ \ + return PyLong_FromUnsignedLong(mpd_get##mem(CTX(self))); \ +} + +Dec_CONTEXT_GET_SSIZE(prec) +Dec_CONTEXT_GET_SSIZE(emax) +Dec_CONTEXT_GET_SSIZE(emin) +Dec_CONTEXT_GET_SSIZE(round) +Dec_CONTEXT_GET_SSIZE(clamp) + +#ifdef EXTRA_FUNCTIONALITY +Dec_CONTEXT_GET_ULONG(traps) +Dec_CONTEXT_GET_ULONG(status) +#endif + +static PyObject * +context_getcapitals(PyObject *self, void *closure UNUSED) +{ + return PyLong_FromLong(CtxCaps(self)); +} + +#ifdef EXTRA_FUNCTIONALITY +static PyObject * +context_getallcr(PyObject *self, void *closure UNUSED) +{ + return PyLong_FromLong(mpd_getcr(CTX(self))); +} +#endif + +static PyObject * +context_getetiny(PyObject *self, PyObject *dummy UNUSED) +{ + return PyLong_FromSsize_t(mpd_etiny(CTX(self))); +} + +static PyObject * +context_getetop(PyObject *self, PyObject *dummy UNUSED) +{ + return PyLong_FromSsize_t(mpd_etop(CTX(self))); +} + +static int +context_setprec(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetprec(ctx, x)) { + return value_error_int( + "valid range for prec is [1, MAX_PREC]"); + } + + return 0; +} + +static int +context_setemin(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetemin(ctx, x)) { + return value_error_int( + "valid range for Emin is [MIN_EMIN, 0]"); + } + + return 0; +} + +static int +context_setemax(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetemax(ctx, x)) { + return value_error_int( + "valid range for Emax is [0, MAX_EMAX]"); + } + + return 0; +} + +#ifdef CONFIG_32 +static PyObject * +context_unsafe_setprec(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx = CTX(self); + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return NULL; + } + + if (x < 1 || x > 1070000000L) { + return value_error_ptr( + "valid range for unsafe prec is [1, 1070000000]"); + } + + ctx->prec = x; + Py_RETURN_NONE; +} + +static PyObject * +context_unsafe_setemin(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx = CTX(self); + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return NULL; + } + + if (x < -1070000000L || x > 0) { + return value_error_ptr( + "valid range for unsafe emin is [-1070000000, 0]"); + } + + ctx->emin = x; + Py_RETURN_NONE; +} + +static PyObject * +context_unsafe_setemax(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx = CTX(self); + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return NULL; + } + + if (x < 0 || x > 1070000000L) { + return value_error_ptr( + "valid range for unsafe emax is [0, 1070000000]"); + } + + ctx->emax = x; + Py_RETURN_NONE; +} +#endif + +static int +context_setround(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + BOUNDS_CHECK(x, INT_MIN, INT_MAX); + + ctx = CTX(self); + if (!mpd_qsetround(ctx, (int)x)) { + return type_error_int(invalid_rounding_err); + } + + return 0; +} + +static int +context_setcapitals(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + + if (x != 0 && x != 1) { + return value_error_int( + "valid values for capitals are 0 or 1"); + } + CtxCaps(self) = (int)x; + + return 0; +} + +#ifdef EXTRA_FUNCTIONALITY +static int +context_settraps(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + uint32_t flags; + + flags = long_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsettraps(ctx, flags)) { + INTERNAL_ERROR_INT("context_settraps"); + } + + return 0; +} +#endif + +static int +context_settraps_list(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx; + uint32_t flags; + + flags = list_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsettraps(ctx, flags)) { + INTERNAL_ERROR_INT("context_settraps_list"); + } + + return 0; +} + +static int +context_settraps_dict(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx; + uint32_t flags; + + if (PyDecSignalDict_Check(value)) { + flags = SdFlags(value); + } + else { + flags = dict_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + } + + ctx = CTX(self); + if (!mpd_qsettraps(ctx, flags)) { + INTERNAL_ERROR_INT("context_settraps_dict"); + } + + return 0; +} + +#ifdef EXTRA_FUNCTIONALITY +static int +context_setstatus(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + uint32_t flags; + + flags = long_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetstatus(ctx, flags)) { + INTERNAL_ERROR_INT("context_setstatus"); + } + + return 0; +} +#endif + +static int +context_setstatus_list(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx; + uint32_t flags; + + flags = list_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + + ctx = CTX(self); + if (!mpd_qsetstatus(ctx, flags)) { + INTERNAL_ERROR_INT("context_setstatus_list"); + } + + return 0; +} + +static int +context_setstatus_dict(PyObject *self, PyObject *value) +{ + mpd_context_t *ctx; + uint32_t flags; + + if (PyDecSignalDict_Check(value)) { + flags = SdFlags(value); + } + else { + flags = dict_as_flags(value); + if (flags & DEC_ERRORS) { + return -1; + } + } + + ctx = CTX(self); + if (!mpd_qsetstatus(ctx, flags)) { + INTERNAL_ERROR_INT("context_setstatus_dict"); + } + + return 0; +} + +static int +context_setclamp(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + BOUNDS_CHECK(x, INT_MIN, INT_MAX); + + ctx = CTX(self); + if (!mpd_qsetclamp(ctx, (int)x)) { + return value_error_int("valid values for clamp are 0 or 1"); + } + + return 0; +} + +#ifdef EXTRA_FUNCTIONALITY +static int +context_setallcr(PyObject *self, PyObject *value, void *closure UNUSED) +{ + mpd_context_t *ctx; + mpd_ssize_t x; + + x = PyLong_AsSsize_t(value); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + BOUNDS_CHECK(x, INT_MIN, INT_MAX); + + ctx = CTX(self); + if (!mpd_qsetcr(ctx, (int)x)) { + return value_error_int("valid values for _allcr are 0 or 1"); + } + + return 0; +} +#endif + +static PyObject * +context_getattr(PyObject *self, PyObject *name) +{ + PyObject *retval; + + if (PyUnicode_Check(name)) { + if (PyUnicode_CompareWithASCIIString(name, "traps") == 0) { + retval = ((PyDecContextObject *)self)->traps; + Py_INCREF(retval); + return retval; + } + if (PyUnicode_CompareWithASCIIString(name, "flags") == 0) { + retval = ((PyDecContextObject *)self)->flags; + Py_INCREF(retval); + return retval; + } + } + + return PyObject_GenericGetAttr(self, name); +} + +static int +context_setattr(PyObject *self, PyObject *name, PyObject *value) +{ + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, + "context attributes cannot be deleted"); + return -1; + } + + if (PyUnicode_Check(name)) { + if (PyUnicode_CompareWithASCIIString(name, "traps") == 0) { + return context_settraps_dict(self, value); + } + if (PyUnicode_CompareWithASCIIString(name, "flags") == 0) { + return context_setstatus_dict(self, value); + } + } + + return PyObject_GenericSetAttr(self, name, value); +} + +static PyObject * +context_clear_traps(PyObject *self, PyObject *dummy UNUSED) +{ + CTX(self)->traps = 0; + Py_RETURN_NONE; +} + +static PyObject * +context_clear_flags(PyObject *self, PyObject *dummy UNUSED) +{ + CTX(self)->status = 0; + Py_RETURN_NONE; +} + +#define DEC_DFLT_EMAX 999999 +#define DEC_DFLT_EMIN -999999 + +static mpd_context_t dflt_ctx = { + 28, DEC_DFLT_EMAX, DEC_DFLT_EMIN, + MPD_IEEE_Invalid_operation|MPD_Division_by_zero|MPD_Overflow, + 0, 0, MPD_ROUND_HALF_EVEN, 0, 1 +}; + +static PyObject * +context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) +{ + PyDecContextObject *self = NULL; + mpd_context_t *ctx; + + if (type == &PyDecContext_Type) { + self = PyObject_New(PyDecContextObject, &PyDecContext_Type); + } + else { + self = (PyDecContextObject *)type->tp_alloc(type, 0); + } + + if (self == NULL) { + return NULL; + } + + self->traps = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + if (self->traps == NULL) { + self->flags = NULL; + Py_DECREF(self); + return NULL; + } + self->flags = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + if (self->flags == NULL) { + Py_DECREF(self); + return NULL; + } + + ctx = CTX(self); + + if (default_context_template) { + *ctx = *CTX(default_context_template); + } + else { + *ctx = dflt_ctx; + } + + SdFlagAddr(self->traps) = &ctx->traps; + SdFlagAddr(self->flags) = &ctx->status; + + CtxCaps(self) = 1; + + return (PyObject *)self; +} + +static void +context_dealloc(PyDecContextObject *self) +{ + Py_XDECREF(self->traps); + Py_XDECREF(self->flags); + Py_TYPE(self)->tp_free(self); +} + +static int +getround(PyObject *v) +{ + const char *s; + long x; + int i; + + if (PyLong_Check(v)) { + x = PyLong_AsLong(v); + if (x == -1 && PyErr_Occurred()) { + return -1; + } + BOUNDS_CHECK(x, 0, INT_MAX); + return (int)x; + } + else if (PyUnicode_Check(v)) { + for (i = 0; i < MPD_ROUND_GUARD; i++) { + s = mpd_round_string[i]; + if (PyUnicode_CompareWithASCIIString(v, s) == 0) { + return i; + } + } + } + + return type_error_int("invalid rounding mode"); +} + +static int +context_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = { + "prec", "rounding", "Emin", "Emax", "capitals", "clamp", + "flags", "traps", NULL + }; + PyObject *rounding = NULL; + PyObject *traps = NULL; + PyObject *status = NULL; + mpd_context_t *ctx, t; + int capitals = 1; + int ret; + + assert(PyTuple_Check(args)); + ctx = CTX(self); + + t = *ctx; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, + "|nOnniiOO", kwlist, + &t.prec, &rounding, &t.emin, &t.emax, &capitals, &t.clamp, + &status, &traps + )) { + return -1; + } + if (rounding != NULL) { + t.round = getround(rounding); + if (t.round < 0) { + return -1; + } + } + + if (!mpd_qsetprec(ctx, t.prec) || + !mpd_qsetemin(ctx, t.emin) || + !mpd_qsetemax(ctx, t.emax) || + !mpd_qsetclamp(ctx, t.clamp)) { + return value_error_int("invalid context"); + } + if (!mpd_qsetround(ctx, t.round) || + !mpd_qsettraps(ctx, t.traps) || + !mpd_qsetstatus(ctx, t.status)) { + return type_error_int("invalid context"); + } + + if (capitals != 0 && capitals != 1) { + return value_error_int("invalid context"); + } + CtxCaps(self) = capitals; + + if (traps != NULL) { + if (PyList_Check(traps)) { + ret = context_settraps_list(self, traps); + } +#ifdef EXTRA_FUNCTIONALITY + else if (PyLong_Check(traps)) { + ret = context_settraps(self, traps, NULL); + } +#endif + else { + ret = context_settraps_dict(self, traps); + } + if (ret < 0) { + return ret; + } + } + if (status != NULL) { + if (PyList_Check(status)) { + ret = context_setstatus_list(self, status); + } +#ifdef EXTRA_FUNCTIONALITY + else if (PyLong_Check(status)) { + ret = context_setstatus(self, status, NULL); + } +#endif + else { + ret = context_setstatus_dict(self, status); + } + if (ret < 0) { + return ret; + } + } + + return 0; +} + +static PyObject * +context_repr(PyDecContextObject *self) +{ + mpd_context_t *ctx; + char flags[MPD_MAX_SIGNAL_LIST]; + char traps[MPD_MAX_SIGNAL_LIST]; + int n, mem; + + assert(PyDecContext_Check(self)); + ctx = CTX(self); + + mem = MPD_MAX_SIGNAL_LIST; + n = mpd_lsnprint_signals(flags, mem, ctx->status, dec_signal_string); + if (n < 0 || n >= mem) { + INTERNAL_ERROR_PTR("context_repr"); + } + + n = mpd_lsnprint_signals(traps, mem, ctx->traps, dec_signal_string); + if (n < 0 || n >= mem) { + INTERNAL_ERROR_PTR("context_repr"); + } + + return PyUnicode_FromFormat( + "Context(prec=%zd, rounding=%s, Emin=%zd, Emax=%zd, " + "capitals=%d, clamp=%d, flags=%s, traps=%s)", + ctx->prec, mpd_round_string[ctx->round], ctx->emin, ctx->emax, + self->capitals, ctx->clamp, flags, traps); +} + +static void +init_basic_context(PyObject *v) +{ + mpd_context_t ctx = dflt_ctx; + + ctx.prec = 9; + ctx.traps |= (MPD_Underflow|MPD_Clamped); + ctx.round = MPD_ROUND_HALF_UP; + + *CTX(v) = ctx; + CtxCaps(v) = 1; +} + +static void +init_extended_context(PyObject *v) +{ + mpd_context_t ctx = dflt_ctx; + + ctx.prec = 9; + ctx.traps = 0; + + *CTX(v) = ctx; + CtxCaps(v) = 1; +} + +#ifdef EXTRA_FUNCTIONALITY +/* Factory function for creating IEEE interchange format contexts */ +static PyObject * +ieee_context(PyObject *dummy UNUSED, PyObject *v) +{ + PyObject *context; + mpd_ssize_t bits; + mpd_context_t ctx; + + bits = PyLong_AsSsize_t(v); + if (bits == -1 && PyErr_Occurred()) { + return NULL; + } + if (bits <= 0 || bits > INT_MAX) { + goto error; + } + if (mpd_ieee_context(&ctx, (int)bits) < 0) { + goto error; + } + + context = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + if (context == NULL) { + return NULL; + } + *CTX(context) = ctx; + + return context; + +error: + PyErr_Format(PyExc_ValueError, + "argument must be a multiple of 32, with a maximum of %d", + MPD_IEEE_CONTEXT_MAX_BITS); + + return NULL; +} +#endif + +static PyObject * +context_copy(PyObject *self) +{ + PyObject *copy; + + copy = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + if (copy == NULL) { + return NULL; + } + + *CTX(copy) = *CTX(self); + CTX(copy)->newtrap = 0; + CtxCaps(copy) = CtxCaps(self); + + return copy; +} + +static PyObject * +context_reduce(PyObject *self, PyObject *args UNUSED) +{ + PyObject *flags; + PyObject *traps; + PyObject *ret; + mpd_context_t *ctx; + + ctx = CTX(self); + + flags = signals_as_list(ctx->status); + if (flags == NULL) { + return NULL; + } + traps = signals_as_list(ctx->traps); + if (traps == NULL) { + Py_DECREF(flags); + return NULL; + } + + ret = Py_BuildValue( + "O(nsnniiOO)", + Py_TYPE(self), + ctx->prec, mpd_round_string[ctx->round], ctx->emin, ctx->emax, + CtxCaps(self), ctx->clamp, flags, traps + ); + + Py_DECREF(flags); + Py_DECREF(traps); + return ret; +} + + +static PyGetSetDef context_getsets [] = +{ + { "prec", (getter)context_getprec, (setter)context_setprec, NULL, NULL}, + { "Emax", (getter)context_getemax, (setter)context_setemax, NULL, NULL}, + { "Emin", (getter)context_getemin, (setter)context_setemin, NULL, NULL}, + { "rounding", (getter)context_getround, (setter)context_setround, NULL, NULL}, + { "capitals", (getter)context_getcapitals, (setter)context_setcapitals, NULL, NULL}, + { "clamp", (getter)context_getclamp, (setter)context_setclamp, NULL, NULL}, +#ifdef EXTRA_FUNCTIONALITY + { "_allcr", (getter)context_getallcr, (setter)context_setallcr, NULL, NULL}, + { "_traps", (getter)context_gettraps, (setter)context_settraps, NULL, NULL}, + { "_flags", (getter)context_getstatus, (setter)context_setstatus, NULL, NULL}, +#endif + {NULL} +}; + + +#define CONTEXT_CHECK(obj) \ + if (!PyDecContext_Check(obj)) { \ + PyErr_SetString(PyExc_TypeError, \ + "argument must be a context"); \ + return NULL; \ + } + +#define CONTEXT_CHECK_VA(obj) \ + if (!PyDecContext_Check(obj)) { \ + PyErr_SetString(PyExc_TypeError, \ + "optional argument must be a context"); \ + return NULL; \ + } + + +/******************************************************************************/ +/* Global, thread local and temporary contexts */ +/******************************************************************************/ + +#ifdef WITHOUT_THREADS +/* Return borrowed reference to the current context. When compiled + * without threads, this is always the module context. */ +static int module_context_set = 0; +static PyObject * +current_context(void) +{ + /* In decimal.py, the module context is automatically initialized + * from the DefaultContext when it is first accessed. This + * complicates the code and has a speed penalty of 1-2%. */ + if (module_context_set) { + return module_context; + } + + *CTX(module_context) = *CTX(default_context_template); + module_context_set = 1; + return module_context; +} + +/* ctxobj := borrowed reference to the current context */ +#define CURRENT_CONTEXT(ctxobj) \ + ctxobj = current_context() + +/* ctx := pointer to the mpd_context_t struct of the current context */ +#define CURRENT_CONTEXT_ADDR(ctx) \ + ctx = CTX(current_context()) + +/* Return current context, increment reference */ +static PyObject * +PyDec_GetCurrentContext(void) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + + Py_INCREF(context); + return context; +} + +/* Set the module context to a new context, decrement old reference */ +static PyObject * +PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) +{ + CONTEXT_CHECK(v); + + /* If the new context is one of the templates, make a copy. + * This is the current behavior of decimal.py. */ + if (v == default_context_template || + v == basic_context_template || + v == extended_context_template) { + v = context_copy(v); + if (v == NULL) { + return NULL; + } + } + else { + Py_INCREF(v); + } + + Py_XDECREF(module_context); + module_context = v; + module_context_set = 1; + Py_RETURN_NONE; +} +#else +/* + * Thread local storage currently has a speed penalty of about 16%. + * All functions that map Python's arithmetic operators to mpdecimal + * functions have to look up the current context for each and every + * operation. + */ + +/* Return borrowed reference to thread local context. */ +static PyObject * +current_context(void) +{ + PyObject *dict = NULL; + PyObject *tl_context = NULL; + + dict = PyThreadState_GetDict(); + if (dict == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "cannot get thread state"); + return NULL; + } + + tl_context = PyDict_GetItemWithError(dict, tls_context_key); + if (tl_context != NULL) { + /* We already have a thread local context and + * return a borrowed reference. */ + CONTEXT_CHECK(tl_context); + return tl_context; + } + if (PyErr_Occurred()) { + return NULL; + } + + /* Otherwise, set up a new thread local context. */ + tl_context = context_copy(default_context_template); + if (tl_context == NULL) { + return NULL; + } + if (PyDict_SetItem(dict, tls_context_key, tl_context) < 0) { + Py_DECREF(tl_context); + return NULL; + } + Py_DECREF(tl_context); + + /* refcount is 1 */ + return tl_context; +} + +/* ctxobj := borrowed reference to the current context */ +#define CURRENT_CONTEXT(ctxobj) \ + ctxobj = current_context(); \ + if (ctxobj == NULL) { \ + return NULL; \ + } + +/* ctx := pointer to the mpd_context_t struct of the current context */ +#define CURRENT_CONTEXT_ADDR(ctx) { \ + PyObject *_c_t_x_o_b_j = current_context(); \ + if (_c_t_x_o_b_j == NULL) { \ + return NULL; \ + } \ + ctx = CTX(_c_t_x_o_b_j); \ +} + +/* Return current context, increment reference */ +static PyObject * +PyDec_GetCurrentContext(void) +{ + PyObject *context; + + context = current_context(); + if (context == NULL) { + return NULL; + } + + Py_INCREF(context); + return context; +} + +/* Set the thread local context to a new context, decrement old reference */ +static PyObject * +PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) +{ + PyObject *dict; + + CONTEXT_CHECK(v); + + dict = PyThreadState_GetDict(); + if (dict == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "cannot get thread state"); + return NULL; + } + + /* If the new context is one of the templates, make a copy. + * This is the current behavior of decimal.py. */ + if (v == default_context_template || + v == basic_context_template || + v == extended_context_template) { + v = context_copy(v); + if (v == NULL) { + return NULL; + } + } + else { + Py_INCREF(v); + } + + if (PyDict_SetItem(dict, tls_context_key, v) < 0) { + Py_DECREF(v); + return NULL; + } + + Py_DECREF(v); + Py_RETURN_NONE; +} +#endif + +/* Context manager object for the 'with' statement. The manager + * owns one reference to the global (outer) context and one + * to the local (inner) context. */ +static PyObject * +ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args) +{ + PyDecContextManagerObject *self; + PyObject *local; + PyObject *global; + + CURRENT_CONTEXT(global); + local = global; + if (!PyArg_ParseTuple(args, "|O", &local)) { + return NULL; + } + CONTEXT_CHECK_VA(local); + + self = PyObject_New(PyDecContextManagerObject, + &PyDecContextManager_Type); + if (self == NULL) { + return NULL; + } + + self->local = context_copy(local); + if (self->local == NULL) { + self->global = NULL; + Py_DECREF(self); + return NULL; + } + self->global = global; + Py_INCREF(self->global); + + return (PyObject *)self; +} + +static void +ctxmanager_dealloc(PyDecContextManagerObject *self) +{ + Py_XDECREF(self->local); + Py_XDECREF(self->global); + PyObject_Del(self); +} + +static PyObject * +ctxmanager_set_local(PyDecContextManagerObject *self, PyObject *args UNUSED) +{ + PyObject *ret; + + ret = PyDec_SetCurrentContext(NULL, self->local); + if (ret == NULL) { + return NULL; + } + Py_DECREF(ret); + + Py_INCREF(self->local); + return self->local; +} + +static PyObject * +ctxmanager_restore_global(PyDecContextManagerObject *self, + PyObject *args UNUSED) +{ + PyObject *ret; + + ret = PyDec_SetCurrentContext(NULL, self->global); + if (ret == NULL) { + return NULL; + } + Py_DECREF(ret); + + Py_RETURN_NONE; +} + + +static PyMethodDef ctxmanager_methods[] = { + {"__enter__", (PyCFunction)ctxmanager_set_local, METH_NOARGS, NULL}, + {"__exit__", (PyCFunction)ctxmanager_restore_global, METH_VARARGS, NULL}, + {NULL, NULL} +}; + +static PyTypeObject PyDecContextManager_Type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "decimal.ContextManager", /* tp_name */ + sizeof(PyDecContextManagerObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) ctxmanager_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc) 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + (PyBufferProcs *) 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + ctxmanager_methods, /* tp_methods */ +}; + + +/******************************************************************************/ +/* New Decimal Object */ +/******************************************************************************/ + +static PyObject * +PyDecType_New(PyTypeObject *type) +{ + PyObject *dec; + + if (type == &PyDec_Type) { + dec = (PyObject *)PyObject_New(PyDecObject, &PyDec_Type); + } + else { + dec = type->tp_alloc(type, 0); + } + if (dec == NULL) { + return NULL; + } + + MPD(dec) = mpd_qnew(); + if (MPD(dec) == NULL) { + Py_DECREF(dec); + PyErr_NoMemory(); + return NULL; + } + + return dec; +} +#define dec_alloc() PyDecType_New(&PyDec_Type) + +static void +dec_dealloc(PyObject *dec) +{ + if (MPD(dec)) { + mpd_del(MPD(dec)); + } + Py_TYPE(dec)->tp_free(dec); +} + + +/******************************************************************************/ +/* Conversions to Decimal */ +/******************************************************************************/ + +Py_LOCAL_INLINE(int) +is_space(enum PyUnicode_Kind kind, void *data, Py_ssize_t pos) +{ + Py_UCS4 ch = PyUnicode_READ(kind, data, pos); + return Py_UNICODE_ISSPACE(ch); +} + +/* Return the ASCII representation of a numeric Unicode string. The numeric + string may contain ascii characters in the range [1, 127], any Unicode + space and any unicode digit. If strip_ws is true, leading and trailing + whitespace is stripped. + + Return NULL if malloc fails and an empty string if invalid characters + are found. */ +static char * +numeric_as_ascii(const PyObject *u, int strip_ws) +{ + enum PyUnicode_Kind kind; + void *data; + Py_UCS4 ch; + char *res, *cp; + Py_ssize_t j, len; + int d; + + assert(PyUnicode_IS_READY(u)); + + kind = PyUnicode_KIND(u); + data = PyUnicode_DATA(u); + len = PyUnicode_GET_LENGTH(u); + + cp = res = PyMem_Malloc(len+1); + if (res == NULL) { + PyErr_NoMemory(); + return NULL; + } + + j = 0; + if (strip_ws) { + while (len > 0 && is_space(kind, data, len-1)) { + len--; + } + while (j < len && is_space(kind, data, j)) { + j++; + } + } + + for (; j < len; j++) { + ch = PyUnicode_READ(kind, data, j); + if (0 < ch && ch <= 127) { + *cp++ = ch; + continue; + } + if (Py_UNICODE_ISSPACE(ch)) { + *cp++ = ' '; + continue; + } + d = Py_UNICODE_TODECIMAL(ch); + if (d < 0) { + /* empty string triggers ConversionSyntax */ + *res = '\0'; + return res; + } + *cp++ = '0' + d; + } + *cp = '\0'; + return res; +} + +/* Return a new PyDecObject or a subtype from a C string. Use the context + during conversion. */ +static PyObject * +PyDecType_FromCString(PyTypeObject *type, const char *s, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + mpd_qset_string(MPD(dec), s, CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + return dec; +} + +/* Return a new PyDecObject or a subtype from a C string. Attempt exact + conversion. If the operand cannot be converted exactly, set + InvalidOperation. */ +static PyObject * +PyDecType_FromCStringExact(PyTypeObject *type, const char *s, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + mpd_context_t maxctx; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + mpd_maxcontext(&maxctx); + + mpd_qset_string(MPD(dec), s, &maxctx, &status); + if (status & (MPD_Inexact|MPD_Rounded)) { + /* we want exact results */ + mpd_seterror(MPD(dec), MPD_Invalid_operation, &status); + } + status &= MPD_Errors; + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + + return dec; +} + +/* Return a new PyDecObject or a subtype from a PyUnicodeObject. */ +static PyObject * +PyDecType_FromUnicode(PyTypeObject *type, const PyObject *u, + PyObject *context) +{ + PyObject *dec; + char *s; + + s = numeric_as_ascii(u, 0); + if (s == NULL) { + return NULL; + } + + dec = PyDecType_FromCString(type, s, context); + PyMem_Free(s); + return dec; +} + +/* Return a new PyDecObject or a subtype from a PyUnicodeObject. Attempt exact + * conversion. If the conversion is not exact, fail with InvalidOperation. + * Allow leading and trailing whitespace in the input operand. */ +static PyObject * +PyDecType_FromUnicodeExactWS(PyTypeObject *type, const PyObject *u, + PyObject *context) +{ + PyObject *dec; + char *s; + + s = numeric_as_ascii(u, 1); + if (s == NULL) { + return NULL; + } + + dec = PyDecType_FromCStringExact(type, s, context); + PyMem_Free(s); + return dec; +} + +/* Set PyDecObject from triple without any error checking. */ +Py_LOCAL_INLINE(void) +_dec_settriple(PyObject *dec, uint8_t sign, uint32_t v, mpd_ssize_t exp) +{ + +#ifdef CONFIG_64 + MPD(dec)->data[0] = v; + MPD(dec)->len = 1; +#else + uint32_t q, r; + q = v / MPD_RADIX; + r = v - q * MPD_RADIX; + MPD(dec)->data[1] = q; + MPD(dec)->data[0] = r; + MPD(dec)->len = q ? 2 : 1; +#endif + mpd_set_flags(MPD(dec), sign); + MPD(dec)->exp = exp; + mpd_setdigits(MPD(dec)); +} + +/* Return a new PyDecObject from an mpd_ssize_t. */ +static PyObject * +PyDecType_FromSsize(PyTypeObject *type, mpd_ssize_t v, PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + mpd_qset_ssize(MPD(dec), v, CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + return dec; +} + +/* Return a new PyDecObject from an mpd_ssize_t. Conversion is exact. */ +static PyObject * +PyDecType_FromSsizeExact(PyTypeObject *type, mpd_ssize_t v, PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + mpd_context_t maxctx; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + mpd_maxcontext(&maxctx); + + mpd_qset_ssize(MPD(dec), v, &maxctx, &status); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + return dec; +} + +/* Convert from a PyLongObject. The context is not modified; flags set + during conversion are accumulated in the status parameter. */ +static PyObject * +dec_from_long(PyTypeObject *type, const PyObject *v, + const mpd_context_t *ctx, uint32_t *status) +{ + PyObject *dec; + PyLongObject *l = (PyLongObject *)v; + Py_ssize_t ob_size; + size_t len; + uint8_t sign; + + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + + ob_size = Py_SIZE(l); + if (ob_size == 0) { + _dec_settriple(dec, MPD_POS, 0, 0); + return dec; + } + + if (ob_size < 0) { + len = -ob_size; + sign = MPD_NEG; + } + else { + len = ob_size; + sign = MPD_POS; + } + + if (len == 1) { + _dec_settriple(dec, sign, *l->ob_digit, 0); + mpd_qfinalize(MPD(dec), ctx, status); + return dec; + } + +#if PYLONG_BITS_IN_DIGIT == 30 + mpd_qimport_u32(MPD(dec), l->ob_digit, len, sign, PyLong_BASE, + ctx, status); +#elif PYLONG_BITS_IN_DIGIT == 15 + mpd_qimport_u16(MPD(dec), l->ob_digit, len, sign, PyLong_BASE, + ctx, status); +#else + #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" +#endif + + return dec; +} + +/* Return a new PyDecObject from a PyLongObject. Use the context for + conversion. */ +static PyObject * +PyDecType_FromLong(PyTypeObject *type, const PyObject *pylong, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + + dec = dec_from_long(type, pylong, CTX(context), &status); + if (dec == NULL) { + return NULL; + } + + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + + return dec; +} + +/* Return a new PyDecObject from a PyLongObject. Use a maximum context + for conversion. If the conversion is not exact, set InvalidOperation. */ +static PyObject * +PyDecType_FromLongExact(PyTypeObject *type, const PyObject *pylong, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + mpd_context_t maxctx; + + mpd_maxcontext(&maxctx); + dec = dec_from_long(type, pylong, &maxctx, &status); + if (dec == NULL) { + return NULL; + } + + if (status & (MPD_Inexact|MPD_Rounded)) { + /* we want exact results */ + mpd_seterror(MPD(dec), MPD_Invalid_operation, &status); + } + status &= MPD_Errors; + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + + return dec; +} + +/* Return a PyDecObject or a subtype from a PyFloatObject. + Conversion is exact. */ +static PyObject * +PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, + PyObject *context) +{ + PyObject *dec, *tmp; + PyObject *n, *d, *n_d; + mpd_ssize_t k; + double x; + int sign; + mpd_t *d1, *d2; + uint32_t status = 0; + mpd_context_t maxctx; + + + assert(PyType_IsSubtype(type, &PyDec_Type)); + + if (PyLong_Check(v)) { + return PyDecType_FromLongExact(type, v, context); + } + if (!PyFloat_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "argument must be int of float"); + return NULL; + } + + x = PyFloat_AsDouble(v); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + sign = (copysign(1.0, x) == 1.0) ? 0 : 1; + + if (Py_IS_NAN(x) || Py_IS_INFINITY(x)) { + dec = PyDecType_New(type); + if (dec == NULL) { + return NULL; + } + if (Py_IS_NAN(x)) { + /* decimal.py calls repr(float(+-nan)), + * which always gives a positive result. */ + mpd_setspecial(MPD(dec), MPD_POS, MPD_NAN); + } + else { + mpd_setspecial(MPD(dec), sign, MPD_INF); + } + return dec; + } + + /* absolute value of the float */ + tmp = PyObject_CallMethod(v, "__abs__", NULL); + if (tmp == NULL) { + return NULL; + } + + /* float as integer ratio: numerator/denominator */ + n_d = PyObject_CallMethod(tmp, "as_integer_ratio", NULL); + Py_DECREF(tmp); + if (n_d == NULL) { + return NULL; + } + n = PyTuple_GET_ITEM(n_d, 0); + d = PyTuple_GET_ITEM(n_d, 1); + + tmp = PyObject_CallMethod(d, "bit_length", NULL); + if (tmp == NULL) { + Py_DECREF(n_d); + return NULL; + } + k = PyLong_AsSsize_t(tmp); + Py_DECREF(tmp); + if (k == -1 && PyErr_Occurred()) { + Py_DECREF(n_d); + return NULL; + } + k--; + + dec = PyDecType_FromLongExact(type, n, context); + Py_DECREF(n_d); + if (dec == NULL) { + return NULL; + } + + d1 = mpd_qnew(); + if (d1 == NULL) { + Py_DECREF(dec); + PyErr_NoMemory(); + return NULL; + } + d2 = mpd_qnew(); + if (d2 == NULL) { + mpd_del(d1); + Py_DECREF(dec); + PyErr_NoMemory(); + return NULL; + } + + mpd_maxcontext(&maxctx); + mpd_qset_uint(d1, 5, &maxctx, &status); + mpd_qset_ssize(d2, k, &maxctx, &status); + mpd_qpow(d1, d1, d2, &maxctx, &status); + if (dec_addstatus(context, status)) { + mpd_del(d1); + mpd_del(d2); + Py_DECREF(dec); + return NULL; + } + + /* result = n * 5**k */ + mpd_qmul(MPD(dec), MPD(dec), d1, &maxctx, &status); + mpd_del(d1); + mpd_del(d2); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + /* result = +- n * 5**k * 10**-k */ + mpd_set_sign(MPD(dec), sign); + MPD(dec)->exp = -k; + + return dec; +} + +static PyObject * +PyDecType_FromFloat(PyTypeObject *type, PyObject *v, + PyObject *context) +{ + PyObject *dec; + uint32_t status = 0; + + dec = PyDecType_FromFloatExact(type, v, context); + if (dec == NULL) { + return NULL; + } + + mpd_qfinalize(MPD(dec), CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(dec); + return NULL; + } + + return dec; +} + +static PyObject * +sequence_as_tuple(PyObject *v, PyObject *ex, const char *mesg) +{ + if (PyTuple_Check(v)) { + Py_INCREF(v); + return v; + } + if (PyList_Check(v)) { + return PyList_AsTuple(v); + } + + PyErr_SetString(ex, mesg); + return NULL; +} + +/* Return a new C string representation of a DecimalTuple. */ +static char * +dectuple_as_str(PyObject *dectuple) +{ + PyObject *digits = NULL, *tmp; + char *decstring = NULL; + char sign_special[6]; + char *cp; + long sign, l; + mpd_ssize_t exp = 0; + Py_ssize_t i, mem, tsize; + int n; + + assert(PyTuple_Check(dectuple)); + + if (PyTuple_Size(dectuple) != 3) { + PyErr_SetString(PyExc_ValueError, + "argument must be a sequence of length 3"); + goto error; + } + + /* sign */ + tmp = PyTuple_GET_ITEM(dectuple, 0); + if (!PyLong_Check(tmp)) { + PyErr_SetString(PyExc_ValueError, + "sign must be an integer with the value 0 or 1"); + goto error; + } + sign = PyLong_AsLong(tmp); + if (sign == -1 && PyErr_Occurred()) { + goto error; + } + if (sign != 0 && sign != 1) { + PyErr_SetString(PyExc_ValueError, + "sign must be an integer with the value 0 or 1"); + goto error; + } + sign_special[0] = sign ? '-' : '+'; + sign_special[1] = '\0'; + + /* exponent or encoding for a special number */ + tmp = PyTuple_GET_ITEM(dectuple, 2); + if (PyUnicode_Check(tmp)) { + /* special */ + if (PyUnicode_CompareWithASCIIString(tmp, "F") == 0) { + strcat(sign_special, "Inf"); + } + else if (PyUnicode_CompareWithASCIIString(tmp, "n") == 0) { + strcat(sign_special, "NaN"); + } + else if (PyUnicode_CompareWithASCIIString(tmp, "N") == 0) { + strcat(sign_special, "sNaN"); + } + else { + PyErr_SetString(PyExc_ValueError, + "string argument in the third position " + "must be 'F', 'n' or 'N'"); + goto error; + } + } + else { + /* exponent */ + if (!PyLong_Check(tmp)) { + PyErr_SetString(PyExc_ValueError, + "exponent must be an integer"); + goto error; + } + exp = PyLong_AsSsize_t(tmp); + if (exp == -1 && PyErr_Occurred()) { + goto error; + } + } + + /* coefficient */ + digits = sequence_as_tuple(PyTuple_GET_ITEM(dectuple, 1), + PyExc_ValueError, "coefficient must be a tuple of digits"); + if (digits == NULL) { + goto error; + } + + tsize = PyTuple_Size(digits); + /* [sign][coeffdigits+1][E][-][expdigits+1]['\0'] */ + mem = 1 + tsize + 3 + MPD_EXPDIGITS + 2; + cp = decstring = PyMem_Malloc(mem); + if (decstring == NULL) { + PyErr_NoMemory(); + goto error; + } + + n = snprintf(cp, mem, "%s", sign_special); + if (n < 0 || n >= mem) { + PyErr_SetString(PyExc_RuntimeError, + "internal error in dec_sequence_as_str"); + goto error; + } + cp += n; + + if (tsize == 0 && sign_special[1] == '\0') { + /* empty tuple: zero coefficient, except for special numbers */ + *cp++ = '0'; + } + for (i = 0; i < tsize; i++) { + tmp = PyTuple_GET_ITEM(digits, i); + if (!PyLong_Check(tmp)) { + PyErr_SetString(PyExc_ValueError, + "coefficient must be a tuple of digits"); + goto error; + } + l = PyLong_AsLong(tmp); + if (l == -1 && PyErr_Occurred()) { + goto error; + } + if (l < 0 || l > 9) { + PyErr_SetString(PyExc_ValueError, + "coefficient must be a tuple of digits"); + goto error; + } + *cp++ = (char)l + '0'; + } + *cp = '\0'; + + if (sign_special[1] == '\0') { + /* not a special number */ + *cp++ = 'E'; + n = snprintf(cp, MPD_EXPDIGITS+1, "%" PRI_mpd_ssize_t, exp); + if (n < 0 || n >= MPD_EXPDIGITS+1) { + PyErr_SetString(PyExc_RuntimeError, + "internal error in dec_sequence_as_str"); + goto error; + } + } + + Py_XDECREF(digits); + return decstring; + + +error: + Py_XDECREF(digits); + if (decstring) PyMem_Free(decstring); + return NULL; +} + +/* Currently accepts tuples and lists. */ +static PyObject * +PyDecType_FromSequence(PyTypeObject *type, PyObject *v, + PyObject *context) +{ + PyObject *dectuple; + PyObject *dec; + char *s; + + dectuple = sequence_as_tuple(v, PyExc_TypeError, + "argument must be a tuple or list"); + if (dectuple == NULL) { + return NULL; + } + + s = dectuple_as_str(dectuple); + Py_DECREF(dectuple); + if (s == NULL) { + return NULL; + } + + dec = PyDecType_FromCString(type, s, context); + + PyMem_Free(s); + return dec; +} + +/* Currently accepts tuples and lists. */ +static PyObject * +PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v, + PyObject *context) +{ + PyObject *dectuple; + PyObject *dec; + char *s; + + dectuple = sequence_as_tuple(v, PyExc_TypeError, + "argument must be a tuple or list"); + if (dectuple == NULL) { + return NULL; + } + + s = dectuple_as_str(dectuple); + Py_DECREF(dectuple); + if (s == NULL) { + return NULL; + } + + dec = PyDecType_FromCStringExact(type, s, context); + + PyMem_Free(s); + return dec; +} + +#define PyDec_FromCString(str, context) \ + PyDecType_FromCString(&PyDec_Type, str, context) +#define PyDec_FromCStringExact(str, context) \ + PyDecType_FromCStringExact(&PyDec_Type, str, context) + +#define PyDec_FromUnicode(unicode, context) \ + PyDecType_FromUnicode(&PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExact(unicode, context) \ + PyDecType_FromUnicodeExact(&PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExactWS(unicode, context) \ + PyDecType_FromUnicodeExactWS(&PyDec_Type, unicode, context) + +#define PyDec_FromSsize(v, context) \ + PyDecType_FromSsize(&PyDec_Type, v, context) +#define PyDec_FromSsizeExact(v, context) \ + PyDecType_FromSsizeExact(&PyDec_Type, v, context) + +#define PyDec_FromLong(pylong, context) \ + PyDecType_FromLong(&PyDec_Type, pylong, context) +#define PyDec_FromLongExact(pylong, context) \ + PyDecType_FromLongExact(&PyDec_Type, pylong, context) + +#define PyDec_FromFloat(pyfloat, context) \ + PyDecType_FromFloat(&PyDec_Type, pyfloat, context) +#define PyDec_FromFloatExact(pyfloat, context) \ + PyDecType_FromFloatExact(&PyDec_Type, pyfloat, context) + +#define PyDec_FromSequence(sequence, context) \ + PyDecType_FromSequence(&PyDec_Type, sequence, context) +#define PyDec_FromSequenceExact(sequence, context) \ + PyDecType_FromSequenceExact(&PyDec_Type, sequence, context) + +/* class method */ +static PyObject * +dec_from_float(PyObject *dec, PyObject *pyfloat) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return PyDecType_FromFloatExact((PyTypeObject *)dec, pyfloat, context); +} + +/* create_decimal_from_float */ +static PyObject * +ctx_from_float(PyObject *context, PyObject *v) +{ + return PyDec_FromFloat(v, context); +} + +/* Apply the context to the input operand. Return a new PyDecObject. */ +static PyObject * +dec_apply(PyObject *v, PyObject *context) +{ + PyObject *result; + uint32_t status = 0; + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + mpd_qcopy(MPD(result), MPD(v), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + mpd_qfinalize(MPD(result), CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +/* 'v' can have any type accepted by the Decimal constructor. Attempt + an exact conversion. If the result does not meet the restrictions + for an mpd_t, fail with InvalidOperation. */ +static PyObject * +PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) +{ + if (v == NULL) { + return PyDecType_FromSsizeExact(type, 0, context); + } + else if (PyDec_Check(v)) { + Py_INCREF(v); + return v; + } + else if (PyUnicode_Check(v)) { + return PyDecType_FromUnicodeExactWS(type, v, context); + } + else if (PyLong_Check(v)) { + return PyDecType_FromLongExact(type, v, context); + } + else if (PyTuple_Check(v) || PyList_Check(v)) { + return PyDecType_FromSequenceExact(type, v, context); + } + else if (PyFloat_Check(v)) { + if (dec_addstatus(context, MPD_Float_operation)) { + return NULL; + } + return PyDecType_FromFloatExact(type, v, context); + } + else { + PyErr_Format(PyExc_TypeError, + "conversion from %s to Decimal is not supported", + v->ob_type->tp_name); + return NULL; + } +} + +/* The context is used during conversion. This function is the + equivalent of context.create_decimal(). */ +static PyObject * +PyDec_FromObject(PyObject *v, PyObject *context) +{ + if (v == NULL) { + return PyDec_FromSsize(0, context); + } + else if (PyDec_Check(v)) { + mpd_context_t *ctx = CTX(context); + if (mpd_isnan(MPD(v)) && + MPD(v)->digits > ctx->prec - ctx->clamp) { + /* Special case: too many NaN payload digits */ + PyObject *result; + if (dec_addstatus(context, MPD_Conversion_syntax)) { + return NULL; + } + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + mpd_setspecial(MPD(result), MPD_POS, MPD_NAN); + return result; + } + return dec_apply(v, context); + } + else if (PyUnicode_Check(v)) { + return PyDec_FromUnicode(v, context); + } + else if (PyLong_Check(v)) { + return PyDec_FromLong(v, context); + } + else if (PyTuple_Check(v) || PyList_Check(v)) { + return PyDec_FromSequence(v, context); + } + else if (PyFloat_Check(v)) { + if (dec_addstatus(context, MPD_Float_operation)) { + return NULL; + } + return PyDec_FromFloat(v, context); + } + else { + PyErr_Format(PyExc_TypeError, + "conversion from %s to Decimal is not supported", + v->ob_type->tp_name); + return NULL; + } +} + +static PyObject * +dec_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"value", "context", NULL}; + PyObject *v = NULL; + PyObject *context; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, + &v, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + return PyDecType_FromObjectExact(type, v, context); +} + +static PyObject * +ctx_create_decimal(PyObject *context, PyObject *args) +{ + PyObject *v = NULL; + + if (!PyArg_ParseTuple(args, "|O", &v)) { + return NULL; + } + + return PyDec_FromObject(v, context); +} + + +/******************************************************************************/ +/* Implicit conversions to Decimal */ +/******************************************************************************/ + +/* Try to convert PyObject v to a new PyDecObject conv. If the conversion + fails, set conv to NULL (exception is set). If the conversion is not + implemented, set conv to Py_NotImplemented. */ +#define NOT_IMPL 0 +#define TYPE_ERR 1 +Py_LOCAL_INLINE(int) +convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context) +{ + + if (PyDec_Check(v)) { + *conv = v; + Py_INCREF(v); + return 1; + } + if (PyLong_Check(v)) { + *conv = PyDec_FromLongExact(v, context); + if (*conv == NULL) { + return 0; + } + return 1; + } + + if (type_err) { + PyErr_Format(PyExc_TypeError, + "conversion from %s to Decimal is not supported", + v->ob_type->tp_name); + } + else { + Py_INCREF(Py_NotImplemented); + *conv = Py_NotImplemented; + } + return 0; +} + +/* Return NotImplemented for unsupported types. */ +#define CONVERT_OP(a, v, context) \ + if (!convert_op(NOT_IMPL, a, v, context)) { \ + return *(a); \ + } + +#define CONVERT_BINOP(a, b, v, w, context) \ + if (!convert_op(NOT_IMPL, a, v, context)) { \ + return *(a); \ + } \ + if (!convert_op(NOT_IMPL, b, w, context)) { \ + Py_DECREF(*(a)); \ + return *(b); \ + } + +#define CONVERT_TERNOP(a, b, c, v, w, x, context) \ + if (!convert_op(NOT_IMPL, a, v, context)) { \ + return *(a); \ + } \ + if (!convert_op(NOT_IMPL, b, w, context)) { \ + Py_DECREF(*(a)); \ + return *(b); \ + } \ + if (!convert_op(NOT_IMPL, c, x, context)) { \ + Py_DECREF(*(a)); \ + Py_DECREF(*(b)); \ + return *(c); \ + } + +/* Raise TypeError for unsupported types. */ +#define CONVERT_OP_RAISE(a, v, context) \ + if (!convert_op(TYPE_ERR, a, v, context)) { \ + return NULL; \ + } + +#define CONVERT_BINOP_RAISE(a, b, v, w, context) \ + if (!convert_op(TYPE_ERR, a, v, context)) { \ + return NULL; \ + } \ + if (!convert_op(TYPE_ERR, b, w, context)) { \ + Py_DECREF(*(a)); \ + return NULL; \ + } + +#define CONVERT_TERNOP_RAISE(a, b, c, v, w, x, context) \ + if (!convert_op(TYPE_ERR, a, v, context)) { \ + return NULL; \ + } \ + if (!convert_op(TYPE_ERR, b, w, context)) { \ + Py_DECREF(*(a)); \ + return NULL; \ + } \ + if (!convert_op(TYPE_ERR, c, x, context)) { \ + Py_DECREF(*(a)); \ + Py_DECREF(*(b)); \ + return NULL; \ + } + + +/******************************************************************************/ +/* Implicit conversions to Decimal for comparison */ +/******************************************************************************/ + +/* Convert rationals for comparison */ +static PyObject *Rational = NULL; +static PyObject * +multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) +{ + PyObject *result; + PyObject *tmp = NULL; + PyObject *denom = NULL; + uint32_t status = 0; + mpd_context_t maxctx; + mpd_ssize_t exp; + mpd_t *vv; + + /* v is not special, r is a rational */ + tmp = PyObject_GetAttrString(r, "denominator"); + if (tmp == NULL) { + return NULL; + } + denom = PyDec_FromLongExact(tmp, context); + Py_DECREF(tmp); + if (denom == NULL) { + return NULL; + } + + vv = mpd_qncopy(MPD(v)); + if (vv == NULL) { + Py_DECREF(denom); + PyErr_NoMemory(); + return NULL; + } + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(denom); + mpd_del(vv); + return NULL; + } + + mpd_maxcontext(&maxctx); + /* Prevent Overflow in the following multiplication. The result of + the multiplication is only used in mpd_qcmp, which can handle + values that are technically out of bounds, like (for 32-bit) + 99999999999999999999...99999999e+425000000. */ + exp = vv->exp; + vv->exp = 0; + mpd_qmul(MPD(result), vv, MPD(denom), &maxctx, &status); + MPD(result)->exp = exp; + + Py_DECREF(denom); + mpd_del(vv); + /* If any status has been accumulated during the multiplication, + the result is invalid. This is very unlikely, since even the + 32-bit version supports 425000000 digits. */ + if (status) { + PyErr_SetString(PyExc_ValueError, + "exact conversion for comparison failed"); + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +numerator_as_decimal(PyObject *r, PyObject *context) +{ + PyObject *tmp, *num; + + tmp = PyObject_GetAttrString(r, "numerator"); + if (tmp == NULL) { + return NULL; + } + + num = PyDec_FromLongExact(tmp, context); + Py_DECREF(tmp); + return num; +} + +/* Convert v and w for comparison. v is a Decimal. If w is a Rational, both + v and w have to be transformed. Return 1 for success, with new references + to the converted objects in vcmp and wcmp. Return 0 for failure. In that + case wcmp is either NULL or Py_NotImplemented (new reference) and vcmp + is undefined. */ +static int +convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, + int op, PyObject *context) +{ + mpd_context_t *ctx = CTX(context); + + *vcmp = v; + + if (PyDec_Check(w)) { + Py_INCREF(w); + *wcmp = w; + } + else if (PyLong_Check(w)) { + *wcmp = PyDec_FromLongExact(w, context); + } + else if (PyFloat_Check(w)) { + if (op != Py_EQ && op != Py_NE && + dec_addstatus(context, MPD_Float_operation)) { + *wcmp = NULL; + } + else { + ctx->status |= MPD_Float_operation; + *wcmp = PyDec_FromFloatExact(w, context); + } + } + else if (PyComplex_Check(w) && (op == Py_EQ || op == Py_NE)) { + Py_complex c = PyComplex_AsCComplex(w); + if (c.real == -1.0 && PyErr_Occurred()) { + *wcmp = NULL; + } + else if (c.imag == 0.0) { + PyObject *tmp = PyFloat_FromDouble(c.real); + if (tmp == NULL) { + *wcmp = NULL; + } + else { + ctx->status |= MPD_Float_operation; + *wcmp = PyDec_FromFloatExact(tmp, context); + Py_DECREF(tmp); + } + } + else { + Py_INCREF(Py_NotImplemented); + *wcmp = Py_NotImplemented; + } + } + else if (PyObject_IsInstance(w, Rational)) { + *wcmp = numerator_as_decimal(w, context); + if (*wcmp && !mpd_isspecial(MPD(v))) { + *vcmp = multiply_by_denominator(v, w, context); + if (*vcmp == NULL) { + Py_CLEAR(*wcmp); + } + } + } + else { + Py_INCREF(Py_NotImplemented); + *wcmp = Py_NotImplemented; + } + + if (*wcmp == NULL || *wcmp == Py_NotImplemented) { + return 0; + } + if (*vcmp == v) { + Py_INCREF(v); + } + return 1; +} + +#define CONVERT_BINOP_CMP(vcmp, wcmp, v, w, op, ctx) \ + if (!convert_op_cmp(vcmp, wcmp, v, w, op, ctx)) { \ + return *(wcmp); \ + } \ + + +/******************************************************************************/ +/* Conversions from decimal */ +/******************************************************************************/ + +static PyObject * +unicode_fromascii(const char *s, Py_ssize_t size) +{ + PyObject *res; + + res = PyUnicode_New(size, 127); + if (res == NULL) { + return NULL; + } + + memcpy(PyUnicode_1BYTE_DATA(res), s, size); + return res; +} + +/* PyDecObject as a string. The default module context is only used for + the value of 'capitals'. */ +static PyObject * +dec_str(PyObject *dec) +{ + PyObject *res, *context; + mpd_ssize_t size; + char *cp; + + CURRENT_CONTEXT(context); + size = mpd_to_sci_size(&cp, MPD(dec), CtxCaps(context)); + if (size < 0) { + PyErr_NoMemory(); + return NULL; + } + + res = unicode_fromascii(cp, size); + mpd_free(cp); + return res; +} + +/* Representation of a PyDecObject. */ +static PyObject * +dec_repr(PyObject *dec) +{ + PyObject *res, *context; + char *cp; + + CURRENT_CONTEXT(context); + cp = mpd_to_sci(MPD(dec), CtxCaps(context)); + if (cp == NULL) { + PyErr_NoMemory(); + return NULL; + } + + res = PyUnicode_FromFormat("Decimal('%s')", cp); + mpd_free(cp); + return res; +} + +/* Convert decimal_point or thousands_sep, which may be multibyte or in + the range [128, 255], to a UTF8 string. */ +static PyObject * +dotsep_as_utf8(const char *s) +{ + PyObject *utf8; + PyObject *tmp; + wchar_t buf[2]; + size_t n; + + n = mbstowcs(buf, s, 2); + if (n != 1) { /* Issue #7442 */ + PyErr_SetString(PyExc_ValueError, + "invalid decimal point or unsupported " + "combination of LC_CTYPE and LC_NUMERIC"); + return NULL; + } + tmp = PyUnicode_FromWideChar(buf, n); + if (tmp == NULL) { + return NULL; + } + utf8 = PyUnicode_AsUTF8String(tmp); + Py_DECREF(tmp); + return utf8; +} + +/* Formatted representation of a PyDecObject. */ +static PyObject * +dec_format(PyObject *dec, PyObject *args) +{ + PyObject *result = NULL; + PyObject *override = NULL; + PyObject *dot = NULL; + PyObject *sep = NULL; + PyObject *grouping = NULL; + PyObject *fmt = NULL; + PyObject *fmtarg; + PyObject *context; + mpd_spec_t spec; + char *decstring= NULL; + uint32_t status = 0; + size_t n; + + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTuple(args, "O|O", &fmtarg, &override)) { + return NULL; + } + + if (PyUnicode_Check(fmtarg)) { + fmt = PyUnicode_AsUTF8String(fmtarg); + if (fmt == NULL) { + return NULL; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "format arg must be str"); + return NULL; + } + + if (!mpd_parse_fmt_str(&spec, PyBytes_AS_STRING(fmt), + CtxCaps(context))) { + PyErr_SetString(PyExc_ValueError, + "invalid format string"); + goto finish; + } + if (override) { + /* Values for decimal_point, thousands_sep and grouping can + be explicitly specified in the override dict. These values + take precedence over the values obtained from localeconv() + in mpd_parse_fmt_str(). The feature is not documented and + is only used in test_decimal. */ + if (!PyDict_Check(override)) { + PyErr_SetString(PyExc_TypeError, + "optional argument must be a dict"); + goto finish; + } + if ((dot = PyDict_GetItemString(override, "decimal_point"))) { + if ((dot = PyUnicode_AsUTF8String(dot)) == NULL) { + goto finish; + } + spec.dot = PyBytes_AS_STRING(dot); + } + if ((sep = PyDict_GetItemString(override, "thousands_sep"))) { + if ((sep = PyUnicode_AsUTF8String(sep)) == NULL) { + goto finish; + } + spec.sep = PyBytes_AS_STRING(sep); + } + if ((grouping = PyDict_GetItemString(override, "grouping"))) { + if ((grouping = PyUnicode_AsUTF8String(grouping)) == NULL) { + goto finish; + } + spec.grouping = PyBytes_AS_STRING(grouping); + } + if (mpd_validate_lconv(&spec) < 0) { + PyErr_SetString(PyExc_ValueError, + "invalid override dict"); + goto finish; + } + } + else { + n = strlen(spec.dot); + if (n > 1 || (n == 1 && !isascii((uchar)spec.dot[0]))) { + /* fix locale dependent non-ascii characters */ + dot = dotsep_as_utf8(spec.dot); + if (dot == NULL) { + goto finish; + } + spec.dot = PyBytes_AS_STRING(dot); + } + n = strlen(spec.sep); + if (n > 1 || (n == 1 && !isascii((uchar)spec.sep[0]))) { + /* fix locale dependent non-ascii characters */ + sep = dotsep_as_utf8(spec.sep); + if (sep == NULL) { + goto finish; + } + spec.sep = PyBytes_AS_STRING(sep); + } + } + + + decstring = mpd_qformat_spec(MPD(dec), &spec, CTX(context), &status); + if (decstring == NULL) { + dec_addstatus(context, status); + goto finish; + } + result = PyUnicode_DecodeUTF8(decstring, strlen(decstring), NULL); + + +finish: + Py_XDECREF(grouping); + Py_XDECREF(sep); + Py_XDECREF(dot); + Py_XDECREF(fmt); + if (decstring) mpd_free(decstring); + return result; +} + +/* Return a PyLongObject from a PyDecObject, using the specified rounding + * mode. The context precision is not observed. */ +static PyObject * +dec_as_long(PyObject *dec, PyObject *context, int round) +{ + PyLongObject *pylong; + size_t maxsize, n; + Py_ssize_t i; + mpd_t *x; + mpd_context_t workctx; + uint32_t status = 0; + + if (mpd_isspecial(MPD(dec))) { + if (mpd_isnan(MPD(dec))) { + PyErr_SetString(PyExc_ValueError, + "cannot convert NaN to integer"); + } + else { + PyErr_SetString(PyExc_OverflowError, + "cannot convert Infinity to integer"); + } + return NULL; + } + + x = mpd_qnew(); + if (x == NULL) { + PyErr_NoMemory(); + return NULL; + } + workctx = *CTX(context); + workctx.round = round; + mpd_qround_to_int(x, MPD(dec), &workctx, &status); + if (dec_addstatus(context, status)) { + mpd_del(x); + return NULL; + } + + maxsize = mpd_sizeinbase(x, PyLong_BASE); + if (maxsize > PY_SSIZE_T_MAX) { + mpd_del(x); + PyErr_NoMemory(); + return NULL; + } + pylong = _PyLong_New(maxsize); + if (pylong == NULL) { + mpd_del(x); + return NULL; + } + + status = 0; +#if PYLONG_BITS_IN_DIGIT == 30 + n = mpd_qexport_u32(pylong->ob_digit, maxsize, PyLong_BASE, x, &status); +#elif PYLONG_BITS_IN_DIGIT == 15 + n = mpd_qexport_u16(pylong->ob_digit, maxsize, PyLong_BASE, x, &status); +#else + #error "PYLONG_BITS_IN_DIGIT should be 15 or 30" +#endif + if (dec_addstatus(context, status)) { + Py_DECREF((PyObject *) pylong); + mpd_del(x); + return NULL; + } + + i = n; + while ((i > 0) && (pylong->ob_digit[i-1] == 0)) { + i--; + } + + Py_SIZE(pylong) = i; + if (mpd_isnegative(x) && !mpd_iszero(x)) { + Py_SIZE(pylong) = -i; + } + + mpd_del(x); + return (PyObject *) pylong; +} + +static PyObject * +PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"rounding", "context", NULL}; + PyObject *result; + PyObject *context; + uint32_t status = 0; + mpd_context_t workctx; + int round = -1; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, + &round, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + workctx = *CTX(context); + if (round >= 0) { + if (!mpd_qsetround(&workctx, round)) { + return type_error_ptr(invalid_rounding_err); + } + } + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + mpd_qround_to_int(MPD(result), MPD(dec), &workctx, &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"rounding", "context", NULL}; + PyObject *result; + PyObject *context; + uint32_t status = 0; + mpd_context_t workctx; + int round = -1; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, + &round, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + workctx = *CTX(context); + if (round >= 0) { + if (!mpd_qsetround(&workctx, round)) { + return type_error_ptr(invalid_rounding_err); + } + } + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + mpd_qround_to_intx(MPD(result), MPD(dec), &workctx, &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +PyDec_AsFloat(PyObject *dec) +{ + PyObject *f, *s; + + s = dec_str(dec); + if (s == NULL) { + return NULL; + } + + f = PyFloat_FromString(s); + Py_DECREF(s); + + return f; +} + +static PyObject * +PyDec_Round(PyObject *dec, PyObject *args) +{ + PyObject *result; + PyObject *x = NULL; + uint32_t status = 0; + PyObject *context; + + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTuple(args, "|O", &x)) { + return NULL; + } + + if (x) { + mpd_uint_t dq[1] = {1}; + mpd_t q = {MPD_STATIC|MPD_CONST_DATA,0,1,1,1,dq}; + mpd_ssize_t y; + + if (!PyLong_Check(x)) { + PyErr_SetString(PyExc_TypeError, + "optional arg must be an integer"); + return NULL; + } + + y = PyLong_AsSsize_t(x); + if (y == -1 && PyErr_Occurred()) { + return NULL; + } + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + q.exp = (y == MPD_SSIZE_MIN) ? MPD_SSIZE_MAX : -y; + mpd_qquantize(MPD(result), MPD(dec), &q, CTX(context), &status); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; + } + else { + return dec_as_long(dec, context, MPD_ROUND_HALF_EVEN); + } +} + +PyObject *DecimalTuple = NULL; +/* Return the DecimalTuple representation of a PyDecObject. */ +static PyObject * +PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED) +{ + PyObject *result = NULL; + PyObject *sign = NULL; + PyObject *coeff = NULL; + PyObject *expt = NULL; + PyObject *tmp = NULL; + mpd_t *x = NULL; + char *intstring = NULL; + Py_ssize_t intlen, i; + + + x = mpd_qncopy(MPD(dec)); + if (x == NULL) { + PyErr_NoMemory(); + goto out; + } + + sign = PyLong_FromUnsignedLong(mpd_sign(MPD(dec))); + if (sign == NULL) { + goto out; + } + + if (mpd_isinfinite(x)) { + expt = PyUnicode_FromString("F"); + if (expt == NULL) { + goto out; + } + /* decimal.py has non-compliant infinity payloads. */ + coeff = Py_BuildValue("(i)", 0); + if (coeff == NULL) { + goto out; + } + } + else { + if (mpd_isnan(x)) { + expt = PyUnicode_FromString(mpd_isqnan(x)?"n":"N"); + } + else { + expt = PyLong_FromSsize_t(MPD(dec)->exp); + } + if (expt == NULL) { + goto out; + } + + /* coefficient is defined */ + if (x->len > 0) { + + /* make an integer */ + x->exp = 0; + /* clear NaN and sign */ + mpd_clear_flags(x); + intstring = mpd_to_sci(x, 1); + if (intstring == NULL) { + PyErr_NoMemory(); + goto out; + } + + intlen = strlen(intstring); + coeff = PyTuple_New(intlen); + if (coeff == NULL) { + goto out; + } + + for (i = 0; i < intlen; i++) { + tmp = PyLong_FromLong(intstring[i]-'0'); + if (tmp == NULL) { + goto out; + } + PyTuple_SET_ITEM(coeff, i, tmp); + } + } + else { + coeff = PyTuple_New(0); + if (coeff == NULL) { + goto out; + } + } + } + + result = PyObject_CallFunctionObjArgs(DecimalTuple, + sign, coeff, expt, NULL); + +out: + if (x) mpd_del(x); + if (intstring) mpd_free(intstring); + Py_XDECREF(sign); + Py_XDECREF(coeff); + Py_XDECREF(expt); + return result; +} + + +/******************************************************************************/ +/* Macros for converting mpdecimal functions to Decimal methods */ +/******************************************************************************/ + +/* Unary number method that uses the default module context. */ +#define Dec_UnaryNumberMethod(MPDFUNC) \ +static PyObject * \ +nm_##MPDFUNC(PyObject *self) \ +{ \ + PyObject *result; \ + PyObject *context; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if ((result = dec_alloc()) == NULL) { \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(self), CTX(context), &status); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Binary number method that uses default module context. */ +#define Dec_BinaryNumberMethod(MPDFUNC) \ +static PyObject * \ +nm_##MPDFUNC(PyObject *self, PyObject *other) \ +{ \ + PyObject *a, *b; \ + PyObject *result; \ + PyObject *context; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context) ; \ + CONVERT_BINOP(&a, &b, self, other, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Boolean function without a context arg. */ +#define Dec_BoolFunc(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *dummy UNUSED) \ +{ \ + return MPDFUNC(MPD(self)) ? incr_true() : incr_false(); \ +} + +/* Boolean function with an optional context arg. */ +#define Dec_BoolFuncVA(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"context", NULL}; \ + PyObject *context; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ + &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + \ + return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \ +} + +/* Unary function with an optional context arg. */ +#define Dec_UnaryFuncVA(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"context", NULL}; \ + PyObject *result; \ + PyObject *context; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ + &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(self), CTX(context), &status); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Unary function with an optional context arg. The actual MPDFUNC + only takes a status parameter. */ +#define Dec_UnaryFuncVA_NO_CTX(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"context", NULL}; \ + PyObject *result; \ + PyObject *context; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, \ + &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(self), &status); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Binary function with an optional context arg. */ +#define Dec_BinaryFuncVA(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"other", "context", NULL}; \ + PyObject *other, *context; \ + PyObject *a, *b; \ + PyObject *result; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ + &other, &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Binary function with an optional context arg. Actual MPDFUNC does + NOT take a context. The context is used to record InvalidOperation + if the second operand cannot be converted exactly. */ +#define Dec_BinaryFuncVA_NO_CTX(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"other", "context", NULL}; \ + PyObject *other, *context; \ + PyObject *a, *b; \ + PyObject *result; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, \ + &other, &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b)); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + \ + return result; \ +} + +/* Ternary function with an optional context arg. */ +#define Dec_TernaryFuncVA(MPDFUNC) \ +static PyObject * \ +dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ +{ \ + static char *kwlist[] = {"other", "third", "context", NULL}; \ + PyObject *other, *third, *context; \ + PyObject *a, *b, *c; \ + PyObject *result; \ + uint32_t status = 0; \ + \ + CURRENT_CONTEXT(context); \ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist, \ + &other, &third, &context)) { \ + return NULL; \ + } \ + CONTEXT_CHECK_VA(context); \ + CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + Py_DECREF(c); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), MPD(c), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + Py_DECREF(c); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + + +/**********************************************/ +/* Number methods */ +/**********************************************/ + +Dec_UnaryNumberMethod(mpd_qminus) +Dec_UnaryNumberMethod(mpd_qplus) +Dec_UnaryNumberMethod(mpd_qabs) + +Dec_BinaryNumberMethod(mpd_qadd) +Dec_BinaryNumberMethod(mpd_qsub) +Dec_BinaryNumberMethod(mpd_qmul) +Dec_BinaryNumberMethod(mpd_qdiv) +Dec_BinaryNumberMethod(mpd_qrem) +Dec_BinaryNumberMethod(mpd_qdivint) + +static PyObject * +nm_dec_as_long(PyObject *dec) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return dec_as_long(dec, context, MPD_ROUND_DOWN); +} + +static int +nm_nonzero(PyDecObject *v) +{ + return !mpd_iszero(v->dec); +} + +static PyObject * +nm_mpd_qdivmod(PyObject *v, PyObject *w) +{ + PyObject *a, *b; + PyObject *q, *r; + PyObject *context; + uint32_t status = 0; + PyObject *ret; + + CURRENT_CONTEXT(context); + CONVERT_BINOP(&a, &b, v, w, context); + + q = dec_alloc(); + if (q == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + r = dec_alloc(); + if (r == NULL) { + Py_DECREF(a); + Py_DECREF(b); + Py_DECREF(q); + return NULL; + } + + mpd_qdivmod(MPD(q), MPD(r), MPD(a), MPD(b), CTX(context), &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(r); + Py_DECREF(q); + return NULL; + } + + ret = Py_BuildValue("(OO)", q, r); + Py_DECREF(r); + Py_DECREF(q); + return ret; +} + +static mpd_uint_t data_zero[1] = {0}; +static const mpd_t zero = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_zero}; + +static PyObject * +nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod) +{ + PyObject *a, *b, *c = NULL; + PyObject *result; + PyObject *context; + uint32_t status = 0; + + CURRENT_CONTEXT(context); + CONVERT_BINOP(&a, &b, base, exp, context); + + if (mod != Py_None) { + if (!convert_op(NOT_IMPL, &c, mod, context)) { + Py_DECREF(a); + Py_DECREF(b); + return c; + } + } + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + Py_XDECREF(c); + return NULL; + } + + if (c == NULL) { + mpd_qpow(MPD(result), MPD(a), MPD(b), + CTX(context), &status); + } + else { + mpd_qpowmod(MPD(result), MPD(a), MPD(b), MPD(c), + CTX(context), &status); + status = (status == MPD_Clamped) ? 0 : status; + /* remove ideal exponent for compatibility with decimal.py */ + mpd_qquantize(MPD(result), MPD(result), &zero, + CTX(context), &status); + Py_DECREF(c); + } + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + + +/******************************************************************************/ +/* Decimal Methods */ +/******************************************************************************/ + +/* Unary arithmetic functions, optional context arg */ +Dec_UnaryFuncVA(mpd_qexp) +Dec_UnaryFuncVA(mpd_qln) +Dec_UnaryFuncVA(mpd_qlog10) +Dec_UnaryFuncVA(mpd_qnext_minus) +Dec_UnaryFuncVA(mpd_qnext_plus) +Dec_UnaryFuncVA(mpd_qreduce) +Dec_UnaryFuncVA(mpd_qsqrt) + +/* Binary arithmetic functions, optional context arg */ +Dec_BinaryFuncVA(mpd_qcompare) +Dec_BinaryFuncVA(mpd_qcompare_signal) +Dec_BinaryFuncVA(mpd_qmax) +Dec_BinaryFuncVA(mpd_qmax_mag) +Dec_BinaryFuncVA(mpd_qmin) +Dec_BinaryFuncVA(mpd_qmin_mag) +Dec_BinaryFuncVA(mpd_qnext_toward) +Dec_BinaryFuncVA(mpd_qrem_near) + +/* Ternary arithmetic functions, optional context arg */ +Dec_TernaryFuncVA(mpd_qfma) + +/* Boolean functions, no context arg */ +Dec_BoolFunc(mpd_iscanonical) +Dec_BoolFunc(mpd_isfinite) +Dec_BoolFunc(mpd_isinfinite) +Dec_BoolFunc(mpd_isnan) +Dec_BoolFunc(mpd_isqnan) +Dec_BoolFunc(mpd_issnan) +Dec_BoolFunc(mpd_issigned) +Dec_BoolFunc(mpd_iszero) + +/* Boolean functions, optional context arg */ +Dec_BoolFuncVA(mpd_isnormal) +Dec_BoolFuncVA(mpd_issubnormal) + +/* Unary functions, no context arg */ +static PyObject * +dec_mpd_adjexp(PyObject *self, PyObject *dummy UNUSED) +{ + mpd_ssize_t retval; + + if (mpd_isspecial(MPD(self))) { + retval = 0; + } + else { + retval = mpd_adjexp(MPD(self)); + } + + return PyLong_FromSsize_t(retval); +} + +static PyObject * +dec_canonical(PyObject *self, PyObject *dummy UNUSED) +{ + Py_INCREF(self); + return self; +} + +static PyObject * +dec_conjugate(PyObject *self, PyObject *dummy UNUSED) +{ + Py_INCREF(self); + return self; +} + +static PyObject * +dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED) +{ + PyObject *result; + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + _dec_settriple(result, MPD_POS, 10, 0); + return result; +} + +/* Unary functions, optional context arg for conversion errors */ +Dec_UnaryFuncVA_NO_CTX(mpd_qcopy_abs) +Dec_UnaryFuncVA_NO_CTX(mpd_qcopy_negate) + +/* Unary functions, optional context arg */ +Dec_UnaryFuncVA(mpd_qinvert) +Dec_UnaryFuncVA(mpd_qlogb) + +static PyObject * +dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"context", NULL}; + PyObject *context; + const char *cp; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, + &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + cp = mpd_class(MPD(self), CTX(context)); + return PyUnicode_FromString(cp); +} + +static PyObject * +dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"context", NULL}; + PyObject *result; + PyObject *context; + mpd_ssize_t size; + char *s; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, + &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + size = mpd_to_eng_size(&s, MPD(self), CtxCaps(context)); + if (size < 0) { + PyErr_NoMemory(); + return NULL; + } + + result = unicode_fromascii(s, size); + mpd_free(s); + + return result; +} + +/* Binary functions, optional context arg for conversion errors */ +Dec_BinaryFuncVA_NO_CTX(mpd_compare_total) +Dec_BinaryFuncVA_NO_CTX(mpd_compare_total_mag) + +static PyObject * +dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"other", "context", NULL}; + PyObject *other, *context; + PyObject *a, *b; + PyObject *result; + uint32_t status = 0; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, + &other, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + CONVERT_BINOP_RAISE(&a, &b, self, other, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + + mpd_qcopy_sign(MPD(result), MPD(a), MPD(b), &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"other", "context", NULL}; + PyObject *other, *context; + PyObject *a, *b; + PyObject *result; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, + &other, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + CONVERT_BINOP_RAISE(&a, &b, self, other, context); + + result = mpd_same_quantum(MPD(a), MPD(b)) ? incr_true() : incr_false(); + Py_DECREF(a); + Py_DECREF(b); + + return result; +} + +/* Binary functions, optional context arg */ +Dec_BinaryFuncVA(mpd_qand) +Dec_BinaryFuncVA(mpd_qor) +Dec_BinaryFuncVA(mpd_qxor) + +Dec_BinaryFuncVA(mpd_qrotate) +Dec_BinaryFuncVA(mpd_qscaleb) +Dec_BinaryFuncVA(mpd_qshift) + +static PyObject * +dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"exp", "rounding", "context", NULL}; + PyObject *w, *context; + PyObject *a, *b; + PyObject *result; + uint32_t status = 0; + mpd_context_t workctx; + int round = -1; + + CURRENT_CONTEXT(context); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO", kwlist, + &w, &round, &context)) { + return NULL; + } + CONTEXT_CHECK_VA(context); + + workctx = *CTX(context); + if (round >= 0) { + if (!mpd_qsetround(&workctx, round)) { + return type_error_ptr(invalid_rounding_err); + } + } + + CONVERT_BINOP_RAISE(&a, &b, v, w, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + + mpd_qquantize(MPD(result), MPD(a), MPD(b), &workctx, &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +/* Special methods */ +static PyObject * +dec_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *a; + PyObject *b; + PyObject *context; + uint32_t status = 0; + int a_issnan, b_issnan; + int r; + + assert(PyDec_Check(v)); + + CURRENT_CONTEXT(context); + CONVERT_BINOP_CMP(&a, &b, v, w, op, context); + + a_issnan = mpd_issnan(MPD(a)); + b_issnan = mpd_issnan(MPD(b)); + + r = mpd_qcmp(MPD(a), MPD(b), &status); + Py_DECREF(a); + Py_DECREF(b); + if (r == INT_MAX) { + /* sNaNs or op={le,ge,lt,gt} always signal. */ + if (a_issnan || b_issnan || (op != Py_EQ && op != Py_NE)) { + if (dec_addstatus(context, status)) { + return NULL; + } + } + /* qNaN comparison with op={eq,ne} or comparison + * with InvalidOperation disabled. */ + return (op == Py_NE) ? incr_true() : incr_false(); + } + + switch (op) { + case Py_EQ: + r = (r == 0); + break; + case Py_NE: + r = (r != 0); + break; + case Py_LE: + r = (r <= 0); + break; + case Py_GE: + r = (r >= 0); + break; + case Py_LT: + r = (r == -1); + break; + case Py_GT: + r = (r == 1); + break; + } + + return PyBool_FromLong(r); +} + +/* __ceil__ */ +static PyObject * +dec_ceil(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return dec_as_long(self, context, MPD_ROUND_CEILING); +} + +/* __complex__ */ +static PyObject * +dec_complex(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *f; + double x; + + f = PyDec_AsFloat(self); + if (f == NULL) { + return NULL; + } + + x = PyFloat_AsDouble(f); + Py_DECREF(f); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + + return PyComplex_FromDoubles(x, 0); +} + +/* __copy__ and __deepcopy__ */ +static PyObject * +dec_copy(PyObject *self, PyObject *dummy UNUSED) +{ + Py_INCREF(self); + return self; +} + +/* __floor__ */ +static PyObject * +dec_floor(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return dec_as_long(self, context, MPD_ROUND_FLOOR); +} + +/* Always uses the module context */ +static Py_hash_t +dec_hash(PyObject *v) +{ +#if defined(CONFIG_64) && _PyHASH_BITS == 61 + /* 2**61 - 1 */ + mpd_uint_t p_data[1] = {2305843009213693951ULL}; + mpd_t p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 19, 1, 1, p_data}; + /* Inverse of 10 modulo p */ + mpd_uint_t inv10_p_data[2] = {2075258708292324556ULL}; + mpd_t inv10_p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, + 0, 19, 1, 1, inv10_p_data}; +#elif defined(CONFIG_32) && _PyHASH_BITS == 31 + /* 2**31 - 1 */ + mpd_uint_t p_data[2] = {147483647UL, 2}; + mpd_t p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, 0, 10, 2, 2, p_data}; + /* Inverse of 10 modulo p */ + mpd_uint_t inv10_p_data[2] = {503238553UL, 1}; + mpd_t inv10_p = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, + 0, 10, 2, 2, inv10_p_data}; +#else + #error "No valid combination of CONFIG_64, CONFIG_32 and _PyHASH_BITS" +#endif + const Py_hash_t py_hash_inf = 314159; + const Py_hash_t py_hash_nan = 0; + mpd_uint_t ten_data[1] = {10}; + mpd_t ten = {MPD_POS|MPD_STATIC|MPD_CONST_DATA, + 0, 2, 1, 1, ten_data}; + Py_hash_t result; + mpd_t *exp_hash = NULL; + mpd_t *tmp = NULL; + mpd_ssize_t exp; + uint32_t status = 0; + mpd_context_t maxctx; + PyObject *context; + + + context = current_context(); + if (context == NULL) { + return -1; + } + + if (mpd_isspecial(MPD(v))) { + if (mpd_issnan(MPD(v))) { + PyErr_SetString(PyExc_TypeError, + "Cannot hash a signaling NaN value"); + return -1; + } + else if (mpd_isnan(MPD(v))) { + return py_hash_nan; + } + else { + return py_hash_inf * mpd_arith_sign(MPD(v)); + } + } + + mpd_maxcontext(&maxctx); + exp_hash = mpd_qnew(); + if (exp_hash == NULL) { + goto malloc_error; + } + tmp = mpd_qnew(); + if (tmp == NULL) { + goto malloc_error; + } + + /* + * exp(v): exponent of v + * int(v): coefficient of v + */ + exp = MPD(v)->exp; + if (exp >= 0) { + /* 10**exp(v) % p */ + mpd_qsset_ssize(tmp, exp, &maxctx, &status); + mpd_qpowmod(exp_hash, &ten, tmp, &p, &maxctx, &status); + } + else { + /* inv10_p**(-exp(v)) % p */ + mpd_qsset_ssize(tmp, -exp, &maxctx, &status); + mpd_qpowmod(exp_hash, &inv10_p, tmp, &p, &maxctx, &status); + } + + /* hash = (int(v) * exp_hash) % p */ + if (!mpd_qcopy(tmp, MPD(v), &status)) { + goto malloc_error; + } + tmp->exp = 0; + mpd_set_positive(tmp); + mpd_qmul(tmp, tmp, exp_hash, &maxctx, &status); + mpd_qrem(tmp, tmp, &p, &maxctx, &status); + + result = mpd_qget_ssize(tmp, &status); + result = mpd_ispositive(MPD(v)) ? result : -result; + result = (result == -1) ? -2 : result; + + if (status != 0) { + status |= MPD_Invalid_operation; + if (dec_addstatus(context, status)) { + result = -1; + goto finish; + } + } + + +finish: + if (exp_hash) mpd_del(exp_hash); + if (tmp) mpd_del(tmp); + return result; + +malloc_error: + PyErr_NoMemory(); + result = -1; + goto finish; +} + +/* __reduce__ */ +static PyObject * +dec_reduce(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *result, *str; + + str = dec_str(self); + if (str == NULL) { + return NULL; + } + + result = Py_BuildValue("O(O)", Py_TYPE(self), str); + Py_DECREF(str); + + return result; +} + +/* __trunc__ */ +static PyObject * +dec_trunc(PyObject *self, PyObject *dummy UNUSED) +{ + PyObject *context; + + CURRENT_CONTEXT(context); + return dec_as_long(self, context, MPD_ROUND_DOWN); +} + +/* real and imag */ +static PyObject * +dec_real(PyObject *self, void *closure UNUSED) +{ + Py_INCREF(self); + return self; +} + +static PyObject * +dec_imag(PyObject *self UNUSED, void *closure UNUSED) +{ + PyObject *result; + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + _dec_settriple(result, MPD_POS, 0, 0); + return result; +} + + +static PyGetSetDef dec_getsets [] = +{ + { "real", (getter)dec_real, NULL, NULL, NULL}, + { "imag", (getter)dec_imag, NULL, NULL, NULL}, + {NULL} +}; + +static PyNumberMethods dec_number_methods = +{ + (binaryfunc) nm_mpd_qadd, + (binaryfunc) nm_mpd_qsub, + (binaryfunc) nm_mpd_qmul, + (binaryfunc) nm_mpd_qrem, + (binaryfunc) nm_mpd_qdivmod, + (ternaryfunc) nm_mpd_qpow, + (unaryfunc) nm_mpd_qminus, + (unaryfunc) nm_mpd_qplus, + (unaryfunc) nm_mpd_qabs, + (inquiry) nm_nonzero, + (unaryfunc) 0, /* no bit-complement */ + (binaryfunc) 0, /* no shiftl */ + (binaryfunc) 0, /* no shiftr */ + (binaryfunc) 0, /* no bit-and */ + (binaryfunc) 0, /* no bit-xor */ + (binaryfunc) 0, /* no bit-ior */ + (unaryfunc) nm_dec_as_long, + 0, /* nb_reserved */ + (unaryfunc) PyDec_AsFloat, + 0, /* binaryfunc nb_inplace_add; */ + 0, /* binaryfunc nb_inplace_subtract; */ + 0, /* binaryfunc nb_inplace_multiply; */ + 0, /* binaryfunc nb_inplace_remainder; */ + 0, /* ternaryfunc nb_inplace_power; */ + 0, /* binaryfunc nb_inplace_lshift; */ + 0, /* binaryfunc nb_inplace_rshift; */ + 0, /* binaryfunc nb_inplace_and; */ + 0, /* binaryfunc nb_inplace_xor; */ + 0, /* binaryfunc nb_inplace_or; */ + (binaryfunc) nm_mpd_qdivint, /* binaryfunc nb_floor_divide; */ + (binaryfunc) nm_mpd_qdiv, /* binaryfunc nb_true_divide; */ + 0, /* binaryfunc nb_inplace_floor_divide; */ + 0, /* binaryfunc nb_inplace_true_divide; */ +}; + +static PyMethodDef dec_methods [] = +{ + /* Unary arithmetic functions, optional context arg */ + { "exp", (PyCFunction)dec_mpd_qexp, METH_VARARGS|METH_KEYWORDS, doc_exp }, + { "ln", (PyCFunction)dec_mpd_qln, METH_VARARGS|METH_KEYWORDS, doc_ln }, + { "log10", (PyCFunction)dec_mpd_qlog10, METH_VARARGS|METH_KEYWORDS, doc_log10 }, + { "next_minus", (PyCFunction)dec_mpd_qnext_minus, METH_VARARGS|METH_KEYWORDS, doc_next_minus }, + { "next_plus", (PyCFunction)dec_mpd_qnext_plus, METH_VARARGS|METH_KEYWORDS, doc_next_plus }, + { "normalize", (PyCFunction)dec_mpd_qreduce, METH_VARARGS|METH_KEYWORDS, doc_normalize }, + { "to_integral", (PyCFunction)PyDec_ToIntegralValue, METH_VARARGS|METH_KEYWORDS, doc_to_integral }, + { "to_integral_exact", (PyCFunction)PyDec_ToIntegralExact, METH_VARARGS|METH_KEYWORDS, doc_to_integral_exact }, + { "to_integral_value", (PyCFunction)PyDec_ToIntegralValue, METH_VARARGS|METH_KEYWORDS, doc_to_integral_value }, + { "sqrt", (PyCFunction)dec_mpd_qsqrt, METH_VARARGS|METH_KEYWORDS, doc_sqrt }, + + /* Binary arithmetic functions, optional context arg */ + { "compare", (PyCFunction)dec_mpd_qcompare, METH_VARARGS|METH_KEYWORDS, doc_compare }, + { "compare_signal", (PyCFunction)dec_mpd_qcompare_signal, METH_VARARGS|METH_KEYWORDS, doc_compare_signal }, + { "max", (PyCFunction)dec_mpd_qmax, METH_VARARGS|METH_KEYWORDS, doc_max }, + { "max_mag", (PyCFunction)dec_mpd_qmax_mag, METH_VARARGS|METH_KEYWORDS, doc_max_mag }, + { "min", (PyCFunction)dec_mpd_qmin, METH_VARARGS|METH_KEYWORDS, doc_min }, + { "min_mag", (PyCFunction)dec_mpd_qmin_mag, METH_VARARGS|METH_KEYWORDS, doc_min_mag }, + { "next_toward", (PyCFunction)dec_mpd_qnext_toward, METH_VARARGS|METH_KEYWORDS, doc_next_toward }, + { "quantize", (PyCFunction)dec_mpd_qquantize, METH_VARARGS|METH_KEYWORDS, doc_quantize }, + { "remainder_near", (PyCFunction)dec_mpd_qrem_near, METH_VARARGS|METH_KEYWORDS, doc_remainder_near }, + + /* Ternary arithmetic functions, optional context arg */ + { "fma", (PyCFunction)dec_mpd_qfma, METH_VARARGS|METH_KEYWORDS, doc_fma }, + + /* Boolean functions, no context arg */ + { "is_canonical", dec_mpd_iscanonical, METH_NOARGS, doc_is_canonical }, + { "is_finite", dec_mpd_isfinite, METH_NOARGS, doc_is_finite }, + { "is_infinite", dec_mpd_isinfinite, METH_NOARGS, doc_is_infinite }, + { "is_nan", dec_mpd_isnan, METH_NOARGS, doc_is_nan }, + { "is_qnan", dec_mpd_isqnan, METH_NOARGS, doc_is_qnan }, + { "is_snan", dec_mpd_issnan, METH_NOARGS, doc_is_snan }, + { "is_signed", dec_mpd_issigned, METH_NOARGS, doc_is_signed }, + { "is_zero", dec_mpd_iszero, METH_NOARGS, doc_is_zero }, + + /* Boolean functions, optional context arg */ + { "is_normal", (PyCFunction)dec_mpd_isnormal, METH_VARARGS|METH_KEYWORDS, doc_is_normal }, + { "is_subnormal", (PyCFunction)dec_mpd_issubnormal, METH_VARARGS|METH_KEYWORDS, doc_is_subnormal }, + + /* Unary functions, no context arg */ + { "adjusted", dec_mpd_adjexp, METH_NOARGS, doc_adjusted }, + { "canonical", dec_canonical, METH_NOARGS, doc_canonical }, + { "conjugate", dec_conjugate, METH_NOARGS, doc_conjugate }, + { "radix", dec_mpd_radix, METH_NOARGS, doc_radix }, + + /* Unary functions, optional context arg for conversion errors */ + { "copy_abs", (PyCFunction)dec_mpd_qcopy_abs, METH_VARARGS|METH_KEYWORDS, doc_copy_abs }, + { "copy_negate", (PyCFunction)dec_mpd_qcopy_negate, METH_VARARGS|METH_KEYWORDS, doc_copy_negate }, + + /* Unary functions, optional context arg */ + { "logb", (PyCFunction)dec_mpd_qlogb, METH_VARARGS|METH_KEYWORDS, doc_logb }, + { "logical_invert", (PyCFunction)dec_mpd_qinvert, METH_VARARGS|METH_KEYWORDS, doc_logical_invert }, + { "number_class", (PyCFunction)dec_mpd_class, METH_VARARGS|METH_KEYWORDS, doc_number_class }, + { "to_eng_string", (PyCFunction)dec_mpd_to_eng, METH_VARARGS|METH_KEYWORDS, doc_to_eng_string }, + + /* Binary functions, optional context arg for conversion errors */ + { "compare_total", (PyCFunction)dec_mpd_compare_total, METH_VARARGS|METH_KEYWORDS, doc_compare_total }, + { "compare_total_mag", (PyCFunction)dec_mpd_compare_total_mag, METH_VARARGS|METH_KEYWORDS, doc_compare_total_mag }, + { "copy_sign", (PyCFunction)dec_mpd_qcopy_sign, METH_VARARGS|METH_KEYWORDS, doc_copy_sign }, + { "same_quantum", (PyCFunction)dec_mpd_same_quantum, METH_VARARGS|METH_KEYWORDS, doc_same_quantum }, + + /* Binary functions, optional context arg */ + { "logical_and", (PyCFunction)dec_mpd_qand, METH_VARARGS|METH_KEYWORDS, doc_logical_and }, + { "logical_or", (PyCFunction)dec_mpd_qor, METH_VARARGS|METH_KEYWORDS, doc_logical_or }, + { "logical_xor", (PyCFunction)dec_mpd_qxor, METH_VARARGS|METH_KEYWORDS, doc_logical_xor }, + { "rotate", (PyCFunction)dec_mpd_qrotate, METH_VARARGS|METH_KEYWORDS, doc_rotate }, + { "scaleb", (PyCFunction)dec_mpd_qscaleb, METH_VARARGS|METH_KEYWORDS, doc_scaleb }, + { "shift", (PyCFunction)dec_mpd_qshift, METH_VARARGS|METH_KEYWORDS, doc_shift }, + + /* Miscellaneous */ + { "from_float", dec_from_float, METH_O|METH_CLASS, doc_from_float }, + { "as_tuple", PyDec_AsTuple, METH_NOARGS, doc_as_tuple }, + + /* Special methods */ + { "__copy__", dec_copy, METH_NOARGS, NULL }, + { "__deepcopy__", dec_copy, METH_O, NULL }, + { "__format__", dec_format, METH_VARARGS, NULL }, + { "__reduce__", dec_reduce, METH_NOARGS, NULL }, + { "__round__", PyDec_Round, METH_VARARGS, NULL }, + { "__ceil__", dec_ceil, METH_NOARGS, NULL }, + { "__floor__", dec_floor, METH_NOARGS, NULL }, + { "__trunc__", dec_trunc, METH_NOARGS, NULL }, + { "__complex__", dec_complex, METH_NOARGS, NULL }, + + { NULL, NULL, 1 } +}; + +static PyTypeObject PyDec_Type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "decimal.Decimal", /* tp_name */ + sizeof(PyDecObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) dec_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc) dec_repr, /* tp_repr */ + &dec_number_methods, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc) dec_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc) dec_str, /* tp_str */ + (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ + (setattrofunc) 0, /* tp_setattro */ + (PyBufferProcs *) 0, /* tp_as_buffer */ + (Py_TPFLAGS_DEFAULT| + Py_TPFLAGS_BASETYPE), /* tp_flags */ + doc_decimal, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + dec_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + dec_methods, /* tp_methods */ + 0, /* tp_members */ + dec_getsets, /* 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 */ + dec_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + +/******************************************************************************/ +/* Context Object, Part 2 */ +/******************************************************************************/ + + +/************************************************************************/ +/* Macros for converting mpdecimal functions to Context methods */ +/************************************************************************/ + +/* Boolean context method. */ +#define DecCtx_BoolFunc(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *v) \ +{ \ + PyObject *ret; \ + PyObject *a; \ + \ + CONVERT_OP_RAISE(&a, v, context); \ + \ + ret = MPDFUNC(MPD(a), CTX(context)) ? incr_true() : incr_false(); \ + Py_DECREF(a); \ + return ret; \ +} + +/* Boolean context method. MPDFUNC does NOT use a context. */ +#define DecCtx_BoolFunc_NO_CTX(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *v) \ +{ \ + PyObject *ret; \ + PyObject *a; \ + \ + CONVERT_OP_RAISE(&a, v, context); \ + \ + ret = MPDFUNC(MPD(a)) ? incr_true() : incr_false(); \ + Py_DECREF(a); \ + return ret; \ +} + +/* Unary context method. */ +#define DecCtx_UnaryFunc(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *v) \ +{ \ + PyObject *result, *a; \ + uint32_t status = 0; \ + \ + CONVERT_OP_RAISE(&a, v, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), CTX(context), &status); \ + Py_DECREF(a); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* Binary context method. */ +#define DecCtx_BinaryFunc(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *args) \ +{ \ + PyObject *v, *w; \ + PyObject *a, *b; \ + PyObject *result; \ + uint32_t status = 0; \ + \ + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { \ + return NULL; \ + } \ + \ + CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + +/* + * Binary context method. The context is only used for conversion. + * The actual MPDFUNC does NOT take a context arg. + */ +#define DecCtx_BinaryFunc_NO_CTX(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *args) \ +{ \ + PyObject *v, *w; \ + PyObject *a, *b; \ + PyObject *result; \ + \ + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { \ + return NULL; \ + } \ + \ + CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b)); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + \ + return result; \ +} + +/* Ternary context method. */ +#define DecCtx_TernaryFunc(MPDFUNC) \ +static PyObject * \ +ctx_##MPDFUNC(PyObject *context, PyObject *args) \ +{ \ + PyObject *v, *w, *x; \ + PyObject *a, *b, *c; \ + PyObject *result; \ + uint32_t status = 0; \ + \ + if (!PyArg_ParseTuple(args, "OOO", &v, &w, &x)) { \ + return NULL; \ + } \ + \ + CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context); \ + \ + if ((result = dec_alloc()) == NULL) { \ + Py_DECREF(a); \ + Py_DECREF(b); \ + Py_DECREF(c); \ + return NULL; \ + } \ + \ + MPDFUNC(MPD(result), MPD(a), MPD(b), MPD(c), CTX(context), &status); \ + Py_DECREF(a); \ + Py_DECREF(b); \ + Py_DECREF(c); \ + if (dec_addstatus(context, status)) { \ + Py_DECREF(result); \ + return NULL; \ + } \ + \ + return result; \ +} + + +/* Unary arithmetic functions */ +DecCtx_UnaryFunc(mpd_qabs) +DecCtx_UnaryFunc(mpd_qexp) +DecCtx_UnaryFunc(mpd_qln) +DecCtx_UnaryFunc(mpd_qlog10) +DecCtx_UnaryFunc(mpd_qminus) +DecCtx_UnaryFunc(mpd_qnext_minus) +DecCtx_UnaryFunc(mpd_qnext_plus) +DecCtx_UnaryFunc(mpd_qplus) +DecCtx_UnaryFunc(mpd_qreduce) +DecCtx_UnaryFunc(mpd_qround_to_int) +DecCtx_UnaryFunc(mpd_qround_to_intx) +DecCtx_UnaryFunc(mpd_qsqrt) + +/* Binary arithmetic functions */ +DecCtx_BinaryFunc(mpd_qadd) +DecCtx_BinaryFunc(mpd_qcompare) +DecCtx_BinaryFunc(mpd_qcompare_signal) +DecCtx_BinaryFunc(mpd_qdiv) +DecCtx_BinaryFunc(mpd_qdivint) +DecCtx_BinaryFunc(mpd_qmax) +DecCtx_BinaryFunc(mpd_qmax_mag) +DecCtx_BinaryFunc(mpd_qmin) +DecCtx_BinaryFunc(mpd_qmin_mag) +DecCtx_BinaryFunc(mpd_qmul) +DecCtx_BinaryFunc(mpd_qnext_toward) +DecCtx_BinaryFunc(mpd_qquantize) +DecCtx_BinaryFunc(mpd_qrem) +DecCtx_BinaryFunc(mpd_qrem_near) +DecCtx_BinaryFunc(mpd_qsub) + +static PyObject * +ctx_mpd_qdivmod(PyObject *context, PyObject *args) +{ + PyObject *v, *w; + PyObject *a, *b; + PyObject *q, *r; + uint32_t status = 0; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { + return NULL; + } + + CONVERT_BINOP_RAISE(&a, &b, v, w, context); + + q = dec_alloc(); + if (q == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + r = dec_alloc(); + if (r == NULL) { + Py_DECREF(a); + Py_DECREF(b); + Py_DECREF(q); + return NULL; + } + + mpd_qdivmod(MPD(q), MPD(r), MPD(a), MPD(b), CTX(context), &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(r); + Py_DECREF(q); + return NULL; + } + + ret = Py_BuildValue("(OO)", q, r); + Py_DECREF(r); + Py_DECREF(q); + return ret; +} + +/* Binary or ternary arithmetic functions */ +static PyObject * +ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"a", "b", "modulo", NULL}; + PyObject *base, *exp, *mod = NULL; + PyObject *a, *b, *c = NULL; + PyObject *result; + uint32_t status = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist, + &base, &exp, &mod)) { + return NULL; + } + + CONVERT_BINOP_RAISE(&a, &b, base, exp, context); + + if (mod != NULL) { + if (!convert_op(TYPE_ERR, &c, mod, context)) { + Py_DECREF(a); + Py_DECREF(b); + return c; + } + } + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + Py_XDECREF(c); + return NULL; + } + + if (c == NULL) { + mpd_qpow(MPD(result), MPD(a), MPD(b), + CTX(context), &status); + } + else { + mpd_qpowmod(MPD(result), MPD(a), MPD(b), MPD(c), + CTX(context), &status); + status = (status == MPD_Clamped) ? 0 : status; + /* remove ideal exponent for compatibility with decimal.py */ + mpd_qquantize(MPD(result), MPD(result), &zero, + CTX(context), &status); + Py_DECREF(c); + } + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +/* Ternary arithmetic functions */ +DecCtx_TernaryFunc(mpd_qfma) + +/* No argument */ +static PyObject * +ctx_mpd_radix(PyObject *context, PyObject *dummy) +{ + return dec_mpd_radix(context, dummy); +} + +/* Boolean functions: single decimal argument */ +DecCtx_BoolFunc(mpd_isnormal) +DecCtx_BoolFunc(mpd_issubnormal) +DecCtx_BoolFunc_NO_CTX(mpd_isfinite) +DecCtx_BoolFunc_NO_CTX(mpd_isinfinite) +DecCtx_BoolFunc_NO_CTX(mpd_isnan) +DecCtx_BoolFunc_NO_CTX(mpd_isqnan) +DecCtx_BoolFunc_NO_CTX(mpd_issigned) +DecCtx_BoolFunc_NO_CTX(mpd_issnan) +DecCtx_BoolFunc_NO_CTX(mpd_iszero) + +static PyObject * +ctx_iscanonical(PyObject *context UNUSED, PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "argument must be a Decimal"); + return NULL; + } + + return mpd_iscanonical(MPD(v)) ? incr_true() : incr_false(); +} + +/* Functions with a single decimal argument */ +static PyObject * +PyDecContext_Apply(PyObject *context, PyObject *v) +{ + PyObject *result, *a; + + CONVERT_OP_RAISE(&a, v, context); + + result = dec_apply(a, context); + Py_DECREF(a); + return result; +} + +static PyObject * +ctx_canonical(PyObject *context UNUSED, PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "argument must be a Decimal"); + return NULL; + } + + Py_INCREF(v); + return v; +} + +static PyObject * +ctx_mpd_qcopy_abs(PyObject *context, PyObject *v) +{ + PyObject *result, *a; + uint32_t status = 0; + + CONVERT_OP_RAISE(&a, v, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + return NULL; + } + + mpd_qcopy_abs(MPD(result), MPD(a), &status); + Py_DECREF(a); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +ctx_copy_decimal(PyObject *context, PyObject *v) +{ + PyObject *result; + + CONVERT_OP_RAISE(&result, v, context); + return result; +} + +static PyObject * +ctx_mpd_qcopy_negate(PyObject *context, PyObject *v) +{ + PyObject *result, *a; + uint32_t status = 0; + + CONVERT_OP_RAISE(&a, v, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + return NULL; + } + + mpd_qcopy_negate(MPD(result), MPD(a), &status); + Py_DECREF(a); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +DecCtx_UnaryFunc(mpd_qlogb) +DecCtx_UnaryFunc(mpd_qinvert) + +static PyObject * +ctx_mpd_class(PyObject *context, PyObject *v) +{ + PyObject *a; + const char *cp; + + CONVERT_OP_RAISE(&a, v, context); + + cp = mpd_class(MPD(a), CTX(context)); + Py_DECREF(a); + + return PyUnicode_FromString(cp); +} + +static PyObject * +ctx_mpd_to_sci(PyObject *context, PyObject *v) +{ + PyObject *result; + PyObject *a; + mpd_ssize_t size; + char *s; + + CONVERT_OP_RAISE(&a, v, context); + + size = mpd_to_sci_size(&s, MPD(a), CtxCaps(context)); + Py_DECREF(a); + if (size < 0) { + PyErr_NoMemory(); + return NULL; + } + + result = unicode_fromascii(s, size); + mpd_free(s); + + return result; +} + +static PyObject * +ctx_mpd_to_eng(PyObject *context, PyObject *v) +{ + PyObject *result; + PyObject *a; + mpd_ssize_t size; + char *s; + + CONVERT_OP_RAISE(&a, v, context); + + size = mpd_to_eng_size(&s, MPD(a), CtxCaps(context)); + Py_DECREF(a); + if (size < 0) { + PyErr_NoMemory(); + return NULL; + } + + result = unicode_fromascii(s, size); + mpd_free(s); + + return result; +} + +/* Functions with two decimal arguments */ +DecCtx_BinaryFunc_NO_CTX(mpd_compare_total) +DecCtx_BinaryFunc_NO_CTX(mpd_compare_total_mag) + +static PyObject * +ctx_mpd_qcopy_sign(PyObject *context, PyObject *args) +{ + PyObject *v, *w; + PyObject *a, *b; + PyObject *result; + uint32_t status = 0; + + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { + return NULL; + } + + CONVERT_BINOP_RAISE(&a, &b, v, w, context); + + result = dec_alloc(); + if (result == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + + mpd_qcopy_sign(MPD(result), MPD(a), MPD(b), &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +DecCtx_BinaryFunc(mpd_qand) +DecCtx_BinaryFunc(mpd_qor) +DecCtx_BinaryFunc(mpd_qxor) + +DecCtx_BinaryFunc(mpd_qrotate) +DecCtx_BinaryFunc(mpd_qscaleb) +DecCtx_BinaryFunc(mpd_qshift) + +static PyObject * +ctx_mpd_same_quantum(PyObject *context, PyObject *args) +{ + PyObject *v, *w; + PyObject *a, *b; + PyObject *result; + + if (!PyArg_ParseTuple(args, "OO", &v, &w)) { + return NULL; + } + + CONVERT_BINOP_RAISE(&a, &b, v, w, context); + + result = mpd_same_quantum(MPD(a), MPD(b)) ? incr_true() : incr_false(); + Py_DECREF(a); + Py_DECREF(b); + + return result; +} + + +static PyMethodDef context_methods [] = +{ + /* Unary arithmetic functions */ + { "abs", ctx_mpd_qabs, METH_O, doc_ctx_abs }, + { "exp", ctx_mpd_qexp, METH_O, doc_ctx_exp }, + { "ln", ctx_mpd_qln, METH_O, doc_ctx_ln }, + { "log10", ctx_mpd_qlog10, METH_O, doc_ctx_log10 }, + { "minus", ctx_mpd_qminus, METH_O, doc_ctx_minus }, + { "next_minus", ctx_mpd_qnext_minus, METH_O, doc_ctx_next_minus }, + { "next_plus", ctx_mpd_qnext_plus, METH_O, doc_ctx_next_plus }, + { "normalize", ctx_mpd_qreduce, METH_O, doc_ctx_normalize }, + { "plus", ctx_mpd_qplus, METH_O, doc_ctx_plus }, + { "to_integral", ctx_mpd_qround_to_int, METH_O, doc_ctx_to_integral }, + { "to_integral_exact", ctx_mpd_qround_to_intx, METH_O, doc_ctx_to_integral_exact }, + { "to_integral_value", ctx_mpd_qround_to_int, METH_O, doc_ctx_to_integral_value }, + { "sqrt", ctx_mpd_qsqrt, METH_O, doc_ctx_sqrt }, + + /* Binary arithmetic functions */ + { "add", ctx_mpd_qadd, METH_VARARGS, doc_ctx_add }, + { "compare", ctx_mpd_qcompare, METH_VARARGS, doc_ctx_compare }, + { "compare_signal", ctx_mpd_qcompare_signal, METH_VARARGS, doc_ctx_compare_signal }, + { "divide", ctx_mpd_qdiv, METH_VARARGS, doc_ctx_divide }, + { "divide_int", ctx_mpd_qdivint, METH_VARARGS, doc_ctx_divide_int }, + { "divmod", ctx_mpd_qdivmod, METH_VARARGS, doc_ctx_divmod }, + { "max", ctx_mpd_qmax, METH_VARARGS, doc_ctx_max }, + { "max_mag", ctx_mpd_qmax_mag, METH_VARARGS, doc_ctx_max_mag }, + { "min", ctx_mpd_qmin, METH_VARARGS, doc_ctx_min }, + { "min_mag", ctx_mpd_qmin_mag, METH_VARARGS, doc_ctx_min_mag }, + { "multiply", ctx_mpd_qmul, METH_VARARGS, doc_ctx_multiply }, + { "next_toward", ctx_mpd_qnext_toward, METH_VARARGS, doc_ctx_next_toward }, + { "quantize", ctx_mpd_qquantize, METH_VARARGS, doc_ctx_quantize }, + { "remainder", ctx_mpd_qrem, METH_VARARGS, doc_ctx_remainder }, + { "remainder_near", ctx_mpd_qrem_near, METH_VARARGS, doc_ctx_remainder_near }, + { "subtract", ctx_mpd_qsub, METH_VARARGS, doc_ctx_subtract }, + + /* Binary or ternary arithmetic functions */ + { "power", (PyCFunction)ctx_mpd_qpow, METH_VARARGS|METH_KEYWORDS, doc_ctx_power }, + + /* Ternary arithmetic functions */ + { "fma", ctx_mpd_qfma, METH_VARARGS, doc_ctx_fma }, + + /* No argument */ + { "Etiny", context_getetiny, METH_NOARGS, doc_ctx_Etiny }, + { "Etop", context_getetop, METH_NOARGS, doc_ctx_Etop }, + { "radix", ctx_mpd_radix, METH_NOARGS, doc_ctx_radix }, + + /* Boolean functions */ + { "is_canonical", ctx_iscanonical, METH_O, doc_ctx_is_canonical }, + { "is_finite", ctx_mpd_isfinite, METH_O, doc_ctx_is_finite }, + { "is_infinite", ctx_mpd_isinfinite, METH_O, doc_ctx_is_infinite }, + { "is_nan", ctx_mpd_isnan, METH_O, doc_ctx_is_nan }, + { "is_normal", ctx_mpd_isnormal, METH_O, doc_ctx_is_normal }, + { "is_qnan", ctx_mpd_isqnan, METH_O, doc_ctx_is_qnan }, + { "is_signed", ctx_mpd_issigned, METH_O, doc_ctx_is_signed }, + { "is_snan", ctx_mpd_issnan, METH_O, doc_ctx_is_snan }, + { "is_subnormal", ctx_mpd_issubnormal, METH_O, doc_ctx_is_subnormal }, + { "is_zero", ctx_mpd_iszero, METH_O, doc_ctx_is_zero }, + + /* Functions with a single decimal argument */ + { "_apply", PyDecContext_Apply, METH_O, NULL }, /* alias for apply */ +#ifdef EXTRA_FUNCTIONALITY + { "apply", PyDecContext_Apply, METH_O, doc_ctx_apply }, +#endif + { "canonical", ctx_canonical, METH_O, doc_ctx_canonical }, + { "copy_abs", ctx_mpd_qcopy_abs, METH_O, doc_ctx_copy_abs }, + { "copy_decimal", ctx_copy_decimal, METH_O, doc_ctx_copy_decimal }, + { "copy_negate", ctx_mpd_qcopy_negate, METH_O, doc_ctx_copy_negate }, + { "logb", ctx_mpd_qlogb, METH_O, doc_ctx_logb }, + { "logical_invert", ctx_mpd_qinvert, METH_O, doc_ctx_logical_invert }, + { "number_class", ctx_mpd_class, METH_O, doc_ctx_number_class }, + { "to_sci_string", ctx_mpd_to_sci, METH_O, doc_ctx_to_sci_string }, + { "to_eng_string", ctx_mpd_to_eng, METH_O, doc_ctx_to_eng_string }, + + /* Functions with two decimal arguments */ + { "compare_total", ctx_mpd_compare_total, METH_VARARGS, doc_ctx_compare_total }, + { "compare_total_mag", ctx_mpd_compare_total_mag, METH_VARARGS, doc_ctx_compare_total_mag }, + { "copy_sign", ctx_mpd_qcopy_sign, METH_VARARGS, doc_ctx_copy_sign }, + { "logical_and", ctx_mpd_qand, METH_VARARGS, doc_ctx_logical_and }, + { "logical_or", ctx_mpd_qor, METH_VARARGS, doc_ctx_logical_or }, + { "logical_xor", ctx_mpd_qxor, METH_VARARGS, doc_ctx_logical_xor }, + { "rotate", ctx_mpd_qrotate, METH_VARARGS, doc_ctx_rotate }, + { "same_quantum", ctx_mpd_same_quantum, METH_VARARGS, doc_ctx_same_quantum }, + { "scaleb", ctx_mpd_qscaleb, METH_VARARGS, doc_ctx_scaleb }, + { "shift", ctx_mpd_qshift, METH_VARARGS, doc_ctx_shift }, + + /* Set context values */ + { "clear_flags", context_clear_flags, METH_NOARGS, doc_ctx_clear_flags }, + { "clear_traps", context_clear_traps, METH_NOARGS, doc_ctx_clear_traps }, + +#ifdef CONFIG_32 + /* Unsafe set functions with relaxed range checks */ + { "_unsafe_setprec", context_unsafe_setprec, METH_O, NULL }, + { "_unsafe_setemin", context_unsafe_setemin, METH_O, NULL }, + { "_unsafe_setemax", context_unsafe_setemax, METH_O, NULL }, +#endif + + /* Miscellaneous */ + { "__copy__", (PyCFunction)context_copy, METH_NOARGS, NULL }, + { "__reduce__", context_reduce, METH_NOARGS, NULL }, + { "copy", (PyCFunction)context_copy, METH_NOARGS, doc_ctx_copy }, + { "create_decimal", ctx_create_decimal, METH_VARARGS, doc_ctx_create_decimal }, + { "create_decimal_from_float", ctx_from_float, METH_O, doc_ctx_create_decimal_from_float }, + + { NULL, NULL, 1 } +}; + +static PyTypeObject PyDecContext_Type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "decimal.Context", /* tp_name */ + sizeof(PyDecContextObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) context_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) 0, /* tp_getattr */ + (setattrfunc) 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc) context_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc) 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc) context_repr, /* tp_str */ + (getattrofunc) context_getattr, /* tp_getattro */ + (setattrofunc) context_setattr, /* tp_setattro */ + (PyBufferProcs *) 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + doc_context, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + context_methods, /* tp_methods */ + 0, /* tp_members */ + context_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + context_init, /* tp_init */ + 0, /* tp_alloc */ + context_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + +static PyMethodDef _decimal_methods [] = +{ + { "getcontext", (PyCFunction)PyDec_GetCurrentContext, METH_NOARGS, doc_getcontext}, + { "setcontext", (PyCFunction)PyDec_SetCurrentContext, METH_O, doc_setcontext}, + { "localcontext", (PyCFunction)ctxmanager_new, METH_VARARGS, doc_localcontext}, +#ifdef EXTRA_FUNCTIONALITY + { "IEEEContext", (PyCFunction)ieee_context, METH_O, doc_ieee_context}, +#endif + { NULL, NULL, 1, NULL } +}; + +static struct PyModuleDef _decimal_module = { + PyModuleDef_HEAD_INIT, + "decimal", + doc__decimal, + -1, + _decimal_methods, + NULL, + NULL, + NULL, + NULL +}; + +struct ssize_constmap { const char *name; mpd_ssize_t val; }; +static struct ssize_constmap ssize_constants [] = { + {"MAX_PREC", MPD_MAX_PREC}, + {"MAX_EMAX", MPD_MAX_EMAX}, + {"MIN_EMIN", MPD_MIN_EMIN}, + {"MIN_ETINY", MPD_MIN_ETINY}, + {NULL} +}; + +struct int_constmap { const char *name; int val; }; +static struct int_constmap int_constants [] = { + /* int constants */ +#ifdef EXTRA_FUNCTIONALITY + {"DECIMAL32", MPD_DECIMAL32}, + {"DECIMAL64", MPD_DECIMAL64}, + {"DECIMAL128", MPD_DECIMAL128}, + {"IEEE_CONTEXT_MAX_BITS", MPD_IEEE_CONTEXT_MAX_BITS}, +#endif + {"ROUND_CEILING", MPD_ROUND_CEILING}, + {"ROUND_FLOOR", MPD_ROUND_FLOOR}, + {"ROUND_UP", MPD_ROUND_UP}, + {"ROUND_DOWN", MPD_ROUND_DOWN}, + {"ROUND_HALF_UP", MPD_ROUND_HALF_UP}, + {"ROUND_HALF_DOWN", MPD_ROUND_HALF_DOWN}, + {"ROUND_HALF_EVEN", MPD_ROUND_HALF_EVEN}, + {"ROUND_05UP", MPD_ROUND_05UP}, +#ifdef EXTRA_FUNCTIONALITY + {"ROUND_TRUNC", MPD_ROUND_TRUNC}, + /* int condition flags */ + {"DecClamped", MPD_Clamped}, + {"DecConversionSyntax", MPD_Conversion_syntax}, + {"DecDivisionByZero", MPD_Division_by_zero}, + {"DecDivisionImpossible", MPD_Division_impossible}, + {"DecDivisionUndefined", MPD_Division_undefined}, + {"DecFpuError", MPD_Fpu_error}, + {"DecInexact", MPD_Inexact}, + {"DecInvalidContext", MPD_Invalid_context}, + {"DecInvalidOperation", MPD_Invalid_operation}, + {"DecIEEEInvalidOperation", MPD_IEEE_Invalid_operation}, + {"DecMallocError", MPD_Malloc_error}, + {"DecFloatOperation", MPD_Float_operation}, + {"DecOverflow", MPD_Overflow}, + {"DecRounded", MPD_Rounded}, + {"DecSubnormal", MPD_Subnormal}, + {"DecUnderflow", MPD_Underflow}, + {"DecErrors", MPD_Errors}, + {"DecTraps", MPD_Traps}, +#endif + {NULL} +}; + + +#define CHECK_INT(expr) \ + do { if ((expr) < 0) goto error; } while (0) +#define ASSIGN_PTR(result, expr) \ + do { result = (expr); if (result == NULL) goto error; } while (0) +#define CHECK_PTR(expr) \ + do { if ((expr) == NULL) goto error; } while (0) + +PyMODINIT_FUNC +PyInit__decimal(void) +{ + PyObject *m = NULL; + PyObject *numbers = NULL; + PyObject *Number = NULL; + PyObject *collections = NULL; + PyObject *MutableMapping = NULL; + PyObject *obj = NULL; + DecCondMap *cm; + struct ssize_constmap *ssize_cm; + struct int_constmap *int_cm; + int i; + + + /* Init libmpdec */ + mpd_traphandler = dec_traphandler; + mpd_mallocfunc = PyMem_Malloc; + mpd_reallocfunc = PyMem_Realloc; + mpd_callocfunc = mpd_callocfunc_em; + mpd_free = PyMem_Free; + mpd_setminalloc(4); + + + /* Init types */ + PyDec_Type.tp_base = &PyBaseObject_Type; + PyDecContext_Type.tp_base = &PyBaseObject_Type; + PyDecContextManager_Type.tp_base = &PyBaseObject_Type; + PyDecSignalDictMixin_Type.tp_base = &PyBaseObject_Type; + + CHECK_INT(PyType_Ready(&PyDec_Type)); + CHECK_INT(PyType_Ready(&PyDecContext_Type)); + CHECK_INT(PyType_Ready(&PyDecSignalDictMixin_Type)); + CHECK_INT(PyType_Ready(&PyDecContextManager_Type)); + + ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); + CHECK_INT(PyDict_SetItemString(PyDec_Type.tp_dict, "__module__", obj)); + CHECK_INT(PyDict_SetItemString(PyDecContext_Type.tp_dict, + "__module__", obj)); + Py_CLEAR(obj); + + + /* Numeric abstract base classes */ + ASSIGN_PTR(numbers, PyImport_ImportModule("numbers")); + ASSIGN_PTR(Number, PyObject_GetAttrString(numbers, "Number")); + /* Register Decimal with the Number abstract base class */ + ASSIGN_PTR(obj, PyObject_CallMethod(Number, "register", "(O)", + (PyObject *)&PyDec_Type)); + Py_CLEAR(obj); + /* Rational is a global variable used for fraction comparisons. */ + ASSIGN_PTR(Rational, PyObject_GetAttrString(numbers, "Rational")); + /* Done with numbers, Number */ + Py_CLEAR(numbers); + Py_CLEAR(Number); + + /* DecimalTuple */ + ASSIGN_PTR(collections, PyImport_ImportModule("collections")); + ASSIGN_PTR(DecimalTuple, PyObject_CallMethod(collections, + "namedtuple", "(ss)", "DecimalTuple", + "sign digits exponent")); + /* MutableMapping */ + ASSIGN_PTR(MutableMapping, PyObject_GetAttrString(collections, + "MutableMapping")); + /* Create SignalDict type */ + ASSIGN_PTR(PyDecSignalDict_Type, + (PyTypeObject *)PyObject_CallFunction( + (PyObject *)&PyType_Type, "s(OO){}", + "SignalDict", &PyDecSignalDictMixin_Type, + MutableMapping)); + + /* Done with collections, MutableMapping */ + Py_CLEAR(collections); + Py_CLEAR(MutableMapping); + + + /* Create the module */ + ASSIGN_PTR(m, PyModule_Create(&_decimal_module)); + + + /* Add types to the module */ + Py_INCREF(&PyDec_Type); + CHECK_INT(PyModule_AddObject(m, "Decimal", (PyObject *)&PyDec_Type)); + Py_INCREF(&PyDecContext_Type); + CHECK_INT(PyModule_AddObject(m, "Context", + (PyObject *)&PyDecContext_Type)); + Py_INCREF(DecimalTuple); + CHECK_INT(PyModule_AddObject(m, "DecimalTuple", DecimalTuple)); + + + /* Create top level exception */ + ASSIGN_PTR(DecimalException, PyErr_NewException( + "decimal.DecimalException", + PyExc_ArithmeticError, NULL)); + Py_INCREF(DecimalException); + CHECK_INT(PyModule_AddObject(m, "DecimalException", DecimalException)); + + /* Create signal tuple */ + ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); + + /* Add exceptions that correspond to IEEE signals */ + for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { + ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, + DecimalException, NULL)); + + /* add to module */ + Py_INCREF(cm->ex); + CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex)); + + /* add to signal tuple */ + Py_INCREF(cm->ex); + PyTuple_SET_ITEM(SignalTuple, i, cm->ex); + } + + /* + * Unfortunately, InvalidOperation is a signal that comprises + * several conditions, including InvalidOperation! Naming the + * signal IEEEInvalidOperation would prevent the confusion. + */ + cond_map[0].ex = signal_map[0].ex; + + /* Add remaining exceptions, inherit from InvalidOperation */ + for (cm = cond_map+1; cm->name != NULL; cm++) { + ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, + signal_map[0].ex, NULL)); + Py_INCREF(cm->ex); + CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex)); + } + + + /* Init default context template first */ + ASSIGN_PTR(default_context_template, + PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + Py_INCREF(default_context_template); + CHECK_INT(PyModule_AddObject(m, "DefaultContext", + default_context_template)); + +#ifdef WITHOUT_THREADS + /* Init module context */ + ASSIGN_PTR(module_context, + PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + Py_INCREF(Py_False); + CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_False)); +#else + ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); + Py_INCREF(Py_True); + CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_True)); +#endif + + /* Init basic context template */ + ASSIGN_PTR(basic_context_template, + PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + init_basic_context(basic_context_template); + Py_INCREF(basic_context_template); + CHECK_INT(PyModule_AddObject(m, "BasicContext", + basic_context_template)); + + /* Init extended context template */ + ASSIGN_PTR(extended_context_template, + PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + init_extended_context(extended_context_template); + Py_INCREF(extended_context_template); + CHECK_INT(PyModule_AddObject(m, "ExtendedContext", + extended_context_template)); + + + /* Init mpd_ssize_t constants */ + for (ssize_cm = ssize_constants; ssize_cm->name != NULL; ssize_cm++) { + ASSIGN_PTR(obj, PyLong_FromSsize_t(ssize_cm->val)); + CHECK_INT(PyModule_AddObject(m, ssize_cm->name, obj)); + } + + /* Init int constants */ + for (int_cm = int_constants; int_cm->name != NULL; int_cm++) { + CHECK_INT(PyModule_AddIntConstant(m, int_cm->name, + int_cm->val)); + } + + /* Add specification version number */ + CHECK_INT(PyModule_AddStringConstant(m, "__version__", " 1.70")); + + + return m; + + +error: + Py_XDECREF(obj); /* GCOV_NOT_REACHED */ + Py_XDECREF(numbers); /* GCOV_NOT_REACHED */ + Py_XDECREF(Number); /* GCOV_NOT_REACHED */ + Py_XDECREF(Rational); /* GCOV_NOT_REACHED */ + Py_XDECREF(collections); /* GCOV_NOT_REACHED */ + Py_XDECREF(MutableMapping); /* GCOV_NOT_REACHED */ + Py_XDECREF(SignalTuple); /* GCOV_NOT_REACHED */ + Py_XDECREF(DecimalTuple); /* GCOV_NOT_REACHED */ +#ifdef WITHOUT_THREADS + Py_XDECREF(module_context); /* GCOV_NOT_REACHED */ +#else + Py_XDECREF(default_context_template); /* GCOV_NOT_REACHED */ + Py_XDECREF(tls_context_key); /* GCOV_NOT_REACHED */ +#endif + Py_XDECREF(basic_context_template); /* GCOV_NOT_REACHED */ + Py_XDECREF(extended_context_template); /* GCOV_NOT_REACHED */ + Py_XDECREF(m); /* GCOV_NOT_REACHED */ + + return NULL; /* GCOV_NOT_REACHED */ +} + + diff --git a/Modules/_decimal/docstrings.h b/Modules/_decimal/docstrings.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/docstrings.h @@ -0,0 +1,753 @@ +/* + * Copyright (c) 2001-2012 Python Software Foundation. All Rights Reserved. + * Modified and extended by Stefan Krah. + */ + + +#ifndef DOCSTRINGS_H +#define DOCSTRINGS_H + + +#include "pymacro.h" + + +/******************************************************************************/ +/* Module */ +/******************************************************************************/ + + +PyDoc_STRVAR(doc__decimal, +"C decimal arithmetic module"); + +PyDoc_STRVAR(doc_getcontext,"\n\ +getcontext() - Get the current default context.\n\ +\n"); + +PyDoc_STRVAR(doc_setcontext,"\n\ +setcontext(c) - Set a new default context.\n\ +\n"); + +PyDoc_STRVAR(doc_localcontext,"\n\ +localcontext(c) - Return a context manager that will set the default context\n\ +to a copy of c on entry to the with-statement and restore the previous default\n\ +context when exiting the with-statement. If no context is specified, a copy of\n\ +the current default context is used.\n\ +\n"); + +#ifdef EXTRA_FUNCTIONALITY +PyDoc_STRVAR(doc_ieee_context,"\n\ +IEEEContext(bits) - Return a context object initialized to the proper values for\n\ +one of the IEEE interchange formats. The argument must be a multiple of 32 and\n\ +less than IEEE_CONTEXT_MAX_BITS. For the most common values, the constants\n\ +DECIMAL32, DECIMAL64 and DECIMAL128 are provided.\n\ +\n"); +#endif + + +/******************************************************************************/ +/* Decimal Object and Methods */ +/******************************************************************************/ + +PyDoc_STRVAR(doc_decimal,"\n\ +Decimal([value[, context]]): Construct a new Decimal object from value.\n\ +\n\ +value can be an integer, string, tuple, or another Decimal object.\n\ +If no value is given, return Decimal('0'). The context does not affect\n\ +the conversion and is only passed to determine if the InvalidOperation\n\ +trap is active.\n\ +\n"); + +PyDoc_STRVAR(doc_adjusted,"\n\ +adjusted() - Return the adjusted exponent of the number.\n\ +\n\ +Defined as exp + digits - 1.\n\ +\n"); + +PyDoc_STRVAR(doc_as_tuple,"\n\ +as_tuple() - Return a tuple representation of the number.\n\ +\n"); + +PyDoc_STRVAR(doc_canonical,"\n\ +canonical() - Return the canonical encoding of the argument. Currently,\n\ +the encoding of a Decimal instance is always canonical, so this operation\n\ +returns its argument unchanged.\n\ +\n"); + +PyDoc_STRVAR(doc_compare,"\n\ +compare(other[, context]) - Compare self to other. Return a decimal value:\n\ +\n\ + a or b is a NaN ==> Decimal('NaN')\n\ + a < b ==> Decimal('-1')\n\ + a == b ==> Decimal('0')\n\ + a > b ==> Decimal('1')\n\ +\n"); + +PyDoc_STRVAR(doc_compare_signal,"\n\ +compare_signal(other[, context]) - Identical to compare, except that\n\ +all NaNs signal.\n\ +\n"); + +PyDoc_STRVAR(doc_compare_total,"\n\ +compare_total(other) - Compare two operands using their abstract representation\n\ +rather than their numerical value. Similar to the compare() method, but the\n\ +result gives a total ordering on Decimal instances. Two Decimal instances with\n\ +the same numeric value but different representations compare unequal in this\n\ +ordering:\n\ +\n\ + >>> Decimal('12.0').compare_total(Decimal('12'))\n\ + Decimal('-1')\n\ +\n\ +Quiet and signaling NaNs are also included in the total ordering. The result\n\ +of this function is Decimal('0') if both operands have the same representation,\n\ +Decimal('-1') if the first operand is lower in the total order than the second,\n\ +and Decimal('1') if the first operand is higher in the total order than the\n\ +second operand. See the specification for details of the total order.\n\ +\n"); + +PyDoc_STRVAR(doc_compare_total_mag,"\n\ +compare_total_mag(other) - Compare two operands using their abstract\n\ +representation rather than their value as in compare_total(), but\n\ +ignoring the sign of each operand. x.compare_total_mag(y) is\n\ +equivalent to x.copy_abs().compare_total(y.copy_abs()).\n\ +\n"); + +PyDoc_STRVAR(doc_conjugate,"\n\ +conjugate() - Return self.\n\ +\n"); + +PyDoc_STRVAR(doc_copy_abs,"\n\ +copy_abs() - Return the absolute value of the argument. This operation\n\ +is unaffected by the context and is quiet: no flags are changed and no\n\ +rounding is performed.\n\ +\n"); + +PyDoc_STRVAR(doc_copy_negate,"\n\ +copy_negate() - Return the negation of the argument. This operation is\n\ +unaffected by the context and is quiet: no flags are changed and no\n\ +rounding is performed.\n\ +\n"); + +PyDoc_STRVAR(doc_copy_sign,"\n\ +copy_sign(other) - Return a copy of the first operand with the sign set\n\ +to be the same as the sign of the second operand. For example:\n\ +\n\ + >>> Decimal('2.3').copy_sign(Decimal('-1.5'))\n\ + Decimal('-2.3')\n\ +\n\ +This operation is unaffected by the context and is quiet: no flags are\n\ +changed and no rounding is performed.\n\ +\n"); + +PyDoc_STRVAR(doc_exp,"\n\ +exp([context]) - Return the value of the (natural) exponential function e**x\n\ +at the given number. The function always uses the ROUND_HALF_EVEN mode and\n\ +the result is correctly rounded.\n\ +\n"); + +PyDoc_STRVAR(doc_from_float,"\n\ +from_float(f) - Class method that converts a float to a decimal number, exactly.\n\ +Since 0.1 is not exactly representable in binary floating point,\n\ +Decimal.from_float(0.1) is not the same as Decimal('0.1').\n\ +\n\ + >>> Decimal.from_float(0.1)\n\ + Decimal('0.1000000000000000055511151231257827021181583404541015625')\n\ + >>> Decimal.from_float(float('nan'))\n\ + Decimal('NaN')\n\ + >>> Decimal.from_float(float('inf'))\n\ + Decimal('Infinity')\n\ + >>> Decimal.from_float(float('-inf'))\n\ + Decimal('-Infinity')\n\ +\n\ +\n"); + +PyDoc_STRVAR(doc_fma,"\n\ +fma(other, third[, context]) - Fused multiply-add. Return self*other+third\n\ +with no rounding of the intermediate product self*other.\n\ +\n\ + >>> Decimal(2).fma(3, 5)\n\ + Decimal('11')\n\ +\n\ +\n"); + +PyDoc_STRVAR(doc_is_canonical,"\n\ +is_canonical() - Return True if the argument is canonical and False otherwise.\n\ +Currently, a Decimal instance is always canonical, so this operation always\n\ +returns True.\n\ +\n"); + +PyDoc_STRVAR(doc_is_finite,"\n\ +is_finite() - Return True if the argument is a finite number, and False if the\n\ +argument is infinite or a NaN.\n\ +\n"); + +PyDoc_STRVAR(doc_is_infinite,"\n\ +is_infinite() - Return True if the argument is either positive or negative\n\ +infinity and False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_is_nan,"\n\ +is_nan() - Return True if the argument is a (quiet or signaling) NaN and\n\ +False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_is_normal,"\n\ +is_normal([context]) - Return True if the argument is a normal finite non-zero\n\ +number with an adjusted exponent greater than or equal to Emin. Return False\n\ +if the argument is zero, subnormal, infinite or a NaN.\n\ +\n"); + +PyDoc_STRVAR(doc_is_qnan,"\n\ +is_qnan() - Return True if the argument is a quiet NaN, and False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_is_signed,"\n\ +is_signed() - Return True if the argument has a negative sign and\n\ +False otherwise. Note that both zeros and NaNs can carry signs.\n\ +\n"); + +PyDoc_STRVAR(doc_is_snan,"\n\ +is_snan() - Return True if the argument is a signaling NaN and False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_is_subnormal,"\n\ +is_subnormal([context]) - Return True if the argument is subnormal, and False\n\ +otherwise. A number is subnormal if it is non-zero, finite, and has an\n\ +adjusted exponent less than Emin.\n\ +\n"); + +PyDoc_STRVAR(doc_is_zero,"\n\ +is_zero() - Return True if the argument is a (positive or negative) zero and\n\ +False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ln,"\n\ +ln([context]) - Return the natural (base e) logarithm of the operand.\n\ +The function always uses the ROUND_HALF_EVEN mode and the result is\n\ +correctly rounded.\n\ +\n"); + +PyDoc_STRVAR(doc_log10,"\n\ +log10([context]) - Return the base ten logarithm of the operand.\n\ +The function always uses the ROUND_HALF_EVEN mode and the result is\n\ +correctly rounded.\n\ +\n"); + +PyDoc_STRVAR(doc_logb,"\n\ +logb([context]) - For a non-zero number, return the adjusted exponent\n\ +of the operand as a Decimal instance. If the operand is a zero, then\n\ +Decimal('-Infinity') is returned and the DivisionByZero condition is\n\ +raised. If the operand is an infinity then Decimal('Infinity') is returned.\n\ +\n"); + +PyDoc_STRVAR(doc_logical_and,"\n\ +logical_and(other[, context]) - Return the digit-wise and of the two\n\ +(logical) operands.\n\ +\n"); + +PyDoc_STRVAR(doc_logical_invert,"\n\ +logical_invert([context]) - Return the digit-wise inversion of the\n\ +(logical) operand.\n\ +\n"); + +PyDoc_STRVAR(doc_logical_or,"\n\ +logical_or(other[, context]) - Return the digit-wise or of the two\n\ +(logical) operands.\n\ +\n"); + +PyDoc_STRVAR(doc_logical_xor,"\n\ +logical_xor(other[, context]) - Return the digit-wise exclusive or of the\n\ +two (logical) operands.\n\ +\n"); + +PyDoc_STRVAR(doc_max,"\n\ +max(other[, context]) - Maximum of self and other. If one operand is a quiet\n\ +NaN and the other is numeric, the numeric operand is returned.\n\ +\n"); + +PyDoc_STRVAR(doc_max_mag,"\n\ +max_mag(other[, context]) - Similar to the max() method, but the comparison is\n\ +done using the absolute values of the operands.\n\ +\n"); + +PyDoc_STRVAR(doc_min,"\n\ +min(other[, context]) - Minimum of self and other. If one operand is a quiet\n\ +NaN and the other is numeric, the numeric operand is returned.\n\ +\n"); + +PyDoc_STRVAR(doc_min_mag,"\n\ +min_mag(other[, context]) - Similar to the min() method, but the comparison is\n\ +done using the absolute values of the operands.\n\ +\n"); + +PyDoc_STRVAR(doc_next_minus,"\n\ +next_minus([context]) - Return the largest number representable in the given\n\ +context (or in the current default context if no context is given) that is\n\ +smaller than the given operand.\n\ +\n"); + +PyDoc_STRVAR(doc_next_plus,"\n\ +next_plus([context]) - Return the smallest number representable in the given\n\ +context (or in the current default context if no context is given) that is\n\ +larger than the given operand.\n\ +\n"); + +PyDoc_STRVAR(doc_next_toward,"\n\ +next_toward(other[, context]) - If the two operands are unequal, return the\n\ +number closest to the first operand in the direction of the second operand.\n\ +If both operands are numerically equal, return a copy of the first operand\n\ +with the sign set to be the same as the sign of the second operand.\n\ +\n"); + +PyDoc_STRVAR(doc_normalize,"\n\ +normalize([context]) - Normalize the number by stripping the rightmost trailing\n\ +zeros and converting any result equal to Decimal('0') to Decimal('0e0'). Used\n\ +for producing canonical values for members of an equivalence class. For example,\n\ +Decimal('32.100') and Decimal('0.321000e+2') both normalize to the equivalent\n\ +value Decimal('32.1').\n\ +\n"); + +PyDoc_STRVAR(doc_number_class,"\n\ +number_class([context]) - Return a string describing the class of the operand.\n\ +The returned value is one of the following ten strings:\n\ +\n\ + * '-Infinity', indicating that the operand is negative infinity.\n\ + * '-Normal', indicating that the operand is a negative normal number.\n\ + * '-Subnormal', indicating that the operand is negative and subnormal.\n\ + * '-Zero', indicating that the operand is a negative zero.\n\ + * '+Zero', indicating that the operand is a positive zero.\n\ + * '+Subnormal', indicating that the operand is positive and subnormal.\n\ + * '+Normal', indicating that the operand is a positive normal number.\n\ + * '+Infinity', indicating that the operand is positive infinity.\n\ + * 'NaN', indicating that the operand is a quiet NaN (Not a Number).\n\ + * 'sNaN', indicating that the operand is a signaling NaN.\n\ +\n\ +\n"); + +PyDoc_STRVAR(doc_quantize,"\n\ +quantize(exp[, rounding[, context]]) - Return a value equal to the first\n\ +operand after rounding and having the exponent of the second operand.\n\ +\n\ + >>> Decimal('1.41421356').quantize(Decimal('1.000'))\n\ + Decimal('1.414')\n\ +\n\ +Unlike other operations, if the length of the coefficient after the quantize\n\ +operation would be greater than precision, then an InvalidOperation is signaled.\n\ +This guarantees that, unless there is an error condition, the quantized exponent\n\ +is always equal to that of the right-hand operand.\n\ +\n\ +Also unlike other operations, quantize never signals Underflow, even if the\n\ +result is subnormal and inexact.\n\ +\n\ +If the exponent of the second operand is larger than that of the first, then\n\ +rounding may be necessary. In this case, the rounding mode is determined by the\n\ +rounding argument if given, else by the given context argument; if neither\n\ +argument is given, the rounding mode of the current thread's context is used.\n\ +\n"); + +PyDoc_STRVAR(doc_radix,"\n\ +radix() - Return Decimal(10), the radix (base) in which the Decimal class does\n\ +all its arithmetic. Included for compatibility with the specification.\n\ +\n"); + +PyDoc_STRVAR(doc_remainder_near,"\n\ +remainder_near(other[, context]) - Compute the modulo as either a positive\n\ +or negative value depending on which is closest to zero. For instance,\n\ +Decimal(10).remainder_near(6) returns Decimal('-2'), which is closer to zero\n\ +than Decimal('4').\n\ +\n\ +If both are equally close, the one chosen will have the same sign as self.\n\ +\n"); + +PyDoc_STRVAR(doc_rotate,"\n\ +rotate(other[, context]) - Return the result of rotating the digits of the\n\ +first operand by an amount specified by the second operand. The second operand\n\ +must be an integer in the range -precision through precision. The absolute\n\ +value of the second operand gives the number of places to rotate. If the second\n\ +operand is positive then rotation is to the left; otherwise rotation is to the\n\ +right. The coefficient of the first operand is padded on the left with zeros to\n\ +length precision if necessary. The sign and exponent of the first operand are\n\ +unchanged.\n\ +\n"); + +PyDoc_STRVAR(doc_same_quantum,"\n\ +same_quantum(other[, context]) - Test whether self and other have the\n\ +same exponent or whether both are NaN.\n\ +\n"); + +PyDoc_STRVAR(doc_scaleb,"\n\ +scaleb(other[, context]) - Return the first operand with the exponent adjusted\n\ +the second. Equivalently, return the first operand multiplied by 10**other.\n\ +The second operand must be an integer.\n\ +\n"); + +PyDoc_STRVAR(doc_shift,"\n\ +shift(other[, context]) - Return the result of shifting the digits of\n\ +the first operand by an amount specified by the second operand. The second\n\ +operand must be an integer in the range -precision through precision. The\n\ +absolute value of the second operand gives the number of places to shift.\n\ +If the second operand is positive, then the shift is to the left; otherwise\n\ +the shift is to the right. Digits shifted into the coefficient are zeros.\n\ +The sign and exponent of the first operand are unchanged.\n\ +\n"); + +PyDoc_STRVAR(doc_sqrt,"\n\ +sqrt([context]) - Return the square root of the argument to full precision.\n\ +The result is correctly rounded using the ROUND_HALF_EVEN rounding mode.\n\ +\n"); + +PyDoc_STRVAR(doc_to_eng_string,"\n\ +to_eng_string([context]) - Convert to an engineering-type string.\n\ +Engineering notation has an exponent which is a multiple of 3, so\n\ +there are up to 3 digits left of the decimal place. For example,\n\ +Decimal('123E+1') is converted to Decimal('1.23E+3')\n\ +\n"); + +PyDoc_STRVAR(doc_to_integral,"\n\ +to_integral([rounding[, context]]) - Identical to the to_integral_value()\n\ +method. The to_integral name has been kept for compatibility with older\n\ +versions.\n\ +\n"); + +PyDoc_STRVAR(doc_to_integral_exact,"\n\ +to_integral_exact([rounding[, context]]) - Round to the nearest integer,\n\ +signaling Inexact or Rounded as appropriate if rounding occurs. The rounding\n\ +mode is determined by the rounding parameter if given, else by the given\n\ +context. If neither parameter is given, then the rounding mode of the current\n\ +default context is used.\n\ +\n"); + +PyDoc_STRVAR(doc_to_integral_value,"\n\ +to_integral_value([rounding[, context]]) - Round to the nearest integer without\n\ +signaling Inexact or Rounded. The rounding mode is determined by the rounding\n\ +parameter if given, else by the given context. If neither parameter is given,\n\ +then the rounding mode of the current default context is used.\n\ +\n"); + + +/******************************************************************************/ +/* Context Object and Methods */ +/******************************************************************************/ + +PyDoc_STRVAR(doc_context,"\n\ +The context affects almost all operations and controls rounding,\n\ +Over/Underflow, raising of exceptions and much more. A new context\n\ +can be constructed as follows:\n\ +\n\ + >>> c = Context(prec=28, Emin=-425000000, Emax=425000000,\n\ + ... rounding=ROUND_HALF_EVEN, capitals=1, clamp=1,\n\ + ... traps=[InvalidOperation, DivisionByZero, Overflow],\n\ + ... flags=[])\n\ + >>>\n\ +\n\ +\n"); + +#ifdef EXTRA_FUNCTIONALITY +PyDoc_STRVAR(doc_ctx_apply,"\n\ +apply(x) - Apply self to Decimal x.\n\ +\n"); +#endif + +PyDoc_STRVAR(doc_ctx_clear_flags,"\n\ +clear_flags() - Reset all flags to False.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_clear_traps,"\n\ +clear_traps() - Set all traps to False.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy,"\n\ +copy() - Return a duplicate of the context with all flags cleared.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy_decimal,"\n\ +copy_decimal(x) - Return a copy of Decimal x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_create_decimal,"\n\ +create_decimal(x) - Create a new Decimal instance from x, using self as the\n\ +context. Unlike the Decimal constructor, this function observes the context\n\ +limits.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_create_decimal_from_float,"\n\ +create_decimal_from_float(f) - Create a new Decimal instance from float f.\n\ +Unlike the Decimal.from_float() class method, this function observes the\n\ +context limits.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_Etiny,"\n\ +Etiny() - Return a value equal to Emin - prec + 1, which is the minimum\n\ +exponent value for subnormal results. When underflow occurs, the exponent\n\ +is set to Etiny.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_Etop,"\n\ +Etop() - Return a value equal to Emax - prec + 1. This is the maximum exponent\n\ +if the _clamp field of the context is set to 1 (IEEE clamp mode). Etop() must\n\ +not be negative.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_abs,"\n\ +abs(x) - Return the absolute value of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_add,"\n\ +add(x, y) - Return the sum of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_canonical,"\n\ +canonical(x) - Return a new instance of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_compare,"\n\ +compare(x, y) - Compare x and y numerically.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_compare_signal,"\n\ +compare_signal(x, y) - Compare x and y numerically. All NaNs signal.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_compare_total,"\n\ +compare_total(x, y) - Compare x and y using their abstract representation.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_compare_total_mag,"\n\ +compare_total_mag(x, y) - Compare x and y using their abstract representation,\n\ +ignoring sign.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy_abs,"\n\ +copy_abs(x) - Return a copy of x with the sign set to 0.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy_negate,"\n\ +copy_negate(x) - Return a copy of x with the sign inverted.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_copy_sign,"\n\ +copy_sign(x, y) - Copy the sign from y to x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_divide,"\n\ +divide(x, y) - Return x divided by y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_divide_int,"\n\ +divide_int(x, y) - Return x divided by y, truncated to an integer.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_divmod,"\n\ +divmod(x, y) - Return quotient and remainder of the division x / y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_exp,"\n\ +exp(x) - Return e ** x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_fma,"\n\ +fma(x, y, z) - Return x multiplied by y, plus z.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_canonical,"\n\ +is_canonical(x) - Return True if x is canonical, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_finite,"\n\ +is_finite(x) - Return True if x is finite, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_infinite,"\n\ +is_infinite(x) - Return True if x is infinite, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_nan,"\n\ +is_nan(x) - Return True if x is a qNaN or sNaN, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_normal,"\n\ +is_normal(x) - Return True if x is a normal number, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_qnan,"\n\ +is_qnan(x) - Return True if x is a quiet NaN, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_signed,"\n\ +is_signed(x) - Return True if x is negative, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_snan,"\n\ +is_snan() - Return True if x is a signaling NaN, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_subnormal,"\n\ +is_subnormal(x) - Return True if x is subnormal, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_is_zero,"\n\ +is_zero(x) - Return True if x is a zero, False otherwise.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_ln,"\n\ +ln(x) - Return the natural (base e) logarithm of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_log10,"\n\ +log10(x) - Return the base 10 logarithm of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logb,"\n\ +logb(x) - Return the exponent of the magnitude of the operand's MSD.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logical_and,"\n\ +logical_and(x, y) - Digit-wise and of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logical_invert,"\n\ +logical_invert(x) - Invert all digits of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logical_or,"\n\ +logical_or(x, y) - Digit-wise or of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_logical_xor,"\n\ +logical_xor(x, y) - Digit-wise xor of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_max,"\n\ +max(x, y) - Compare the values numerically and return the maximum.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_max_mag,"\n\ +max_mag(x, y) - Compare the values numerically with their sign ignored.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_min,"\n\ +min(x, y) - Compare the values numerically and return the minimum.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_min_mag,"\n\ +min_mag(x, y) - Compare the values numerically with their sign ignored.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_minus,"\n\ +minus(x) - Minus corresponds to the unary prefix minus operator in Python,\n\ +but applies the context to the result.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_multiply,"\n\ +multiply(x, y) - Return the product of x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_next_minus,"\n\ +next_minus(x) - Return the largest representable number smaller than x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_next_plus,"\n\ +next_plus(x) - Return the smallest representable number larger than x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_next_toward,"\n\ +next_toward(x) - Return the number closest to x, in the direction towards y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_normalize,"\n\ +normalize(x) - Reduce x to its simplest form. Alias for reduce(x).\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_number_class,"\n\ +number_class(x) - Return an indication of the class of x.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_plus,"\n\ +plus(x) - Plus corresponds to the unary prefix plus operator in Python,\n\ +but applies the context to the result.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_power,"\n\ +power(x, y) - Compute x**y. If x is negative, then y must be integral.\n\ +The result will be inexact unless y is integral and the result is finite\n\ +and can be expressed exactly in 'precision' digits. In the Python version\n\ +the result is always correctly rounded, in the C version the result is\n\ +almost always correctly rounded.\n\ +\n\ +power(x, y, m) - Compute (x**y) % m. The following restrictions hold:\n\ +\n\ + * all three arguments must be integral\n\ + * y must be nonnegative\n\ + * at least one of x or y must be nonzero\n\ + * m must be nonzero and less than 10**prec in absolute value\n\ +\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_quantize,"\n\ +quantize(x, y) - Return a value equal to x (rounded), having the exponent of y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_radix,"\n\ +radix() - Return 10.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_remainder,"\n\ +remainder(x, y) - Return the remainder from integer division. The sign of\n\ +the result, if non-zero, is the same as that of the original dividend.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_remainder_near,"\n\ +remainder_near(x, y) - Return x - y * n, where n is the integer nearest the\n\ +exact value of x / y (if the result is 0 then its sign will be the sign of x).\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_rotate,"\n\ +rotate(x, y) - Return a copy of x, rotated by y places.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_same_quantum,"\n\ +same_quantum(x, y) - Return True if the two operands have the same exponent.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_scaleb,"\n\ +scaleb(x, y) - Return the first operand after adding the second value\n\ +to its exp.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_shift,"\n\ +shift(x, y) - Return a copy of x, shifted by y places.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_sqrt,"\n\ +sqrt(x) - Square root of a non-negative number to context precision.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_subtract,"\n\ +subtract(x, y) - Return the difference between x and y.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_eng_string,"\n\ +to_eng_string(x) - Convert a number to a string, using engineering notation.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_integral,"\n\ +to_integral(x) - Identical to to_integral_value(x).\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_integral_exact,"\n\ +to_integral_exact(x) - Round to an integer. Signal if the result is\n\ +rounded or inexact.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_integral_value,"\n\ +to_integral_value(x) - Round to an integer.\n\ +\n"); + +PyDoc_STRVAR(doc_ctx_to_sci_string,"\n\ +to_sci_string(x) - Convert a number to a string using scientific notation.\n\ +\n"); + + +#endif /* DOCSTRINGS_H */ + + + diff --git a/Modules/_decimal/libmpdec/README.txt b/Modules/_decimal/libmpdec/README.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/README.txt @@ -0,0 +1,90 @@ + + +libmpdec +======== + +libmpdec is a fast C/C++ library for correctly-rounded arbitrary precision +decimal floating point arithmetic. It is a complete implementation of +Mike Cowlishaw/IBM's General Decimal Arithmetic Specification. + + +Files required for the Python _decimal module +============================================= + + Core files for small and medium precision arithmetic + ---------------------------------------------------- + + basearith.{c,h} -> Core arithmetic in base 10**9 or 10**19. + bits.h -> Portable detection of least/most significant one-bit. + constants.{c,h} -> Constants that are used in multiple files. + context.c -> Context functions. + io.{c,h} -> Conversions between mpd_t and ASCII strings, + mpd_t formatting (allows UTF-8 fill character). + memory.{c,h} -> Allocation handlers with overflow detection + and functions for switching between static + and dynamic mpd_t. + mpdecimal.{c,h} -> All (quiet) functions of the specification. + typearith.h -> Fast primitives for double word multiplication, + division etc. + + Visual Studio only: + ~~~~~~~~~~~~~~~~~~~ + vccompat.h -> snprintf <==> sprintf_s and similar things. + vcstdint.h -> stdint.h (included in VS 2010 but not in VS 2008). + vcdiv64.asm -> Double word division used in typearith.h. VS 2008 does + not allow inline asm for x64. Also, it does not provide + an intrinsic for double word division. + + Files for bignum arithmetic: + ---------------------------- + + The following files implement the Fast Number Theoretic Transform + used for multiplying coefficients with more than 1024 words (see + mpdecimal.c: _mpd_fntmul()). + + umodarith.h -> Fast low level routines for unsigned modular arithmetic. + numbertheory.{c,h} -> Routines for setting up the Number Theoretic Transform. + difradix2.{c,h} -> Decimation in frequency transform, used as the + "base case" by the following three files: + + fnt.{c,h} -> Transform arrays up to 4096 words. + sixstep.{c,h} -> Transform larger arrays of length 2**n. + fourstep.{c,h} -> Transform larger arrays of length 3 * 2**n. + + convolute.{c,h} -> Fast convolution using one of the three transform + functions. + transpose.{c,h} -> Transpositions needed for the sixstep algorithm. + crt.{c,h} -> Chinese Remainder Theorem: use information from three + transforms modulo three different primes to get the + final result. + + +Pointers to literature, proofs and more +======================================= + + literature/ + ----------- + + REFERENCES.txt -> List of relevant papers. + bignum.txt -> Explanation of the Fast Number Theoretic Transform (FNT). + fnt.py -> Verify constants used in the FNT; Python demo for the + O(N**2) discrete transform. + + matrix-transform.txt -> Proof for the Matrix Fourier Transform used in + fourstep.c. + six-step.txt -> Show that the algorithm used in sixstep.c is + a variant of the Matrix Fourier Transform. + mulmod-64.txt -> Proof for the mulmod64 algorithm from + umodarith.h. + mulmod-ppro.txt -> Proof for the x87 FPU modular multiplication + from umodarith.h. + umodarith.lisp -> ACL2 proofs for many functions from umodarith.h. + + +Library Author +============== + + Stefan Krah + + + diff --git a/Modules/_decimal/libmpdec/basearith.c b/Modules/_decimal/libmpdec/basearith.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/basearith.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include +#include "constants.h" +#include "memory.h" +#include "typearith.h" +#include "basearith.h" + + +/*********************************************************************/ +/* Calculations in base MPD_RADIX */ +/*********************************************************************/ + + +/* + * Knuth, TAOCP, Volume 2, 4.3.1: + * w := sum of u (len m) and v (len n) + * n > 0 and m >= n + * The calling function has to handle a possible final carry. + */ +mpd_uint_t +_mpd_baseadd(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n) +{ + mpd_uint_t s; + mpd_uint_t carry = 0; + mpd_size_t i; + + assert(n > 0 && m >= n); + + /* add n members of u and v */ + for (i = 0; i < n; i++) { + s = u[i] + (v[i] + carry); + carry = (s < u[i]) | (s >= MPD_RADIX); + w[i] = carry ? s-MPD_RADIX : s; + } + /* if there is a carry, propagate it */ + for (; carry && i < m; i++) { + s = u[i] + carry; + carry = (s == MPD_RADIX); + w[i] = carry ? 0 : s; + } + /* copy the rest of u */ + for (; i < m; i++) { + w[i] = u[i]; + } + + return carry; +} + +/* + * Add the contents of u to w. Carries are propagated further. The caller + * has to make sure that w is big enough. + */ +void +_mpd_baseaddto(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n) +{ + mpd_uint_t s; + mpd_uint_t carry = 0; + mpd_size_t i; + + if (n == 0) return; + + /* add n members of u to w */ + for (i = 0; i < n; i++) { + s = w[i] + (u[i] + carry); + carry = (s < w[i]) | (s >= MPD_RADIX); + w[i] = carry ? s-MPD_RADIX : s; + } + /* if there is a carry, propagate it */ + for (; carry; i++) { + s = w[i] + carry; + carry = (s == MPD_RADIX); + w[i] = carry ? 0 : s; + } +} + +/* + * Add v to w (len m). The calling function has to handle a possible + * final carry. Assumption: m > 0. + */ +mpd_uint_t +_mpd_shortadd(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v) +{ + mpd_uint_t s; + mpd_uint_t carry; + mpd_size_t i; + + assert(m > 0); + + /* add v to w */ + s = w[0] + v; + carry = (s < v) | (s >= MPD_RADIX); + w[0] = carry ? s-MPD_RADIX : s; + + /* if there is a carry, propagate it */ + for (i = 1; carry && i < m; i++) { + s = w[i] + carry; + carry = (s == MPD_RADIX); + w[i] = carry ? 0 : s; + } + + return carry; +} + +/* Increment u. The calling function has to handle a possible carry. */ +mpd_uint_t +_mpd_baseincr(mpd_uint_t *u, mpd_size_t n) +{ + mpd_uint_t s; + mpd_uint_t carry = 1; + mpd_size_t i; + + assert(n > 0); + + /* if there is a carry, propagate it */ + for (i = 0; carry && i < n; i++) { + s = u[i] + carry; + carry = (s == MPD_RADIX); + u[i] = carry ? 0 : s; + } + + return carry; +} + +/* + * Knuth, TAOCP, Volume 2, 4.3.1: + * w := difference of u (len m) and v (len n). + * number in u >= number in v; + */ +void +_mpd_basesub(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n) +{ + mpd_uint_t d; + mpd_uint_t borrow = 0; + mpd_size_t i; + + assert(m > 0 && n > 0); + + /* subtract n members of v from u */ + for (i = 0; i < n; i++) { + d = u[i] - (v[i] + borrow); + borrow = (u[i] < d); + w[i] = borrow ? d + MPD_RADIX : d; + } + /* if there is a borrow, propagate it */ + for (; borrow && i < m; i++) { + d = u[i] - borrow; + borrow = (u[i] == 0); + w[i] = borrow ? MPD_RADIX-1 : d; + } + /* copy the rest of u */ + for (; i < m; i++) { + w[i] = u[i]; + } +} + +/* + * Subtract the contents of u from w. w is larger than u. Borrows are + * propagated further, but eventually w can absorb the final borrow. + */ +void +_mpd_basesubfrom(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n) +{ + mpd_uint_t d; + mpd_uint_t borrow = 0; + mpd_size_t i; + + if (n == 0) return; + + /* subtract n members of u from w */ + for (i = 0; i < n; i++) { + d = w[i] - (u[i] + borrow); + borrow = (w[i] < d); + w[i] = borrow ? d + MPD_RADIX : d; + } + /* if there is a borrow, propagate it */ + for (; borrow; i++) { + d = w[i] - borrow; + borrow = (w[i] == 0); + w[i] = borrow ? MPD_RADIX-1 : d; + } +} + +/* w := product of u (len n) and v (single word) */ +void +_mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v) +{ + mpd_uint_t hi, lo; + mpd_uint_t carry = 0; + mpd_size_t i; + + assert(n > 0); + + for (i=0; i < n; i++) { + + _mpd_mul_words(&hi, &lo, u[i], v); + lo = carry + lo; + if (lo < carry) hi++; + + _mpd_div_words_r(&carry, &w[i], hi, lo); + } + w[i] = carry; +} + +/* + * Knuth, TAOCP, Volume 2, 4.3.1: + * w := product of u (len m) and v (len n) + * w must be initialized to zero + */ +void +_mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n) +{ + mpd_uint_t hi, lo; + mpd_uint_t carry; + mpd_size_t i, j; + + assert(m > 0 && n > 0); + + for (j=0; j < n; j++) { + carry = 0; + for (i=0; i < m; i++) { + + _mpd_mul_words(&hi, &lo, u[i], v[j]); + lo = w[i+j] + lo; + if (lo < w[i+j]) hi++; + lo = carry + lo; + if (lo < carry) hi++; + + _mpd_div_words_r(&carry, &w[i+j], hi, lo); + } + w[j+m] = carry; + } +} + +/* + * Knuth, TAOCP Volume 2, 4.3.1, exercise 16: + * w := quotient of u (len n) divided by a single word v + */ +mpd_uint_t +_mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v) +{ + mpd_uint_t hi, lo; + mpd_uint_t rem = 0; + mpd_size_t i; + + assert(n > 0); + + for (i=n-1; i != MPD_SIZE_MAX; i--) { + + _mpd_mul_words(&hi, &lo, rem, MPD_RADIX); + lo = u[i] + lo; + if (lo < u[i]) hi++; + + _mpd_div_words(&w[i], &rem, hi, lo, v); + } + + return rem; +} + +/* + * Knuth, TAOCP Volume 2, 4.3.1: + * q, r := quotient and remainder of uconst (len nplusm) + * divided by vconst (len n) + * nplusm >= n + * + * If r is not NULL, r will contain the remainder. If r is NULL, the + * return value indicates if there is a remainder: 1 for true, 0 for + * false. A return value of -1 indicates an error. + */ +int +_mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r, + const mpd_uint_t *uconst, const mpd_uint_t *vconst, + mpd_size_t nplusm, mpd_size_t n) +{ + mpd_uint_t ustatic[MPD_MINALLOC_MAX]; + mpd_uint_t vstatic[MPD_MINALLOC_MAX]; + mpd_uint_t *u = ustatic; + mpd_uint_t *v = vstatic; + mpd_uint_t d, qhat, rhat, w2[2]; + mpd_uint_t hi, lo, x; + mpd_uint_t carry; + mpd_size_t i, j, m; + int retval = 0; + + assert(n > 1 && nplusm >= n); + m = sub_size_t(nplusm, n); + + /* D1: normalize */ + d = MPD_RADIX / (vconst[n-1] + 1); + + if (nplusm >= MPD_MINALLOC_MAX) { + if ((u = mpd_alloc(nplusm+1, sizeof *u)) == NULL) { + return -1; + } + } + if (n >= MPD_MINALLOC_MAX) { + if ((v = mpd_alloc(n+1, sizeof *v)) == NULL) { + mpd_free(u); + return -1; + } + } + + _mpd_shortmul(u, uconst, nplusm, d); + _mpd_shortmul(v, vconst, n, d); + + /* D2: loop */ + for (j=m; j != MPD_SIZE_MAX; j--) { + + /* D3: calculate qhat and rhat */ + rhat = _mpd_shortdiv(w2, u+j+n-1, 2, v[n-1]); + qhat = w2[1] * MPD_RADIX + w2[0]; + + while (1) { + if (qhat < MPD_RADIX) { + _mpd_singlemul(w2, qhat, v[n-2]); + if (w2[1] <= rhat) { + if (w2[1] != rhat || w2[0] <= u[j+n-2]) { + break; + } + } + } + qhat -= 1; + rhat += v[n-1]; + if (rhat < v[n-1] || rhat >= MPD_RADIX) { + break; + } + } + /* D4: multiply and subtract */ + carry = 0; + for (i=0; i <= n; i++) { + + _mpd_mul_words(&hi, &lo, qhat, v[i]); + + lo = carry + lo; + if (lo < carry) hi++; + + _mpd_div_words_r(&hi, &lo, hi, lo); + + x = u[i+j] - lo; + carry = (u[i+j] < x); + u[i+j] = carry ? x+MPD_RADIX : x; + carry += hi; + } + q[j] = qhat; + /* D5: test remainder */ + if (carry) { + q[j] -= 1; + /* D6: add back */ + (void)_mpd_baseadd(u+j, u+j, v, n+1, n); + } + } + + /* D8: unnormalize */ + if (r != NULL) { + _mpd_shortdiv(r, u, n, d); + /* we are not interested in the return value here */ + retval = 0; + } + else { + retval = !_mpd_isallzero(u, n); + } + + +if (u != ustatic) mpd_free(u); +if (v != vstatic) mpd_free(v); +return retval; +} + +/* + * Left shift of src by 'shift' digits; src may equal dest. + * + * dest := area of n mpd_uint_t with space for srcdigits+shift digits. + * src := coefficient with length m. + * + * The case splits in the function are non-obvious. The following + * equations might help: + * + * Let msdigits denote the number of digits in the most significant + * word of src. Then 1 <= msdigits <= rdigits. + * + * 1) shift = q * rdigits + r + * 2) srcdigits = qsrc * rdigits + msdigits + * 3) destdigits = shift + srcdigits + * = q * rdigits + r + qsrc * rdigits + msdigits + * = q * rdigits + (qsrc * rdigits + (r + msdigits)) + * + * The result has q zero words, followed by the coefficient that + * is left-shifted by r. The case r == 0 is trivial. For r > 0, it + * is important to keep in mind that we always read m source words, + * but write m+1 destination words if r + msdigits > rdigits, m words + * otherwise. + */ +void +_mpd_baseshiftl(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t n, mpd_size_t m, + mpd_size_t shift) +{ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) + /* spurious uninitialized warnings */ + mpd_uint_t l=l, lprev=lprev, h=h; +#else + mpd_uint_t l, lprev, h; +#endif + mpd_uint_t q, r; + mpd_uint_t ph; + + assert(m > 0 && n >= m); + + _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS); + + if (r != 0) { + + ph = mpd_pow10[r]; + + --m; --n; + _mpd_divmod_pow10(&h, &lprev, src[m--], MPD_RDIGITS-r); + if (h != 0) { /* r + msdigits > rdigits <==> h != 0 */ + dest[n--] = h; + } + /* write m-1 shifted words */ + for (; m != MPD_SIZE_MAX; m--,n--) { + _mpd_divmod_pow10(&h, &l, src[m], MPD_RDIGITS-r); + dest[n] = ph * lprev + h; + lprev = l; + } + /* write least significant word */ + dest[q] = ph * lprev; + } + else { + while (--m != MPD_SIZE_MAX) { + dest[m+q] = src[m]; + } + } + + mpd_uint_zero(dest, q); +} + +/* + * Right shift of src by 'shift' digits; src may equal dest. + * Assumption: srcdigits-shift > 0. + * + * dest := area with space for srcdigits-shift digits. + * src := coefficient with length 'slen'. + * + * The case splits in the function rely on the following equations: + * + * Let msdigits denote the number of digits in the most significant + * word of src. Then 1 <= msdigits <= rdigits. + * + * 1) shift = q * rdigits + r + * 2) srcdigits = qsrc * rdigits + msdigits + * 3) destdigits = srcdigits - shift + * = qsrc * rdigits + msdigits - (q * rdigits + r) + * = (qsrc - q) * rdigits + msdigits - r + * + * Since destdigits > 0 and 1 <= msdigits <= rdigits: + * + * 4) qsrc >= q + * 5) qsrc == q ==> msdigits > r + * + * The result has slen-q words if msdigits > r, slen-q-1 words otherwise. + */ +mpd_uint_t +_mpd_baseshiftr(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t slen, + mpd_size_t shift) +{ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) + /* spurious uninitialized warnings */ + mpd_uint_t l=l, h=h, hprev=hprev; /* low, high, previous high */ +#else + mpd_uint_t l, h, hprev; /* low, high, previous high */ +#endif + mpd_uint_t rnd, rest; /* rounding digit, rest */ + mpd_uint_t q, r; + mpd_size_t i, j; + mpd_uint_t ph; + + assert(slen > 0); + + _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS); + + rnd = rest = 0; + if (r != 0) { + + ph = mpd_pow10[MPD_RDIGITS-r]; + + _mpd_divmod_pow10(&hprev, &rest, src[q], r); + _mpd_divmod_pow10(&rnd, &rest, rest, r-1); + + if (rest == 0 && q > 0) { + rest = !_mpd_isallzero(src, q); + } + /* write slen-q-1 words */ + for (j=0,i=q+1; i 0) { + _mpd_divmod_pow10(&rnd, &rest, src[q-1], MPD_RDIGITS-1); + /* is there any non-zero digit below rnd? */ + if (rest == 0) rest = !_mpd_isallzero(src, q-1); + } + for (j = 0; j < slen-q; j++) { + dest[j] = src[q+j]; + } + } + + /* 0-4 ==> rnd+rest < 0.5 */ + /* 5 ==> rnd+rest == 0.5 */ + /* 6-9 ==> rnd+rest > 0.5 */ + return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd; +} + + +/*********************************************************************/ +/* Calculations in base b */ +/*********************************************************************/ + +/* + * Add v to w (len m). The calling function has to handle a possible + * final carry. Assumption: m > 0. + */ +mpd_uint_t +_mpd_shortadd_b(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v, mpd_uint_t b) +{ + mpd_uint_t s; + mpd_uint_t carry; + mpd_size_t i; + + assert(m > 0); + + /* add v to w */ + s = w[0] + v; + carry = (s < v) | (s >= b); + w[0] = carry ? s-b : s; + + /* if there is a carry, propagate it */ + for (i = 1; carry && i < m; i++) { + s = w[i] + carry; + carry = (s == b); + w[i] = carry ? 0 : s; + } + + return carry; +} + +/* w := product of u (len n) and v (single word) */ +void +_mpd_shortmul_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v, mpd_uint_t b) +{ + mpd_uint_t hi, lo; + mpd_uint_t carry = 0; + mpd_size_t i; + + assert(n > 0); + + for (i=0; i < n; i++) { + + _mpd_mul_words(&hi, &lo, u[i], v); + lo = carry + lo; + if (lo < carry) hi++; + + _mpd_div_words(&carry, &w[i], hi, lo, b); + } + w[i] = carry; +} + +/* + * Knuth, TAOCP Volume 2, 4.3.1, exercise 16: + * w := quotient of u (len n) divided by a single word v + */ +mpd_uint_t +_mpd_shortdiv_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v, mpd_uint_t b) +{ + mpd_uint_t hi, lo; + mpd_uint_t rem = 0; + mpd_size_t i; + + assert(n > 0); + + for (i=n-1; i != MPD_SIZE_MAX; i--) { + + _mpd_mul_words(&hi, &lo, rem, b); + lo = u[i] + lo; + if (lo < u[i]) hi++; + + _mpd_div_words(&w[i], &rem, hi, lo, v); + } + + return rem; +} + + + diff --git a/Modules/_decimal/libmpdec/basearith.h b/Modules/_decimal/libmpdec/basearith.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/basearith.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef BASEARITH_H +#define BASEARITH_H + + +#include "mpdecimal.h" +#include +#include "typearith.h" + + +mpd_uint_t _mpd_baseadd(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n); +void _mpd_baseaddto(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n); +mpd_uint_t _mpd_shortadd(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v); +mpd_uint_t _mpd_shortadd_b(mpd_uint_t *w, mpd_size_t m, mpd_uint_t v, + mpd_uint_t b); +mpd_uint_t _mpd_baseincr(mpd_uint_t *u, mpd_size_t n); +void _mpd_basesub(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n); +void _mpd_basesubfrom(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n); +void _mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t m, mpd_size_t n); +void _mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v); +void _mpd_shortmul_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v, mpd_uint_t b); +mpd_uint_t _mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v); +mpd_uint_t _mpd_shortdiv_b(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, + mpd_uint_t v, mpd_uint_t b); +int _mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r, const mpd_uint_t *uconst, + const mpd_uint_t *vconst, mpd_size_t nplusm, mpd_size_t n); +void _mpd_baseshiftl(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t n, + mpd_size_t m, mpd_size_t shift); +mpd_uint_t _mpd_baseshiftr(mpd_uint_t *dest, mpd_uint_t *src, mpd_size_t slen, + mpd_size_t shift); + + + +#ifdef CONFIG_64 +extern const mpd_uint_t mprime_rdx; + +/* + * Algorithm from: Division by Invariant Integers using Multiplication, + * T. Granlund and P. L. Montgomery, Proceedings of the SIGPLAN '94 + * Conference on Programming Language Design and Implementation. + * + * http://gmplib.org/~tege/divcnst-pldi94.pdf + * + * Variables from the paper and their translations (See section 8): + * + * N := 64 + * d := MPD_RADIX + * l := 64 + * m' := floor((2**(64+64) - 1)/MPD_RADIX) - 2**64 + * + * Since N-l == 0: + * + * dnorm := d + * n2 := hi + * n10 := lo + * + * ACL2 proof: mpd-div-words-r-correct + */ +static inline void +_mpd_div_words_r(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo) +{ + mpd_uint_t n_adj, h, l, t; + mpd_uint_t n1_neg; + + /* n1_neg = if lo >= 2**63 then MPD_UINT_MAX else 0 */ + n1_neg = (lo & (1ULL<<63)) ? MPD_UINT_MAX : 0; + /* n_adj = if lo >= 2**63 then lo+MPD_RADIX else lo */ + n_adj = lo + (n1_neg & MPD_RADIX); + + /* (h, l) = if lo >= 2**63 then m'*(hi+1) else m'*hi */ + _mpd_mul_words(&h, &l, mprime_rdx, hi-n1_neg); + l = l + n_adj; + if (l < n_adj) h++; + t = h + hi; + /* At this point t == qest, with q == qest or q == qest+1: + * 1) 0 <= 2**64*hi + lo - qest*MPD_RADIX < 2*MPD_RADIX + */ + + /* t = 2**64-1 - qest = 2**64 - (qest+1) */ + t = MPD_UINT_MAX - t; + + /* (h, l) = 2**64*MPD_RADIX - (qest+1)*MPD_RADIX */ + _mpd_mul_words(&h, &l, t, MPD_RADIX); + l = l + lo; + if (l < lo) h++; + h += hi; + h -= MPD_RADIX; + /* (h, l) = 2**64*hi + lo - (qest+1)*MPD_RADIX (mod 2**128) + * Case q == qest+1: + * a) h == 0, l == r + * b) q := h - t == qest+1 + * c) r := l + * Case q == qest: + * a) h == MPD_UINT_MAX, l == 2**64-(MPD_RADIX-r) + * b) q := h - t == qest + * c) r := l + MPD_RADIX = r + */ + + *q = (h - t); + *r = l + (MPD_RADIX & h); +} +#else +static inline void +_mpd_div_words_r(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo) +{ + _mpd_div_words(q, r, hi, lo, MPD_RADIX); +} +#endif + + +/* Multiply two single base MPD_RADIX words, store result in array w[2]. */ +static inline void +_mpd_singlemul(mpd_uint_t w[2], mpd_uint_t u, mpd_uint_t v) +{ + mpd_uint_t hi, lo; + + _mpd_mul_words(&hi, &lo, u, v); + _mpd_div_words_r(&w[1], &w[0], hi, lo); +} + +/* Multiply u (len 2) and v (len m, 1 <= m <= 2). */ +static inline void +_mpd_mul_2_le2(mpd_uint_t w[4], mpd_uint_t u[2], mpd_uint_t v[2], mpd_ssize_t m) +{ + mpd_uint_t hi, lo; + + _mpd_mul_words(&hi, &lo, u[0], v[0]); + _mpd_div_words_r(&w[1], &w[0], hi, lo); + + _mpd_mul_words(&hi, &lo, u[1], v[0]); + lo = w[1] + lo; + if (lo < w[1]) hi++; + _mpd_div_words_r(&w[2], &w[1], hi, lo); + if (m == 1) return; + + _mpd_mul_words(&hi, &lo, u[0], v[1]); + lo = w[1] + lo; + if (lo < w[1]) hi++; + _mpd_div_words_r(&w[3], &w[1], hi, lo); + + _mpd_mul_words(&hi, &lo, u[1], v[1]); + lo = w[2] + lo; + if (lo < w[2]) hi++; + lo = w[3] + lo; + if (lo < w[3]) hi++; + _mpd_div_words_r(&w[3], &w[2], hi, lo); +} + + +/* + * Test if all words from data[len-1] to data[0] are zero. If len is 0, nothing + * is tested and the coefficient is regarded as "all zero". + */ +static inline int +_mpd_isallzero(const mpd_uint_t *data, mpd_ssize_t len) +{ + while (--len >= 0) { + if (data[len] != 0) return 0; + } + return 1; +} + +/* + * Test if all full words from data[len-1] to data[0] are MPD_RADIX-1 + * (all nines). Return true if len == 0. + */ +static inline int +_mpd_isallnine(const mpd_uint_t *data, mpd_ssize_t len) +{ + while (--len >= 0) { + if (data[len] != MPD_RADIX-1) return 0; + } + return 1; +} + + +#endif /* BASEARITH_H */ + + + diff --git a/Modules/_decimal/libmpdec/bits.h b/Modules/_decimal/libmpdec/bits.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/bits.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef BITS_H +#define BITS_H + + +#include "mpdecimal.h" +#include + + +/* Check if n is a power of 2. */ +static inline int +ispower2(mpd_size_t n) +{ + return n != 0 && (n & (n-1)) == 0; +} + +#if defined(ANSI) +/* + * Return the most significant bit position of n from 0 to 31 (63). + * Assumptions: n != 0. + */ +static inline int +mpd_bsr(mpd_size_t n) +{ + int pos = 0; + mpd_size_t tmp; + +#ifdef CONFIG_64 + tmp = n >> 32; + if (tmp != 0) { n = tmp; pos += 32; } +#endif + tmp = n >> 16; + if (tmp != 0) { n = tmp; pos += 16; } + tmp = n >> 8; + if (tmp != 0) { n = tmp; pos += 8; } + tmp = n >> 4; + if (tmp != 0) { n = tmp; pos += 4; } + tmp = n >> 2; + if (tmp != 0) { n = tmp; pos += 2; } + tmp = n >> 1; + if (tmp != 0) { n = tmp; pos += 1; } + + return pos + (int)n - 1; +} + +/* + * Return the least significant bit position of n from 0 to 31 (63). + * Assumptions: n != 0. + */ +static inline int +mpd_bsf(mpd_size_t n) +{ + int pos; + +#ifdef CONFIG_64 + pos = 63; + if (n & 0x00000000FFFFFFFFULL) { pos -= 32; } else { n >>= 32; } + if (n & 0x000000000000FFFFULL) { pos -= 16; } else { n >>= 16; } + if (n & 0x00000000000000FFULL) { pos -= 8; } else { n >>= 8; } + if (n & 0x000000000000000FULL) { pos -= 4; } else { n >>= 4; } + if (n & 0x0000000000000003ULL) { pos -= 2; } else { n >>= 2; } + if (n & 0x0000000000000001ULL) { pos -= 1; } +#else + pos = 31; + if (n & 0x000000000000FFFFUL) { pos -= 16; } else { n >>= 16; } + if (n & 0x00000000000000FFUL) { pos -= 8; } else { n >>= 8; } + if (n & 0x000000000000000FUL) { pos -= 4; } else { n >>= 4; } + if (n & 0x0000000000000003UL) { pos -= 2; } else { n >>= 2; } + if (n & 0x0000000000000001UL) { pos -= 1; } +#endif + return pos; +} +/* END ANSI */ + +#elif defined(ASM) +/* + * Bit scan reverse. Assumptions: a != 0. + */ +static inline int +mpd_bsr(mpd_size_t a) +{ + mpd_size_t retval; + + __asm__ ( +#ifdef CONFIG_64 + "bsrq %1, %0\n\t" +#else + "bsr %1, %0\n\t" +#endif + :"=r" (retval) + :"r" (a) + :"cc" + ); + + return (int)retval; +} + +/* + * Bit scan forward. Assumptions: a != 0. + */ +static inline int +mpd_bsf(mpd_size_t a) +{ + mpd_size_t retval; + + __asm__ ( +#ifdef CONFIG_64 + "bsfq %1, %0\n\t" +#else + "bsf %1, %0\n\t" +#endif + :"=r" (retval) + :"r" (a) + :"cc" + ); + + return (int)retval; +} +/* END ASM */ + +#elif defined(MASM) +#include +/* + * Bit scan reverse. Assumptions: a != 0. + */ +static inline int __cdecl +mpd_bsr(mpd_size_t a) +{ + unsigned long retval; + +#ifdef CONFIG_64 + _BitScanReverse64(&retval, a); +#else + _BitScanReverse(&retval, a); +#endif + + return (int)retval; +} + +/* + * Bit scan forward. Assumptions: a != 0. + */ +static inline int __cdecl +mpd_bsf(mpd_size_t a) +{ + unsigned long retval; + +#ifdef CONFIG_64 + _BitScanForward64(&retval, a); +#else + _BitScanForward(&retval, a); +#endif + + return (int)retval; +} +/* END MASM (_MSC_VER) */ +#else + #error "missing preprocessor definitions" +#endif /* BSR/BSF */ + + +#endif /* BITS_H */ + + + diff --git a/Modules/_decimal/libmpdec/constants.c b/Modules/_decimal/libmpdec/constants.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/constants.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include "constants.h" + + +#if defined(CONFIG_64) + + /* number-theory.c */ + const mpd_uint_t mpd_moduli[3] = { + 18446744069414584321ULL, 18446744056529682433ULL, 18446742974197923841ULL + }; + const mpd_uint_t mpd_roots[3] = {7ULL, 10ULL, 19ULL}; + + /* crt.c */ + const mpd_uint_t INV_P1_MOD_P2 = 18446744055098026669ULL; + const mpd_uint_t INV_P1P2_MOD_P3 = 287064143708160ULL; + const mpd_uint_t LH_P1P2 = 18446744052234715137ULL; /* (P1*P2) % 2^64 */ + const mpd_uint_t UH_P1P2 = 18446744052234715141ULL; /* (P1*P2) / 2^64 */ + + /* transpose.c */ + const mpd_size_t mpd_bits[64] = { + 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, + 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, + 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, + 2147483648ULL, 4294967296ULL, 8589934592ULL, 17179869184ULL, 34359738368ULL, + 68719476736ULL, 137438953472ULL, 274877906944ULL, 549755813888ULL, + 1099511627776ULL, 2199023255552ULL, 4398046511104, 8796093022208ULL, + 17592186044416ULL, 35184372088832ULL, 70368744177664ULL, 140737488355328ULL, + 281474976710656ULL, 562949953421312ULL, 1125899906842624ULL, + 2251799813685248ULL, 4503599627370496ULL, 9007199254740992ULL, + 18014398509481984ULL, 36028797018963968ULL, 72057594037927936ULL, + 144115188075855872ULL, 288230376151711744ULL, 576460752303423488ULL, + 1152921504606846976ULL, 2305843009213693952ULL, 4611686018427387904ULL, + 9223372036854775808ULL + }; + + /* mpdecimal.c */ + const mpd_uint_t mpd_pow10[MPD_RDIGITS+1] = { + 1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000, + 10000000000ULL,100000000000ULL,1000000000000ULL,10000000000000ULL, + 100000000000000ULL,1000000000000000ULL,10000000000000000ULL, + 100000000000000000ULL,1000000000000000000ULL,10000000000000000000ULL + }; + + /* magic number for constant division by MPD_RADIX */ + const mpd_uint_t mprime_rdx = 15581492618384294730ULL; + +#elif defined(CONFIG_32) + + /* number-theory.c */ + const mpd_uint_t mpd_moduli[3] = {2113929217UL, 2013265921UL, 1811939329UL}; + const mpd_uint_t mpd_roots[3] = {5UL, 31UL, 13UL}; + + /* PentiumPro modular multiplication: These constants have to be loaded as + * 80 bit long doubles, which are not supported by certain compilers. */ + const uint32_t mpd_invmoduli[3][3] = { + {4293885170U, 2181570688U, 16352U}, /* ((long double) 1 / 2113929217UL) */ + {1698898177U, 2290649223U, 16352U}, /* ((long double) 1 / 2013265921UL) */ + {2716021846U, 2545165803U, 16352U} /* ((long double) 1 / 1811939329UL) */ + }; + + const float MPD_TWO63 = 9223372036854775808.0; /* 2^63 */ + + /* crt.c */ + const mpd_uint_t INV_P1_MOD_P2 = 2013265901UL; + const mpd_uint_t INV_P1P2_MOD_P3 = 54UL; + const mpd_uint_t LH_P1P2 = 4127195137UL; /* (P1*P2) % 2^32 */ + const mpd_uint_t UH_P1P2 = 990904320UL; /* (P1*P2) / 2^32 */ + + /* transpose.c */ + const mpd_size_t mpd_bits[32] = { + 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, + 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, + 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, + 2147483648UL + }; + + /* mpdecimal.c */ + const mpd_uint_t mpd_pow10[MPD_RDIGITS+1] = { + 1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000 + }; + +#else + #error "CONFIG_64 or CONFIG_32 must be defined." +#endif + +const char *mpd_round_string[MPD_ROUND_GUARD] = { + "ROUND_UP", /* round away from 0 */ + "ROUND_DOWN", /* round toward 0 (truncate) */ + "ROUND_CEILING", /* round toward +infinity */ + "ROUND_FLOOR", /* round toward -infinity */ + "ROUND_HALF_UP", /* 0.5 is rounded up */ + "ROUND_HALF_DOWN", /* 0.5 is rounded down */ + "ROUND_HALF_EVEN", /* 0.5 is rounded to even */ + "ROUND_05UP", /* round zero or five away from 0 */ + "ROUND_TRUNC", /* truncate, but set infinity */ +}; + +const char *mpd_clamp_string[MPD_CLAMP_GUARD] = { + "CLAMP_DEFAULT", + "CLAMP_IEEE_754" +}; + + diff --git a/Modules/_decimal/libmpdec/constants.h b/Modules/_decimal/libmpdec/constants.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/constants.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef CONSTANTS_H +#define CONSTANTS_H + + +#include "mpdecimal.h" + + +/* choice of optimized functions */ +#if defined(CONFIG_64) +/* x64 */ + #define MULMOD(a, b) x64_mulmod(a, b, umod) + #define MULMOD2C(a0, a1, w) x64_mulmod2c(a0, a1, w, umod) + #define MULMOD2(a0, b0, a1, b1) x64_mulmod2(a0, b0, a1, b1, umod) + #define POWMOD(base, exp) x64_powmod(base, exp, umod) + #define SETMODULUS(modnum) std_setmodulus(modnum, &umod) + #define SIZE3_NTT(x0, x1, x2, w3table) std_size3_ntt(x0, x1, x2, w3table, umod) +#elif defined(PPRO) +/* PentiumPro (or later) gcc inline asm */ + #define MULMOD(a, b) ppro_mulmod(a, b, &dmod, dinvmod) + #define MULMOD2C(a0, a1, w) ppro_mulmod2c(a0, a1, w, &dmod, dinvmod) + #define MULMOD2(a0, b0, a1, b1) ppro_mulmod2(a0, b0, a1, b1, &dmod, dinvmod) + #define POWMOD(base, exp) ppro_powmod(base, exp, &dmod, dinvmod) + #define SETMODULUS(modnum) ppro_setmodulus(modnum, &umod, &dmod, dinvmod) + #define SIZE3_NTT(x0, x1, x2, w3table) ppro_size3_ntt(x0, x1, x2, w3table, umod, &dmod, dinvmod) +#else + /* ANSI C99 */ + #define MULMOD(a, b) std_mulmod(a, b, umod) + #define MULMOD2C(a0, a1, w) std_mulmod2c(a0, a1, w, umod) + #define MULMOD2(a0, b0, a1, b1) std_mulmod2(a0, b0, a1, b1, umod) + #define POWMOD(base, exp) std_powmod(base, exp, umod) + #define SETMODULUS(modnum) std_setmodulus(modnum, &umod) + #define SIZE3_NTT(x0, x1, x2, w3table) std_size3_ntt(x0, x1, x2, w3table, umod) +#endif + +/* PentiumPro (or later) gcc inline asm */ +extern const float MPD_TWO63; +extern const uint32_t mpd_invmoduli[3][3]; + +enum {P1, P2, P3}; + +extern const mpd_uint_t mpd_moduli[]; +extern const mpd_uint_t mpd_roots[]; +extern const mpd_size_t mpd_bits[]; +extern const mpd_uint_t mpd_pow10[]; + +extern const mpd_uint_t INV_P1_MOD_P2; +extern const mpd_uint_t INV_P1P2_MOD_P3; +extern const mpd_uint_t LH_P1P2; +extern const mpd_uint_t UH_P1P2; + + +#endif /* CONSTANTS_H */ + + + diff --git a/Modules/_decimal/libmpdec/context.c b/Modules/_decimal/libmpdec/context.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/context.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include + + +void +mpd_dflt_traphandler(mpd_context_t *ctx UNUSED) +{ + raise(SIGFPE); +} + +void (* mpd_traphandler)(mpd_context_t *) = mpd_dflt_traphandler; + + +/* Set guaranteed minimum number of coefficient words. The function may + be used once at program start. Setting MPD_MINALLOC to out-of-bounds + values is a catastrophic error, so in that case the function exits rather + than relying on the user to check a return value. */ +void +mpd_setminalloc(mpd_ssize_t n) +{ + static int minalloc_is_set = 0; + + if (minalloc_is_set) { + mpd_err_warn("mpd_setminalloc: ignoring request to set " + "MPD_MINALLOC a second time\n"); + return; + } + if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) { + mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */ + } + MPD_MINALLOC = n; + minalloc_is_set = 1; +} + +void +mpd_init(mpd_context_t *ctx, mpd_ssize_t prec) +{ + mpd_ssize_t ideal_minalloc; + + mpd_defaultcontext(ctx); + + if (!mpd_qsetprec(ctx, prec)) { + mpd_addstatus_raise(ctx, MPD_Invalid_context); + return; + } + + ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS); + if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN; + if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX; + + mpd_setminalloc(ideal_minalloc); +} + +void +mpd_maxcontext(mpd_context_t *ctx) +{ + ctx->prec=MPD_MAX_PREC; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_EVEN; + ctx->traps=MPD_Traps; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; +} + +void +mpd_defaultcontext(mpd_context_t *ctx) +{ + ctx->prec=2*MPD_RDIGITS; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_UP; + ctx->traps=MPD_Traps; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; +} + +void +mpd_basiccontext(mpd_context_t *ctx) +{ + ctx->prec=9; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_UP; + ctx->traps=MPD_Traps|MPD_Clamped; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; +} + +int +mpd_ieee_context(mpd_context_t *ctx, int bits) +{ + if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) { + return -1; + } + + ctx->prec = 9 * (bits/32) - 2; + ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3)); + ctx->emin = 1 - ctx->emax; + ctx->round=MPD_ROUND_HALF_EVEN; + ctx->traps=0; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=1; + ctx->allcr=1; + + return 0; +} + +mpd_ssize_t +mpd_getprec(const mpd_context_t *ctx) +{ + return ctx->prec; +} + +mpd_ssize_t +mpd_getemax(const mpd_context_t *ctx) +{ + return ctx->emax; +} + +mpd_ssize_t +mpd_getemin(const mpd_context_t *ctx) +{ + return ctx->emin; +} + +int +mpd_getround(const mpd_context_t *ctx) +{ + return ctx->round; +} + +uint32_t +mpd_gettraps(const mpd_context_t *ctx) +{ + return ctx->traps; +} + +uint32_t +mpd_getstatus(const mpd_context_t *ctx) +{ + return ctx->status; +} + +int +mpd_getclamp(const mpd_context_t *ctx) +{ + return ctx->clamp; +} + +int +mpd_getcr(const mpd_context_t *ctx) +{ + return ctx->allcr; +} + + +int +mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec) +{ + if (prec <= 0 || prec > MPD_MAX_PREC) { + return 0; + } + ctx->prec = prec; + return 1; +} + +int +mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax) +{ + if (emax < 0 || emax > MPD_MAX_EMAX) { + return 0; + } + ctx->emax = emax; + return 1; +} + +int +mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin) +{ + if (emin > 0 || emin < MPD_MIN_EMIN) { + return 0; + } + ctx->emin = emin; + return 1; +} + +int +mpd_qsetround(mpd_context_t *ctx, int round) +{ + if (!(0 <= round && round < MPD_ROUND_GUARD)) { + return 0; + } + ctx->round = round; + return 1; +} + +int +mpd_qsettraps(mpd_context_t *ctx, uint32_t traps) +{ + if (traps > MPD_Max_status) { + return 0; + } + ctx->traps = traps; + return 1; +} + +int +mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags) +{ + if (flags > MPD_Max_status) { + return 0; + } + ctx->status = flags; + return 1; +} + +int +mpd_qsetclamp(mpd_context_t *ctx, int c) +{ + if (c != 0 && c != 1) { + return 0; + } + ctx->clamp = c; + return 1; +} + +int +mpd_qsetcr(mpd_context_t *ctx, int c) +{ + if (c != 0 && c != 1) { + return 0; + } + ctx->allcr = c; + return 1; +} + + +void +mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags) +{ + ctx->status |= flags; + if (flags&ctx->traps) { + ctx->newtrap = (flags&ctx->traps); + mpd_traphandler(ctx); + } +} + + diff --git a/Modules/_decimal/libmpdec/convolute.c b/Modules/_decimal/libmpdec/convolute.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/convolute.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include "bits.h" +#include "constants.h" +#include "fnt.h" +#include "fourstep.h" +#include "numbertheory.h" +#include "sixstep.h" +#include "umodarith.h" +#include "convolute.h" + + +/* Bignum: Fast convolution using the Number Theoretic Transform. Used for + the multiplication of very large coefficients. */ + + +/* Convolute the data in c1 and c2. Result is in c1. */ +int +fnt_convolute(mpd_uint_t *c1, mpd_uint_t *c2, mpd_size_t n, int modnum) +{ + int (*fnt)(mpd_uint_t *, mpd_size_t, int); + int (*inv_fnt)(mpd_uint_t *, mpd_size_t, int); +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t n_inv, umod; + mpd_size_t i; + + + SETMODULUS(modnum); + n_inv = POWMOD(n, (umod-2)); + + if (ispower2(n)) { + if (n > SIX_STEP_THRESHOLD) { + fnt = six_step_fnt; + inv_fnt = inv_six_step_fnt; + } + else { + fnt = std_fnt; + inv_fnt = std_inv_fnt; + } + } + else { + fnt = four_step_fnt; + inv_fnt = inv_four_step_fnt; + } + + if (!fnt(c1, n, modnum)) { + return 0; + } + if (!fnt(c2, n, modnum)) { + return 0; + } + for (i = 0; i < n-1; i += 2) { + mpd_uint_t x0 = c1[i]; + mpd_uint_t y0 = c2[i]; + mpd_uint_t x1 = c1[i+1]; + mpd_uint_t y1 = c2[i+1]; + MULMOD2(&x0, y0, &x1, y1); + c1[i] = x0; + c1[i+1] = x1; + } + + if (!inv_fnt(c1, n, modnum)) { + return 0; + } + for (i = 0; i < n-3; i += 4) { + mpd_uint_t x0 = c1[i]; + mpd_uint_t x1 = c1[i+1]; + mpd_uint_t x2 = c1[i+2]; + mpd_uint_t x3 = c1[i+3]; + MULMOD2C(&x0, &x1, n_inv); + MULMOD2C(&x2, &x3, n_inv); + c1[i] = x0; + c1[i+1] = x1; + c1[i+2] = x2; + c1[i+3] = x3; + } + + return 1; +} + +/* Autoconvolute the data in c1. Result is in c1. */ +int +fnt_autoconvolute(mpd_uint_t *c1, mpd_size_t n, int modnum) +{ + int (*fnt)(mpd_uint_t *, mpd_size_t, int); + int (*inv_fnt)(mpd_uint_t *, mpd_size_t, int); +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t n_inv, umod; + mpd_size_t i; + + + SETMODULUS(modnum); + n_inv = POWMOD(n, (umod-2)); + + if (ispower2(n)) { + if (n > SIX_STEP_THRESHOLD) { + fnt = six_step_fnt; + inv_fnt = inv_six_step_fnt; + } + else { + fnt = std_fnt; + inv_fnt = std_inv_fnt; + } + } + else { + fnt = four_step_fnt; + inv_fnt = inv_four_step_fnt; + } + + if (!fnt(c1, n, modnum)) { + return 0; + } + for (i = 0; i < n-1; i += 2) { + mpd_uint_t x0 = c1[i]; + mpd_uint_t x1 = c1[i+1]; + MULMOD2(&x0, x0, &x1, x1); + c1[i] = x0; + c1[i+1] = x1; + } + + if (!inv_fnt(c1, n, modnum)) { + return 0; + } + for (i = 0; i < n-3; i += 4) { + mpd_uint_t x0 = c1[i]; + mpd_uint_t x1 = c1[i+1]; + mpd_uint_t x2 = c1[i+2]; + mpd_uint_t x3 = c1[i+3]; + MULMOD2C(&x0, &x1, n_inv); + MULMOD2C(&x2, &x3, n_inv); + c1[i] = x0; + c1[i+1] = x1; + c1[i+2] = x2; + c1[i+3] = x3; + } + + return 1; +} + + diff --git a/Modules/_decimal/libmpdec/convolute.h b/Modules/_decimal/libmpdec/convolute.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/convolute.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef CONVOLUTE_H +#define CONVOLUTE_H + + +#include "mpdecimal.h" +#include + +#define SIX_STEP_THRESHOLD 4096 + + +int fnt_convolute(mpd_uint_t *c1, mpd_uint_t *c2, mpd_size_t n, int modnum); +int fnt_autoconvolute(mpd_uint_t *c1, mpd_size_t n, int modnum); + + +#endif diff --git a/Modules/_decimal/libmpdec/crt.c b/Modules/_decimal/libmpdec/crt.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/crt.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include "numbertheory.h" +#include "umodarith.h" +#include "crt.h" + + +/* Bignum: Chinese Remainder Theorem, extends the maximum transform length. */ + + +/* Multiply P1P2 by v, store result in w. */ +static inline void +_crt_mulP1P2_3(mpd_uint_t w[3], mpd_uint_t v) +{ + mpd_uint_t hi1, hi2, lo; + + _mpd_mul_words(&hi1, &lo, LH_P1P2, v); + w[0] = lo; + + _mpd_mul_words(&hi2, &lo, UH_P1P2, v); + lo = hi1 + lo; + if (lo < hi1) hi2++; + + w[1] = lo; + w[2] = hi2; +} + +/* Add 3 words from v to w. The result is known to fit in w. */ +static inline void +_crt_add3(mpd_uint_t w[3], mpd_uint_t v[3]) +{ + mpd_uint_t carry; + mpd_uint_t s; + + s = w[0] + v[0]; + carry = (s < w[0]); + w[0] = s; + + s = w[1] + (v[1] + carry); + carry = (s < w[1]); + w[1] = s; + + w[2] = w[2] + (v[2] + carry); +} + +/* Divide 3 words in u by v, store result in w, return remainder. */ +static inline mpd_uint_t +_crt_div3(mpd_uint_t *w, const mpd_uint_t *u, mpd_uint_t v) +{ + mpd_uint_t r1 = u[2]; + mpd_uint_t r2; + + if (r1 < v) { + w[2] = 0; + } + else { + _mpd_div_word(&w[2], &r1, u[2], v); /* GCOV_NOT_REACHED */ + } + + _mpd_div_words(&w[1], &r2, r1, u[1], v); + _mpd_div_words(&w[0], &r1, r2, u[0], v); + + return r1; +} + + +/* + * Chinese Remainder Theorem: + * Algorithm from Joerg Arndt, "Matters Computational", + * Chapter 37.4.1 [http://www.jjj.de/fxt/] + * + * See also Knuth, TAOCP, Volume 2, 4.3.2, exercise 7. + */ + +/* + * CRT with carry: x1, x2, x3 contain numbers modulo p1, p2, p3. For each + * triple of members of the arrays, find the unique z modulo p1*p2*p3, with + * zmax = p1*p2*p3 - 1. + * + * In each iteration of the loop, split z into result[i] = z % MPD_RADIX + * and carry = z / MPD_RADIX. Let N be the size of carry[] and cmax the + * maximum carry. + * + * Limits for the 32-bit build: + * + * N = 2**96 + * cmax = 7711435591312380274 + * + * Limits for the 64 bit build: + * + * N = 2**192 + * cmax = 627710135393475385904124401220046371710 + * + * The following statements hold for both versions: + * + * 1) cmax + zmax < N, so the addition does not overflow. + * + * 2) (cmax + zmax) / MPD_RADIX == cmax. + * + * 3) If c <= cmax, then c_next = (c + zmax) / MPD_RADIX <= cmax. + */ +void +crt3(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_size_t rsize) +{ + mpd_uint_t p1 = mpd_moduli[P1]; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t a1, a2, a3; + mpd_uint_t s; + mpd_uint_t z[3], t[3]; + mpd_uint_t carry[3] = {0,0,0}; + mpd_uint_t hi, lo; + mpd_size_t i; + + for (i = 0; i < rsize; i++) { + + a1 = x1[i]; + a2 = x2[i]; + a3 = x3[i]; + + SETMODULUS(P2); + s = ext_submod(a2, a1, umod); + s = MULMOD(s, INV_P1_MOD_P2); + + _mpd_mul_words(&hi, &lo, s, p1); + lo = lo + a1; + if (lo < a1) hi++; + + SETMODULUS(P3); + s = dw_submod(a3, hi, lo, umod); + s = MULMOD(s, INV_P1P2_MOD_P3); + + z[0] = lo; + z[1] = hi; + z[2] = 0; + + _crt_mulP1P2_3(t, s); + _crt_add3(z, t); + _crt_add3(carry, z); + + x1[i] = _crt_div3(carry, carry, MPD_RADIX); + } + + assert(carry[0] == 0 && carry[1] == 0 && carry[2] == 0); +} + + diff --git a/Modules/_decimal/libmpdec/crt.h b/Modules/_decimal/libmpdec/crt.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/crt.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef CRT_H +#define CRT_H + + +#include "mpdecimal.h" +#include + + +void crt3(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_size_t nmemb); + + +#endif diff --git a/Modules/_decimal/libmpdec/difradix2.c b/Modules/_decimal/libmpdec/difradix2.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/difradix2.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include "bits.h" +#include "numbertheory.h" +#include "umodarith.h" +#include "difradix2.h" + + +/* Bignum: The actual transform routine (decimation in frequency). */ + + +/* + * Generate index pairs (x, bitreverse(x)) and carry out the permutation. + * n must be a power of two. + * Algorithm due to Brent/Lehmann, see Joerg Arndt, "Matters Computational", + * Chapter 1.14.4. [http://www.jjj.de/fxt/] + */ +static inline void +bitreverse_permute(mpd_uint_t a[], mpd_size_t n) +{ + mpd_size_t x = 0; + mpd_size_t r = 0; + mpd_uint_t t; + + do { /* Invariant: r = bitreverse(x) */ + if (r > x) { + t = a[x]; + a[x] = a[r]; + a[r] = t; + } + /* Flip trailing consecutive 1 bits and the first zero bit + * that absorbs a possible carry. */ + x += 1; + /* Mirror the operation on r: Flip n_trailing_zeros(x)+1 + high bits of r. */ + r ^= (n - (n >> (mpd_bsf(x)+1))); + /* The loop invariant is preserved. */ + } while (x < n); +} + + +/* Fast Number Theoretic Transform, decimation in frequency. */ +void +fnt_dif2(mpd_uint_t a[], mpd_size_t n, struct fnt_params *tparams) +{ + mpd_uint_t *wtable = tparams->wtable; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t u0, u1, v0, v1; + mpd_uint_t w, w0, w1, wstep; + mpd_size_t m, mhalf; + mpd_size_t j, r; + + + assert(ispower2(n)); + assert(n >= 4); + + SETMODULUS(tparams->modnum); + + /* m == n */ + mhalf = n / 2; + for (j = 0; j < mhalf; j += 2) { + + w0 = wtable[j]; + w1 = wtable[j+1]; + + u0 = a[j]; + v0 = a[j+mhalf]; + + u1 = a[j+1]; + v1 = a[j+1+mhalf]; + + a[j] = addmod(u0, v0, umod); + v0 = submod(u0, v0, umod); + + a[j+1] = addmod(u1, v1, umod); + v1 = submod(u1, v1, umod); + + MULMOD2(&v0, w0, &v1, w1); + + a[j+mhalf] = v0; + a[j+1+mhalf] = v1; + + } + + wstep = 2; + for (m = n/2; m >= 2; m>>=1, wstep<<=1) { + + mhalf = m / 2; + + /* j == 0 */ + for (r = 0; r < n; r += 2*m) { + + u0 = a[r]; + v0 = a[r+mhalf]; + + u1 = a[m+r]; + v1 = a[m+r+mhalf]; + + a[r] = addmod(u0, v0, umod); + v0 = submod(u0, v0, umod); + + a[m+r] = addmod(u1, v1, umod); + v1 = submod(u1, v1, umod); + + a[r+mhalf] = v0; + a[m+r+mhalf] = v1; + } + + for (j = 1; j < mhalf; j++) { + + w = wtable[j*wstep]; + + for (r = 0; r < n; r += 2*m) { + + u0 = a[r+j]; + v0 = a[r+j+mhalf]; + + u1 = a[m+r+j]; + v1 = a[m+r+j+mhalf]; + + a[r+j] = addmod(u0, v0, umod); + v0 = submod(u0, v0, umod); + + a[m+r+j] = addmod(u1, v1, umod); + v1 = submod(u1, v1, umod); + + MULMOD2C(&v0, &v1, w); + + a[r+j+mhalf] = v0; + a[m+r+j+mhalf] = v1; + } + + } + + } + + bitreverse_permute(a, n); +} + + diff --git a/Modules/_decimal/libmpdec/difradix2.h b/Modules/_decimal/libmpdec/difradix2.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/difradix2.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef DIF_RADIX2_H +#define DIF_RADIX2_H + + +#include "mpdecimal.h" +#include +#include "numbertheory.h" + + +void fnt_dif2(mpd_uint_t a[], mpd_size_t n, struct fnt_params *tparams); + + +#endif diff --git a/Modules/_decimal/libmpdec/fnt.c b/Modules/_decimal/libmpdec/fnt.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/fnt.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include "bits.h" +#include "difradix2.h" +#include "numbertheory.h" +#include "fnt.h" + + +/* Bignum: Fast transform for medium-sized coefficients. */ + + +/* forward transform, sign = -1 */ +int +std_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + struct fnt_params *tparams; + + assert(ispower2(n)); + assert(n >= 4); + assert(n <= 3*MPD_MAXTRANSFORM_2N); + + if ((tparams = _mpd_init_fnt_params(n, -1, modnum)) == NULL) { + return 0; + } + fnt_dif2(a, n, tparams); + + mpd_free(tparams); + return 1; +} + +/* reverse transform, sign = 1 */ +int +std_inv_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + struct fnt_params *tparams; + + assert(ispower2(n)); + assert(n >= 4); + assert(n <= 3*MPD_MAXTRANSFORM_2N); + + if ((tparams = _mpd_init_fnt_params(n, 1, modnum)) == NULL) { + return 0; + } + fnt_dif2(a, n, tparams); + + mpd_free(tparams); + return 1; +} + + + diff --git a/Modules/_decimal/libmpdec/fnt.h b/Modules/_decimal/libmpdec/fnt.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/fnt.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef FNT_H +#define FNT_H + + +#include "mpdecimal.h" +#include + + +int std_fnt(mpd_uint_t a[], mpd_size_t n, int modnum); +int std_inv_fnt(mpd_uint_t a[], mpd_size_t n, int modnum); + + +#endif + diff --git a/Modules/_decimal/libmpdec/fourstep.c b/Modules/_decimal/libmpdec/fourstep.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/fourstep.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include "numbertheory.h" +#include "sixstep.h" +#include "transpose.h" +#include "umodarith.h" +#include "fourstep.h" + + +/* Bignum: Cache efficient Matrix Fourier Transform for arrays of the + form 3 * 2**n (See literature/matrix-transform.txt). */ + + +#ifndef PPRO +static inline void +std_size3_ntt(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, + mpd_uint_t w3table[3], mpd_uint_t umod) +{ + mpd_uint_t r1, r2; + mpd_uint_t w; + mpd_uint_t s, tmp; + + + /* k = 0 -> w = 1 */ + s = *x1; + s = addmod(s, *x2, umod); + s = addmod(s, *x3, umod); + + r1 = s; + + /* k = 1 */ + s = *x1; + + w = w3table[1]; + tmp = MULMOD(*x2, w); + s = addmod(s, tmp, umod); + + w = w3table[2]; + tmp = MULMOD(*x3, w); + s = addmod(s, tmp, umod); + + r2 = s; + + /* k = 2 */ + s = *x1; + + w = w3table[2]; + tmp = MULMOD(*x2, w); + s = addmod(s, tmp, umod); + + w = w3table[1]; + tmp = MULMOD(*x3, w); + s = addmod(s, tmp, umod); + + *x3 = s; + *x2 = r2; + *x1 = r1; +} +#else /* PPRO */ +static inline void +ppro_size3_ntt(mpd_uint_t *x1, mpd_uint_t *x2, mpd_uint_t *x3, mpd_uint_t w3table[3], + mpd_uint_t umod, double *dmod, uint32_t dinvmod[3]) +{ + mpd_uint_t r1, r2; + mpd_uint_t w; + mpd_uint_t s, tmp; + + + /* k = 0 -> w = 1 */ + s = *x1; + s = addmod(s, *x2, umod); + s = addmod(s, *x3, umod); + + r1 = s; + + /* k = 1 */ + s = *x1; + + w = w3table[1]; + tmp = ppro_mulmod(*x2, w, dmod, dinvmod); + s = addmod(s, tmp, umod); + + w = w3table[2]; + tmp = ppro_mulmod(*x3, w, dmod, dinvmod); + s = addmod(s, tmp, umod); + + r2 = s; + + /* k = 2 */ + s = *x1; + + w = w3table[2]; + tmp = ppro_mulmod(*x2, w, dmod, dinvmod); + s = addmod(s, tmp, umod); + + w = w3table[1]; + tmp = ppro_mulmod(*x3, w, dmod, dinvmod); + s = addmod(s, tmp, umod); + + *x3 = s; + *x2 = r2; + *x1 = r1; +} +#endif + + +/* forward transform, sign = -1; transform length = 3 * 2**n */ +int +four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + mpd_size_t R = 3; /* number of rows */ + mpd_size_t C = n / 3; /* number of columns */ + mpd_uint_t w3table[3]; + mpd_uint_t kernel, w0, w1, wstep; + mpd_uint_t *s, *p0, *p1, *p2; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_size_t i, k; + + + assert(n >= 48); + assert(n <= 3*MPD_MAXTRANSFORM_2N); + + + /* Length R transform on the columns. */ + SETMODULUS(modnum); + _mpd_init_w3table(w3table, -1, modnum); + for (p0=a, p1=p0+C, p2=p0+2*C; p0= 48); + assert(n <= 3*MPD_MAXTRANSFORM_2N); + + +#if 0 /* An unordered transform is sufficient for convolution. */ + /* Transpose the matrix, producing an R*C matrix. */ + transpose_3xpow2(a, C, R); +#endif + + /* Length C transform on the rows. */ + for (s = a; s < a+n; s += C) { + if (!inv_six_step_fnt(s, C, modnum)) { + return 0; + } + } + + /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */ + SETMODULUS(modnum); + kernel = _mpd_getkernel(n, 1, modnum); + for (i = 1; i < R; i++) { + w0 = 1; + w1 = POWMOD(kernel, i); + wstep = MULMOD(w1, w1); + for (k = 0; k < C; k += 2) { + mpd_uint_t x0 = a[i*C+k]; + mpd_uint_t x1 = a[i*C+k+1]; + MULMOD2(&x0, w0, &x1, w1); + MULMOD2C(&w0, &w1, wstep); + a[i*C+k] = x0; + a[i*C+k+1] = x1; + } + } + + /* Length R transform on the columns. */ + _mpd_init_w3table(w3table, 1, modnum); + for (p0=a, p1=p0+C, p2=p0+2*C; p0 + + +int four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); +int inv_four_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); + + +#endif diff --git a/Modules/_decimal/libmpdec/io.c b/Modules/_decimal/libmpdec/io.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/io.c @@ -0,0 +1,1575 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "bits.h" +#include "constants.h" +#include "memory.h" +#include "typearith.h" +#include "io.h" + + +/* This file contains functions for decimal <-> string conversions, including + PEP-3101 formatting for numeric types. */ + + +/* + * Work around the behavior of tolower() and strcasecmp() in certain + * locales. For example, in tr_TR.utf8: + * + * tolower((unsigned char)'I') == 'I' + * + * u is the exact uppercase version of l; n is strlen(l) or strlen(l)+1 + */ +static inline int +_mpd_strneq(const char *s, const char *l, const char *u, size_t n) +{ + while (--n != SIZE_MAX) { + if (*s != *l && *s != *u) { + return 0; + } + s++; u++; l++; + } + + return 1; +} + +static mpd_ssize_t +strtoexp(const char *s) +{ + char *end; + mpd_ssize_t retval; + + errno = 0; + retval = mpd_strtossize(s, &end, 10); + if (errno == 0 && !(*s != '\0' && *end == '\0')) + errno = EINVAL; + + return retval; +} + +/* + * Scan 'len' words. The most significant word contains 'r' digits, + * the remaining words are full words. Skip dpoint. The string 's' must + * consist of digits and an optional single decimal point at 'dpoint'. + */ +static void +string_to_coeff(mpd_uint_t *data, const char *s, const char *dpoint, int r, + size_t len) +{ + int j; + + if (r > 0) { + data[--len] = 0; + for (j = 0; j < r; j++, s++) { + if (s == dpoint) s++; + data[len] = 10 * data[len] + (*s - '0'); + } + } + + while (--len != SIZE_MAX) { + data[len] = 0; + for (j = 0; j < MPD_RDIGITS; j++, s++) { + if (s == dpoint) s++; + data[len] = 10 * data[len] + (*s - '0'); + } + } +} + +/* + * Partially verify a numeric string of the form: + * + * [cdigits][.][cdigits][eE][+-][edigits] + * + * If successful, return a pointer to the location of the first + * relevant coefficient digit. This digit is either non-zero or + * part of one of the following patterns: + * + * ["0\x00", "0.\x00", "0.E", "0.e", "0E", "0e"] + * + * The locations of a single optional dot or indicator are stored + * in 'dpoint' and 'exp'. + * + * The end of the string is stored in 'end'. If an indicator [eE] + * occurs without trailing [edigits], the condition is caught + * later by strtoexp(). + */ +static const char * +scan_dpoint_exp(const char *s, const char **dpoint, const char **exp, + const char **end) +{ + const char *coeff = NULL; + + *dpoint = NULL; + *exp = NULL; + for (; *s != '\0'; s++) { + switch (*s) { + case '.': + if (*dpoint != NULL || *exp != NULL) + return NULL; + *dpoint = s; + break; + case 'E': case 'e': + if (*exp != NULL) + return NULL; + *exp = s; + if (*(s+1) == '+' || *(s+1) == '-') + s++; + break; + default: + if (!isdigit((uchar)*s)) + return NULL; + if (coeff == NULL && *exp == NULL) { + if (*s == '0') { + if (!isdigit((uchar)*(s+1))) + if (!(*(s+1) == '.' && + isdigit((uchar)*(s+2)))) + coeff = s; + } + else { + coeff = s; + } + } + break; + + } + } + + *end = s; + return coeff; +} + +/* scan the payload of a NaN */ +static const char * +scan_payload(const char *s, const char **end) +{ + const char *coeff; + + while (*s == '0') + s++; + coeff = s; + + while (isdigit((uchar)*s)) + s++; + *end = s; + + return (*s == '\0') ? coeff : NULL; +} + +/* convert a character string to a decimal */ +void +mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_ssize_t q, r, len; + const char *coeff, *end; + const char *dpoint = NULL, *exp = NULL; + size_t digits; + uint8_t sign = MPD_POS; + + mpd_set_flags(dec, 0); + dec->len = 0; + dec->exp = 0; + + /* sign */ + if (*s == '+') { + s++; + } + else if (*s == '-') { + mpd_set_negative(dec); + sign = MPD_NEG; + s++; + } + + if (_mpd_strneq(s, "nan", "NAN", 3)) { /* NaN */ + s += 3; + mpd_setspecial(dec, sign, MPD_NAN); + if (*s == '\0') + return; + /* validate payload: digits only */ + if ((coeff = scan_payload(s, &end)) == NULL) + goto conversion_error; + /* payload consists entirely of zeros */ + if (*coeff == '\0') + return; + digits = end - coeff; + /* prec >= 1, clamp is 0 or 1 */ + if (digits > (size_t)(ctx->prec-ctx->clamp)) + goto conversion_error; + } /* sNaN */ + else if (_mpd_strneq(s, "snan", "SNAN", 4)) { + s += 4; + mpd_setspecial(dec, sign, MPD_SNAN); + if (*s == '\0') + return; + /* validate payload: digits only */ + if ((coeff = scan_payload(s, &end)) == NULL) + goto conversion_error; + /* payload consists entirely of zeros */ + if (*coeff == '\0') + return; + digits = end - coeff; + if (digits > (size_t)(ctx->prec-ctx->clamp)) + goto conversion_error; + } + else if (_mpd_strneq(s, "inf", "INF", 3)) { + s += 3; + if (*s == '\0' || _mpd_strneq(s, "inity", "INITY", 6)) { + /* numeric-value: infinity */ + mpd_setspecial(dec, sign, MPD_INF); + return; + } + goto conversion_error; + } + else { + /* scan for start of coefficient, decimal point, indicator, end */ + if ((coeff = scan_dpoint_exp(s, &dpoint, &exp, &end)) == NULL) + goto conversion_error; + + /* numeric-value: [exponent-part] */ + if (exp) { + /* exponent-part */ + end = exp; exp++; + dec->exp = strtoexp(exp); + if (errno) { + if (!(errno == ERANGE && + (dec->exp == MPD_SSIZE_MAX || + dec->exp == MPD_SSIZE_MIN))) + goto conversion_error; + } + } + + digits = end - coeff; + if (dpoint) { + size_t fracdigits = end-dpoint-1; + if (dpoint > coeff) digits--; + + if (fracdigits > MPD_MAX_PREC) { + goto conversion_error; + } + if (dec->exp < MPD_SSIZE_MIN+(mpd_ssize_t)fracdigits) { + dec->exp = MPD_SSIZE_MIN; + } + else { + dec->exp -= (mpd_ssize_t)fracdigits; + } + } + if (digits > MPD_MAX_PREC) { + goto conversion_error; + } + if (dec->exp > MPD_EXP_INF) { + dec->exp = MPD_EXP_INF; + } + if (dec->exp == MPD_SSIZE_MIN) { + dec->exp = MPD_SSIZE_MIN+1; + } + } + + _mpd_idiv_word(&q, &r, (mpd_ssize_t)digits, MPD_RDIGITS); + + len = (r == 0) ? q : q+1; + if (len == 0) { + goto conversion_error; /* GCOV_NOT_REACHED */ + } + if (!mpd_qresize(dec, len, status)) { + mpd_seterror(dec, MPD_Malloc_error, status); + return; + } + dec->len = len; + + string_to_coeff(dec->data, coeff, dpoint, (int)r, len); + + mpd_setdigits(dec); + mpd_qfinalize(dec, ctx, status); + return; + +conversion_error: + /* standard wants a positive NaN */ + mpd_seterror(dec, MPD_Conversion_syntax, status); +} + +/* Print word x with n decimal digits to string s. dot is either NULL + or the location of a decimal point. */ +#define EXTRACT_DIGIT(s, x, d, dot) \ + if (s == dot) *s++ = '.'; *s++ = '0' + (char)(x / d); x %= d +static inline char * +word_to_string(char *s, mpd_uint_t x, int n, char *dot) +{ + switch(n) { +#ifdef CONFIG_64 + case 20: EXTRACT_DIGIT(s, x, 10000000000000000000ULL, dot); /* GCOV_NOT_REACHED */ + case 19: EXTRACT_DIGIT(s, x, 1000000000000000000ULL, dot); + case 18: EXTRACT_DIGIT(s, x, 100000000000000000ULL, dot); + case 17: EXTRACT_DIGIT(s, x, 10000000000000000ULL, dot); + case 16: EXTRACT_DIGIT(s, x, 1000000000000000ULL, dot); + case 15: EXTRACT_DIGIT(s, x, 100000000000000ULL, dot); + case 14: EXTRACT_DIGIT(s, x, 10000000000000ULL, dot); + case 13: EXTRACT_DIGIT(s, x, 1000000000000ULL, dot); + case 12: EXTRACT_DIGIT(s, x, 100000000000ULL, dot); + case 11: EXTRACT_DIGIT(s, x, 10000000000ULL, dot); +#endif + case 10: EXTRACT_DIGIT(s, x, 1000000000UL, dot); + case 9: EXTRACT_DIGIT(s, x, 100000000UL, dot); + case 8: EXTRACT_DIGIT(s, x, 10000000UL, dot); + case 7: EXTRACT_DIGIT(s, x, 1000000UL, dot); + case 6: EXTRACT_DIGIT(s, x, 100000UL, dot); + case 5: EXTRACT_DIGIT(s, x, 10000UL, dot); + case 4: EXTRACT_DIGIT(s, x, 1000UL, dot); + case 3: EXTRACT_DIGIT(s, x, 100UL, dot); + case 2: EXTRACT_DIGIT(s, x, 10UL, dot); + default: if (s == dot) *s++ = '.'; *s++ = '0' + (char)x; + } + + *s = '\0'; + return s; +} + +/* Print exponent x to string s. Undefined for MPD_SSIZE_MIN. */ +static inline char * +exp_to_string(char *s, mpd_ssize_t x) +{ + char sign = '+'; + + if (x < 0) { + sign = '-'; + x = -x; + } + *s++ = sign; + + return word_to_string(s, x, mpd_word_digits(x), NULL); +} + +/* Print the coefficient of dec to string s. len(dec) > 0. */ +static inline char * +coeff_to_string(char *s, const mpd_t *dec) +{ + mpd_uint_t x; + mpd_ssize_t i; + + /* most significant word */ + x = mpd_msword(dec); + s = word_to_string(s, x, mpd_word_digits(x), NULL); + + /* remaining full words */ + for (i=dec->len-2; i >= 0; --i) { + x = dec->data[i]; + s = word_to_string(s, x, MPD_RDIGITS, NULL); + } + + return s; +} + +/* Print the coefficient of dec to string s. len(dec) > 0. dot is either + NULL or a pointer to the location of a decimal point. */ +static inline char * +coeff_to_string_dot(char *s, char *dot, const mpd_t *dec) +{ + mpd_uint_t x; + mpd_ssize_t i; + + /* most significant word */ + x = mpd_msword(dec); + s = word_to_string(s, x, mpd_word_digits(x), dot); + + /* remaining full words */ + for (i=dec->len-2; i >= 0; --i) { + x = dec->data[i]; + s = word_to_string(s, x, MPD_RDIGITS, dot); + } + + return s; +} + +/* Format type */ +#define MPD_FMT_LOWER 0x00000000 +#define MPD_FMT_UPPER 0x00000001 +#define MPD_FMT_TOSCI 0x00000002 +#define MPD_FMT_TOENG 0x00000004 +#define MPD_FMT_EXP 0x00000008 +#define MPD_FMT_FIXED 0x00000010 +#define MPD_FMT_PERCENT 0x00000020 +#define MPD_FMT_SIGN_SPACE 0x00000040 +#define MPD_FMT_SIGN_PLUS 0x00000080 + +/* Default place of the decimal point for MPD_FMT_TOSCI, MPD_FMT_EXP */ +#define MPD_DEFAULT_DOTPLACE 1 + +/* + * Set *result to the string representation of a decimal. Return the length + * of *result, not including the terminating '\0' character. + * + * Formatting is done according to 'flags'. A return value of -1 with *result + * set to NULL indicates MPD_Malloc_error. + * + * 'dplace' is the default place of the decimal point. It is always set to + * MPD_DEFAULT_DOTPLACE except for zeros in combination with MPD_FMT_EXP. + */ +static mpd_ssize_t +_mpd_to_string(char **result, const mpd_t *dec, int flags, mpd_ssize_t dplace) +{ + char *decstring = NULL, *cp = NULL; + mpd_ssize_t ldigits; + mpd_ssize_t mem = 0, k; + + if (mpd_isspecial(dec)) { + + mem = sizeof "-Infinity"; + if (mpd_isnan(dec) && dec->len > 0) { + /* diagnostic code */ + mem += dec->digits; + } + cp = decstring = mpd_alloc(mem, sizeof *decstring); + if (cp == NULL) { + *result = NULL; + return -1; + } + + if (mpd_isnegative(dec)) { + *cp++ = '-'; + } + else if (flags&MPD_FMT_SIGN_SPACE) { + *cp++ = ' '; + } + else if (flags&MPD_FMT_SIGN_PLUS) { + *cp++ = '+'; + } + + if (mpd_isnan(dec)) { + if (mpd_isqnan(dec)) { + strcpy(cp, "NaN"); + cp += 3; + } + else { + strcpy(cp, "sNaN"); + cp += 4; + } + if (dec->len > 0) { /* diagnostic code */ + cp = coeff_to_string(cp, dec); + } + } + else if (mpd_isinfinite(dec)) { + strcpy(cp, "Infinity"); + cp += 8; + } + else { /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + } + else { + assert(dec->len > 0); + + /* + * For easier manipulation of the decimal point's location + * and the exponent that is finally printed, the number is + * rescaled to a virtual representation with exp = 0. Here + * ldigits denotes the number of decimal digits to the left + * of the decimal point and remains constant once initialized. + * + * dplace is the location of the decimal point relative to + * the start of the coefficient. Note that 3) always holds + * when dplace is shifted. + * + * 1) ldigits := dec->digits - dec->exp + * 2) dplace := ldigits (initially) + * 3) exp := ldigits - dplace (initially exp = 0) + * + * 0.00000_.____._____000000. + * ^ ^ ^ ^ + * | | | | + * | | | `- dplace >= digits + * | | `- dplace in the middle of the coefficient + * | ` dplace = 1 (after the first coefficient digit) + * `- dplace <= 0 + */ + + ldigits = dec->digits + dec->exp; + + if (flags&MPD_FMT_EXP) { + ; + } + else if (flags&MPD_FMT_FIXED || (dec->exp <= 0 && ldigits > -6)) { + /* MPD_FMT_FIXED: always use fixed point notation. + * MPD_FMT_TOSCI, MPD_FMT_TOENG: for a certain range, + * override exponent notation. */ + dplace = ldigits; + } + else if (flags&MPD_FMT_TOENG) { + if (mpd_iszero(dec)) { + /* If the exponent is divisible by three, + * dplace = 1. Otherwise, move dplace one + * or two places to the left. */ + dplace = -1 + mod_mpd_ssize_t(dec->exp+2, 3); + } + else { /* ldigits-1 is the adjusted exponent, which + * should be divisible by three. If not, move + * dplace one or two places to the right. */ + dplace += mod_mpd_ssize_t(ldigits-1, 3); + } + } + + /* + * Basic space requirements: + * + * [-][.][coeffdigits][E][-][expdigits+1][%]['\0'] + * + * If the decimal point lies outside of the coefficient digits, + * space is adjusted accordingly. + */ + if (dplace <= 0) { + mem = -dplace + dec->digits + 2; + } + else if (dplace >= dec->digits) { + mem = dplace; + } + else { + mem = dec->digits; + } + mem += (MPD_EXPDIGITS+1+6); + + cp = decstring = mpd_alloc(mem, sizeof *decstring); + if (cp == NULL) { + *result = NULL; + return -1; + } + + + if (mpd_isnegative(dec)) { + *cp++ = '-'; + } + else if (flags&MPD_FMT_SIGN_SPACE) { + *cp++ = ' '; + } + else if (flags&MPD_FMT_SIGN_PLUS) { + *cp++ = '+'; + } + + if (dplace <= 0) { + /* space: -dplace+dec->digits+2 */ + *cp++ = '0'; + *cp++ = '.'; + for (k = 0; k < -dplace; k++) { + *cp++ = '0'; + } + cp = coeff_to_string(cp, dec); + } + else if (dplace >= dec->digits) { + /* space: dplace */ + cp = coeff_to_string(cp, dec); + for (k = 0; k < dplace-dec->digits; k++) { + *cp++ = '0'; + } + } + else { + /* space: dec->digits+1 */ + cp = coeff_to_string_dot(cp, cp+dplace, dec); + } + + /* + * Conditions for printing an exponent: + * + * MPD_FMT_TOSCI, MPD_FMT_TOENG: only if ldigits != dplace + * MPD_FMT_FIXED: never (ldigits == dplace) + * MPD_FMT_EXP: always + */ + if (ldigits != dplace || flags&MPD_FMT_EXP) { + /* space: expdigits+2 */ + *cp++ = (flags&MPD_FMT_UPPER) ? 'E' : 'e'; + cp = exp_to_string(cp, ldigits-dplace); + } + + if (flags&MPD_FMT_PERCENT) { + *cp++ = '%'; + } + } + + assert(cp < decstring+mem); + assert(cp-decstring < MPD_SSIZE_MAX); + + *cp = '\0'; + *result = decstring; + return (mpd_ssize_t)(cp-decstring); +} + +char * +mpd_to_sci(const mpd_t *dec, int fmt) +{ + char *res; + int flags = MPD_FMT_TOSCI; + + flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; + (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE); + return res; +} + +char * +mpd_to_eng(const mpd_t *dec, int fmt) +{ + char *res; + int flags = MPD_FMT_TOENG; + + flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; + (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE); + return res; +} + +mpd_ssize_t +mpd_to_sci_size(char **res, const mpd_t *dec, int fmt) +{ + int flags = MPD_FMT_TOSCI; + + flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; + return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE); +} + +mpd_ssize_t +mpd_to_eng_size(char **res, const mpd_t *dec, int fmt) +{ + int flags = MPD_FMT_TOENG; + + flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER; + return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE); +} + +/* Copy a single UTF-8 char to dest. See: The Unicode Standard, version 5.2, + chapter 3.9: Well-formed UTF-8 byte sequences. */ +static int +_mpd_copy_utf8(char dest[5], const char *s) +{ + const uchar *cp = (const uchar *)s; + uchar lb, ub; + int count, i; + + + if (*cp == 0) { + /* empty string */ + dest[0] = '\0'; + return 0; + } + else if (*cp <= 0x7f) { + /* ascii */ + dest[0] = *cp; + dest[1] = '\0'; + return 1; + } + else if (0xc2 <= *cp && *cp <= 0xdf) { + lb = 0x80; ub = 0xbf; + count = 2; + } + else if (*cp == 0xe0) { + lb = 0xa0; ub = 0xbf; + count = 3; + } + else if (*cp <= 0xec) { + lb = 0x80; ub = 0xbf; + count = 3; + } + else if (*cp == 0xed) { + lb = 0x80; ub = 0x9f; + count = 3; + } + else if (*cp <= 0xef) { + lb = 0x80; ub = 0xbf; + count = 3; + } + else if (*cp == 0xf0) { + lb = 0x90; ub = 0xbf; + count = 4; + } + else if (*cp <= 0xf3) { + lb = 0x80; ub = 0xbf; + count = 4; + } + else if (*cp == 0xf4) { + lb = 0x80; ub = 0x8f; + count = 4; + } + else { + /* invalid */ + goto error; + } + + dest[0] = *cp++; + if (*cp < lb || ub < *cp) { + goto error; + } + dest[1] = *cp++; + for (i = 2; i < count; i++) { + if (*cp < 0x80 || 0xbf < *cp) { + goto error; + } + dest[i] = *cp++; + } + dest[i] = '\0'; + + return count; + +error: + dest[0] = '\0'; + return -1; +} + +int +mpd_validate_lconv(mpd_spec_t *spec) +{ + size_t n; +#if CHAR_MAX == SCHAR_MAX + const char *cp = spec->grouping; + while (*cp != '\0') { + if (*cp++ < 0) { + return -1; + } + } +#endif + n = strlen(spec->dot); + if (n == 0 || n > 4) { + return -1; + } + if (strlen(spec->sep) > 4) { + return -1; + } + + return 0; +} + +int +mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps) +{ + char *cp = (char *)fmt; + int have_align = 0, n; + + /* defaults */ + spec->min_width = 0; + spec->prec = -1; + spec->type = caps ? 'G' : 'g'; + spec->align = '>'; + spec->sign = '-'; + spec->dot = ""; + spec->sep = ""; + spec->grouping = ""; + + + /* presume that the first character is a UTF-8 fill character */ + if ((n = _mpd_copy_utf8(spec->fill, cp)) < 0) { + return 0; + } + + /* alignment directive, prefixed by a fill character */ + if (*cp && (*(cp+n) == '<' || *(cp+n) == '>' || + *(cp+n) == '=' || *(cp+n) == '^')) { + cp += n; + spec->align = *cp++; + have_align = 1; + } /* alignment directive */ + else { + /* default fill character */ + spec->fill[0] = ' '; + spec->fill[1] = '\0'; + if (*cp == '<' || *cp == '>' || + *cp == '=' || *cp == '^') { + spec->align = *cp++; + have_align = 1; + } + } + + /* sign formatting */ + if (*cp == '+' || *cp == '-' || *cp == ' ') { + spec->sign = *cp++; + } + + /* zero padding */ + if (*cp == '0') { + /* zero padding implies alignment, which should not be + * specified twice. */ + if (have_align) { + return 0; + } + spec->align = 'z'; + spec->fill[0] = *cp++; + spec->fill[1] = '\0'; + } + + /* minimum width */ + if (isdigit((uchar)*cp)) { + if (*cp == '0') { + return 0; + } + errno = 0; + spec->min_width = mpd_strtossize(cp, &cp, 10); + if (errno == ERANGE || errno == EINVAL) { + return 0; + } + } + + /* thousands separator */ + if (*cp == ',') { + spec->dot = "."; + spec->sep = ","; + spec->grouping = "\003\003"; + cp++; + } + + /* fraction digits or significant digits */ + if (*cp == '.') { + cp++; + if (!isdigit((uchar)*cp)) { + return 0; + } + errno = 0; + spec->prec = mpd_strtossize(cp, &cp, 10); + if (errno == ERANGE || errno == EINVAL) { + return 0; + } + } + + /* type */ + if (*cp == 'E' || *cp == 'e' || *cp == 'F' || *cp == 'f' || + *cp == 'G' || *cp == 'g' || *cp == '%') { + spec->type = *cp++; + } + else if (*cp == 'N' || *cp == 'n') { + /* locale specific conversion */ + struct lconv *lc; + /* separator has already been specified */ + if (*spec->sep) { + return 0; + } + spec->type = *cp++; + spec->type = (spec->type == 'N') ? 'G' : 'g'; + lc = localeconv(); + spec->dot = lc->decimal_point; + spec->sep = lc->thousands_sep; + spec->grouping = lc->grouping; + if (mpd_validate_lconv(spec) < 0) { + return 0; /* GCOV_NOT_REACHED */ + } + } + + /* check correctness */ + if (*cp != '\0') { + return 0; + } + + return 1; +} + +/* + * The following functions assume that spec->min_width <= MPD_MAX_PREC, which + * is made sure in mpd_qformat_spec. Then, even with a spec that inserts a + * four-byte separator after each digit, nbytes in the following struct + * cannot overflow. + */ + +/* Multibyte string */ +typedef struct { + mpd_ssize_t nbytes; /* length in bytes */ + mpd_ssize_t nchars; /* length in chars */ + mpd_ssize_t cur; /* current write index */ + char *data; +} mpd_mbstr_t; + +static inline void +_mpd_bcopy(char *dest, const char *src, mpd_ssize_t n) +{ + while (--n >= 0) { + dest[n] = src[n]; + } +} + +static inline void +_mbstr_copy_char(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n) +{ + dest->nbytes += n; + dest->nchars += (n > 0 ? 1 : 0); + dest->cur -= n; + + if (dest->data != NULL) { + _mpd_bcopy(dest->data+dest->cur, src, n); + } +} + +static inline void +_mbstr_copy_ascii(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n) +{ + dest->nbytes += n; + dest->nchars += n; + dest->cur -= n; + + if (dest->data != NULL) { + _mpd_bcopy(dest->data+dest->cur, src, n); + } +} + +static inline void +_mbstr_copy_pad(mpd_mbstr_t *dest, mpd_ssize_t n) +{ + dest->nbytes += n; + dest->nchars += n; + dest->cur -= n; + + if (dest->data != NULL) { + char *cp = dest->data + dest->cur; + while (--n >= 0) { + cp[n] = '0'; + } + } +} + +/* + * Copy a numeric string to dest->data, adding separators in the integer + * part according to spec->grouping. If leading zero padding is enabled + * and the result is smaller than spec->min_width, continue adding zeros + * and separators until the minimum width is reached. + * + * The final length of dest->data is stored in dest->nbytes. The number + * of UTF-8 characters is stored in dest->nchars. + * + * First run (dest->data == NULL): determine the length of the result + * string and store it in dest->nbytes. + * + * Second run (write to dest->data): data is written in chunks and in + * reverse order, starting with the rest of the numeric string. + */ +static void +_mpd_add_sep_dot(mpd_mbstr_t *dest, + const char *sign, /* location of optional sign */ + const char *src, mpd_ssize_t n_src, /* integer part and length */ + const char *dot, /* location of optional decimal point */ + const char *rest, mpd_ssize_t n_rest, /* remaining part and length */ + const mpd_spec_t *spec) +{ + mpd_ssize_t n_sep, n_sign, consume; + const char *g; + int pad = 0; + + n_sign = sign ? 1 : 0; + n_sep = (mpd_ssize_t)strlen(spec->sep); + /* Initial write index: set to location of '\0' in the output string. + * Irrelevant for the first run. */ + dest->cur = dest->nbytes; + dest->nbytes = dest->nchars = 0; + + _mbstr_copy_ascii(dest, rest, n_rest); + + if (dot) { + _mbstr_copy_char(dest, dot, (mpd_ssize_t)strlen(dot)); + } + + g = spec->grouping; + consume = *g; + while (1) { + /* If the group length is 0 or CHAR_MAX or greater than the + * number of source bytes, consume all remaining bytes. */ + if (*g == 0 || *g == CHAR_MAX || consume > n_src) { + consume = n_src; + } + n_src -= consume; + if (pad) { + _mbstr_copy_pad(dest, consume); + } + else { + _mbstr_copy_ascii(dest, src+n_src, consume); + } + + if (n_src == 0) { + /* Either the real source of intpart digits or the virtual + * source of padding zeros is exhausted. */ + if (spec->align == 'z' && + dest->nchars + n_sign < spec->min_width) { + /* Zero padding is set and length < min_width: + * Generate n_src additional characters. */ + n_src = spec->min_width - (dest->nchars + n_sign); + /* Next iteration: + * case *g == 0 || *g == CHAR_MAX: + * consume all padding characters + * case consume < g*: + * fill remainder of current group + * case consume == g* + * copying is a no-op */ + consume = *g - consume; + /* Switch on virtual source of zeros. */ + pad = 1; + continue; + } + break; + } + + if (n_sep > 0) { + /* If padding is switched on, separators are counted + * as padding characters. This rule does not apply if + * the separator would be the first character of the + * result string. */ + if (pad && n_src > 1) n_src -= 1; + _mbstr_copy_char(dest, spec->sep, n_sep); + } + + /* If non-NUL, use the next value for grouping. */ + if (*g && *(g+1)) g++; + consume = *g; + } + + if (sign) { + _mbstr_copy_ascii(dest, sign, 1); + } + + if (dest->data) { + dest->data[dest->nbytes] = '\0'; + } +} + +/* + * Convert a numeric-string to its locale-specific appearance. + * The string must have one of these forms: + * + * 1) [sign] digits [exponent-part] + * 2) [sign] digits '.' [digits] [exponent-part] + * + * Not allowed, since _mpd_to_string() never returns this form: + * + * 3) [sign] '.' digits [exponent-part] + * + * Input: result->data := original numeric string (ASCII) + * result->bytes := strlen(result->data) + * result->nchars := strlen(result->data) + * + * Output: result->data := modified or original string + * result->bytes := strlen(result->data) + * result->nchars := number of characters (possibly UTF-8) + */ +static int +_mpd_apply_lconv(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status) +{ + const char *sign = NULL, *intpart = NULL, *dot = NULL; + const char *rest, *dp; + char *decstring; + mpd_ssize_t n_int, n_rest; + + /* original numeric string */ + dp = result->data; + + /* sign */ + if (*dp == '+' || *dp == '-' || *dp == ' ') { + sign = dp++; + } + /* integer part */ + assert(isdigit((uchar)*dp)); + intpart = dp++; + while (isdigit((uchar)*dp)) { + dp++; + } + n_int = (mpd_ssize_t)(dp-intpart); + /* decimal point */ + if (*dp == '.') { + dp++; dot = spec->dot; + } + /* rest */ + rest = dp; + n_rest = result->nbytes - (mpd_ssize_t)(dp-result->data); + + if (dot == NULL && (*spec->sep == '\0' || *spec->grouping == '\0')) { + /* _mpd_add_sep_dot() would not change anything */ + return 1; + } + + /* Determine the size of the new decimal string after inserting the + * decimal point, optional separators and optional padding. */ + decstring = result->data; + result->data = NULL; + _mpd_add_sep_dot(result, sign, intpart, n_int, dot, + rest, n_rest, spec); + + result->data = mpd_alloc(result->nbytes+1, 1); + if (result->data == NULL) { + *status |= MPD_Malloc_error; + mpd_free(decstring); + return 0; + } + + /* Perform actual writes. */ + _mpd_add_sep_dot(result, sign, intpart, n_int, dot, + rest, n_rest, spec); + + mpd_free(decstring); + return 1; +} + +/* Add padding to the formatted string if necessary. */ +static int +_mpd_add_pad(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status) +{ + if (result->nchars < spec->min_width) { + mpd_ssize_t add_chars, add_bytes; + size_t lpad = 0, rpad = 0; + size_t n_fill, len, i, j; + char align = spec->align; + uint8_t err = 0; + char *cp; + + n_fill = strlen(spec->fill); + add_chars = (spec->min_width - result->nchars); + /* max value: MPD_MAX_PREC * 4 */ + add_bytes = add_chars * (mpd_ssize_t)n_fill; + + cp = result->data = mpd_realloc(result->data, + result->nbytes+add_bytes+1, + sizeof *result->data, &err); + if (err) { + *status |= MPD_Malloc_error; + mpd_free(result->data); + return 0; + } + + if (align == 'z') { + align = '='; + } + + if (align == '<') { + rpad = add_chars; + } + else if (align == '>' || align == '=') { + lpad = add_chars; + } + else { /* align == '^' */ + lpad = add_chars/2; + rpad = add_chars-lpad; + } + + len = result->nbytes; + if (align == '=' && (*cp == '-' || *cp == '+' || *cp == ' ')) { + /* leave sign in the leading position */ + cp++; len--; + } + + memmove(cp+n_fill*lpad, cp, len); + for (i = 0; i < lpad; i++) { + for (j = 0; j < n_fill; j++) { + cp[i*n_fill+j] = spec->fill[j]; + } + } + cp += (n_fill*lpad + len); + for (i = 0; i < rpad; i++) { + for (j = 0; j < n_fill; j++) { + cp[i*n_fill+j] = spec->fill[j]; + } + } + + result->nbytes += add_bytes; + result->nchars += add_chars; + result->data[result->nbytes] = '\0'; + } + + return 1; +} + +/* Round a number to prec digits. The adjusted exponent stays the same + or increases by one if rounding up crosses a power of ten boundary. + If result->digits would exceed MPD_MAX_PREC+1, MPD_Invalid_operation + is set and the result is NaN. */ +static inline void +_mpd_round(mpd_t *result, const mpd_t *a, mpd_ssize_t prec, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t exp = a->exp + a->digits - prec; + + if (prec <= 0) { + mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_NOT_REACHED */ + return; /* GCOV_NOT_REACHED */ + } + if (mpd_isspecial(a) || mpd_iszero(a)) { + mpd_qcopy(result, a, status); /* GCOV_NOT_REACHED */ + return; /* GCOV_NOT_REACHED */ + } + + mpd_qrescale_fmt(result, a, exp, ctx, status); + if (result->digits > prec) { + mpd_qrescale_fmt(result, result, exp+1, ctx, status); + } +} + +/* + * Return the string representation of an mpd_t, formatted according to 'spec'. + * The format specification is assumed to be valid. Memory errors are indicated + * as usual. This function is quiet. + */ +char * +mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t dt[MPD_MINALLOC_MAX]; + mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt}; + mpd_ssize_t dplace = MPD_DEFAULT_DOTPLACE; + mpd_mbstr_t result; + mpd_spec_t stackspec; + char type = spec->type; + int flags = 0; + + + if (spec->min_width > MPD_MAX_PREC) { + *status |= MPD_Invalid_operation; + return NULL; + } + + if (isupper((uchar)type)) { + type = tolower((uchar)type); + flags |= MPD_FMT_UPPER; + } + if (spec->sign == ' ') { + flags |= MPD_FMT_SIGN_SPACE; + } + else if (spec->sign == '+') { + flags |= MPD_FMT_SIGN_PLUS; + } + + if (mpd_isspecial(dec)) { + if (spec->align == 'z') { + stackspec = *spec; + stackspec.fill[0] = ' '; + stackspec.fill[1] = '\0'; + stackspec.align = '>'; + spec = &stackspec; + } + } + else { + uint32_t workstatus = 0; + mpd_ssize_t prec; + + switch (type) { + case 'g': flags |= MPD_FMT_TOSCI; break; + case 'e': flags |= MPD_FMT_EXP; break; + case '%': flags |= MPD_FMT_PERCENT; + if (!mpd_qcopy(&tmp, dec, status)) { + return NULL; + } + tmp.exp += 2; + dec = &tmp; + type = 'f'; /* fall through */ + case 'f': flags |= MPD_FMT_FIXED; break; + default: abort(); /* debug: GCOV_NOT_REACHED */ + } + + if (spec->prec >= 0) { + if (spec->prec > MPD_MAX_PREC) { + *status |= MPD_Invalid_operation; + goto error; + } + + switch (type) { + case 'g': + prec = (spec->prec == 0) ? 1 : spec->prec; + if (dec->digits > prec) { + _mpd_round(&tmp, dec, prec, ctx, + &workstatus); + dec = &tmp; + } + break; + case 'e': + if (mpd_iszero(dec)) { + dplace = 1-spec->prec; + } + else { + _mpd_round(&tmp, dec, spec->prec+1, ctx, + &workstatus); + dec = &tmp; + } + break; + case 'f': + mpd_qrescale(&tmp, dec, -spec->prec, ctx, + &workstatus); + dec = &tmp; + break; + } + } + + if (type == 'f') { + if (mpd_iszero(dec) && dec->exp > 0) { + mpd_qrescale(&tmp, dec, 0, ctx, &workstatus); + dec = &tmp; + } + } + + if (workstatus&MPD_Errors) { + *status |= (workstatus&MPD_Errors); + goto error; + } + } + + /* + * At this point, for all scaled or non-scaled decimals: + * 1) 1 <= digits <= MAX_PREC+1 + * 2) adjexp(scaled) = adjexp(orig) [+1] + * 3) case 'g': MIN_ETINY <= exp <= MAX_EMAX+1 + * case 'e': MIN_ETINY-MAX_PREC <= exp <= MAX_EMAX+1 + * case 'f': MIN_ETINY <= exp <= MAX_EMAX+1 + * 4) max memory alloc in _mpd_to_string: + * case 'g': MAX_PREC+36 + * case 'e': MAX_PREC+36 + * case 'f': 2*MPD_MAX_PREC+30 + */ + result.nbytes = _mpd_to_string(&result.data, dec, flags, dplace); + result.nchars = result.nbytes; + if (result.nbytes < 0) { + *status |= MPD_Malloc_error; + goto error; + } + + if (*spec->dot != '\0' && !mpd_isspecial(dec)) { + if (result.nchars > MPD_MAX_PREC+36) { + /* Since a group length of one is not explicitly + * disallowed, ensure that it is always possible to + * insert a four byte separator after each digit. */ + *status |= MPD_Invalid_operation; + mpd_free(result.data); + goto error; + } + if (!_mpd_apply_lconv(&result, spec, status)) { + goto error; + } + } + + if (spec->min_width) { + if (!_mpd_add_pad(&result, spec, status)) { + goto error; + } + } + + mpd_del(&tmp); + return result.data; + +error: + mpd_del(&tmp); + return NULL; +} + +char * +mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_spec_t spec; + + if (!mpd_parse_fmt_str(&spec, fmt, 1)) { + *status |= MPD_Invalid_operation; + return NULL; + } + + return mpd_qformat_spec(dec, &spec, ctx, status); +} + +/* + * The specification has a *condition* called Invalid_operation and an + * IEEE *signal* called Invalid_operation. The former corresponds to + * MPD_Invalid_operation, the latter to MPD_IEEE_Invalid_operation. + * MPD_IEEE_Invalid_operation comprises the following conditions: + * + * [MPD_Conversion_syntax, MPD_Division_impossible, MPD_Division_undefined, + * MPD_Fpu_error, MPD_Invalid_context, MPD_Invalid_operation, + * MPD_Malloc_error] + * + * In the following functions, 'flag' denotes the condition, 'signal' + * denotes the IEEE signal. + */ + +static const char *mpd_flag_string[MPD_NUM_FLAGS] = { + "Clamped", + "Conversion_syntax", + "Division_by_zero", + "Division_impossible", + "Division_undefined", + "Fpu_error", + "Inexact", + "Invalid_context", + "Invalid_operation", + "Malloc_error", + "Not_implemented", + "Overflow", + "Rounded", + "Subnormal", + "Underflow", +}; + +static const char *mpd_signal_string[MPD_NUM_FLAGS] = { + "Clamped", + "IEEE_Invalid_operation", + "Division_by_zero", + "IEEE_Invalid_operation", + "IEEE_Invalid_operation", + "IEEE_Invalid_operation", + "Inexact", + "IEEE_Invalid_operation", + "IEEE_Invalid_operation", + "IEEE_Invalid_operation", + "Not_implemented", + "Overflow", + "Rounded", + "Subnormal", + "Underflow", +}; + +/* print conditions to buffer, separated by spaces */ +int +mpd_snprint_flags(char *dest, int nmemb, uint32_t flags) +{ + char *cp; + int n, j; + + assert(nmemb >= MPD_MAX_FLAG_STRING); + + *dest = '\0'; cp = dest; + for (j = 0; j < MPD_NUM_FLAGS; j++) { + if (flags & (1U<= nmemb) return -1; + cp += n; nmemb -= n; + } + } + + if (cp != dest) { + *(--cp) = '\0'; + } + + return (int)(cp-dest); +} + +/* print conditions to buffer, in list form */ +int +mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[]) +{ + char *cp; + int n, j; + + assert(nmemb >= MPD_MAX_FLAG_LIST); + if (flag_string == NULL) { + flag_string = mpd_flag_string; + } + + *dest = '['; + *(dest+1) = '\0'; + cp = dest+1; + --nmemb; + + for (j = 0; j < MPD_NUM_FLAGS; j++) { + if (flags & (1U<= nmemb) return -1; + cp += n; nmemb -= n; + } + } + + /* erase the last ", " */ + if (cp != dest+1) { + cp -= 2; + } + + *cp++ = ']'; + *cp = '\0'; + + return (int)(cp-dest); /* strlen, without NUL terminator */ +} + +/* print signals to buffer, in list form */ +int +mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[]) +{ + char *cp; + int n, j; + int ieee_invalid_done = 0; + + assert(nmemb >= MPD_MAX_SIGNAL_LIST); + if (signal_string == NULL) { + signal_string = mpd_signal_string; + } + + *dest = '['; + *(dest+1) = '\0'; + cp = dest+1; + --nmemb; + + for (j = 0; j < MPD_NUM_FLAGS; j++) { + uint32_t f = flags & (1U<= nmemb) return -1; + cp += n; nmemb -= n; + } + } + + /* erase the last ", " */ + if (cp != dest+1) { + cp -= 2; + } + + *cp++ = ']'; + *cp = '\0'; + + return (int)(cp-dest); /* strlen, without NUL terminator */ +} + +/* The following two functions are mainly intended for debugging. */ +void +mpd_fprint(FILE *file, const mpd_t *dec) +{ + char *decstring; + + decstring = mpd_to_sci(dec, 1); + if (decstring != NULL) { + fprintf(file, "%s\n", decstring); + mpd_free(decstring); + } + else { + fputs("mpd_fprint: output error\n", file); /* GCOV_NOT_REACHED */ + } +} + +void +mpd_print(const mpd_t *dec) +{ + char *decstring; + + decstring = mpd_to_sci(dec, 1); + if (decstring != NULL) { + printf("%s\n", decstring); + mpd_free(decstring); + } + else { + fputs("mpd_fprint: output error\n", stderr); /* GCOV_NOT_REACHED */ + } +} + + diff --git a/Modules/_decimal/libmpdec/io.h b/Modules/_decimal/libmpdec/io.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/io.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef IO_H +#define IO_H + + +#include +#include "mpdecimal.h" + + +#if SIZE_MAX == MPD_SIZE_MAX + #define mpd_strtossize _mpd_strtossize +#else +static inline mpd_ssize_t +mpd_strtossize(const char *s, char **end, int base) +{ + int64_t retval; + + errno = 0; + retval = _mpd_strtossize(s, end, base); + if (errno == 0 && (retval > MPD_SSIZE_MAX || retval < MPD_SSIZE_MIN)) { + errno = ERANGE; + } + if (errno == ERANGE) { + return (retval < 0) ? MPD_SSIZE_MIN : MPD_SSIZE_MAX; + } + + return (mpd_ssize_t)retval; +} +#endif + + +#endif diff --git a/Modules/_decimal/libmpdec/literature/REFERENCES.txt b/Modules/_decimal/libmpdec/literature/REFERENCES.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/REFERENCES.txt @@ -0,0 +1,51 @@ + + +This document contains links to the literature used in the process of +creating the library. The list is probably not complete. + + +Mike Cowlishaw: General Decimal Arithmetic Specification +http://speleotrove.com/decimal/decarith.html + + +Jean-Michel Muller: On the definition of ulp (x) +lara.inist.fr/bitstream/2332/518/1/LIP-RR2005-09.pdf + + +T. E. Hull, A. Abrham: Properly rounded variable precision square root +http://portal.acm.org/citation.cfm?id=214413 + + +T. E. Hull, A. Abrham: Variable precision exponential function +http://portal.acm.org/citation.cfm?id=6498 + + +Roman E. Maeder: Storage allocation for the Karatsuba integer multiplication +algorithm. http://www.springerlink.com/content/w15058mj6v59t565/ + + +J. M. Pollard: The fast Fourier transform in a finite field +http://www.ams.org/journals/mcom/1971-25-114/S0025-5718-1971-0301966-0/home.html + + +David H. Bailey: FFTs in External or Hierarchical Memory +http://crd.lbl.gov/~dhbailey/dhbpapers/ + + +W. Morven Gentleman: Matrix Multiplication and Fast Fourier Transforms +http://www.alcatel-lucent.com/bstj/vol47-1968/articles/bstj47-6-1099.pdf + + +Mikko Tommila: Apfloat documentation +http://www.apfloat.org/apfloat/2.41/apfloat.pdf + + +Joerg Arndt: "Matters Computational" +http://www.jjj.de/fxt/ + + +Karl Hasselstrom: Fast Division of Large Integers +www.treskal.com/kalle/exjobb/original-report.pdf + + + diff --git a/Modules/_decimal/libmpdec/literature/bignum.txt b/Modules/_decimal/libmpdec/literature/bignum.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/bignum.txt @@ -0,0 +1,83 @@ + + +Bignum support (Fast Number Theoretic Transform or FNT): +======================================================== + +Bignum arithmetic in libmpdec uses the scheme for fast convolution +of integer sequences from: + +J. M. Pollard: The fast Fourier transform in a finite field +http://www.ams.org/journals/mcom/1971-25-114/S0025-5718-1971-0301966-0/home.html + + +The transform in a finite field can be used for convolution in the same +way as the Fourier Transform. The main advantages of the Number Theoretic +Transform are that it is both exact and very memory efficient. + + +Convolution in pseudo-code: +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + fnt_convolute(a, b): + x = fnt(a) # forward transform of a + y = fnt(b) # forward transform of b + z = pairwise multiply x[i] and y[i] + result = inv_fnt(z) # backward transform of z. + + +Extending the maximum transform length (Chinese Remainder Theorem): +------------------------------------------------------------------- + +The maximum transform length is quite limited when using a single +prime field. However, it is possible to use multiple primes and +recover the result using the Chinese Remainder Theorem. + + +Multiplication in pseudo-code: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + _mpd_fntmul(u, v): + c1 = fnt_convolute(u, v, P1) # convolute modulo prime1 + c2 = fnt_convolute(u, v, P2) # convolute modulo prime2 + c3 = fnt_convolute(u, v, P3) # convolute modulo prime3 + result = crt3(c1, c2, c3) # Chinese Remainder Theorem + + +Optimized transform functions: +------------------------------ + +There are three different fnt() functions: + + std_fnt: "standard" decimation in frequency transform for array lengths + of 2**n. Performs well up to 1024 words. + + sixstep: Cache-friendly algorithm for array lengths of 2**n. Outperforms + std_fnt for large arrays. + + fourstep: Algorithm for array lengths of 3 * 2**n. Also cache friendly + in large parts. + + +List of bignum-only files: +-------------------------- + +Functions from these files are only used in _mpd_fntmul(). + + umodarith.h -> fast low level routines for unsigned modular arithmetic + numbertheory.c -> routines for setting up the FNT + difradix2.c -> decimation in frequency transform, used as the + "base case" by the following three files: + + fnt.c -> standard transform for smaller arrays + sixstep.c -> transform large arrays of length 2**n + fourstep.c -> transform arrays of length 3 * 2**n + + convolute.c -> do the actual fast convolution, using one of + the three transform functions. + transpose.c -> transpositions needed for the sixstep algorithm. + crt.c -> Chinese Remainder Theorem: use information from three + transforms modulo three different primes to get the + final result. + + + diff --git a/Modules/_decimal/libmpdec/literature/fnt.py b/Modules/_decimal/libmpdec/literature/fnt.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/fnt.py @@ -0,0 +1,208 @@ +# +# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + + +###################################################################### +# This file lists and checks some of the constants and limits used # +# in libmpdec's Number Theoretic Transform. At the end of the file # +# there is an example function for the plain DFT transform. # +###################################################################### + + +# +# Number theoretic transforms are done in subfields of F(p). P[i] +# are the primes, D[i] = P[i] - 1 are highly composite and w[i] +# are the respective primitive roots of F(p). +# +# The strategy is to convolute two coefficients modulo all three +# primes, then use the Chinese Remainder Theorem on the three +# result arrays to recover the result in the usual base RADIX +# form. +# + +# ====================================================================== +# Primitive roots +# ====================================================================== + +# +# Verify primitive roots: +# +# For a prime field, r is a primitive root if and only if for all prime +# factors f of p-1, r**((p-1)/f) =/= 1 (mod p). +# +def prod(F, E): + """Check that the factorization of P-1 is correct. F is the list of + factors of P-1, E lists the number of occurrences of each factor.""" + x = 1 + for y, z in zip(F, E): + x *= y**z + return x + +def is_primitive_root(r, p, factors, exponents): + """Check if r is a primitive root of F(p).""" + if p != prod(factors, exponents) + 1: + return False + for f in factors: + q, control = divmod(p-1, f) + if control != 0: + return False + if pow(r, q, p) == 1: + return False + return True + + +# ================================================================= +# Constants and limits for the 64-bit version +# ================================================================= + +RADIX = 10**19 + +# Primes P1, P2 and P3: +P = [2**64-2**32+1, 2**64-2**34+1, 2**64-2**40+1] + +# P-1, highly composite. The transform length d is variable and +# must divide D = P-1. Since all D are divisible by 3 * 2**32, +# transform lengths can be 2**n or 3 * 2**n (where n <= 32). +D = [2**32 * 3 * (5 * 17 * 257 * 65537), + 2**34 * 3**2 * (7 * 11 * 31 * 151 * 331), + 2**40 * 3**2 * (5 * 7 * 13 * 17 * 241)] + +# Prime factors of P-1 and their exponents: +F = [(2,3,5,17,257,65537), (2,3,7,11,31,151,331), (2,3,5,7,13,17,241)] +E = [(32,1,1,1,1,1), (34,2,1,1,1,1,1), (40,2,1,1,1,1,1)] + +# Maximum transform length for 2**n. Above that only 3 * 2**31 +# or 3 * 2**32 are possible. +MPD_MAXTRANSFORM_2N = 2**32 + + +# Limits in the terminology of Pollard's paper: +m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array. +M1 = M2 = RADIX-1 # Maximum value per single word. +L = m2 * M1 * M2 +P[0] * P[1] * P[2] > 2 * L + + +# Primitive roots of F(P1), F(P2) and F(P3): +w = [7, 10, 19] + +# The primitive roots are correct: +for i in range(3): + if not is_primitive_root(w[i], P[i], F[i], E[i]): + print("FAIL") + + +# ================================================================= +# Constants and limits for the 32-bit version +# ================================================================= + +RADIX = 10**9 + +# Primes P1, P2 and P3: +P = [2113929217, 2013265921, 1811939329] + +# P-1, highly composite. All D = P-1 are divisible by 3 * 2**25, +# allowing for transform lengths up to 3 * 2**25 words. +D = [2**25 * 3**2 * 7, + 2**27 * 3 * 5, + 2**26 * 3**3] + +# Prime factors of P-1 and their exponents: +F = [(2,3,7), (2,3,5), (2,3)] +E = [(25,2,1), (27,1,1), (26,3)] + +# Maximum transform length for 2**n. Above that only 3 * 2**24 or +# 3 * 2**25 are possible. +MPD_MAXTRANSFORM_2N = 2**25 + + +# Limits in the terminology of Pollard's paper: +m2 = (MPD_MAXTRANSFORM_2N * 3) // 2 # Maximum length of the smaller array. +M1 = M2 = RADIX-1 # Maximum value per single word. +L = m2 * M1 * M2 +P[0] * P[1] * P[2] > 2 * L + + +# Primitive roots of F(P1), F(P2) and F(P3): +w = [5, 31, 13] + +# The primitive roots are correct: +for i in range(3): + if not is_primitive_root(w[i], P[i], F[i], E[i]): + print("FAIL") + + +# ====================================================================== +# Example transform using a single prime +# ====================================================================== + +def ntt(lst, dir): + """Perform a transform on the elements of lst. len(lst) must + be 2**n or 3 * 2**n, where n <= 25. This is the slow DFT.""" + p = 2113929217 # prime + d = len(lst) # transform length + d_prime = pow(d, (p-2), p) # inverse of d + xi = (p-1)//d + w = 5 # primitive root of F(p) + r = pow(w, xi, p) # primitive root of the subfield + r_prime = pow(w, (p-1-xi), p) # inverse of r + if dir == 1: # forward transform + a = lst # input array + A = [0] * d # transformed values + for i in range(d): + s = 0 + for j in range(d): + s += a[j] * pow(r, i*j, p) + A[i] = s % p + return A + elif dir == -1: # backward transform + A = lst # input array + a = [0] * d # transformed values + for j in range(d): + s = 0 + for i in range(d): + s += A[i] * pow(r_prime, i*j, p) + a[j] = (d_prime * s) % p + return a + +def ntt_convolute(a, b): + """convolute arrays a and b.""" + assert(len(a) == len(b)) + x = ntt(a, 1) + y = ntt(b, 1) + for i in range(len(a)): + y[i] = y[i] * x[i] + r = ntt(y, -1) + return r + + +# Example: Two arrays representing 21 and 81 in little-endian: +a = [1, 2, 0, 0] +b = [1, 8, 0, 0] + +assert(ntt_convolute(a, b) == [1, 10, 16, 0]) +assert(21 * 81 == (1*10**0 + 10*10**1 + 16*10**2 + 0*10**3)) diff --git a/Modules/_decimal/libmpdec/literature/matrix-transform.txt b/Modules/_decimal/libmpdec/literature/matrix-transform.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/matrix-transform.txt @@ -0,0 +1,256 @@ + + +(* Copyright (c) 2011 Stefan Krah. All rights reserved. *) + + +The Matrix Fourier Transform: +============================= + +In libmpdec, the Matrix Fourier Transform [1] is called four-step transform +after a variant that appears in [2]. The algorithm requires that the input +array can be viewed as an R*C matrix. + +All operations are done modulo p. For readability, the proofs drop all +instances of (mod p). + + +Algorithm four-step (forward transform): +---------------------------------------- + + a := input array + d := len(a) = R * C + p := prime + w := primitive root of unity of the prime field + r := w**((p-1)/d) + A := output array + + 1) Apply a length R FNT to each column. + + 2) Multiply each matrix element (addressed by j*C+m) by r**(j*m). + + 3) Apply a length C FNT to each row. + + 4) Transpose the matrix. + + +Proof (forward transform): +-------------------------- + + The algorithm can be derived starting from the regular definition of + the finite-field transform of length d: + + d-1 + ,---- + \ + A[k] = | a[l] * r**(k * l) + / + `---- + l = 0 + + + The sum can be rearranged into the sum of the sums of columns: + + C-1 R-1 + ,---- ,---- + \ \ + = | | a[i * C + j] * r**(k * (i * C + j)) + / / + `---- `---- + j = 0 i = 0 + + + Extracting a constant from the inner sum: + + C-1 R-1 + ,---- ,---- + \ \ + = | r**k*j * | a[i * C + j] * r**(k * i * C) + / / + `---- `---- + j = 0 i = 0 + + + Without any loss of generality, let k = n * R + m, + where n < C and m < R: + + C-1 R-1 + ,---- ,---- + \ \ + A[n*R+m] = | r**(R*n*j) * r**(m*j) * | a[i*C+j] * r**(R*C*n*i) * r**(C*m*i) + / / + `---- `---- + j = 0 i = 0 + + + Since r = w ** ((p-1) / (R*C)): + + a) r**(R*C*n*i) = w**((p-1)*n*i) = 1 + + b) r**(C*m*i) = w**((p-1) / R) ** (m*i) = r_R ** (m*i) + + c) r**(R*n*j) = w**((p-1) / C) ** (n*j) = r_C ** (n*j) + + r_R := root of the subfield of length R. + r_C := root of the subfield of length C. + + + C-1 R-1 + ,---- ,---- + \ \ + A[n*R+m] = | r_C**(n*j) * [ r**(m*j) * | a[i*C+j] * r_R**(m*i) ] + / ^ / + `---- | `---- 1) transform the columns + j = 0 | i = 0 + ^ | + | `-- 2) multiply + | + `-- 3) transform the rows + + + Note that the entire RHS is a function of n and m and that the results + for each pair (n, m) are stored in Fortran order. + + Let the term in square brackets be f(m, j). Step 1) and 2) precalculate + the term for all (m, j). After that, the original matrix is now a lookup + table with the mth element in the jth column at location m * C + j. + + Let the complete RHS be g(m, n). Step 3) does an in-place transform of + length n on all rows. After that, the original matrix is now a lookup + table with the mth element in the nth column at location m * C + n. + + But each (m, n) pair should be written to location n * R + m. Therefore, + step 4) transposes the result of step 3). + + + +Algorithm four-step (inverse transform): +---------------------------------------- + + A := input array + d := len(A) = R * C + p := prime + d' := d**(p-2) # inverse of d + w := primitive root of unity of the prime field + r := w**((p-1)/d) # root of the subfield + r' := w**((p-1) - (p-1)/d) # inverse of r + a := output array + + 0) View the matrix as a C*R matrix. + + 1) Transpose the matrix, producing an R*C matrix. + + 2) Apply a length C FNT to each row. + + 3) Multiply each matrix element (addressed by i*C+n) by r**(i*n). + + 4) Apply a length R FNT to each column. + + +Proof (inverse transform): +-------------------------- + + The algorithm can be derived starting from the regular definition of + the finite-field inverse transform of length d: + + d-1 + ,---- + \ + a[k] = d' * | A[l] * r' ** (k * l) + / + `---- + l = 0 + + + The sum can be rearranged into the sum of the sums of columns. Note + that at this stage we still have a C*R matrix, so C denotes the number + of rows: + + R-1 C-1 + ,---- ,---- + \ \ + = d' * | | a[j * R + i] * r' ** (k * (j * R + i)) + / / + `---- `---- + i = 0 j = 0 + + + Extracting a constant from the inner sum: + + R-1 C-1 + ,---- ,---- + \ \ + = d' * | r' ** (k*i) * | a[j * R + i] * r' ** (k * j * R) + / / + `---- `---- + i = 0 j = 0 + + + Without any loss of generality, let k = m * C + n, + where m < R and n < C: + + R-1 C-1 + ,---- ,---- + \ \ + A[m*C+n] = d' * | r' ** (C*m*i) * r' ** (n*i) * | a[j*R+i] * r' ** (R*C*m*j) * r' ** (R*n*j) + / / + `---- `---- + i = 0 j = 0 + + + Since r' = w**((p-1) - (p-1)/d) and d = R*C: + + a) r' ** (R*C*m*j) = w**((p-1)*R*C*m*j - (p-1)*m*j) = 1 + + b) r' ** (C*m*i) = w**((p-1)*C - (p-1)/R) ** (m*i) = r_R' ** (m*i) + + c) r' ** (R*n*j) = r_C' ** (n*j) + + d) d' = d**(p-2) = (R*C) ** (p-2) = R**(p-2) * C**(p-2) = R' * C' + + r_R' := inverse of the root of the subfield of length R. + r_C' := inverse of the root of the subfield of length C. + R' := inverse of R + C' := inverse of C + + + R-1 C-1 + ,---- ,---- 2) transform the rows of a^T + \ \ + A[m*C+n] = R' * | r_R' ** (m*i) * [ r' ** (n*i) * C' * | a[j*R+i] * r_C' ** (n*j) ] + / ^ / ^ + `---- | `---- | + i = 0 | j = 0 | + ^ | `-- 1) Transpose input matrix + | `-- 3) multiply to address elements by + | i * C + j + `-- 3) transform the columns + + + + Note that the entire RHS is a function of m and n and that the results + for each pair (m, n) are stored in C order. + + Let the term in square brackets be f(n, i). Without step 1), the sum + would perform a length C transform on the columns of the input matrix. + This is a) inefficient and b) the results are needed in C order, so + step 1) exchanges rows and columns. + + Step 2) and 3) precalculate f(n, i) for all (n, i). After that, the + original matrix is now a lookup table with the ith element in the nth + column at location i * C + n. + + Let the complete RHS be g(m, n). Step 4) does an in-place transform of + length m on all columns. After that, the original matrix is now a lookup + table with the mth element in the nth column at location m * C + n, + which means that all A[k] = A[m * C + n] are in the correct order. + + +-- + + [1] Joerg Arndt: "Matters Computational" + http://www.jjj.de/fxt/ + [2] David H. Bailey: FFTs in External or Hierarchical Memory + http://crd.lbl.gov/~dhbailey/dhbpapers/ + + + diff --git a/Modules/_decimal/libmpdec/literature/mulmod-64.txt b/Modules/_decimal/libmpdec/literature/mulmod-64.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/mulmod-64.txt @@ -0,0 +1,127 @@ + + +(* Copyright (c) 2011 Stefan Krah. All rights reserved. *) + + +========================================================================== + Calculate (a * b) % p using special primes +========================================================================== + +A description of the algorithm can be found in the apfloat manual by +Tommila [1]. + + +Definitions: +------------ + +In the whole document, "==" stands for "is congruent with". + +Result of a * b in terms of high/low words: + + (1) hi * 2**64 + lo = a * b + +Special primes: + + (2) p = 2**64 - z + 1, where z = 2**n + +Single step modular reduction: + + (3) R(hi, lo) = hi * z - hi + lo + + +Strategy: +--------- + + a) Set (hi, lo) to the result of a * b. + + b) Set (hi', lo') to the result of R(hi, lo). + + c) Repeat step b) until 0 <= hi' * 2**64 + lo' < 2*p. + + d) If the result is less than p, return lo'. Otherwise return lo' - p. + + +The reduction step b) preserves congruence: +------------------------------------------- + + hi * 2**64 + lo == hi * z - hi + lo (mod p) + + Proof: + ~~~~~~ + + hi * 2**64 + lo = (2**64 - z + 1) * hi + z * hi - hi + lo + + = p * hi + z * hi - hi + lo + + == z * hi - hi + lo (mod p) + + +Maximum numbers of step b): +--------------------------- + +# To avoid unneccessary formalism, define: + +def R(hi, lo, z): + return divmod(hi * z - hi + lo, 2**64) + +# For simplicity, assume hi=2**64-1, lo=2**64-1 after the +# initial multiplication a * b. This is of course impossible +# but certainly covers all cases. + +# Then, for p1: +hi=2**64-1; lo=2**64-1; z=2**32 +p1 = 2**64 - z + 1 + +hi, lo = R(hi, lo, z) # First reduction +hi, lo = R(hi, lo, z) # Second reduction +hi * 2**64 + lo < 2 * p1 # True + +# For p2: +hi=2**64-1; lo=2**64-1; z=2**34 +p2 = 2**64 - z + 1 + +hi, lo = R(hi, lo, z) # First reduction +hi, lo = R(hi, lo, z) # Second reduction +hi, lo = R(hi, lo, z) # Third reduction +hi * 2**64 + lo < 2 * p2 # True + +# For p3: +hi=2**64-1; lo=2**64-1; z=2**40 +p3 = 2**64 - z + 1 + +hi, lo = R(hi, lo, z) # First reduction +hi, lo = R(hi, lo, z) # Second reduction +hi, lo = R(hi, lo, z) # Third reduction +hi * 2**64 + lo < 2 * p3 # True + + +Step d) preserves congruence and yields a result < p: +----------------------------------------------------- + + Case hi = 0: + + Case lo < p: trivial. + + Case lo >= p: + + lo == lo - p (mod p) # result is congruent + + p <= lo < 2*p -> 0 <= lo - p < p # result is in the correct range + + Case hi = 1: + + p < 2**64 /\ 2**64 + lo < 2*p -> lo < p # lo is always less than p + + 2**64 + lo == 2**64 + (lo - p) (mod p) # result is congruent + + = lo - p # exactly the same value as the previous RHS + # in uint64_t arithmetic. + + p < 2**64 + lo < 2*p -> 0 < 2**64 + (lo - p) < p # correct range + + + +[1] http://www.apfloat.org/apfloat/2.40/apfloat.pdf + + + diff --git a/Modules/_decimal/libmpdec/literature/mulmod-ppro.txt b/Modules/_decimal/libmpdec/literature/mulmod-ppro.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/mulmod-ppro.txt @@ -0,0 +1,269 @@ + + +(* Copyright (c) 2011 Stefan Krah. All rights reserved. *) + + +======================================================================== + Calculate (a * b) % p using the 80-bit x87 FPU +======================================================================== + +A description of the algorithm can be found in the apfloat manual by +Tommila [1]. + +The proof follows an argument made by Granlund/Montgomery in [2]. + + +Definitions and assumptions: +---------------------------- + +The 80-bit extended precision format uses 64 bits for the significand: + + (1) F = 64 + +The modulus is prime and less than 2**31: + + (2) 2 <= p < 2**31 + +The factors are less than p: + + (3) 0 <= a < p + (4) 0 <= b < p + +The product a * b is less than 2**62 and is thus exact in 64 bits: + + (5) n = a * b + +The product can be represented in terms of quotient and remainder: + + (6) n = q * p + r + +Using (3), (4) and the fact that p is prime, the remainder is always +greater than zero: + + (7) 0 <= q < p /\ 1 <= r < p + + +Strategy: +--------- + +Precalculate the 80-bit long double inverse of p, with a maximum +relative error of 2**(1-F): + + (8) pinv = (long double)1.0 / p + +Calculate an estimate for q = floor(n/p). The multiplication has another +maximum relative error of 2**(1-F): + + (9) qest = n * pinv + +If we can show that q < qest < q+1, then trunc(qest) = q. It is then +easy to recover the remainder r. The complete algorithm is: + + a) Set the control word to 64-bit precision and truncation mode. + + b) n = a * b # Calculate exact product. + + c) qest = n * pinv # Calculate estimate for the quotient. + + d) q = (qest+2**63)-2**63 # Truncate qest to the exact quotient. + + f) r = n - q * p # Calculate remainder. + + +Proof for q < qest < q+1: +------------------------- + +Using the cumulative error, the error bounds for qest are: + + n n * (1 + 2**(1-F))**2 + (9) --------------------- <= qest <= --------------------- + p * (1 + 2**(1-F))**2 p + + + Lemma 1: + -------- + n q * p + r + (10) q < --------------------- = --------------------- + p * (1 + 2**(1-F))**2 p * (1 + 2**(1-F))**2 + + + Proof: + ~~~~~~ + + (I) q * p * (1 + 2**(1-F))**2 < q * p + r + + (II) q * p * 2**(2-F) + q * p * 2**(2-2*F) < r + + Using (1) and (7), it is sufficient to show that: + + (III) q * p * 2**(-62) + q * p * 2**(-126) < 1 <= r + + (III) can easily be verified by substituting the largest possible + values p = 2**31-1 and q = 2**31-2. + + The critical cases occur when r = 1, n = m * p + 1. These cases + can be exhaustively verified with a test program. + + + Lemma 2: + -------- + + n * (1 + 2**(1-F))**2 (q * p + r) * (1 + 2**(1-F))**2 + (11) --------------------- = ------------------------------- < q + 1 + p p + + Proof: + ~~~~~~ + + (I) (q * p + r) + (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < q * p + p + + (II) (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < p - r + + Using (1) and (7), it is sufficient to show that: + + (III) (q * p + r) * 2**(-62) + (q * p + r) * 2**(-126) < 1 <= p - r + + (III) can easily be verified by substituting the largest possible + values p = 2**31-1, q = 2**31-2 and r = 2**31-2. + + The critical cases occur when r = (p - 1), n = m * p - 1. These cases + can be exhaustively verified with a test program. + + +[1] http://www.apfloat.org/apfloat/2.40/apfloat.pdf +[2] http://gmplib.org/~tege/divcnst-pldi94.pdf + [Section 7: "Use of floating point"] + + + +(* Coq proof for (10) and (11) *) + +Require Import ZArith. +Require Import QArith. +Require Import Qpower. +Require Import Qabs. +Require Import Psatz. + +Open Scope Q_scope. + + +Ltac qreduce T := + rewrite <- (Qred_correct (T)); simpl (Qred (T)). + +Theorem Qlt_move_right : + forall x y z:Q, x + z < y <-> x < y - z. +Proof. + intros. + split. + intros. + psatzl Q. + intros. + psatzl Q. +Qed. + +Theorem Qlt_mult_by_z : + forall x y z:Q, 0 < z -> (x < y <-> x * z < y * z). +Proof. + intros. + split. + intros. + apply Qmult_lt_compat_r. trivial. trivial. + intros. + rewrite <- (Qdiv_mult_l x z). rewrite <- (Qdiv_mult_l y z). + apply Qmult_lt_compat_r. + apply Qlt_shift_inv_l. + trivial. psatzl Q. trivial. psatzl Q. psatzl Q. +Qed. + +Theorem Qle_mult_quad : + forall (a b c d:Q), + 0 <= a -> a <= c -> + 0 <= b -> b <= d -> + a * b <= c * d. + intros. + psatz Q. +Qed. + + +Theorem q_lt_qest: + forall (p q r:Q), + (0 < p) -> (p <= (2#1)^31 - 1) -> + (0 <= q) -> (q <= p - 1) -> + (1 <= r) -> (r <= p - 1) -> + q < (q * p + r) / (p * (1 + (2#1)^(-63))^2). +Proof. + intros. + rewrite Qlt_mult_by_z with (z := (p * (1 + (2#1)^(-63))^2)). + + unfold Qdiv. + rewrite <- Qmult_assoc. + rewrite (Qmult_comm (/ (p * (1 + (2 # 1) ^ (-63)) ^ 2)) (p * (1 + (2 # 1) ^ (-63)) ^ 2)). + rewrite Qmult_inv_r. + rewrite Qmult_1_r. + + assert (q * (p * (1 + (2 # 1) ^ (-63)) ^ 2) == q * p + (q * p) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))). + qreduce ((1 + (2 # 1) ^ (-63)) ^ 2). + qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). + ring_simplify. + reflexivity. + rewrite H5. + + rewrite Qplus_comm. + rewrite Qlt_move_right. + ring_simplify (q * p + r - q * p). + qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). + + apply Qlt_le_trans with (y := 1). + rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617). + ring_simplify. + + apply Qle_lt_trans with (y := ((2 # 1) ^ 31 - (2#1)) * ((2 # 1) ^ 31 - 1)). + apply Qle_mult_quad. + assumption. psatzl Q. psatzl Q. psatzl Q. psatzl Q. psatzl Q. assumption. psatzl Q. psatzl Q. +Qed. + +Theorem qest_lt_qplus1: + forall (p q r:Q), + (0 < p) -> (p <= (2#1)^31 - 1) -> + (0 <= q) -> (q <= p - 1) -> + (1 <= r) -> (r <= p - 1) -> + ((q * p + r) * (1 + (2#1)^(-63))^2) / p < q + 1. +Proof. + intros. + rewrite Qlt_mult_by_z with (z := p). + + unfold Qdiv. + rewrite <- Qmult_assoc. + rewrite (Qmult_comm (/ p) p). + rewrite Qmult_inv_r. + rewrite Qmult_1_r. + + assert ((q * p + r) * (1 + (2 # 1) ^ (-63)) ^ 2 == q * p + r + (q * p + r) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))). + qreduce ((1 + (2 # 1) ^ (-63)) ^ 2). + qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). + ring_simplify. reflexivity. + rewrite H5. + + rewrite <- Qplus_assoc. rewrite <- Qplus_comm. rewrite Qlt_move_right. + ring_simplify ((q + 1) * p - q * p). + + rewrite <- Qplus_comm. rewrite Qlt_move_right. + + apply Qlt_le_trans with (y := 1). + qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). + + rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617). + ring_simplify. + + ring_simplify in H0. + apply Qle_lt_trans with (y := (2147483646 # 1) * (2147483647 # 1) + (2147483646 # 1)). + + apply Qplus_le_compat. + apply Qle_mult_quad. + assumption. psatzl Q. auto with qarith. assumption. psatzl Q. + auto with qarith. auto with qarith. + psatzl Q. psatzl Q. assumption. +Qed. + + + diff --git a/Modules/_decimal/libmpdec/literature/six-step.txt b/Modules/_decimal/libmpdec/literature/six-step.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/six-step.txt @@ -0,0 +1,63 @@ + + +(* Copyright (c) 2011 Stefan Krah. All rights reserved. *) + + +The Six Step Transform: +======================= + +In libmpdec, the six-step transform is the Matrix Fourier Transform (See +matrix-transform.txt) in disguise. It is called six-step transform after +a variant that appears in [1]. The algorithm requires that the input +array can be viewed as an R*C matrix. + + +Algorithm six-step (forward transform): +--------------------------------------- + + 1a) Transpose the matrix. + + 1b) Apply a length R FNT to each row. + + 1c) Transpose the matrix. + + 2) Multiply each matrix element (addressed by j*C+m) by r**(j*m). + + 3) Apply a length C FNT to each row. + + 4) Transpose the matrix. + +Note that steps 1a) - 1c) are exactly equivalent to step 1) of the Matrix +Fourier Transform. For large R, it is faster to transpose twice and do +a transform on the rows than to perform a column transpose directly. + + + +Algorithm six-step (inverse transform): +--------------------------------------- + + 0) View the matrix as a C*R matrix. + + 1) Transpose the matrix, producing an R*C matrix. + + 2) Apply a length C FNT to each row. + + 3) Multiply each matrix element (addressed by i*C+n) by r**(i*n). + + 4a) Transpose the matrix. + + 4b) Apply a length R FNT to each row. + + 4c) Transpose the matrix. + +Again, steps 4a) - 4c) are equivalent to step 4) of the Matrix Fourier +Transform. + + + +-- + + [1] David H. Bailey: FFTs in External or Hierarchical Memory + http://crd.lbl.gov/~dhbailey/dhbpapers/ + + diff --git a/Modules/_decimal/libmpdec/literature/umodarith.lisp b/Modules/_decimal/libmpdec/literature/umodarith.lisp new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/literature/umodarith.lisp @@ -0,0 +1,692 @@ +; +; Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; 1. Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; +; 2. Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in the +; documentation and/or other materials provided with the distribution. +; +; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +; SUCH DAMAGE. +; + + +(in-package "ACL2") + +(include-book "arithmetic/top-with-meta" :dir :system) +(include-book "arithmetic-2/floor-mod/floor-mod" :dir :system) + + +;; ===================================================================== +;; Proofs for several functions in umodarith.h +;; ===================================================================== + + + +;; ===================================================================== +;; Helper theorems +;; ===================================================================== + +(defthm elim-mod-m= s m) (mod (- s m) base) s))) + s)) + +(defthmd addmod-correct + (implies (and (< 0 m) (< m base) + (< a m) (<= b m) + (natp m) (natp base) + (natp a) (natp b)) + (equal (addmod a b m base) + (mod (+ a b) m))) + :hints (("Goal" :cases ((<= base (+ a b)))) + ("Subgoal 2.1'" :use ((:instance elim-mod-m= a m) (- a m) a)) + (b (if (>= b m) (- b m) b)) + (d (mod (- a b) base)) + (d (if (< a b) (mod (+ d m) base) d))) + d)) + +; a < 2*m, b < 2*m +(defun ext-submod-2 (a b m base) + (let* ((a (mod a m)) + (b (mod b m)) + (d (mod (- a b) base)) + (d (if (< a b) (mod (+ d m) base) d))) + d)) + +(defthmd ext-submod-ext-submod-2-equal + (implies (and (< 0 m) (< m base) + (< a (* 2 m)) (< b (* 2 m)) + (natp m) (natp base) + (natp a) (natp b)) + (equal (ext-submod a b m base) + (ext-submod-2 a b m base)))) + +(defthmd ext-submod-2-correct + (implies (and (< 0 m) (< m base) + (< a (* 2 m)) (< b (* 2 m)) + (natp m) (natp base) + (natp a) (natp b)) + (equal (ext-submod-2 a b m base) + (mod (- a b) m)))) + + +;; ========================================================================= +;; dw-reduce is correct +;; ========================================================================= + +(defun dw-reduce (hi lo m base) + (let* ((r1 (mod hi m)) + (r2 (mod (+ (* r1 base) lo) m))) + r2)) + +(defthmd dw-reduce-correct + (implies (and (< 0 m) (< m base) + (< hi base) (< lo base) + (natp m) (natp base) + (natp hi) (natp lo)) + (equal (dw-reduce hi lo m base) + (mod (+ (* hi base) lo) m)))) + +(defthmd <=-multiply-both-sides-by-z + (implies (and (rationalp x) (rationalp y) + (< 0 z) (rationalp z)) + (equal (<= x y) + (<= (* z x) (* z y))))) + +(defthmd dw-reduce-aux1 + (implies (and (< 0 m) (< m base) + (natp m) (natp base) + (< lo base) (natp lo) + (< x m) (natp x)) + (< (+ lo (* base x)) (* base m))) + :hints (("Goal" :cases ((<= (+ x 1) m))) + ("Subgoal 1''" :cases ((<= (* base (+ x 1)) (* base m)))) + ("subgoal 1.2" :use ((:instance <=-multiply-both-sides-by-z + (x (+ 1 x)) + (y m) + (z base)))))) + +(defthm dw-reduce-aux2 + (implies (and (< x (* base m)) + (< 0 m) (< m base) + (natp m) (natp base) (natp x)) + (< (floor x m) base))) + +;; This is the necessary condition for using _mpd_div_words(). +(defthmd dw-reduce-second-quotient-fits-in-single-word + (implies (and (< 0 m) (< m base) + (< hi base) (< lo base) + (natp m) (natp base) + (natp hi) (natp lo) + (equal r1 (mod hi m))) + (< (floor (+ (* r1 base) lo) m) + base)) + :hints (("Goal" :cases ((< r1 m))) + ("Subgoal 1''" :cases ((< (+ lo (* base (mod hi m))) (* base m)))) + ("Subgoal 1.2" :use ((:instance dw-reduce-aux1 + (x (mod hi m))))))) + + +;; ========================================================================= +;; dw-submod is correct +;; ========================================================================= + +(defun dw-submod (a hi lo m base) + (let* ((r (dw-reduce hi lo m base)) + (d (mod (- a r) base)) + (d (if (< a r) (mod (+ d m) base) d))) + d)) + +(defthmd dw-submod-aux1 + (implies (and (natp a) (< 0 m) (natp m) + (natp x) (equal r (mod x m))) + (equal (mod (- a x) m) + (mod (- a r) m)))) + +(defthmd dw-submod-correct + (implies (and (< 0 m) (< m base) + (natp a) (< a m) + (< hi base) (< lo base) + (natp m) (natp base) + (natp hi) (natp lo)) + (equal (dw-submod a hi lo m base) + (mod (- a (+ (* base hi) lo)) m))) + :hints (("Goal" :in-theory (disable dw-reduce) + :use ((:instance dw-submod-aux1 + (x (+ lo (* base hi))) + (r (dw-reduce hi lo m base))) + (:instance dw-reduce-correct))))) + + +;; ========================================================================= +;; ANSI C arithmetic for uint64_t +;; ========================================================================= + +(defun add (a b) + (mod (+ a b) + (expt 2 64))) + +(defun sub (a b) + (mod (- a b) + (expt 2 64))) + +(defun << (w n) + (mod (* w (expt 2 n)) + (expt 2 64))) + +(defun >> (w n) + (floor w (expt 2 n))) + +;; join upper and lower half of a double word, yielding a 128 bit number +(defun join (hi lo) + (+ (* (expt 2 64) hi) lo)) + + +;; ============================================================================= +;; Fast modular reduction +;; ============================================================================= + +;; These are the three primes used in the Number Theoretic Transform. +;; A fast modular reduction scheme exists for all of them. +(defmacro p1 () + (+ (expt 2 64) (- (expt 2 32)) 1)) + +(defmacro p2 () + (+ (expt 2 64) (- (expt 2 34)) 1)) + +(defmacro p3 () + (+ (expt 2 64) (- (expt 2 40)) 1)) + + +;; reduce the double word number hi*2**64 + lo (mod p1) +(defun simple-mod-reduce-p1 (hi lo) + (+ (* (expt 2 32) hi) (- hi) lo)) + +;; reduce the double word number hi*2**64 + lo (mod p2) +(defun simple-mod-reduce-p2 (hi lo) + (+ (* (expt 2 34) hi) (- hi) lo)) + +;; reduce the double word number hi*2**64 + lo (mod p3) +(defun simple-mod-reduce-p3 (hi lo) + (+ (* (expt 2 40) hi) (- hi) lo)) + + +; ---------------------------------------------------------- +; The modular reductions given above are correct +; ---------------------------------------------------------- + +(defthmd congruence-p1-aux + (equal (* (expt 2 64) hi) + (+ (* (p1) hi) + (* (expt 2 32) hi) + (- hi)))) + +(defthmd congruence-p2-aux + (equal (* (expt 2 64) hi) + (+ (* (p2) hi) + (* (expt 2 34) hi) + (- hi)))) + +(defthmd congruence-p3-aux + (equal (* (expt 2 64) hi) + (+ (* (p3) hi) + (* (expt 2 40) hi) + (- hi)))) + +(defthmd mod-augment + (implies (and (rationalp x) + (rationalp y) + (rationalp m)) + (equal (mod (+ x y) m) + (mod (+ x (mod y m)) m)))) + +(defthmd simple-mod-reduce-p1-congruent + (implies (and (integerp hi) + (integerp lo)) + (equal (mod (simple-mod-reduce-p1 hi lo) (p1)) + (mod (join hi lo) (p1)))) + :hints (("Goal''" :use ((:instance congruence-p1-aux) + (:instance mod-augment + (m (p1)) + (x (+ (- hi) lo (* (expt 2 32) hi))) + (y (* (p1) hi))))))) + +(defthmd simple-mod-reduce-p2-congruent + (implies (and (integerp hi) + (integerp lo)) + (equal (mod (simple-mod-reduce-p2 hi lo) (p2)) + (mod (join hi lo) (p2)))) + :hints (("Goal''" :use ((:instance congruence-p2-aux) + (:instance mod-augment + (m (p2)) + (x (+ (- hi) lo (* (expt 2 34) hi))) + (y (* (p2) hi))))))) + +(defthmd simple-mod-reduce-p3-congruent + (implies (and (integerp hi) + (integerp lo)) + (equal (mod (simple-mod-reduce-p3 hi lo) (p3)) + (mod (join hi lo) (p3)))) + :hints (("Goal''" :use ((:instance congruence-p3-aux) + (:instance mod-augment + (m (p3)) + (x (+ (- hi) lo (* (expt 2 40) hi))) + (y (* (p3) hi))))))) + + +; --------------------------------------------------------------------- +; We need a number less than 2*p, so that we can use the trick from +; elim-mod-m> hi 32)) + (x (sub lo x)) + (hi (if (> x lo) (+ hi -1) hi)) + (y (<< y 32)) + (lo (add y x)) + (hi (if (< lo y) (+ hi 1) hi))) + (+ (* hi (expt 2 64)) lo))) + +(defun mod-reduce-p2 (hi lo) + (let* ((y hi) + (x y) + (hi (>> hi 30)) + (x (sub lo x)) + (hi (if (> x lo) (+ hi -1) hi)) + (y (<< y 34)) + (lo (add y x)) + (hi (if (< lo y) (+ hi 1) hi))) + (+ (* hi (expt 2 64)) lo))) + +(defun mod-reduce-p3 (hi lo) + (let* ((y hi) + (x y) + (hi (>> hi 24)) + (x (sub lo x)) + (hi (if (> x lo) (+ hi -1) hi)) + (y (<< y 40)) + (lo (add y x)) + (hi (if (< lo y) (+ hi 1) hi))) + (+ (* hi (expt 2 64)) lo))) + + +; ------------------------------------------------------------------------- +; The compiler friendly versions are equal to the simple versions +; ------------------------------------------------------------------------- + +(defthm mod-reduce-aux1 + (implies (and (<= 0 a) (natp a) (natp m) + (< (- m) b) (<= b 0) + (integerp b) + (< (mod (+ b a) m) + (mod a m))) + (equal (mod (+ b a) m) + (+ b (mod a m)))) + :hints (("Subgoal 2" :use ((:instance modaux-1b + (x (+ a b))))))) + +(defthm mod-reduce-aux2 + (implies (and (<= 0 a) (natp a) (natp m) + (< b m) (natp b) + (< (mod (+ b a) m) + (mod a m))) + (equal (+ m (mod (+ b a) m)) + (+ b (mod a m))))) + + +(defthm mod-reduce-aux3 + (implies (and (< 0 a) (natp a) (natp m) + (< (- m) b) (< b 0) + (integerp b) + (<= (mod a m) + (mod (+ b a) m))) + (equal (+ (- m) (mod (+ b a) m)) + (+ b (mod a m)))) + :hints (("Subgoal 1.2'" :use ((:instance modaux-1b + (x b)))) + ("Subgoal 1''" :use ((:instance modaux-2d + (x I)))))) + + +(defthm mod-reduce-aux4 + (implies (and (< 0 a) (natp a) (natp m) + (< b m) (natp b) + (<= (mod a m) + (mod (+ b a) m))) + (equal (mod (+ b a) m) + (+ b (mod a m))))) + + +(defthm mod-reduce-p1==simple-mod-reduce-p1 + (implies (and (< hi (expt 2 64)) + (< lo (expt 2 64)) + (natp hi) (natp lo)) + (equal (mod-reduce-p1 hi lo) + (simple-mod-reduce-p1 hi lo))) + :hints (("Goal" :in-theory (disable expt) + :cases ((< 0 hi))) + ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 32) hi))))) + ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 32) hi))))) + ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 32) hi))))) + ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 32) hi))))))) + + +(defthm mod-reduce-p2==simple-mod-reduce-p2 + (implies (and (< hi (expt 2 64)) + (< lo (expt 2 64)) + (natp hi) (natp lo)) + (equal (mod-reduce-p2 hi lo) + (simple-mod-reduce-p2 hi lo))) + :hints (("Goal" :cases ((< 0 hi))) + ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 34) hi))))) + ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 34) hi))))) + ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 34) hi))))) + ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 34) hi))))))) + + +(defthm mod-reduce-p3==simple-mod-reduce-p3 + (implies (and (< hi (expt 2 64)) + (< lo (expt 2 64)) + (natp hi) (natp lo)) + (equal (mod-reduce-p3 hi lo) + (simple-mod-reduce-p3 hi lo))) + :hints (("Goal" :cases ((< 0 hi))) + ("Subgoal 1.2.2'" :use ((:instance mod-reduce-aux1 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 40) hi))))) + ("Subgoal 1.2.1'" :use ((:instance mod-reduce-aux3 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 40) hi))))) + ("Subgoal 1.1.2'" :use ((:instance mod-reduce-aux2 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 40) hi))))) + ("Subgoal 1.1.1'" :use ((:instance mod-reduce-aux4 + (m (expt 2 64)) + (b (+ (- HI) LO)) + (a (* (expt 2 40) hi))))))) + + + diff --git a/Modules/_decimal/libmpdec/memory.c b/Modules/_decimal/libmpdec/memory.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/memory.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include "typearith.h" +#include "memory.h" + + +/* Guaranteed minimum allocation for a coefficient. May be changed once + at program start using mpd_setminalloc(). */ +mpd_ssize_t MPD_MINALLOC = MPD_MINALLOC_MIN; + +/* Custom allocation and free functions */ +void *(* mpd_mallocfunc)(size_t size) = malloc; +void *(* mpd_reallocfunc)(void *ptr, size_t size) = realloc; +void *(* mpd_callocfunc)(size_t nmemb, size_t size) = calloc; +void (* mpd_free)(void *ptr) = free; + + +/* emulate calloc if it is not available */ +void * +mpd_callocfunc_em(size_t nmemb, size_t size) +{ + void *ptr; + size_t req; + mpd_size_t overflow; + +#if MPD_SIZE_MAX < SIZE_MAX + /* full_coverage test only */ + if (nmemb > MPD_SIZE_MAX || size > MPD_SIZE_MAX) { + return NULL; + } +#endif + + req = mul_size_t_overflow((mpd_size_t)nmemb, (mpd_size_t)size, + &overflow); + if (overflow) { + return NULL; + } + + ptr = mpd_mallocfunc(req); + if (ptr == NULL) { + return NULL; + } + /* used on uint32_t or uint64_t */ + memset(ptr, 0, req); + + return ptr; +} + + +/* malloc with overflow checking */ +void * +mpd_alloc(mpd_size_t nmemb, mpd_size_t size) +{ + mpd_size_t req, overflow; + + req = mul_size_t_overflow(nmemb, size, &overflow); + if (overflow) { + return NULL; + } + + return mpd_mallocfunc(req); +} + +/* calloc with overflow checking */ +void * +mpd_calloc(mpd_size_t nmemb, mpd_size_t size) +{ + mpd_size_t overflow; + + (void)mul_size_t_overflow(nmemb, size, &overflow); + if (overflow) { + return NULL; + } + + return mpd_callocfunc(nmemb, size); +} + +/* realloc with overflow checking */ +void * +mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err) +{ + void *new; + mpd_size_t req, overflow; + + req = mul_size_t_overflow(nmemb, size, &overflow); + if (overflow) { + *err = 1; + return ptr; + } + + new = mpd_reallocfunc(ptr, req); + if (new == NULL) { + *err = 1; + return ptr; + } + + return new; +} + +/* struct hack malloc with overflow checking */ +void * +mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size) +{ + mpd_size_t req, overflow; + + req = mul_size_t_overflow(nmemb, size, &overflow); + if (overflow) { + return NULL; + } + + req = add_size_t_overflow(req, struct_size, &overflow); + if (overflow) { + return NULL; + } + + return mpd_mallocfunc(req); +} + + +/* Allocate a new decimal with a coefficient of length 'nwords'. In case + of an error the return value is NULL. */ +mpd_t * +mpd_qnew_size(mpd_ssize_t nwords) +{ + mpd_t *result; + + nwords = (nwords < MPD_MINALLOC) ? MPD_MINALLOC : nwords; + + result = mpd_alloc(1, sizeof *result); + if (result == NULL) { + return NULL; + } + + result->data = mpd_alloc(nwords, sizeof *result->data); + if (result->data == NULL) { + mpd_free(result); + return NULL; + } + + result->flags = 0; + result->exp = 0; + result->digits = 0; + result->len = 0; + result->alloc = nwords; + + return result; +} + +/* Allocate a new decimal with a coefficient of length MPD_MINALLOC. + In case of an error the return value is NULL. */ +mpd_t * +mpd_qnew(void) +{ + return mpd_qnew_size(MPD_MINALLOC); +} + +/* Allocate new decimal. Caller can check for NULL or MPD_Malloc_error. + Raises on error. */ +mpd_t * +mpd_new(mpd_context_t *ctx) +{ + mpd_t *result; + + result = mpd_qnew(); + if (result == NULL) { + mpd_addstatus_raise(ctx, MPD_Malloc_error); + } + return result; +} + +/* + * Input: 'result' is a static mpd_t with a static coefficient. + * Assumption: 'nwords' >= result->alloc. + * + * Resize the static coefficient to a larger dynamic one and copy the + * existing data. If successful, the value of 'result' is unchanged. + * Otherwise, set 'result' to NaN and update 'status' with MPD_Malloc_error. + */ +int +mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + mpd_uint_t *p = result->data; + + assert(nwords >= result->alloc); + + result->data = mpd_alloc(nwords, sizeof *result->data); + if (result->data == NULL) { + result->data = p; + mpd_set_qnan(result); + mpd_set_positive(result); + result->exp = result->digits = result->len = 0; + *status |= MPD_Malloc_error; + return 0; + } + + memcpy(result->data, p, result->len * (sizeof *result->data)); + result->alloc = nwords; + mpd_set_dynamic_data(result); + return 1; +} + +/* + * Input: 'result' is a static mpd_t with a static coefficient. + * + * Convert the coefficient to a dynamic one that is initialized to zero. If + * malloc fails, set 'result' to NaN and update 'status' with MPD_Malloc_error. + */ +int +mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + mpd_uint_t *p = result->data; + + result->data = mpd_calloc(nwords, sizeof *result->data); + if (result->data == NULL) { + result->data = p; + mpd_set_qnan(result); + mpd_set_positive(result); + result->exp = result->digits = result->len = 0; + *status |= MPD_Malloc_error; + return 0; + } + + result->alloc = nwords; + mpd_set_dynamic_data(result); + + return 1; +} + +/* + * Input: 'result' is a static or a dynamic mpd_t with a dynamic coefficient. + * Resize the coefficient to length 'nwords': + * Case nwords > result->alloc: + * If realloc is successful: + * 'result' has a larger coefficient but the same value. Return 1. + * Otherwise: + * Set 'result' to NaN, update status with MPD_Malloc_error and return 0. + * Case nwords < result->alloc: + * If realloc is successful: + * 'result' has a smaller coefficient. result->len is undefined. Return 1. + * Otherwise (unlikely): + * 'result' is unchanged. Reuse the now oversized coefficient. Return 1. + */ +int +mpd_realloc_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + uint8_t err = 0; + + result->data = mpd_realloc(result->data, nwords, sizeof *result->data, &err); + if (!err) { + result->alloc = nwords; + } + else if (nwords > result->alloc) { + mpd_set_qnan(result); + mpd_set_positive(result); + result->exp = result->digits = result->len = 0; + *status |= MPD_Malloc_error; + return 0; + } + + return 1; +} + + diff --git a/Modules/_decimal/libmpdec/memory.h b/Modules/_decimal/libmpdec/memory.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/memory.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef MEMORY_H +#define MEMORY_H + + +#include "mpdecimal.h" + + +int mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t size, uint32_t *status); +int mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status); +int mpd_realloc_dyn(mpd_t *result, mpd_ssize_t size, uint32_t *status); + + +#endif + + + diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/mpdecimal.c @@ -0,0 +1,7596 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include +#include +#include "basearith.h" +#include "bits.h" +#include "convolute.h" +#include "crt.h" +#include "errno.h" +#include "memory.h" +#include "typearith.h" +#include "umodarith.h" + +#ifdef PPRO + #if defined(_MSC_VER) + #include + #pragma fenv_access(on) + #elif !defined(__OpenBSD__) && !defined(__NetBSD__) + /* C99 */ + #include + #pragma STDC FENV_ACCESS ON + #endif +#endif + +#if defined(__x86_64__) && defined(__GLIBC__) && !defined(__INTEL_COMPILER) + #define USE_80BIT_LONG_DOUBLE +#endif + +#if defined(_MSC_VER) + #define ALWAYS_INLINE __forceinline +#elif defined(LEGACY_COMPILER) + #define ALWAYS_INLINE + #undef inline + #define inline +#else + #ifdef TEST_COVERAGE + #define ALWAYS_INLINE + #else + #define ALWAYS_INLINE inline __attribute__ ((always_inline)) + #endif +#endif + + +#define MPD_NEWTONDIV_CUTOFF 1024L + +#define MPD_NEW_STATIC(name, flags, exp, digits, len) \ + mpd_uint_t name##_data[MPD_MINALLOC_MAX]; \ + mpd_t name = {flags|MPD_STATIC|MPD_STATIC_DATA, exp, digits, \ + len, MPD_MINALLOC_MAX, name##_data} + +#define MPD_NEW_CONST(name, flags, exp, digits, len, alloc, initval) \ + mpd_uint_t name##_data[alloc] = {initval}; \ + mpd_t name = {flags|MPD_STATIC|MPD_CONST_DATA, exp, digits, \ + len, alloc, name##_data} + +#define MPD_NEW_SHARED(name, a) \ + mpd_t name = {(a->flags&~MPD_DATAFLAGS)|MPD_STATIC|MPD_SHARED_DATA, \ + a->exp, a->digits, a->len, a->alloc, a->data} + + +static mpd_uint_t data_one[1] = {1}; +static mpd_uint_t data_zero[1] = {0}; +static const mpd_t one = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_one}; +static const mpd_t minus_one = {MPD_NEG|MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, + data_one}; +static const mpd_t zero = {MPD_STATIC|MPD_CONST_DATA, 0, 1, 1, 1, data_zero}; + +static inline void _mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx, + uint32_t *status); +static void _settriple(mpd_t *result, uint8_t sign, mpd_uint_t a, + mpd_ssize_t exp); +static inline mpd_ssize_t _mpd_real_size(mpd_uint_t *data, mpd_ssize_t size); + +static void _mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status); +static inline void _mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status); +static void _mpd_qbarrett_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, + const mpd_t *b, uint32_t *status); +static inline void _mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, + uint8_t resultsign, const mpd_context_t *ctx, uint32_t *status); + +mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n); + + +/******************************************************************************/ +/* Performance critical inline functions */ +/******************************************************************************/ + +#ifdef CONFIG_64 +/* Digits in a word, primarily useful for the most significant word. */ +ALWAYS_INLINE int +mpd_word_digits(mpd_uint_t word) +{ + if (word < mpd_pow10[9]) { + if (word < mpd_pow10[4]) { + if (word < mpd_pow10[2]) { + return (word < mpd_pow10[1]) ? 1 : 2; + } + return (word < mpd_pow10[3]) ? 3 : 4; + } + if (word < mpd_pow10[6]) { + return (word < mpd_pow10[5]) ? 5 : 6; + } + if (word < mpd_pow10[8]) { + return (word < mpd_pow10[7]) ? 7 : 8; + } + return 9; + } + if (word < mpd_pow10[14]) { + if (word < mpd_pow10[11]) { + return (word < mpd_pow10[10]) ? 10 : 11; + } + if (word < mpd_pow10[13]) { + return (word < mpd_pow10[12]) ? 12 : 13; + } + return 14; + } + if (word < mpd_pow10[18]) { + if (word < mpd_pow10[16]) { + return (word < mpd_pow10[15]) ? 15 : 16; + } + return (word < mpd_pow10[17]) ? 17 : 18; + } + + return (word < mpd_pow10[19]) ? 19 : 20; +} +#else +ALWAYS_INLINE int +mpd_word_digits(mpd_uint_t word) +{ + if (word < mpd_pow10[4]) { + if (word < mpd_pow10[2]) { + return (word < mpd_pow10[1]) ? 1 : 2; + } + return (word < mpd_pow10[3]) ? 3 : 4; + } + if (word < mpd_pow10[6]) { + return (word < mpd_pow10[5]) ? 5 : 6; + } + if (word < mpd_pow10[8]) { + return (word < mpd_pow10[7]) ? 7 : 8; + } + + return (word < mpd_pow10[9]) ? 9 : 10; +} +#endif + + +/* Adjusted exponent */ +ALWAYS_INLINE mpd_ssize_t +mpd_adjexp(const mpd_t *dec) +{ + return (dec->exp + dec->digits) - 1; +} + +/* Etiny */ +ALWAYS_INLINE mpd_ssize_t +mpd_etiny(const mpd_context_t *ctx) +{ + return ctx->emin - (ctx->prec - 1); +} + +/* Etop: used for folding down in IEEE clamping */ +ALWAYS_INLINE mpd_ssize_t +mpd_etop(const mpd_context_t *ctx) +{ + return ctx->emax - (ctx->prec - 1); +} + +/* Most significant word */ +ALWAYS_INLINE mpd_uint_t +mpd_msword(const mpd_t *dec) +{ + assert(dec->len > 0); + return dec->data[dec->len-1]; +} + +/* Most significant digit of a word */ +inline mpd_uint_t +mpd_msd(mpd_uint_t word) +{ + int n; + + n = mpd_word_digits(word); + return word / mpd_pow10[n-1]; +} + +/* Least significant digit of a word */ +ALWAYS_INLINE mpd_uint_t +mpd_lsd(mpd_uint_t word) +{ + return word % 10; +} + +/* Coefficient size needed to store 'digits' */ +ALWAYS_INLINE mpd_ssize_t +mpd_digits_to_size(mpd_ssize_t digits) +{ + mpd_ssize_t q, r; + + _mpd_idiv_word(&q, &r, digits, MPD_RDIGITS); + return (r == 0) ? q : q+1; +} + +/* Number of digits in the exponent. Not defined for MPD_SSIZE_MIN. */ +inline int +mpd_exp_digits(mpd_ssize_t exp) +{ + exp = (exp < 0) ? -exp : exp; + return mpd_word_digits(exp); +} + +/* Canonical */ +ALWAYS_INLINE int +mpd_iscanonical(const mpd_t *dec UNUSED) +{ + return 1; +} + +/* Finite */ +ALWAYS_INLINE int +mpd_isfinite(const mpd_t *dec) +{ + return !(dec->flags & MPD_SPECIAL); +} + +/* Infinite */ +ALWAYS_INLINE int +mpd_isinfinite(const mpd_t *dec) +{ + return dec->flags & MPD_INF; +} + +/* NaN */ +ALWAYS_INLINE int +mpd_isnan(const mpd_t *dec) +{ + return dec->flags & (MPD_NAN|MPD_SNAN); +} + +/* Negative */ +ALWAYS_INLINE int +mpd_isnegative(const mpd_t *dec) +{ + return dec->flags & MPD_NEG; +} + +/* Positive */ +ALWAYS_INLINE int +mpd_ispositive(const mpd_t *dec) +{ + return !(dec->flags & MPD_NEG); +} + +/* qNaN */ +ALWAYS_INLINE int +mpd_isqnan(const mpd_t *dec) +{ + return dec->flags & MPD_NAN; +} + +/* Signed */ +ALWAYS_INLINE int +mpd_issigned(const mpd_t *dec) +{ + return dec->flags & MPD_NEG; +} + +/* sNaN */ +ALWAYS_INLINE int +mpd_issnan(const mpd_t *dec) +{ + return dec->flags & MPD_SNAN; +} + +/* Special */ +ALWAYS_INLINE int +mpd_isspecial(const mpd_t *dec) +{ + return dec->flags & MPD_SPECIAL; +} + +/* Zero */ +ALWAYS_INLINE int +mpd_iszero(const mpd_t *dec) +{ + return !mpd_isspecial(dec) && mpd_msword(dec) == 0; +} + +/* Test for zero when specials have been ruled out already */ +ALWAYS_INLINE int +mpd_iszerocoeff(const mpd_t *dec) +{ + return mpd_msword(dec) == 0; +} + +/* Normal */ +inline int +mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx) +{ + if (mpd_isspecial(dec)) return 0; + if (mpd_iszerocoeff(dec)) return 0; + + return mpd_adjexp(dec) >= ctx->emin; +} + +/* Subnormal */ +inline int +mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx) +{ + if (mpd_isspecial(dec)) return 0; + if (mpd_iszerocoeff(dec)) return 0; + + return mpd_adjexp(dec) < ctx->emin; +} + +/* Odd word */ +ALWAYS_INLINE int +mpd_isoddword(mpd_uint_t word) +{ + return word & 1; +} + +/* Odd coefficient */ +ALWAYS_INLINE int +mpd_isoddcoeff(const mpd_t *dec) +{ + return mpd_isoddword(dec->data[0]); +} + +/* 0 if dec is positive, 1 if dec is negative */ +ALWAYS_INLINE uint8_t +mpd_sign(const mpd_t *dec) +{ + return dec->flags & MPD_NEG; +} + +/* 1 if dec is positive, -1 if dec is negative */ +ALWAYS_INLINE int +mpd_arith_sign(const mpd_t *dec) +{ + return 1 - 2 * mpd_isnegative(dec); +} + +/* Radix */ +ALWAYS_INLINE long +mpd_radix(void) +{ + return 10; +} + +/* Dynamic decimal */ +ALWAYS_INLINE int +mpd_isdynamic(mpd_t *dec) +{ + return !(dec->flags & MPD_STATIC); +} + +/* Static decimal */ +ALWAYS_INLINE int +mpd_isstatic(mpd_t *dec) +{ + return dec->flags & MPD_STATIC; +} + +/* Data of decimal is dynamic */ +ALWAYS_INLINE int +mpd_isdynamic_data(mpd_t *dec) +{ + return !(dec->flags & MPD_DATAFLAGS); +} + +/* Data of decimal is static */ +ALWAYS_INLINE int +mpd_isstatic_data(mpd_t *dec) +{ + return dec->flags & MPD_STATIC_DATA; +} + +/* Data of decimal is shared */ +ALWAYS_INLINE int +mpd_isshared_data(mpd_t *dec) +{ + return dec->flags & MPD_SHARED_DATA; +} + +/* Data of decimal is const */ +ALWAYS_INLINE int +mpd_isconst_data(mpd_t *dec) +{ + return dec->flags & MPD_CONST_DATA; +} + + +/******************************************************************************/ +/* Inline memory handling */ +/******************************************************************************/ + +/* Fill destination with zeros */ +ALWAYS_INLINE void +mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len) +{ + mpd_size_t i; + + for (i = 0; i < len; i++) { + dest[i] = 0; + } +} + +/* Free a decimal */ +ALWAYS_INLINE void +mpd_del(mpd_t *dec) +{ + if (mpd_isdynamic_data(dec)) { + mpd_free(dec->data); + } + if (mpd_isdynamic(dec)) { + mpd_free(dec); + } +} + +/* + * Resize the coefficient. Existing data up to 'nwords' is left untouched. + * Return 1 on success, 0 otherwise. + * + * Input invariants: + * 1) MPD_MINALLOC <= result->alloc. + * 2) 0 <= result->len <= result->alloc. + * + * Case nwords > result->alloc: + * Case realloc success: + * The value of 'result' does not change. Return 1. + * Case realloc failure: + * 'result' is NaN, status is updated with MPD_Malloc_error. Return 0. + * + * Case nwords < result->alloc: + * Case is_static_data or nwords < MPD_MINALLOC or realloc failure [1]: + * 'result' is unchanged. Return 1. + * Case realloc success: + * The value of result is undefined (expected). Return 1. + * + * Case nwords == result->alloc: + * 'result' is unchanged. Return 1. + * + * [1] In that case the old (now oversized) area is still valid. + */ +ALWAYS_INLINE int +mpd_qresize(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + assert(!mpd_isconst_data(result)); /* illegal operation for a const */ + assert(!mpd_isshared_data(result)); /* illegal operation for a shared */ + + if (mpd_isstatic_data(result)) { + if (nwords > result->alloc) { + return mpd_switch_to_dyn(result, nwords, status); + } + } + else if (nwords != result->alloc && nwords >= MPD_MINALLOC) { + return mpd_realloc_dyn(result, nwords, status); + } + + return 1; +} + +/* Same as mpd_qresize, but the complete coefficient (including the old + * memory area!) is initialized to zero. */ +ALWAYS_INLINE int +mpd_qresize_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) +{ + assert(!mpd_isconst_data(result)); /* illegal operation for a const */ + assert(!mpd_isshared_data(result)); /* illegal operation for a shared */ + + if (mpd_isstatic_data(result)) { + if (nwords > result->alloc) { + return mpd_switch_to_dyn_zero(result, nwords, status); + } + } + else if (nwords != result->alloc && nwords >= MPD_MINALLOC) { + if (!mpd_realloc_dyn(result, nwords, status)) { + return 0; + } + } + + mpd_uint_zero(result->data, nwords); + + return 1; +} + +/* + * Reduce memory size for the coefficient to MPD_MINALLOC. In theory, + * realloc may fail even when reducing the memory size. But in that case + * the old memory area is always big enough, so checking for MPD_Malloc_error + * is not imperative. + */ +ALWAYS_INLINE void +mpd_minalloc(mpd_t *result) +{ + assert(!mpd_isconst_data(result)); /* illegal operation for a const */ + assert(!mpd_isshared_data(result)); /* illegal operation for a shared */ + + if (!mpd_isstatic_data(result) && result->alloc > MPD_MINALLOC) { + uint8_t err = 0; + result->data = mpd_realloc(result->data, MPD_MINALLOC, + sizeof *result->data, &err); + if (!err) { + result->alloc = MPD_MINALLOC; + } + } +} + +int +mpd_resize(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx) +{ + uint32_t status = 0; + if (!mpd_qresize(result, nwords, &status)) { + mpd_addstatus_raise(ctx, status); + return 0; + } + return 1; +} + +int +mpd_resize_zero(mpd_t *result, mpd_ssize_t nwords, mpd_context_t *ctx) +{ + uint32_t status = 0; + if (!mpd_qresize_zero(result, nwords, &status)) { + mpd_addstatus_raise(ctx, status); + return 0; + } + return 1; +} + + +/******************************************************************************/ +/* Set attributes of a decimal */ +/******************************************************************************/ + +/* Set digits. Assumption: result->len is initialized and > 0. */ +inline void +mpd_setdigits(mpd_t *result) +{ + mpd_ssize_t wdigits = mpd_word_digits(mpd_msword(result)); + result->digits = wdigits + (result->len-1) * MPD_RDIGITS; +} + +/* Set sign */ +ALWAYS_INLINE void +mpd_set_sign(mpd_t *result, uint8_t sign) +{ + result->flags &= ~MPD_NEG; + result->flags |= sign; +} + +/* Copy sign from another decimal */ +ALWAYS_INLINE void +mpd_signcpy(mpd_t *result, mpd_t *a) +{ + uint8_t sign = a->flags&MPD_NEG; + + result->flags &= ~MPD_NEG; + result->flags |= sign; +} + +/* Set infinity */ +ALWAYS_INLINE void +mpd_set_infinity(mpd_t *result) +{ + result->flags &= ~MPD_SPECIAL; + result->flags |= MPD_INF; +} + +/* Set qNaN */ +ALWAYS_INLINE void +mpd_set_qnan(mpd_t *result) +{ + result->flags &= ~MPD_SPECIAL; + result->flags |= MPD_NAN; +} + +/* Set sNaN */ +ALWAYS_INLINE void +mpd_set_snan(mpd_t *result) +{ + result->flags &= ~MPD_SPECIAL; + result->flags |= MPD_SNAN; +} + +/* Set to negative */ +ALWAYS_INLINE void +mpd_set_negative(mpd_t *result) +{ + result->flags |= MPD_NEG; +} + +/* Set to positive */ +ALWAYS_INLINE void +mpd_set_positive(mpd_t *result) +{ + result->flags &= ~MPD_NEG; +} + +/* Set to dynamic */ +ALWAYS_INLINE void +mpd_set_dynamic(mpd_t *result) +{ + result->flags &= ~MPD_STATIC; +} + +/* Set to static */ +ALWAYS_INLINE void +mpd_set_static(mpd_t *result) +{ + result->flags |= MPD_STATIC; +} + +/* Set data to dynamic */ +ALWAYS_INLINE void +mpd_set_dynamic_data(mpd_t *result) +{ + result->flags &= ~MPD_DATAFLAGS; +} + +/* Set data to static */ +ALWAYS_INLINE void +mpd_set_static_data(mpd_t *result) +{ + result->flags &= ~MPD_DATAFLAGS; + result->flags |= MPD_STATIC_DATA; +} + +/* Set data to shared */ +ALWAYS_INLINE void +mpd_set_shared_data(mpd_t *result) +{ + result->flags &= ~MPD_DATAFLAGS; + result->flags |= MPD_SHARED_DATA; +} + +/* Set data to const */ +ALWAYS_INLINE void +mpd_set_const_data(mpd_t *result) +{ + result->flags &= ~MPD_DATAFLAGS; + result->flags |= MPD_CONST_DATA; +} + +/* Clear flags, preserving memory attributes. */ +ALWAYS_INLINE void +mpd_clear_flags(mpd_t *result) +{ + result->flags &= (MPD_STATIC|MPD_DATAFLAGS); +} + +/* Set flags, preserving memory attributes. */ +ALWAYS_INLINE void +mpd_set_flags(mpd_t *result, uint8_t flags) +{ + result->flags &= (MPD_STATIC|MPD_DATAFLAGS); + result->flags |= flags; +} + +/* Copy flags, preserving memory attributes of result. */ +ALWAYS_INLINE void +mpd_copy_flags(mpd_t *result, const mpd_t *a) +{ + uint8_t aflags = a->flags; + result->flags &= (MPD_STATIC|MPD_DATAFLAGS); + result->flags |= (aflags & ~(MPD_STATIC|MPD_DATAFLAGS)); +} + +/* Initialize a workcontext from ctx. Set traps, flags and newtrap to 0. */ +static inline void +mpd_workcontext(mpd_context_t *workctx, const mpd_context_t *ctx) +{ + workctx->prec = ctx->prec; + workctx->emax = ctx->emax; + workctx->emin = ctx->emin; + workctx->round = ctx->round; + workctx->traps = 0; + workctx->status = 0; + workctx->newtrap = 0; + workctx->clamp = ctx->clamp; + workctx->allcr = ctx->allcr; +} + + +/******************************************************************************/ +/* Getting and setting parts of decimals */ +/******************************************************************************/ + +/* Flip the sign of a decimal */ +static inline void +_mpd_negate(mpd_t *dec) +{ + dec->flags ^= MPD_NEG; +} + +/* Set coefficient to zero */ +void +mpd_zerocoeff(mpd_t *result) +{ + mpd_minalloc(result); + result->digits = 1; + result->len = 1; + result->data[0] = 0; +} + +/* Set the coefficient to all nines. */ +void +mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t len, r; + + _mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS); + len = (r == 0) ? len : len+1; + + if (!mpd_qresize(result, len, status)) { + return; + } + + result->len = len; + result->digits = ctx->prec; + + --len; + if (r > 0) { + result->data[len--] = mpd_pow10[r]-1; + } + for (; len >= 0; --len) { + result->data[len] = MPD_RADIX-1; + } +} + +/* + * Cut off the most significant digits so that the rest fits in ctx->prec. + * Cannot fail. + */ +static void +_mpd_cap(mpd_t *result, const mpd_context_t *ctx) +{ + uint32_t dummy; + mpd_ssize_t len, r; + + if (result->len > 0 && result->digits > ctx->prec) { + _mpd_idiv_word(&len, &r, ctx->prec, MPD_RDIGITS); + len = (r == 0) ? len : len+1; + + if (r != 0) { + result->data[len-1] %= mpd_pow10[r]; + } + + len = _mpd_real_size(result->data, len); + /* resize to fewer words cannot fail */ + mpd_qresize(result, len, &dummy); + result->len = len; + mpd_setdigits(result); + } + if (mpd_iszero(result)) { + _settriple(result, mpd_sign(result), 0, result->exp); + } +} + +/* + * Cut off the most significant digits of a NaN payload so that the rest + * fits in ctx->prec - ctx->clamp. Cannot fail. + */ +static void +_mpd_fix_nan(mpd_t *result, const mpd_context_t *ctx) +{ + uint32_t dummy; + mpd_ssize_t prec; + mpd_ssize_t len, r; + + prec = ctx->prec - ctx->clamp; + if (result->len > 0 && result->digits > prec) { + if (prec == 0) { + mpd_minalloc(result); + result->len = result->digits = 0; + } + else { + _mpd_idiv_word(&len, &r, prec, MPD_RDIGITS); + len = (r == 0) ? len : len+1; + + if (r != 0) { + result->data[len-1] %= mpd_pow10[r]; + } + + len = _mpd_real_size(result->data, len); + /* resize to fewer words cannot fail */ + mpd_qresize(result, len, &dummy); + result->len = len; + mpd_setdigits(result); + if (mpd_iszerocoeff(result)) { + /* NaN0 is not a valid representation */ + result->len = result->digits = 0; + } + } + } +} + +/* + * Get n most significant digits from a decimal, where 0 < n <= MPD_UINT_DIGITS. + * Assumes MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for 32 and 64 bit + * machines. + * + * The result of the operation will be in lo. If the operation is impossible, + * hi will be nonzero. This is used to indicate an error. + */ +static inline void +_mpd_get_msdigits(mpd_uint_t *hi, mpd_uint_t *lo, const mpd_t *dec, + unsigned int n) +{ + mpd_uint_t r, tmp; + + assert(0 < n && n <= MPD_RDIGITS+1); + + _mpd_div_word(&tmp, &r, dec->digits, MPD_RDIGITS); + r = (r == 0) ? MPD_RDIGITS : r; /* digits in the most significant word */ + + *hi = 0; + *lo = dec->data[dec->len-1]; + if (n <= r) { + *lo /= mpd_pow10[r-n]; + } + else if (dec->len > 1) { + /* at this point 1 <= r < n <= MPD_RDIGITS+1 */ + _mpd_mul_words(hi, lo, *lo, mpd_pow10[n-r]); + tmp = dec->data[dec->len-2] / mpd_pow10[MPD_RDIGITS-(n-r)]; + *lo = *lo + tmp; + if (*lo < tmp) (*hi)++; + } +} + + +/******************************************************************************/ +/* Gathering information about a decimal */ +/******************************************************************************/ + +/* The real size of the coefficient without leading zero words. */ +static inline mpd_ssize_t +_mpd_real_size(mpd_uint_t *data, mpd_ssize_t size) +{ + while (size > 1 && data[size-1] == 0) { + size--; + } + + return size; +} + +/* Return number of trailing zeros. No errors are possible. */ +mpd_ssize_t +mpd_trail_zeros(const mpd_t *dec) +{ + mpd_uint_t word; + mpd_ssize_t i, tz = 0; + + for (i=0; i < dec->len; ++i) { + if (dec->data[i] != 0) { + word = dec->data[i]; + tz = i * MPD_RDIGITS; + while (word % 10 == 0) { + word /= 10; + tz++; + } + break; + } + } + + return tz; +} + +/* Integer: Undefined for specials */ +static int +_mpd_isint(const mpd_t *dec) +{ + mpd_ssize_t tz; + + if (mpd_iszerocoeff(dec)) { + return 1; + } + + tz = mpd_trail_zeros(dec); + return (dec->exp + tz >= 0); +} + +/* Integer */ +int +mpd_isinteger(const mpd_t *dec) +{ + if (mpd_isspecial(dec)) { + return 0; + } + return _mpd_isint(dec); +} + +/* Word is a power of 10 */ +static int +mpd_word_ispow10(mpd_uint_t word) +{ + int n; + + n = mpd_word_digits(word); + if (word == mpd_pow10[n-1]) { + return 1; + } + + return 0; +} + +/* Coefficient is a power of 10 */ +static int +mpd_coeff_ispow10(const mpd_t *dec) +{ + if (mpd_word_ispow10(mpd_msword(dec))) { + if (_mpd_isallzero(dec->data, dec->len-1)) { + return 1; + } + } + + return 0; +} + +/* All digits of a word are nines */ +static int +mpd_word_isallnine(mpd_uint_t word) +{ + int n; + + n = mpd_word_digits(word); + if (word == mpd_pow10[n]-1) { + return 1; + } + + return 0; +} + +/* All digits of the coefficient are nines */ +static int +mpd_coeff_isallnine(const mpd_t *dec) +{ + if (mpd_word_isallnine(mpd_msword(dec))) { + if (_mpd_isallnine(dec->data, dec->len-1)) { + return 1; + } + } + + return 0; +} + +/* Odd decimal: Undefined for non-integers! */ +int +mpd_isodd(const mpd_t *dec) +{ + mpd_uint_t q, r; + assert(mpd_isinteger(dec)); + if (mpd_iszerocoeff(dec)) return 0; + if (dec->exp < 0) { + _mpd_div_word(&q, &r, -dec->exp, MPD_RDIGITS); + q = dec->data[q] / mpd_pow10[r]; + return mpd_isoddword(q); + } + return dec->exp == 0 && mpd_isoddword(dec->data[0]); +} + +/* Even: Undefined for non-integers! */ +int +mpd_iseven(const mpd_t *dec) +{ + return !mpd_isodd(dec); +} + +/******************************************************************************/ +/* Getting and setting decimals */ +/******************************************************************************/ + +/* Internal function: Set a static decimal from a triple, no error checking. */ +static void +_ssettriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp) +{ + mpd_set_flags(result, sign); + result->exp = exp; + _mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX); + result->len = (result->data[1] == 0) ? 1 : 2; + mpd_setdigits(result); +} + +/* Internal function: Set a decimal from a triple, no error checking. */ +static void +_settriple(mpd_t *result, uint8_t sign, mpd_uint_t a, mpd_ssize_t exp) +{ + mpd_minalloc(result); + mpd_set_flags(result, sign); + result->exp = exp; + _mpd_div_word(&result->data[1], &result->data[0], a, MPD_RADIX); + result->len = (result->data[1] == 0) ? 1 : 2; + mpd_setdigits(result); +} + +/* Set a special number from a triple */ +void +mpd_setspecial(mpd_t *result, uint8_t sign, uint8_t type) +{ + mpd_minalloc(result); + result->flags &= ~(MPD_NEG|MPD_SPECIAL); + result->flags |= (sign|type); + result->exp = result->digits = result->len = 0; +} + +/* Set result of NaN with an error status */ +void +mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status) +{ + mpd_minalloc(result); + mpd_set_qnan(result); + mpd_set_positive(result); + result->exp = result->digits = result->len = 0; + *status |= flags; +} + +/* quietly set a static decimal from an mpd_ssize_t */ +void +mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_uint_t u; + uint8_t sign = MPD_POS; + + if (a < 0) { + if (a == MPD_SSIZE_MIN) { + u = (mpd_uint_t)MPD_SSIZE_MAX + + (-(MPD_SSIZE_MIN+MPD_SSIZE_MAX)); + } + else { + u = -a; + } + sign = MPD_NEG; + } + else { + u = a; + } + _ssettriple(result, sign, u, 0); + mpd_qfinalize(result, ctx, status); +} + +/* quietly set a static decimal from an mpd_uint_t */ +void +mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + _ssettriple(result, MPD_POS, a, 0); + mpd_qfinalize(result, ctx, status); +} + +/* quietly set a static decimal from an int32_t */ +void +mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qsset_ssize(result, a, ctx, status); +} + +/* quietly set a static decimal from a uint32_t */ +void +mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qsset_uint(result, a, ctx, status); +} + +#ifdef CONFIG_64 +/* quietly set a static decimal from an int64_t */ +void +mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qsset_ssize(result, a, ctx, status); +} + +/* quietly set a static decimal from a uint64_t */ +void +mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qsset_uint(result, a, ctx, status); +} +#endif + +/* quietly set a decimal from an mpd_ssize_t */ +void +mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_minalloc(result); + mpd_qsset_ssize(result, a, ctx, status); +} + +/* quietly set a decimal from an mpd_uint_t */ +void +mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + _settriple(result, MPD_POS, a, 0); + mpd_qfinalize(result, ctx, status); +} + +/* quietly set a decimal from an int32_t */ +void +mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qset_ssize(result, a, ctx, status); +} + +/* quietly set a decimal from a uint32_t */ +void +mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_qset_uint(result, a, ctx, status); +} + +#if defined(CONFIG_32) && !defined(LEGACY_COMPILER) +/* set a decimal from a uint64_t */ +static void +_c32setu64(mpd_t *result, uint64_t u, uint8_t sign, uint32_t *status) +{ + mpd_uint_t w[3]; + uint64_t q; + int i, len; + + len = 0; + do { + q = u / MPD_RADIX; + w[len] = (mpd_uint_t)(u - q * MPD_RADIX); + u = q; len++; + } while (u != 0); + + if (!mpd_qresize(result, len, status)) { + return; + } + for (i = 0; i < len; i++) { + result->data[i] = w[i]; + } + + mpd_set_sign(result, sign); + result->exp = 0; + result->len = len; + mpd_setdigits(result); +} + +static void +_c32_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + _c32setu64(result, a, MPD_POS, status); + mpd_qfinalize(result, ctx, status); +} + +/* set a decimal from an int64_t */ +static void +_c32_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ + uint64_t u; + uint8_t sign = MPD_POS; + + if (a < 0) { + if (a == INT64_MIN) { + u = (uint64_t)INT64_MAX + (-(INT64_MIN+INT64_MAX)); + } + else { + u = -a; + } + sign = MPD_NEG; + } + else { + u = a; + } + _c32setu64(result, u, sign, status); + mpd_qfinalize(result, ctx, status); +} +#endif /* CONFIG_32 && !LEGACY_COMPILER */ + +#ifndef LEGACY_COMPILER +/* quietly set a decimal from an int64_t */ +void +mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ +#ifdef CONFIG_64 + mpd_qset_ssize(result, a, ctx, status); +#else + _c32_qset_i64(result, a, ctx, status); +#endif +} + +/* quietly set a decimal from a uint64_t */ +void +mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, + uint32_t *status) +{ +#ifdef CONFIG_64 + mpd_qset_uint(result, a, ctx, status); +#else + _c32_qset_u64(result, a, ctx, status); +#endif +} +#endif /* !LEGACY_COMPILER */ + + +/* + * Quietly get an mpd_uint_t from a decimal. Assumes + * MPD_UINT_DIGITS == MPD_RDIGITS+1, which is true for + * 32 and 64 bit machines. + * + * If the operation is impossible, MPD_Invalid_operation is set. + */ +static mpd_uint_t +_mpd_qget_uint(int use_sign, const mpd_t *a, uint32_t *status) +{ + mpd_t tmp; + mpd_uint_t tmp_data[2]; + mpd_uint_t lo, hi; + + if (mpd_isspecial(a)) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + if (mpd_iszero(a)) { + return 0; + } + if (use_sign && mpd_isnegative(a)) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + + if (a->digits+a->exp > MPD_RDIGITS+1) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + + if (a->exp < 0) { + if (!_mpd_isint(a)) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + /* At this point a->digits+a->exp <= MPD_RDIGITS+1, + * so the shift fits. */ + tmp.data = tmp_data; + tmp.flags = MPD_STATIC|MPD_CONST_DATA; + mpd_qsshiftr(&tmp, a, -a->exp); + tmp.exp = 0; + a = &tmp; + } + + _mpd_get_msdigits(&hi, &lo, a, MPD_RDIGITS+1); + if (hi) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + + if (a->exp > 0) { + _mpd_mul_words(&hi, &lo, lo, mpd_pow10[a->exp]); + if (hi) { + *status |= MPD_Invalid_operation; + return MPD_UINT_MAX; + } + } + + return lo; +} + +/* + * Sets Invalid_operation for: + * - specials + * - negative numbers (except negative zero) + * - non-integers + * - overflow + */ +mpd_uint_t +mpd_qget_uint(const mpd_t *a, uint32_t *status) +{ + return _mpd_qget_uint(1, a, status); +} + +/* Same as above, but gets the absolute value, i.e. the sign is ignored. */ +mpd_uint_t +mpd_qabs_uint(const mpd_t *a, uint32_t *status) +{ + return _mpd_qget_uint(0, a, status); +} + +/* quietly get an mpd_ssize_t from a decimal */ +mpd_ssize_t +mpd_qget_ssize(const mpd_t *a, uint32_t *status) +{ + mpd_uint_t u; + int isneg; + + u = mpd_qabs_uint(a, status); + if (*status&MPD_Invalid_operation) { + return MPD_SSIZE_MAX; + } + + isneg = mpd_isnegative(a); + if (u <= MPD_SSIZE_MAX) { + return isneg ? -((mpd_ssize_t)u) : (mpd_ssize_t)u; + } + else if (isneg && u-1 == MPD_SSIZE_MAX) { + return MPD_SSIZE_MIN; + } + + *status |= MPD_Invalid_operation; + return MPD_SSIZE_MAX; +} + +#ifdef CONFIG_64 +/* quietly get a uint64_t from a decimal */ +uint64_t +mpd_qget_u64(const mpd_t *a, uint32_t *status) +{ + return mpd_qget_uint(a, status); +} + +/* quietly get an int64_t from a decimal */ +int64_t +mpd_qget_i64(const mpd_t *a, uint32_t *status) +{ + return mpd_qget_ssize(a, status); +} +#else +/* quietly get a uint32_t from a decimal */ +uint32_t +mpd_qget_u32(const mpd_t *a, uint32_t *status) +{ + return mpd_qget_uint(a, status); +} + +/* quietly get an int32_t from a decimal */ +int32_t +mpd_qget_i32(const mpd_t *a, uint32_t *status) +{ + return mpd_qget_ssize(a, status); +} +#endif + + +/******************************************************************************/ +/* Filtering input of functions, finalizing output of functions */ +/******************************************************************************/ + +/* + * Check if the operand is NaN, copy to result and return 1 if this is + * the case. Copying can fail since NaNs are allowed to have a payload that + * does not fit in MPD_MINALLOC. + */ +int +mpd_qcheck_nan(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isnan(a)) { + *status |= mpd_issnan(a) ? MPD_Invalid_operation : 0; + mpd_qcopy(result, a, status); + mpd_set_qnan(result); + _mpd_fix_nan(result, ctx); + return 1; + } + return 0; +} + +/* + * Check if either operand is NaN, copy to result and return 1 if this + * is the case. Copying can fail since NaNs are allowed to have a payload + * that does not fit in MPD_MINALLOC. + */ +int +mpd_qcheck_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + if ((a->flags|b->flags)&(MPD_NAN|MPD_SNAN)) { + const mpd_t *choice = b; + if (mpd_issnan(a)) { + choice = a; + *status |= MPD_Invalid_operation; + } + else if (mpd_issnan(b)) { + *status |= MPD_Invalid_operation; + } + else if (mpd_isqnan(a)) { + choice = a; + } + mpd_qcopy(result, choice, status); + mpd_set_qnan(result); + _mpd_fix_nan(result, ctx); + return 1; + } + return 0; +} + +/* + * Check if one of the operands is NaN, copy to result and return 1 if this + * is the case. Copying can fail since NaNs are allowed to have a payload + * that does not fit in MPD_MINALLOC. + */ +static int +mpd_qcheck_3nans(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, + const mpd_context_t *ctx, uint32_t *status) +{ + if ((a->flags|b->flags|c->flags)&(MPD_NAN|MPD_SNAN)) { + const mpd_t *choice = c; + if (mpd_issnan(a)) { + choice = a; + *status |= MPD_Invalid_operation; + } + else if (mpd_issnan(b)) { + choice = b; + *status |= MPD_Invalid_operation; + } + else if (mpd_issnan(c)) { + *status |= MPD_Invalid_operation; + } + else if (mpd_isqnan(a)) { + choice = a; + } + else if (mpd_isqnan(b)) { + choice = b; + } + mpd_qcopy(result, choice, status); + mpd_set_qnan(result); + _mpd_fix_nan(result, ctx); + return 1; + } + return 0; +} + +/* Check if rounding digit 'rnd' leads to an increment. */ +static inline int +_mpd_rnd_incr(const mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx) +{ + int ld; + + switch (ctx->round) { + case MPD_ROUND_DOWN: case MPD_ROUND_TRUNC: + return 0; + case MPD_ROUND_HALF_UP: + return (rnd >= 5); + case MPD_ROUND_HALF_EVEN: + return (rnd > 5) || ((rnd == 5) && mpd_isoddcoeff(dec)); + case MPD_ROUND_CEILING: + return !(rnd == 0 || mpd_isnegative(dec)); + case MPD_ROUND_FLOOR: + return !(rnd == 0 || mpd_ispositive(dec)); + case MPD_ROUND_HALF_DOWN: + return (rnd > 5); + case MPD_ROUND_UP: + return !(rnd == 0); + case MPD_ROUND_05UP: + ld = (int)mpd_lsd(dec->data[0]); + return (!(rnd == 0) && (ld == 0 || ld == 5)); + default: + /* Without a valid context, further results will be undefined. */ + return 0; /* GCOV_NOT_REACHED */ + } +} + +/* + * Apply rounding to a decimal that has been right-shifted into a full + * precision decimal. If an increment leads to an overflow of the precision, + * adjust the coefficient and the exponent and check the new exponent for + * overflow. + */ +static inline void +_mpd_apply_round(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx, + uint32_t *status) +{ + if (_mpd_rnd_incr(dec, rnd, ctx)) { + /* We have a number with exactly ctx->prec digits. The increment + * can only lead to an overflow if the decimal is all nines. In + * that case, the result is a power of ten with prec+1 digits. + * + * If the precision is a multiple of MPD_RDIGITS, this situation is + * detected by _mpd_baseincr returning a carry. + * If the precision is not a multiple of MPD_RDIGITS, we have to + * check if the result has one digit too many. + */ + mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len); + if (carry) { + dec->data[dec->len-1] = mpd_pow10[MPD_RDIGITS-1]; + dec->exp += 1; + _mpd_check_exp(dec, ctx, status); + return; + } + mpd_setdigits(dec); + if (dec->digits > ctx->prec) { + mpd_qshiftr_inplace(dec, 1); + dec->exp += 1; + dec->digits = ctx->prec; + _mpd_check_exp(dec, ctx, status); + } + } +} + +/* + * Apply rounding to a decimal. Allow overflow of the precision. + */ +static inline void +_mpd_apply_round_excess(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx, + uint32_t *status) +{ + if (_mpd_rnd_incr(dec, rnd, ctx)) { + mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len); + if (carry) { + if (!mpd_qresize(dec, dec->len+1, status)) { + return; + } + dec->data[dec->len] = 1; + dec->len += 1; + } + mpd_setdigits(dec); + } +} + +/* + * Apply rounding to a decimal that has been right-shifted into a decimal + * with full precision or less. Return failure if an increment would + * overflow the precision. + */ +static inline int +_mpd_apply_round_fit(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx, + uint32_t *status) +{ + if (_mpd_rnd_incr(dec, rnd, ctx)) { + mpd_uint_t carry = _mpd_baseincr(dec->data, dec->len); + if (carry) { + if (!mpd_qresize(dec, dec->len+1, status)) { + return 0; + } + dec->data[dec->len] = 1; + dec->len += 1; + } + mpd_setdigits(dec); + if (dec->digits > ctx->prec) { + mpd_seterror(dec, MPD_Invalid_operation, status); + return 0; + } + } + return 1; +} + +/* Check a normal number for overflow, underflow, clamping. If the operand + is modified, it will be zero, special or (sub)normal with a coefficient + that fits into the current context precision. */ +static inline void +_mpd_check_exp(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t adjexp, etiny, shift; + int rnd; + + adjexp = mpd_adjexp(dec); + if (adjexp > ctx->emax) { + + if (mpd_iszerocoeff(dec)) { + dec->exp = ctx->emax; + if (ctx->clamp) { + dec->exp -= (ctx->prec-1); + } + mpd_zerocoeff(dec); + *status |= MPD_Clamped; + return; + } + + switch (ctx->round) { + case MPD_ROUND_HALF_UP: case MPD_ROUND_HALF_EVEN: + case MPD_ROUND_HALF_DOWN: case MPD_ROUND_UP: + case MPD_ROUND_TRUNC: + mpd_setspecial(dec, mpd_sign(dec), MPD_INF); + break; + case MPD_ROUND_DOWN: case MPD_ROUND_05UP: + mpd_qmaxcoeff(dec, ctx, status); + dec->exp = ctx->emax - ctx->prec + 1; + break; + case MPD_ROUND_CEILING: + if (mpd_isnegative(dec)) { + mpd_qmaxcoeff(dec, ctx, status); + dec->exp = ctx->emax - ctx->prec + 1; + } + else { + mpd_setspecial(dec, MPD_POS, MPD_INF); + } + break; + case MPD_ROUND_FLOOR: + if (mpd_ispositive(dec)) { + mpd_qmaxcoeff(dec, ctx, status); + dec->exp = ctx->emax - ctx->prec + 1; + } + else { + mpd_setspecial(dec, MPD_NEG, MPD_INF); + } + break; + default: /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + + *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded; + + } /* fold down */ + else if (ctx->clamp && dec->exp > mpd_etop(ctx)) { + /* At this point adjexp=exp+digits-1 <= emax and exp > etop=emax-prec+1: + * (1) shift = exp -emax+prec-1 > 0 + * (2) digits+shift = exp+digits-1 - emax + prec <= prec */ + shift = dec->exp - mpd_etop(ctx); + if (!mpd_qshiftl(dec, dec, shift, status)) { + return; + } + dec->exp -= shift; + *status |= MPD_Clamped; + if (!mpd_iszerocoeff(dec) && adjexp < ctx->emin) { + /* Underflow is impossible, since exp < etiny=emin-prec+1 + * and exp > etop=emax-prec+1 would imply emax < emin. */ + *status |= MPD_Subnormal; + } + } + else if (adjexp < ctx->emin) { + + etiny = mpd_etiny(ctx); + + if (mpd_iszerocoeff(dec)) { + if (dec->exp < etiny) { + dec->exp = etiny; + mpd_zerocoeff(dec); + *status |= MPD_Clamped; + } + return; + } + + *status |= MPD_Subnormal; + if (dec->exp < etiny) { + /* At this point adjexp=exp+digits-1 < emin and exp < etiny=emin-prec+1: + * (1) shift = emin-prec+1 - exp > 0 + * (2) digits-shift = exp+digits-1 - emin + prec < prec */ + shift = etiny - dec->exp; + rnd = (int)mpd_qshiftr_inplace(dec, shift); + dec->exp = etiny; + /* We always have a spare digit in case of an increment. */ + _mpd_apply_round_excess(dec, rnd, ctx, status); + *status |= MPD_Rounded; + if (rnd) { + *status |= (MPD_Inexact|MPD_Underflow); + if (mpd_iszerocoeff(dec)) { + mpd_zerocoeff(dec); + *status |= MPD_Clamped; + } + } + } + /* Case exp >= etiny=emin-prec+1: + * (1) adjexp=exp+digits-1 < emin + * (2) digits < emin-exp+1 <= prec */ + } +} + +/* Transcendental functions do not always set Underflow reliably, + * since they only use as much precision as is necessary for correct + * rounding. If a result like 1.0000000000e-101 is finalized, there + * is no rounding digit that would trigger Underflow. But we can + * assume Inexact, so a short check suffices. */ +static inline void +mpd_check_underflow(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_adjexp(dec) < ctx->emin && !mpd_iszero(dec) && + dec->exp < mpd_etiny(ctx)) { + *status |= MPD_Underflow; + } +} + +/* Check if a normal number must be rounded after the exponent has been checked. */ +static inline void +_mpd_check_round(mpd_t *dec, const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t rnd; + mpd_ssize_t shift; + + /* must handle specials: _mpd_check_exp() can produce infinities or NaNs */ + if (mpd_isspecial(dec)) { + return; + } + + if (dec->digits > ctx->prec) { + shift = dec->digits - ctx->prec; + rnd = mpd_qshiftr_inplace(dec, shift); + dec->exp += shift; + _mpd_apply_round(dec, rnd, ctx, status); + *status |= MPD_Rounded; + if (rnd) { + *status |= MPD_Inexact; + } + } +} + +/* Finalize all operations. */ +void +mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_isspecial(result)) { + if (mpd_isnan(result)) { + _mpd_fix_nan(result, ctx); + } + return; + } + + _mpd_check_exp(result, ctx, status); + _mpd_check_round(result, ctx, status); +} + + +/******************************************************************************/ +/* Copying */ +/******************************************************************************/ + +/* Internal function: Copy a decimal, share data with src: USE WITH CARE! */ +static inline void +_mpd_copy_shared(mpd_t *dest, const mpd_t *src) +{ + dest->flags = src->flags; + dest->exp = src->exp; + dest->digits = src->digits; + dest->len = src->len; + dest->alloc = src->alloc; + dest->data = src->data; + + mpd_set_shared_data(dest); +} + +/* + * Copy a decimal. In case of an error, status is set to MPD_Malloc_error. + */ +int +mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status) +{ + if (result == a) return 1; + + if (!mpd_qresize(result, a->len, status)) { + return 0; + } + + mpd_copy_flags(result, a); + result->exp = a->exp; + result->digits = a->digits; + result->len = a->len; + memcpy(result->data, a->data, a->len * (sizeof *result->data)); + + return 1; +} + +/* + * Copy to a decimal with a static buffer. The caller has to make sure that + * the buffer is big enough. Cannot fail. + */ +static void +mpd_qcopy_static(mpd_t *result, const mpd_t *a) +{ + if (result == a) return; + + memcpy(result->data, a->data, a->len * (sizeof *result->data)); + + mpd_copy_flags(result, a); + result->exp = a->exp; + result->digits = a->digits; + result->len = a->len; +} + +/* + * Return a newly allocated copy of the operand. In case of an error, + * status is set to MPD_Malloc_error and the return value is NULL. + */ +mpd_t * +mpd_qncopy(const mpd_t *a) +{ + mpd_t *result; + + if ((result = mpd_qnew_size(a->len)) == NULL) { + return NULL; + } + memcpy(result->data, a->data, a->len * (sizeof *result->data)); + mpd_copy_flags(result, a); + result->exp = a->exp; + result->digits = a->digits; + result->len = a->len; + + return result; +} + +/* + * Copy a decimal and set the sign to positive. In case of an error, the + * status is set to MPD_Malloc_error. + */ +int +mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status) +{ + if (!mpd_qcopy(result, a, status)) { + return 0; + } + mpd_set_positive(result); + return 1; +} + +/* + * Copy a decimal and negate the sign. In case of an error, the + * status is set to MPD_Malloc_error. + */ +int +mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status) +{ + if (!mpd_qcopy(result, a, status)) { + return 0; + } + _mpd_negate(result); + return 1; +} + +/* + * Copy a decimal, setting the sign of the first operand to the sign of the + * second operand. In case of an error, the status is set to MPD_Malloc_error. + */ +int +mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status) +{ + uint8_t sign_b = mpd_sign(b); /* result may equal b! */ + + if (!mpd_qcopy(result, a, status)) { + return 0; + } + mpd_set_sign(result, sign_b); + return 1; +} + + +/******************************************************************************/ +/* Comparisons */ +/******************************************************************************/ + +/* + * For all functions that compare two operands and return an int the usual + * convention applies to the return value: + * + * -1 if op1 < op2 + * 0 if op1 == op2 + * 1 if op1 > op2 + * + * INT_MAX for error + */ + + +/* Convenience macro. If a and b are not equal, return from the calling + * function with the correct comparison value. */ +#define CMP_EQUAL_OR_RETURN(a, b) \ + if (a != b) { \ + if (a < b) { \ + return -1; \ + } \ + return 1; \ + } + +/* + * Compare the data of big and small. This function does the equivalent + * of first shifting small to the left and then comparing the data of + * big and small, except that no allocation for the left shift is needed. + */ +static int +_mpd_basecmp(mpd_uint_t *big, mpd_uint_t *small, mpd_size_t n, mpd_size_t m, + mpd_size_t shift) +{ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) + /* spurious uninitialized warnings */ + mpd_uint_t l=l, lprev=lprev, h=h; +#else + mpd_uint_t l, lprev, h; +#endif + mpd_uint_t q, r; + mpd_uint_t ph, x; + + assert(m > 0 && n >= m && shift > 0); + + _mpd_div_word(&q, &r, (mpd_uint_t)shift, MPD_RDIGITS); + + if (r != 0) { + + ph = mpd_pow10[r]; + + --m; --n; + _mpd_divmod_pow10(&h, &lprev, small[m--], MPD_RDIGITS-r); + if (h != 0) { + CMP_EQUAL_OR_RETURN(big[n], h) + --n; + } + for (; m != MPD_SIZE_MAX; m--,n--) { + _mpd_divmod_pow10(&h, &l, small[m], MPD_RDIGITS-r); + x = ph * lprev + h; + CMP_EQUAL_OR_RETURN(big[n], x) + lprev = l; + } + x = ph * lprev; + CMP_EQUAL_OR_RETURN(big[q], x) + } + else { + while (--m != MPD_SIZE_MAX) { + CMP_EQUAL_OR_RETURN(big[m+q], small[m]) + } + } + + return !_mpd_isallzero(big, q); +} + +/* Compare two decimals with the same adjusted exponent. */ +static int +_mpd_cmp_same_adjexp(const mpd_t *a, const mpd_t *b) +{ + mpd_ssize_t shift, i; + + if (a->exp != b->exp) { + /* Cannot wrap: a->exp + a->digits = b->exp + b->digits, so + * a->exp - b->exp = b->digits - a->digits. */ + shift = a->exp - b->exp; + if (shift > 0) { + return -1 * _mpd_basecmp(b->data, a->data, b->len, a->len, shift); + } + else { + return _mpd_basecmp(a->data, b->data, a->len, b->len, -shift); + } + } + + /* + * At this point adjexp(a) == adjexp(b) and a->exp == b->exp, + * so a->digits == b->digits, therefore a->len == b->len. + */ + for (i = a->len-1; i >= 0; --i) { + CMP_EQUAL_OR_RETURN(a->data[i], b->data[i]) + } + + return 0; +} + +/* Compare two numerical values. */ +static int +_mpd_cmp(const mpd_t *a, const mpd_t *b) +{ + mpd_ssize_t adjexp_a, adjexp_b; + + /* equal pointers */ + if (a == b) { + return 0; + } + + /* infinities */ + if (mpd_isinfinite(a)) { + if (mpd_isinfinite(b)) { + return mpd_isnegative(b) - mpd_isnegative(a); + } + return mpd_arith_sign(a); + } + if (mpd_isinfinite(b)) { + return -mpd_arith_sign(b); + } + + /* zeros */ + if (mpd_iszerocoeff(a)) { + if (mpd_iszerocoeff(b)) { + return 0; + } + return -mpd_arith_sign(b); + } + if (mpd_iszerocoeff(b)) { + return mpd_arith_sign(a); + } + + /* different signs */ + if (mpd_sign(a) != mpd_sign(b)) { + return mpd_sign(b) - mpd_sign(a); + } + + /* different adjusted exponents */ + adjexp_a = mpd_adjexp(a); + adjexp_b = mpd_adjexp(b); + if (adjexp_a != adjexp_b) { + if (adjexp_a < adjexp_b) { + return -1 * mpd_arith_sign(a); + } + return mpd_arith_sign(a); + } + + /* same adjusted exponents */ + return _mpd_cmp_same_adjexp(a, b) * mpd_arith_sign(a); +} + +/* Compare the absolutes of two numerical values. */ +static int +_mpd_cmp_abs(const mpd_t *a, const mpd_t *b) +{ + mpd_ssize_t adjexp_a, adjexp_b; + + /* equal pointers */ + if (a == b) { + return 0; + } + + /* infinities */ + if (mpd_isinfinite(a)) { + if (mpd_isinfinite(b)) { + return 0; + } + return 1; + } + if (mpd_isinfinite(b)) { + return -1; + } + + /* zeros */ + if (mpd_iszerocoeff(a)) { + if (mpd_iszerocoeff(b)) { + return 0; + } + return -1; + } + if (mpd_iszerocoeff(b)) { + return 1; + } + + /* different adjusted exponents */ + adjexp_a = mpd_adjexp(a); + adjexp_b = mpd_adjexp(b); + if (adjexp_a != adjexp_b) { + if (adjexp_a < adjexp_b) { + return -1; + } + return 1; + } + + /* same adjusted exponents */ + return _mpd_cmp_same_adjexp(a, b); +} + +/* Compare two values and return an integer result. */ +int +mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status) +{ + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_isnan(a) || mpd_isnan(b)) { + *status |= MPD_Invalid_operation; + return INT_MAX; + } + } + + return _mpd_cmp(a, b); +} + +/* + * Compare a and b, convert the the usual integer result to a decimal and + * store it in 'result'. For convenience, the integer result of the comparison + * is returned. Comparisons involving NaNs return NaN/INT_MAX. + */ +int +mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return INT_MAX; + } + } + + c = _mpd_cmp(a, b); + _settriple(result, (c < 0), (c != 0), 0); + return c; +} + +/* Same as mpd_compare(), but signal for all NaNs, i.e. also for quiet NaNs. */ +int +mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + *status |= MPD_Invalid_operation; + return INT_MAX; + } + } + + c = _mpd_cmp(a, b); + _settriple(result, (c < 0), (c != 0), 0); + return c; +} + +/* Compare the operands using a total order. */ +int +mpd_cmp_total(const mpd_t *a, const mpd_t *b) +{ + mpd_t aa, bb; + int nan_a, nan_b; + int c; + + if (mpd_sign(a) != mpd_sign(b)) { + return mpd_sign(b) - mpd_sign(a); + } + + + if (mpd_isnan(a)) { + c = 1; + if (mpd_isnan(b)) { + nan_a = (mpd_isqnan(a)) ? 1 : 0; + nan_b = (mpd_isqnan(b)) ? 1 : 0; + if (nan_b == nan_a) { + if (a->len > 0 && b->len > 0) { + _mpd_copy_shared(&aa, a); + _mpd_copy_shared(&bb, b); + aa.exp = bb.exp = 0; + /* compare payload */ + c = _mpd_cmp_abs(&aa, &bb); + } + else { + c = (a->len > 0) - (b->len > 0); + } + } + else { + c = nan_a - nan_b; + } + } + } + else if (mpd_isnan(b)) { + c = -1; + } + else { + c = _mpd_cmp_abs(a, b); + if (c == 0 && a->exp != b->exp) { + c = (a->exp < b->exp) ? -1 : 1; + } + } + + return c * mpd_arith_sign(a); +} + +/* + * Compare a and b according to a total order, convert the usual integer result + * to a decimal and store it in 'result'. For convenience, the integer result + * of the comparison is returned. + */ +int +mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b) +{ + int c; + + c = mpd_cmp_total(a, b); + _settriple(result, (c < 0), (c != 0), 0); + return c; +} + +/* Compare the magnitude of the operands using a total order. */ +int +mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b) +{ + mpd_t aa, bb; + + _mpd_copy_shared(&aa, a); + _mpd_copy_shared(&bb, b); + + mpd_set_positive(&aa); + mpd_set_positive(&bb); + + return mpd_cmp_total(&aa, &bb); +} + +/* + * Compare the magnitude of a and b according to a total order, convert the + * the usual integer result to a decimal and store it in 'result'. + * For convenience, the integer result of the comparison is returned. + */ +int +mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b) +{ + int c; + + c = mpd_cmp_total_mag(a, b); + _settriple(result, (c < 0), (c != 0), 0); + return c; +} + +/* Determine an ordering for operands that are numerically equal. */ +static inline int +_mpd_cmp_numequal(const mpd_t *a, const mpd_t *b) +{ + int sign_a, sign_b; + int c; + + sign_a = mpd_sign(a); + sign_b = mpd_sign(b); + if (sign_a != sign_b) { + c = sign_b - sign_a; + } + else { + c = (a->exp < b->exp) ? -1 : 1; + c *= mpd_arith_sign(a); + } + + return c; +} + + +/******************************************************************************/ +/* Shifting the coefficient */ +/******************************************************************************/ + +/* + * Shift the coefficient of the operand to the left, no check for specials. + * Both operands may be the same pointer. If the result length has to be + * increased, mpd_qresize() might fail with MPD_Malloc_error. + */ +int +mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status) +{ + mpd_ssize_t size; + + assert(n >= 0); + + if (mpd_iszerocoeff(a) || n == 0) { + return mpd_qcopy(result, a, status); + } + + size = mpd_digits_to_size(a->digits+n); + if (!mpd_qresize(result, size, status)) { + return 0; /* result is NaN */ + } + + _mpd_baseshiftl(result->data, a->data, size, a->len, n); + + mpd_copy_flags(result, a); + result->len = size; + result->exp = a->exp; + result->digits = a->digits+n; + + return 1; +} + +/* Determine the rounding indicator if all digits of the coefficient are shifted + * out of the picture. */ +static mpd_uint_t +_mpd_get_rnd(const mpd_uint_t *data, mpd_ssize_t len, int use_msd) +{ + mpd_uint_t rnd = 0, rest = 0, word; + + word = data[len-1]; + /* special treatment for the most significant digit if shift == digits */ + if (use_msd) { + _mpd_divmod_pow10(&rnd, &rest, word, mpd_word_digits(word)-1); + if (len > 1 && rest == 0) { + rest = !_mpd_isallzero(data, len-1); + } + } + else { + rest = !_mpd_isallzero(data, len); + } + + return (rnd == 0 || rnd == 5) ? rnd + !!rest : rnd; +} + +/* + * Same as mpd_qshiftr(), but 'result' is a static array. It is the + * caller's responsibility to make sure that the array is big enough. + * The function cannot fail. + */ +mpd_uint_t +mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n) +{ + mpd_uint_t rnd; + mpd_ssize_t size; + + assert(n >= 0); + + if (mpd_iszerocoeff(a) || n == 0) { + mpd_qcopy_static(result, a); + return 0; + } + + if (n >= a->digits) { + rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits)); + mpd_zerocoeff(result); + result->digits = 1; + size = 1; + } + else { + result->digits = a->digits-n; + size = mpd_digits_to_size(result->digits); + rnd = _mpd_baseshiftr(result->data, a->data, a->len, n); + } + + mpd_copy_flags(result, a); + result->exp = a->exp; + result->len = size; + + return rnd; +} + +/* + * Inplace shift of the coefficient to the right, no check for specials. + * Returns the rounding indicator for mpd_rnd_incr(). + * The function cannot fail. + */ +mpd_uint_t +mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n) +{ + uint32_t dummy; + mpd_uint_t rnd; + mpd_ssize_t size; + + assert(n >= 0); + + if (mpd_iszerocoeff(result) || n == 0) { + return 0; + } + + if (n >= result->digits) { + rnd = _mpd_get_rnd(result->data, result->len, (n==result->digits)); + mpd_zerocoeff(result); + result->digits = 1; + size = 1; + } + else { + rnd = _mpd_baseshiftr(result->data, result->data, result->len, n); + result->digits -= n; + size = mpd_digits_to_size(result->digits); + /* reducing the size cannot fail */ + mpd_qresize(result, size, &dummy); + } + + result->len = size; + + return rnd; +} + +/* + * Shift the coefficient of the operand to the right, no check for specials. + * Both operands may be the same pointer. Returns the rounding indicator to + * be used by mpd_rnd_incr(). If the result length has to be increased, + * mpd_qcopy() or mpd_qresize() might fail with MPD_Malloc_error. In those + * cases, MPD_UINT_MAX is returned. + */ +mpd_uint_t +mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status) +{ + mpd_uint_t rnd; + mpd_ssize_t size; + + assert(n >= 0); + + if (mpd_iszerocoeff(a) || n == 0) { + if (!mpd_qcopy(result, a, status)) { + return MPD_UINT_MAX; + } + return 0; + } + + if (n >= a->digits) { + rnd = _mpd_get_rnd(a->data, a->len, (n==a->digits)); + mpd_zerocoeff(result); + result->digits = 1; + size = 1; + } + else { + result->digits = a->digits-n; + size = mpd_digits_to_size(result->digits); + if (result == a) { + rnd = _mpd_baseshiftr(result->data, a->data, a->len, n); + /* reducing the size cannot fail */ + mpd_qresize(result, size, status); + } + else { + if (!mpd_qresize(result, size, status)) { + return MPD_UINT_MAX; + } + rnd = _mpd_baseshiftr(result->data, a->data, a->len, n); + } + } + + mpd_copy_flags(result, a); + result->exp = a->exp; + result->len = size; + + return rnd; +} + + +/******************************************************************************/ +/* Miscellaneous operations */ +/******************************************************************************/ + +/* Logical And */ +void +mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + const mpd_t *big = a, *small = b; + mpd_uint_t x, y, z, xbit, ybit; + int k, mswdigits; + mpd_ssize_t i; + + if (mpd_isspecial(a) || mpd_isspecial(b) || + mpd_isnegative(a) || mpd_isnegative(b) || + a->exp != 0 || b->exp != 0) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (b->digits > a->digits) { + big = b; + small = a; + } + if (!mpd_qresize(result, big->len, status)) { + return; + } + + + /* full words */ + for (i = 0; i < small->len-1; i++) { + x = small->data[i]; + y = big->data[i]; + z = 0; + for (k = 0; k < MPD_RDIGITS; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit&ybit) ? mpd_pow10[k] : 0; + } + result->data[i] = z; + } + /* most significant word of small */ + x = small->data[i]; + y = big->data[i]; + z = 0; + mswdigits = mpd_word_digits(x); + for (k = 0; k < mswdigits; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit&ybit) ? mpd_pow10[k] : 0; + } + result->data[i++] = z; + + /* scan the rest of y for digit > 1 */ + for (; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + } + /* scan the rest of big for digit > 1 */ + for (; i < big->len; i++) { + y = big->data[i]; + for (k = 0; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + } + } + + mpd_clear_flags(result); + result->exp = 0; + result->len = _mpd_real_size(result->data, small->len); + mpd_qresize(result, result->len, status); + mpd_setdigits(result); + _mpd_cap(result, ctx); + return; + +invalid_operation: + mpd_seterror(result, MPD_Invalid_operation, status); +} + +/* Class of an operand. Returns a pointer to the constant name. */ +const char * +mpd_class(const mpd_t *a, const mpd_context_t *ctx) +{ + if (mpd_isnan(a)) { + if (mpd_isqnan(a)) + return "NaN"; + else + return "sNaN"; + } + else if (mpd_ispositive(a)) { + if (mpd_isinfinite(a)) + return "+Infinity"; + else if (mpd_iszero(a)) + return "+Zero"; + else if (mpd_isnormal(a, ctx)) + return "+Normal"; + else + return "+Subnormal"; + } + else { + if (mpd_isinfinite(a)) + return "-Infinity"; + else if (mpd_iszero(a)) + return "-Zero"; + else if (mpd_isnormal(a, ctx)) + return "-Normal"; + else + return "-Subnormal"; + } +} + +/* Logical Xor */ +void +mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_uint_t x, z, xbit; + mpd_ssize_t i, digits, len; + mpd_ssize_t q, r; + int k; + + if (mpd_isspecial(a) || mpd_isnegative(a) || a->exp != 0) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + digits = (a->digits < ctx->prec) ? ctx->prec : a->digits; + _mpd_idiv_word(&q, &r, digits, MPD_RDIGITS); + len = (r == 0) ? q : q+1; + if (!mpd_qresize(result, len, status)) { + return; + } + + for (i = 0; i < len; i++) { + x = (i < a->len) ? a->data[i] : 0; + z = 0; + for (k = 0; k < MPD_RDIGITS; k++) { + xbit = x % 10; + x /= 10; + if (xbit > 1) { + goto invalid_operation; + } + z += !xbit ? mpd_pow10[k] : 0; + } + result->data[i] = z; + } + + mpd_clear_flags(result); + result->exp = 0; + result->len = _mpd_real_size(result->data, len); + mpd_qresize(result, result->len, status); + mpd_setdigits(result); + _mpd_cap(result, ctx); + return; + +invalid_operation: + mpd_seterror(result, MPD_Invalid_operation, status); +} + +/* Exponent of the magnitude of the most significant digit of the operand. */ +void +mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + mpd_setspecial(result, MPD_POS, MPD_INF); + } + else if (mpd_iszerocoeff(a)) { + mpd_setspecial(result, MPD_NEG, MPD_INF); + *status |= MPD_Division_by_zero; + } + else { + mpd_qset_ssize(result, mpd_adjexp(a), ctx, status); + } +} + +/* Logical Or */ +void +mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + const mpd_t *big = a, *small = b; + mpd_uint_t x, y, z, xbit, ybit; + int k, mswdigits; + mpd_ssize_t i; + + if (mpd_isspecial(a) || mpd_isspecial(b) || + mpd_isnegative(a) || mpd_isnegative(b) || + a->exp != 0 || b->exp != 0) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (b->digits > a->digits) { + big = b; + small = a; + } + if (!mpd_qresize(result, big->len, status)) { + return; + } + + + /* full words */ + for (i = 0; i < small->len-1; i++) { + x = small->data[i]; + y = big->data[i]; + z = 0; + for (k = 0; k < MPD_RDIGITS; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit|ybit) ? mpd_pow10[k] : 0; + } + result->data[i] = z; + } + /* most significant word of small */ + x = small->data[i]; + y = big->data[i]; + z = 0; + mswdigits = mpd_word_digits(x); + for (k = 0; k < mswdigits; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit|ybit) ? mpd_pow10[k] : 0; + } + + /* scan and copy the rest of y for digit > 1 */ + for (; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + z += ybit*mpd_pow10[k]; + } + result->data[i++] = z; + /* scan and copy the rest of big for digit > 1 */ + for (; i < big->len; i++) { + y = big->data[i]; + for (k = 0; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + } + result->data[i] = big->data[i]; + } + + mpd_clear_flags(result); + result->exp = 0; + result->len = _mpd_real_size(result->data, big->len); + mpd_qresize(result, result->len, status); + mpd_setdigits(result); + _mpd_cap(result, ctx); + return; + +invalid_operation: + mpd_seterror(result, MPD_Invalid_operation, status); +} + +/* + * Rotate the coefficient of a by b->data digits. b must be an integer with + * exponent 0. + */ +void +mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + MPD_NEW_STATIC(tmp,0,0,0,0); + MPD_NEW_STATIC(big,0,0,0,0); + MPD_NEW_STATIC(small,0,0,0,0); + mpd_ssize_t n, lshift, rshift; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + } + if (b->exp != 0 || mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + n = mpd_qget_ssize(b, &workstatus); + if (workstatus&MPD_Invalid_operation) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (n > ctx->prec || n < -ctx->prec) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(a)) { + mpd_qcopy(result, a, status); + return; + } + + if (n >= 0) { + lshift = n; + rshift = ctx->prec-n; + } + else { + lshift = ctx->prec+n; + rshift = -n; + } + + if (a->digits > ctx->prec) { + if (!mpd_qcopy(&tmp, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + _mpd_cap(&tmp, ctx); + a = &tmp; + } + + if (!mpd_qshiftl(&big, a, lshift, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + _mpd_cap(&big, ctx); + + if (mpd_qshiftr(&small, a, rshift, status) == MPD_UINT_MAX) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + _mpd_qadd(result, &big, &small, ctx, status); + + +finish: + mpd_del(&tmp); + mpd_del(&big); + mpd_del(&small); +} + +/* + * b must be an integer with exponent 0 and in the range +-2*(emax + prec). + * XXX: In my opinion +-(2*emax + prec) would be more sensible. + * The result is a with the value of b added to its exponent. + */ +void +mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_uint_t n, maxjump; +#ifndef LEGACY_COMPILER + int64_t exp; +#else + mpd_uint_t x; + int x_sign, n_sign; + mpd_ssize_t exp; +#endif + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + } + if (b->exp != 0 || mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + n = mpd_qabs_uint(b, &workstatus); + /* the spec demands this */ + maxjump = 2 * (mpd_uint_t)(ctx->emax + ctx->prec); + + if (n > maxjump || workstatus&MPD_Invalid_operation) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(a)) { + mpd_qcopy(result, a, status); + return; + } + +#ifndef LEGACY_COMPILER + exp = a->exp + (int64_t)n * mpd_arith_sign(b); + exp = (exp > MPD_EXP_INF) ? MPD_EXP_INF : exp; + exp = (exp < MPD_EXP_CLAMP) ? MPD_EXP_CLAMP : exp; +#else + x = (a->exp < 0) ? -a->exp : a->exp; + x_sign = (a->exp < 0) ? 1 : 0; + n_sign = mpd_isnegative(b) ? 1 : 0; + + if (x_sign == n_sign) { + x = x + n; + if (x < n) x = MPD_UINT_MAX; + } + else { + x_sign = (x >= n) ? x_sign : n_sign; + x = (x >= n) ? x - n : n - x; + } + if (!x_sign && x > MPD_EXP_INF) x = MPD_EXP_INF; + if (x_sign && x > -MPD_EXP_CLAMP) x = -MPD_EXP_CLAMP; + exp = x_sign ? -((mpd_ssize_t)x) : (mpd_ssize_t)x; +#endif + + mpd_qcopy(result, a, status); + result->exp = (mpd_ssize_t)exp; + + mpd_qfinalize(result, ctx, status); +} + +/* + * Shift the coefficient by n digits, positive n is a left shift. In the case + * of a left shift, the result is decapitated to fit the context precision. If + * you don't want that, use mpd_shiftl(). + */ +void +mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + mpd_qcopy(result, a, status); + return; + } + + if (n >= 0 && n <= ctx->prec) { + mpd_qshiftl(result, a, n, status); + _mpd_cap(result, ctx); + } + else if (n < 0 && n >= -ctx->prec) { + if (!mpd_qcopy(result, a, status)) { + return; + } + _mpd_cap(result, ctx); + mpd_qshiftr_inplace(result, -n); + } + else { + mpd_seterror(result, MPD_Invalid_operation, status); + } +} + +/* + * Same as mpd_shiftn(), but the shift is specified by the decimal b, which + * must be an integer with a zero exponent. Infinities remain infinities. + */ +void +mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, + uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_ssize_t n; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + } + if (b->exp != 0 || mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + n = mpd_qget_ssize(b, &workstatus); + if (workstatus&MPD_Invalid_operation) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (n > ctx->prec || n < -ctx->prec) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(a)) { + mpd_qcopy(result, a, status); + return; + } + + if (n >= 0) { + mpd_qshiftl(result, a, n, status); + _mpd_cap(result, ctx); + } + else { + if (!mpd_qcopy(result, a, status)) { + return; + } + _mpd_cap(result, ctx); + mpd_qshiftr_inplace(result, -n); + } +} + +/* Logical Xor */ +void +mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + const mpd_t *big = a, *small = b; + mpd_uint_t x, y, z, xbit, ybit; + int k, mswdigits; + mpd_ssize_t i; + + if (mpd_isspecial(a) || mpd_isspecial(b) || + mpd_isnegative(a) || mpd_isnegative(b) || + a->exp != 0 || b->exp != 0) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (b->digits > a->digits) { + big = b; + small = a; + } + if (!mpd_qresize(result, big->len, status)) { + return; + } + + + /* full words */ + for (i = 0; i < small->len-1; i++) { + x = small->data[i]; + y = big->data[i]; + z = 0; + for (k = 0; k < MPD_RDIGITS; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit^ybit) ? mpd_pow10[k] : 0; + } + result->data[i] = z; + } + /* most significant word of small */ + x = small->data[i]; + y = big->data[i]; + z = 0; + mswdigits = mpd_word_digits(x); + for (k = 0; k < mswdigits; k++) { + xbit = x % 10; + x /= 10; + ybit = y % 10; + y /= 10; + if (xbit > 1 || ybit > 1) { + goto invalid_operation; + } + z += (xbit^ybit) ? mpd_pow10[k] : 0; + } + + /* scan and copy the rest of y for digit > 1 */ + for (; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + z += ybit*mpd_pow10[k]; + } + result->data[i++] = z; + /* scan and copy the rest of big for digit > 1 */ + for (; i < big->len; i++) { + y = big->data[i]; + for (k = 0; k < MPD_RDIGITS; k++) { + ybit = y % 10; + y /= 10; + if (ybit > 1) { + goto invalid_operation; + } + } + result->data[i] = big->data[i]; + } + + mpd_clear_flags(result); + result->exp = 0; + result->len = _mpd_real_size(result->data, big->len); + mpd_qresize(result, result->len, status); + mpd_setdigits(result); + _mpd_cap(result, ctx); + return; + +invalid_operation: + mpd_seterror(result, MPD_Invalid_operation, status); +} + + +/******************************************************************************/ +/* Arithmetic operations */ +/******************************************************************************/ + +/* + * The absolute value of a. If a is negative, the result is the same + * as the result of the minus operation. Otherwise, the result is the + * result of the plus operation. + */ +void +mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + } + + if (mpd_isnegative(a)) { + mpd_qminus(result, a, ctx, status); + } + else { + mpd_qplus(result, a, ctx, status); + } + + mpd_qfinalize(result, ctx, status); +} + +static inline void +_mpd_ptrswap(mpd_t **a, mpd_t **b) +{ + mpd_t *t = *a; + *a = *b; + *b = t; +} + +/* Add or subtract infinities. */ +static void +_mpd_qaddsub_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b, + uint32_t *status) +{ + if (mpd_isinfinite(a)) { + if (mpd_sign(a) != sign_b && mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + } + else { + mpd_setspecial(result, mpd_sign(a), MPD_INF); + } + return; + } + assert(mpd_isinfinite(b)); + mpd_setspecial(result, sign_b, MPD_INF); +} + +/* Add or subtract non-special numbers. */ +static void +_mpd_qaddsub(mpd_t *result, const mpd_t *a, const mpd_t *b, uint8_t sign_b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_t *big, *small; + MPD_NEW_STATIC(big_aligned,0,0,0,0); + MPD_NEW_CONST(tiny,0,0,0,1,1,1); + mpd_uint_t carry; + mpd_ssize_t newsize, shift; + mpd_ssize_t exp, i; + int swap = 0; + + + /* compare exponents */ + big = (mpd_t *)a; small = (mpd_t *)b; + if (big->exp != small->exp) { + if (small->exp > big->exp) { + _mpd_ptrswap(&big, &small); + swap++; + } + if (!mpd_iszerocoeff(big)) { + /* Test for adjexp(small) + big->digits < adjexp(big), if big-digits > prec + * Test for adjexp(small) + prec + 1 < adjexp(big), if big-digits <= prec + * If true, the magnitudes of the numbers are so far apart that one can as + * well add or subtract 1*10**big->exp. */ + exp = big->exp - 1; + exp += (big->digits > ctx->prec) ? 0 : big->digits-ctx->prec-1; + if (mpd_adjexp(small) < exp) { + mpd_copy_flags(&tiny, small); + tiny.exp = exp; + tiny.digits = 1; + tiny.len = 1; + tiny.data[0] = mpd_iszerocoeff(small) ? 0 : 1; + small = &tiny; + } + /* this cannot wrap: the difference is positive and <= maxprec+1 */ + shift = big->exp - small->exp; + if (!mpd_qshiftl(&big_aligned, big, shift, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + big = &big_aligned; + } + } + result->exp = small->exp; + + + /* compare length of coefficients */ + if (big->len < small->len) { + _mpd_ptrswap(&big, &small); + swap++; + } + + newsize = big->len; + if (!mpd_qresize(result, newsize, status)) { + goto finish; + } + + if (mpd_sign(a) == sign_b) { + + carry = _mpd_baseadd(result->data, big->data, small->data, + big->len, small->len); + + if (carry) { + newsize = big->len + 1; + if (!mpd_qresize(result, newsize, status)) { + goto finish; + } + result->data[newsize-1] = carry; + } + + result->len = newsize; + mpd_set_flags(result, sign_b); + } + else { + if (big->len == small->len) { + for (i=big->len-1; i >= 0; --i) { + if (big->data[i] != small->data[i]) { + if (big->data[i] < small->data[i]) { + _mpd_ptrswap(&big, &small); + swap++; + } + break; + } + } + } + + _mpd_basesub(result->data, big->data, small->data, + big->len, small->len); + newsize = _mpd_real_size(result->data, big->len); + /* resize to smaller cannot fail */ + (void)mpd_qresize(result, newsize, status); + + result->len = newsize; + sign_b = (swap & 1) ? sign_b : mpd_sign(a); + mpd_set_flags(result, sign_b); + + if (mpd_iszerocoeff(result)) { + mpd_set_positive(result); + if (ctx->round == MPD_ROUND_FLOOR) { + mpd_set_negative(result); + } + } + } + + mpd_setdigits(result); + +finish: + mpd_del(&big_aligned); +} + +/* Add a and b. No specials, no finalizing. */ +static void +_mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + _mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status); +} + +/* Subtract b from a. No specials, no finalizing. */ +static void +_mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + _mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status); +} + +/* Add a and b. */ +void +mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + _mpd_qaddsub_inf(result, a, b, mpd_sign(b), status); + return; + } + + _mpd_qaddsub(result, a, b, mpd_sign(b), ctx, status); + mpd_qfinalize(result, ctx, status); +} + +/* Subtract b from a. */ +void +mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + _mpd_qaddsub_inf(result, a, b, !mpd_sign(b), status); + return; + } + + _mpd_qaddsub(result, a, b, !mpd_sign(b), ctx, status); + mpd_qfinalize(result, ctx, status); +} + +/* Add decimal and mpd_ssize_t. */ +void +mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_ssize(&bb, b, &maxcontext, status); + mpd_qadd(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Add decimal and mpd_uint_t. */ +void +mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_uint(&bb, b, &maxcontext, status); + mpd_qadd(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Subtract mpd_ssize_t from decimal. */ +void +mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_ssize(&bb, b, &maxcontext, status); + mpd_qsub(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Subtract mpd_uint_t from decimal. */ +void +mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_uint(&bb, b, &maxcontext, status); + mpd_qsub(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Add decimal and int32_t. */ +void +mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qadd_ssize(result, a, b, ctx, status); +} + +/* Add decimal and uint32_t. */ +void +mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qadd_uint(result, a, b, ctx, status); +} + +#ifdef CONFIG_64 +/* Add decimal and int64_t. */ +void +mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qadd_ssize(result, a, b, ctx, status); +} + +/* Add decimal and uint64_t. */ +void +mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qadd_uint(result, a, b, ctx, status); +} +#endif + +/* Subtract int32_t from decimal. */ +void +mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qsub_ssize(result, a, b, ctx, status); +} + +/* Subtract uint32_t from decimal. */ +void +mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qsub_uint(result, a, b, ctx, status); +} + +#ifdef CONFIG_64 +/* Subtract int64_t from decimal. */ +void +mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qsub_ssize(result, a, b, ctx, status); +} + +/* Subtract uint64_t from decimal. */ +void +mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qsub_uint(result, a, b, ctx, status); +} +#endif + + +/* Divide infinities. */ +static void +_mpd_qdiv_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + if (mpd_isinfinite(a)) { + if (mpd_isinfinite(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF); + return; + } + assert(mpd_isinfinite(b)); + _settriple(result, mpd_sign(a)^mpd_sign(b), 0, mpd_etiny(ctx)); + *status |= MPD_Clamped; +} + +enum {NO_IDEAL_EXP, SET_IDEAL_EXP}; +/* Divide a by b. */ +static void +_mpd_qdiv(int action, mpd_t *q, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + MPD_NEW_STATIC(aligned,0,0,0,0); + mpd_uint_t ld; + mpd_ssize_t shift, exp, tz; + mpd_ssize_t newsize; + mpd_ssize_t ideal_exp; + mpd_uint_t rem; + uint8_t sign_a = mpd_sign(a); + uint8_t sign_b = mpd_sign(b); + + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(q, a, b, ctx, status)) { + return; + } + _mpd_qdiv_inf(q, a, b, ctx, status); + return; + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_seterror(q, MPD_Division_undefined, status); + } + else { + mpd_setspecial(q, sign_a^sign_b, MPD_INF); + *status |= MPD_Division_by_zero; + } + return; + } + if (mpd_iszerocoeff(a)) { + exp = a->exp - b->exp; + _settriple(q, sign_a^sign_b, 0, exp); + mpd_qfinalize(q, ctx, status); + return; + } + + shift = (b->digits - a->digits) + ctx->prec + 1; + ideal_exp = a->exp - b->exp; + exp = ideal_exp - shift; + if (shift > 0) { + if (!mpd_qshiftl(&aligned, a, shift, status)) { + mpd_seterror(q, MPD_Malloc_error, status); + goto finish; + } + a = &aligned; + } + else if (shift < 0) { + shift = -shift; + if (!mpd_qshiftl(&aligned, b, shift, status)) { + mpd_seterror(q, MPD_Malloc_error, status); + goto finish; + } + b = &aligned; + } + + + newsize = a->len - b->len + 1; + if ((q != b && q != a) || (q == b && newsize > b->len)) { + if (!mpd_qresize(q, newsize, status)) { + mpd_seterror(q, MPD_Malloc_error, status); + goto finish; + } + } + + + if (b->len == 1) { + rem = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]); + } + else if (a->len < 2*MPD_NEWTONDIV_CUTOFF && + b->len < MPD_NEWTONDIV_CUTOFF) { + int ret = _mpd_basedivmod(q->data, NULL, a->data, b->data, + a->len, b->len); + if (ret < 0) { + mpd_seterror(q, MPD_Malloc_error, status); + goto finish; + } + rem = ret; + } + else { + MPD_NEW_STATIC(r,0,0,0,0); + _mpd_qbarrett_divmod(q, &r, a, b, status); + if (mpd_isspecial(q) || mpd_isspecial(&r)) { + mpd_del(&r); + goto finish; + } + rem = !mpd_iszerocoeff(&r); + mpd_del(&r); + newsize = q->len; + } + + newsize = _mpd_real_size(q->data, newsize); + /* resize to smaller cannot fail */ + mpd_qresize(q, newsize, status); + q->len = newsize; + mpd_setdigits(q); + + shift = ideal_exp - exp; + if (rem) { + ld = mpd_lsd(q->data[0]); + if (ld == 0 || ld == 5) { + q->data[0] += 1; + } + } + else if (action == SET_IDEAL_EXP && shift > 0) { + tz = mpd_trail_zeros(q); + shift = (tz > shift) ? shift : tz; + mpd_qshiftr_inplace(q, shift); + exp += shift; + } + + mpd_set_flags(q, sign_a^sign_b); + q->exp = exp; + + +finish: + mpd_del(&aligned); + mpd_qfinalize(q, ctx, status); +} + +/* Divide a by b. */ +void +mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + _mpd_qdiv(SET_IDEAL_EXP, q, a, b, ctx, status); +} + +/* Internal function. */ +static void +_mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + MPD_NEW_STATIC(aligned,0,0,0,0); + mpd_ssize_t qsize, rsize; + mpd_ssize_t ideal_exp, expdiff, shift; + uint8_t sign_a = mpd_sign(a); + uint8_t sign_ab = mpd_sign(a)^mpd_sign(b); + + + ideal_exp = (a->exp > b->exp) ? b->exp : a->exp; + if (mpd_iszerocoeff(a)) { + if (!mpd_qcopy(r, a, status)) { + goto nanresult; /* GCOV_NOT_REACHED */ + } + r->exp = ideal_exp; + _settriple(q, sign_ab, 0, 0); + return; + } + + expdiff = mpd_adjexp(a) - mpd_adjexp(b); + if (expdiff < 0) { + if (a->exp > b->exp) { + /* positive and less than b->digits - a->digits */ + shift = a->exp - b->exp; + if (!mpd_qshiftl(r, a, shift, status)) { + goto nanresult; + } + r->exp = ideal_exp; + } + else { + if (!mpd_qcopy(r, a, status)) { + goto nanresult; + } + } + _settriple(q, sign_ab, 0, 0); + return; + } + if (expdiff > ctx->prec) { + *status |= MPD_Division_impossible; + goto nanresult; + } + + + /* + * At this point we have: + * (1) 0 <= a->exp + a->digits - b->exp - b->digits <= prec + * (2) a->exp - b->exp >= b->digits - a->digits + * (3) a->exp - b->exp <= prec + b->digits - a->digits + */ + if (a->exp != b->exp) { + shift = a->exp - b->exp; + if (shift > 0) { + /* by (3), after the shift a->digits <= prec + b->digits */ + if (!mpd_qshiftl(&aligned, a, shift, status)) { + goto nanresult; + } + a = &aligned; + } + else { + shift = -shift; + /* by (2), after the shift b->digits <= a->digits */ + if (!mpd_qshiftl(&aligned, b, shift, status)) { + goto nanresult; + } + b = &aligned; + } + } + + + qsize = a->len - b->len + 1; + if (!(q == a && qsize < a->len) && !(q == b && qsize < b->len)) { + if (!mpd_qresize(q, qsize, status)) { + goto nanresult; + } + } + + rsize = b->len; + if (!(r == a && rsize < a->len)) { + if (!mpd_qresize(r, rsize, status)) { + goto nanresult; + } + } + + if (b->len == 1) { + if (a->len == 1) { + _mpd_div_word(&q->data[0], &r->data[0], a->data[0], b->data[0]); + } + else { + r->data[0] = _mpd_shortdiv(q->data, a->data, a->len, b->data[0]); + } + } + else if (a->len < 2*MPD_NEWTONDIV_CUTOFF && + b->len < MPD_NEWTONDIV_CUTOFF) { + int ret; + ret = _mpd_basedivmod(q->data, r->data, a->data, b->data, + a->len, b->len); + if (ret == -1) { + *status |= MPD_Malloc_error; + goto nanresult; + } + } + else { + _mpd_qbarrett_divmod(q, r, a, b, status); + if (mpd_isspecial(q) || mpd_isspecial(r)) { + goto nanresult; + } + if (mpd_isinfinite(q) || q->digits > ctx->prec) { + *status |= MPD_Division_impossible; + goto nanresult; + } + qsize = q->len; + rsize = r->len; + } + + qsize = _mpd_real_size(q->data, qsize); + /* resize to smaller cannot fail */ + mpd_qresize(q, qsize, status); + q->len = qsize; + mpd_setdigits(q); + mpd_set_flags(q, sign_ab); + q->exp = 0; + if (q->digits > ctx->prec) { + *status |= MPD_Division_impossible; + goto nanresult; + } + + rsize = _mpd_real_size(r->data, rsize); + /* resize to smaller cannot fail */ + mpd_qresize(r, rsize, status); + r->len = rsize; + mpd_setdigits(r); + mpd_set_flags(r, sign_a); + r->exp = ideal_exp; + +out: + mpd_del(&aligned); + return; + +nanresult: + mpd_setspecial(q, MPD_POS, MPD_NAN); + mpd_setspecial(r, MPD_POS, MPD_NAN); + goto out; +} + +/* Integer division with remainder. */ +void +mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + uint8_t sign = mpd_sign(a)^mpd_sign(b); + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(q, a, b, ctx, status)) { + mpd_qcopy(r, q, status); + return; + } + if (mpd_isinfinite(a)) { + if (mpd_isinfinite(b)) { + mpd_setspecial(q, MPD_POS, MPD_NAN); + } + else { + mpd_setspecial(q, sign, MPD_INF); + } + mpd_setspecial(r, MPD_POS, MPD_NAN); + *status |= MPD_Invalid_operation; + return; + } + if (mpd_isinfinite(b)) { + if (!mpd_qcopy(r, a, status)) { + mpd_seterror(q, MPD_Malloc_error, status); + return; + } + mpd_qfinalize(r, ctx, status); + _settriple(q, sign, 0, 0); + return; + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_setspecial(q, MPD_POS, MPD_NAN); + mpd_setspecial(r, MPD_POS, MPD_NAN); + *status |= MPD_Division_undefined; + } + else { + mpd_setspecial(q, sign, MPD_INF); + mpd_setspecial(r, MPD_POS, MPD_NAN); + *status |= (MPD_Division_by_zero|MPD_Invalid_operation); + } + return; + } + + _mpd_qdivmod(q, r, a, b, ctx, status); + mpd_qfinalize(q, ctx, status); + mpd_qfinalize(r, ctx, status); +} + +void +mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + MPD_NEW_STATIC(r,0,0,0,0); + uint8_t sign = mpd_sign(a)^mpd_sign(b); + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(q, a, b, ctx, status)) { + return; + } + if (mpd_isinfinite(a) && mpd_isinfinite(b)) { + mpd_seterror(q, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(a)) { + mpd_setspecial(q, sign, MPD_INF); + return; + } + if (mpd_isinfinite(b)) { + _settriple(q, sign, 0, 0); + return; + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_seterror(q, MPD_Division_undefined, status); + } + else { + mpd_setspecial(q, sign, MPD_INF); + *status |= MPD_Division_by_zero; + } + return; + } + + + _mpd_qdivmod(q, &r, a, b, ctx, status); + mpd_del(&r); + mpd_qfinalize(q, ctx, status); +} + +/* Divide decimal by mpd_ssize_t. */ +void +mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_ssize(&bb, b, &maxcontext, status); + mpd_qdiv(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Divide decimal by mpd_uint_t. */ +void +mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_uint(&bb, b, &maxcontext, status); + mpd_qdiv(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Divide decimal by int32_t. */ +void +mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qdiv_ssize(result, a, b, ctx, status); +} + +/* Divide decimal by uint32_t. */ +void +mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qdiv_uint(result, a, b, ctx, status); +} + +#ifdef CONFIG_64 +/* Divide decimal by int64_t. */ +void +mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qdiv_ssize(result, a, b, ctx, status); +} + +/* Divide decimal by uint64_t. */ +void +mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qdiv_uint(result, a, b, ctx, status); +} +#endif + +#if defined(_MSC_VER) + /* conversion from 'double' to 'mpd_ssize_t', possible loss of data */ + #pragma warning(disable:4244) +#endif +/* + * Get the number of iterations for the Horner scheme in _mpd_qexp(). + */ +static inline mpd_ssize_t +_mpd_get_exp_iterations(const mpd_t *a, mpd_ssize_t prec) +{ + mpd_uint_t dummy; + mpd_uint_t msdigits; + double f; + + /* 9 is MPD_RDIGITS for 32 bit platforms */ + _mpd_get_msdigits(&dummy, &msdigits, a, 9); + f = ((double)msdigits + 1) / mpd_pow10[mpd_word_digits(msdigits)]; + +#ifdef CONFIG_64 + #ifdef USE_80BIT_LONG_DOUBLE + return ceill((1.435*(long double)prec - 1.182) + / log10l((long double)prec/f)); + #else + /* prec > floor((1ULL<<53) / 1.435) */ + if (prec > 6276793905742851LL) { + return MPD_SSIZE_MAX; + } + return ceil((1.435*(double)prec - 1.182) / log10((double)prec/f)); + #endif +#else /* CONFIG_32 */ + return ceil((1.435*(double)prec - 1.182) / log10((double)prec/f)); + #if defined(_MSC_VER) + #pragma warning(default:4244) + #endif +#endif +} + +/* + * Internal function, specials have been dealt with. + * + * The algorithm is from Hull&Abrham, Variable Precision Exponential Function, + * ACM Transactions on Mathematical Software, Vol. 12, No. 2, June 1986. + * + * Main differences: + * + * - The number of iterations for the Horner scheme is calculated using the + * C log10() function. + * + * - The analysis for early abortion has been adapted for the mpd_t + * ranges. + */ +static void +_mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(tmp,0,0,0,0); + MPD_NEW_STATIC(sum,0,0,0,0); + MPD_NEW_CONST(word,0,0,0,1,1,1); + mpd_ssize_t j, n, t; + + assert(!mpd_isspecial(a)); + + /* + * We are calculating e^x = e^(r*10^t) = (e^r)^(10^t), where r < 1 and t >= 0. + * + * If t > 0, we have: + * + * (1) 0.1 <= r < 1, so e^r >= e^0.1. Overflow in the final power operation + * will occur when (e^0.1)^(10^t) > 10^(emax+1). If we consider MAX_EMAX, + * this will happen for t > 10 (32 bit) or (t > 19) (64 bit). + * + * (2) -1 < r <= -0.1, so e^r > e^-1. Underflow in the final power operation + * will occur when (e^-1)^(10^t) < 10^(etiny-1). If we consider MIN_ETINY, + * this will also happen for t > 10 (32 bit) or (t > 19) (64 bit). + */ +#if defined(CONFIG_64) + #define MPD_EXP_MAX_T 19 +#elif defined(CONFIG_32) + #define MPD_EXP_MAX_T 10 +#endif + t = a->digits + a->exp; + t = (t > 0) ? t : 0; + if (t > MPD_EXP_MAX_T) { + if (mpd_ispositive(a)) { + mpd_setspecial(result, MPD_POS, MPD_INF); + *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded; + } + else { + _settriple(result, MPD_POS, 0, mpd_etiny(ctx)); + *status |= (MPD_Inexact|MPD_Rounded|MPD_Subnormal| + MPD_Underflow|MPD_Clamped); + } + return; + } + + mpd_maxcontext(&workctx); + workctx.prec = ctx->prec + t + 2; + workctx.prec = (workctx.prec < 9) ? 9 : workctx.prec; + workctx.round = MPD_ROUND_HALF_EVEN; + + if ((n = _mpd_get_exp_iterations(a, workctx.prec)) == MPD_SSIZE_MAX) { + mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_UNLIKELY */ + goto finish; /* GCOV_UNLIKELY */ + } + + if (!mpd_qcopy(result, a, status)) { + goto finish; + } + result->exp -= t; + + _settriple(&sum, MPD_POS, 1, 0); + + for (j = n-1; j >= 1; j--) { + word.data[0] = j; + mpd_setdigits(&word); + mpd_qdiv(&tmp, result, &word, &workctx, &workctx.status); + mpd_qmul(&sum, &sum, &tmp, &workctx, &workctx.status); + mpd_qadd(&sum, &sum, &one, &workctx, &workctx.status); + } + +#ifdef CONFIG_64 + _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status); +#else + if (t <= MPD_MAX_POW10) { + _mpd_qpow_uint(result, &sum, mpd_pow10[t], MPD_POS, &workctx, status); + } + else { + t -= MPD_MAX_POW10; + _mpd_qpow_uint(&tmp, &sum, mpd_pow10[MPD_MAX_POW10], MPD_POS, + &workctx, status); + _mpd_qpow_uint(result, &tmp, mpd_pow10[t], MPD_POS, &workctx, status); + } +#endif + + +finish: + mpd_del(&tmp); + mpd_del(&sum); + *status |= (workctx.status&MPD_Errors); + *status |= (MPD_Inexact|MPD_Rounded); +} + +/* exp(a) */ +void +mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + _settriple(result, MPD_POS, 0, 0); + } + else { + mpd_setspecial(result, MPD_POS, MPD_INF); + } + return; + } + if (mpd_iszerocoeff(a)) { + _settriple(result, MPD_POS, 1, 0); + return; + } + + workctx = *ctx; + workctx.round = MPD_ROUND_HALF_EVEN; + + if (ctx->allcr) { + MPD_NEW_STATIC(t1, 0,0,0,0); + MPD_NEW_STATIC(t2, 0,0,0,0); + MPD_NEW_STATIC(ulp, 0,0,0,0); + MPD_NEW_STATIC(aa, 0,0,0,0); + mpd_ssize_t prec; + + if (result == a) { + if (!mpd_qcopy(&aa, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + a = &aa; + } + + workctx.clamp = 0; + prec = ctx->prec + 3; + while (1) { + workctx.prec = prec; + _mpd_qexp(result, a, &workctx, status); + _ssettriple(&ulp, MPD_POS, 1, + result->exp + result->digits-workctx.prec-1); + + workctx.prec = ctx->prec; + mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status); + mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status); + if (mpd_isspecial(result) || mpd_iszerocoeff(result) || + mpd_qcmp(&t1, &t2, status) == 0) { + workctx.clamp = ctx->clamp; + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + break; + } + prec += MPD_RDIGITS; + } + mpd_del(&t1); + mpd_del(&t2); + mpd_del(&ulp); + mpd_del(&aa); + } + else { + _mpd_qexp(result, a, &workctx, status); + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + } +} + +/* Fused multiply-add: (a * b) + c, with a single final rounding. */ +void +mpd_qfma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_t *cc = (mpd_t *)c; + + if (result == c) { + if ((cc = mpd_qncopy(c)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + } + + _mpd_qmul(result, a, b, ctx, &workstatus); + if (!(workstatus&MPD_Invalid_operation)) { + mpd_qadd(result, result, cc, ctx, &workstatus); + } + + if (cc != c) mpd_del(cc); + *status |= workstatus; +} + +static inline int +ln_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], mpd_ssize_t maxprec, + mpd_ssize_t initprec) +{ + mpd_ssize_t k; + int i; + + assert(maxprec >= 2 && initprec >= 2); + if (maxprec <= initprec) return -1; + + i = 0; k = maxprec; + do { + k = (k+2) / 2; + klist[i++] = k; + } while (k > initprec); + + return i-1; +} + +#ifdef CONFIG_64 +#if MPD_RDIGITS != 19 + #error "mpdecimal.c: MPD_RDIGITS must be 19." +#endif +static const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = { + 6983716328982174407ULL, 9089704281976336583ULL, 1515961135648465461ULL, + 4416816335727555703ULL, 2900988039194170265ULL, 2307925037472986509ULL, + 107598438319191292ULL, 3466624107184669231ULL, 4450099781311469159ULL, + 9807828059751193854ULL, 7713456862091670584ULL, 1492198849978748873ULL, + 6528728696511086257ULL, 2385392051446341972ULL, 8692180205189339507ULL, + 6518769751037497088ULL, 2375253577097505395ULL, 9095610299291824318ULL, + 982748238504564801ULL, 5438635917781170543ULL, 7547331541421808427ULL, + 752371033310119785ULL, 3171643095059950878ULL, 9785265383207606726ULL, + 2932258279850258550ULL, 5497347726624257094ULL, 2976979522110718264ULL, + 9221477656763693866ULL, 1979650047149510504ULL, 6674183485704422507ULL, + 9702766860595249671ULL, 9278096762712757753ULL, 9314848524948644871ULL, + 6826928280848118428ULL, 754403708474699401ULL, 230105703089634572ULL, + 1929203337658714166ULL, 7589402567763113569ULL, 4208241314695689016ULL, + 2922455440575892572ULL, 9356734206705811364ULL, 2684916746550586856ULL, + 644507064800027750ULL, 9476834636167921018ULL, 5659121373450747856ULL, + 2835522011480466371ULL, 6470806855677432162ULL, 7141748003688084012ULL, + 9619404400222105101ULL, 5504893431493939147ULL, 6674744042432743651ULL, + 2287698219886746543ULL, 7773262884616336622ULL, 1985283935053089653ULL, + 4680843799894826233ULL, 8168948290720832555ULL, 8067566662873690987ULL, + 6248633409525465082ULL, 9829834196778404228ULL, 3524802359972050895ULL, + 3327900967572609677ULL, 110148862877297603ULL, 179914546843642076ULL, + 2302585092994045684ULL +}; +#else +#if MPD_RDIGITS != 9 + #error "mpdecimal.c: MPD_RDIGITS must be 9." +#endif +static const mpd_uint_t mpd_ln10_data[MPD_MINALLOC_MAX] = { + 401682692UL, 708474699UL, 720754403UL, 30896345UL, 602301057UL, 765871416UL, + 192920333UL, 763113569UL, 589402567UL, 956890167UL, 82413146UL, 589257242UL, + 245544057UL, 811364292UL, 734206705UL, 868569356UL, 167465505UL, 775026849UL, + 706480002UL, 18064450UL, 636167921UL, 569476834UL, 734507478UL, 156591213UL, + 148046637UL, 283552201UL, 677432162UL, 470806855UL, 880840126UL, 417480036UL, + 210510171UL, 940440022UL, 939147961UL, 893431493UL, 436515504UL, 440424327UL, + 654366747UL, 821988674UL, 622228769UL, 884616336UL, 537773262UL, 350530896UL, + 319852839UL, 989482623UL, 468084379UL, 720832555UL, 168948290UL, 736909878UL, + 675666628UL, 546508280UL, 863340952UL, 404228624UL, 834196778UL, 508959829UL, + 23599720UL, 967735248UL, 96757260UL, 603332790UL, 862877297UL, 760110148UL, + 468436420UL, 401799145UL, 299404568UL, 230258509UL +}; +#endif +/* _mpd_ln10 is used directly for precisions smaller than MINALLOC_MAX*RDIGITS. + Otherwise, it serves as the initial approximation for calculating ln(10). */ +static const mpd_t _mpd_ln10 = { + MPD_STATIC|MPD_CONST_DATA, -(MPD_MINALLOC_MAX*MPD_RDIGITS-1), + MPD_MINALLOC_MAX*MPD_RDIGITS, MPD_MINALLOC_MAX, MPD_MINALLOC_MAX, + (mpd_uint_t *)mpd_ln10_data +}; + +/* Set 'result' to ln(10), with 'prec' digits, using ROUND_HALF_EVEN. */ +void +mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status) +{ + mpd_context_t varcontext, maxcontext; + MPD_NEW_STATIC(tmp, 0,0,0,0); + MPD_NEW_CONST(static10, 0,0,2,1,1,10); + mpd_ssize_t klist[MPD_MAX_PREC_LOG2]; + mpd_uint_t rnd; + mpd_ssize_t shift; + int i; + + assert(prec >= 1); + + shift = MPD_MINALLOC_MAX*MPD_RDIGITS-prec; + shift = shift < 0 ? 0 : shift; + + rnd = mpd_qshiftr(result, &_mpd_ln10, shift, status); + if (rnd == MPD_UINT_MAX) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + result->exp = -(result->digits-1); + + mpd_maxcontext(&maxcontext); + if (prec < MPD_MINALLOC_MAX*MPD_RDIGITS) { + maxcontext.prec = prec; + _mpd_apply_round_excess(result, rnd, &maxcontext, status); + *status |= (MPD_Inexact|MPD_Rounded); + return; + } + + mpd_maxcontext(&varcontext); + varcontext.round = MPD_ROUND_TRUNC; + + i = ln_schedule_prec(klist, prec+2, result->digits); + for (; i >= 0; i--) { + varcontext.prec = 2*klist[i]+3; + result->flags ^= MPD_NEG; + _mpd_qexp(&tmp, result, &varcontext, status); + result->flags ^= MPD_NEG; + mpd_qmul(&tmp, &static10, &tmp, &varcontext, status); + mpd_qsub(&tmp, &tmp, &one, &maxcontext, status); + mpd_qadd(result, result, &tmp, &maxcontext, status); + if (mpd_isspecial(result)) { + break; + } + } + + mpd_del(&tmp); + maxcontext.prec = prec; + mpd_qfinalize(result, &maxcontext, status); +} + +/* Initial approximations for the ln() iteration */ +static const uint16_t lnapprox[900] = { + /* index 0 - 400: log((i+100)/100) * 1000 */ + 0, 10, 20, 30, 39, 49, 58, 68, 77, 86, 95, 104, 113, 122, 131, 140, 148, 157, + 166, 174, 182, 191, 199, 207, 215, 223, 231, 239, 247, 255, 262, 270, 278, + 285, 293, 300, 308, 315, 322, 329, 336, 344, 351, 358, 365, 372, 378, 385, + 392, 399, 406, 412, 419, 425, 432, 438, 445, 451, 457, 464, 470, 476, 482, + 489, 495, 501, 507, 513, 519, 525, 531, 536, 542, 548, 554, 560, 565, 571, + 577, 582, 588, 593, 599, 604, 610, 615, 621, 626, 631, 637, 642, 647, 652, + 658, 663, 668, 673, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, + 732, 737, 742, 747, 751, 756, 761, 766, 770, 775, 779, 784, 788, 793, 798, + 802, 806, 811, 815, 820, 824, 829, 833, 837, 842, 846, 850, 854, 859, 863, + 867, 871, 876, 880, 884, 888, 892, 896, 900, 904, 908, 912, 916, 920, 924, + 928, 932, 936, 940, 944, 948, 952, 956, 959, 963, 967, 971, 975, 978, 982, + 986, 990, 993, 997, 1001, 1004, 1008, 1012, 1015, 1019, 1022, 1026, 1030, + 1033, 1037, 1040, 1044, 1047, 1051, 1054, 1058, 1061, 1065, 1068, 1072, 1075, + 1078, 1082, 1085, 1089, 1092, 1095, 1099, 1102, 1105, 1109, 1112, 1115, 1118, + 1122, 1125, 1128, 1131, 1135, 1138, 1141, 1144, 1147, 1151, 1154, 1157, 1160, + 1163, 1166, 1169, 1172, 1176, 1179, 1182, 1185, 1188, 1191, 1194, 1197, 1200, + 1203, 1206, 1209, 1212, 1215, 1218, 1221, 1224, 1227, 1230, 1233, 1235, 1238, + 1241, 1244, 1247, 1250, 1253, 1256, 1258, 1261, 1264, 1267, 1270, 1273, 1275, + 1278, 1281, 1284, 1286, 1289, 1292, 1295, 1297, 1300, 1303, 1306, 1308, 1311, + 1314, 1316, 1319, 1322, 1324, 1327, 1330, 1332, 1335, 1338, 1340, 1343, 1345, + 1348, 1351, 1353, 1356, 1358, 1361, 1364, 1366, 1369, 1371, 1374, 1376, 1379, + 1381, 1384, 1386, 1389, 1391, 1394, 1396, 1399, 1401, 1404, 1406, 1409, 1411, + 1413, 1416, 1418, 1421, 1423, 1426, 1428, 1430, 1433, 1435, 1437, 1440, 1442, + 1445, 1447, 1449, 1452, 1454, 1456, 1459, 1461, 1463, 1466, 1468, 1470, 1472, + 1475, 1477, 1479, 1482, 1484, 1486, 1488, 1491, 1493, 1495, 1497, 1500, 1502, + 1504, 1506, 1509, 1511, 1513, 1515, 1517, 1520, 1522, 1524, 1526, 1528, 1530, + 1533, 1535, 1537, 1539, 1541, 1543, 1545, 1548, 1550, 1552, 1554, 1556, 1558, + 1560, 1562, 1564, 1567, 1569, 1571, 1573, 1575, 1577, 1579, 1581, 1583, 1585, + 1587, 1589, 1591, 1593, 1595, 1597, 1599, 1601, 1603, 1605, 1607, 1609, + /* index 401 - 899: -log((i+100)/1000) * 1000 */ + 691, 689, 687, 685, 683, 681, 679, 677, 675, 673, 671, 669, 668, 666, 664, + 662, 660, 658, 656, 654, 652, 650, 648, 646, 644, 642, 641, 639, 637, 635, + 633, 631, 629, 627, 626, 624, 622, 620, 618, 616, 614, 612, 611, 609, 607, + 605, 603, 602, 600, 598, 596, 594, 592, 591, 589, 587, 585, 583, 582, 580, + 578, 576, 574, 573, 571, 569, 567, 566, 564, 562, 560, 559, 557, 555, 553, + 552, 550, 548, 546, 545, 543, 541, 540, 538, 536, 534, 533, 531, 529, 528, + 526, 524, 523, 521, 519, 518, 516, 514, 512, 511, 509, 508, 506, 504, 502, + 501, 499, 498, 496, 494, 493, 491, 489, 488, 486, 484, 483, 481, 480, 478, + 476, 475, 473, 472, 470, 468, 467, 465, 464, 462, 460, 459, 457, 456, 454, + 453, 451, 449, 448, 446, 445, 443, 442, 440, 438, 437, 435, 434, 432, 431, + 429, 428, 426, 425, 423, 422, 420, 419, 417, 416, 414, 412, 411, 410, 408, + 406, 405, 404, 402, 400, 399, 398, 396, 394, 393, 392, 390, 389, 387, 386, + 384, 383, 381, 380, 378, 377, 375, 374, 372, 371, 370, 368, 367, 365, 364, + 362, 361, 360, 358, 357, 355, 354, 352, 351, 350, 348, 347, 345, 344, 342, + 341, 340, 338, 337, 336, 334, 333, 331, 330, 328, 327, 326, 324, 323, 322, + 320, 319, 318, 316, 315, 313, 312, 311, 309, 308, 306, 305, 304, 302, 301, + 300, 298, 297, 296, 294, 293, 292, 290, 289, 288, 286, 285, 284, 282, 281, + 280, 278, 277, 276, 274, 273, 272, 270, 269, 268, 267, 265, 264, 263, 261, + 260, 259, 258, 256, 255, 254, 252, 251, 250, 248, 247, 246, 245, 243, 242, + 241, 240, 238, 237, 236, 234, 233, 232, 231, 229, 228, 227, 226, 224, 223, + 222, 221, 219, 218, 217, 216, 214, 213, 212, 211, 210, 208, 207, 206, 205, + 203, 202, 201, 200, 198, 197, 196, 195, 194, 192, 191, 190, 189, 188, 186, + 185, 184, 183, 182, 180, 179, 178, 177, 176, 174, 173, 172, 171, 170, 168, + 167, 166, 165, 164, 162, 161, 160, 159, 158, 157, 156, 154, 153, 152, 151, + 150, 148, 147, 146, 145, 144, 143, 142, 140, 139, 138, 137, 136, 135, 134, + 132, 131, 130, 129, 128, 127, 126, 124, 123, 122, 121, 120, 119, 118, 116, + 115, 114, 113, 112, 111, 110, 109, 108, 106, 105, 104, 103, 102, 101, 100, + 99, 98, 97, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 84, 83, 82, 81, 80, 79, + 78, 77, 76, 75, 74, 73, 72, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, + 58, 57, 56, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, + 38, 37, 36, 35, 34, 33, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, + 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 +}; + +/* Internal ln() function that does not check for specials, zero or one. */ +static void +_mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t varcontext, maxcontext; + mpd_t *z = (mpd_t *) result; + MPD_NEW_STATIC(v,0,0,0,0); + MPD_NEW_STATIC(vtmp,0,0,0,0); + MPD_NEW_STATIC(tmp,0,0,0,0); + mpd_ssize_t klist[MPD_MAX_PREC_LOG2]; + mpd_ssize_t maxprec, shift, t; + mpd_ssize_t a_digits, a_exp; + mpd_uint_t dummy, x; + int i; + + assert(!mpd_isspecial(a) && !mpd_iszerocoeff(a)); + + /* + * We are calculating ln(a) = ln(v * 10^t) = ln(v) + t*ln(10), + * where 0.5 < v <= 5. + */ + if (!mpd_qcopy(&v, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + + /* Initial approximation: we have at least one non-zero digit */ + _mpd_get_msdigits(&dummy, &x, &v, 3); + if (x < 10) x *= 10; + if (x < 100) x *= 10; + x -= 100; + + /* a may equal z */ + a_digits = a->digits; + a_exp = a->exp; + + mpd_minalloc(z); + mpd_clear_flags(z); + z->data[0] = lnapprox[x]; + z->len = 1; + z->exp = -3; + mpd_setdigits(z); + + if (x <= 400) { + v.exp = -(a_digits - 1); + t = a_exp + a_digits - 1; + } + else { + v.exp = -a_digits; + t = a_exp + a_digits; + mpd_set_negative(z); + } + + mpd_maxcontext(&maxcontext); + mpd_maxcontext(&varcontext); + varcontext.round = MPD_ROUND_TRUNC; + + maxprec = ctx->prec + 2; + if (x <= 10 || x >= 805) { + /* v is close to 1: Estimate the magnitude of the logarithm. + * If v = 1 or ln(v) will underflow, skip the loop. Otherwise, + * adjust the precision upwards in order to obtain a sufficient + * number of significant digits. + * + * 1) x/(1+x) < ln(1+x) < x, for x > -1, x != 0 + * + * 2) (v-1)/v < ln(v) < v-1 + */ + mpd_t *lower = &tmp; + mpd_t *upper = &vtmp; + int cmp = _mpd_cmp(&v, &one); + + varcontext.round = MPD_ROUND_CEILING; + varcontext.prec = maxprec; + mpd_qsub(upper, &v, &one, &varcontext, &varcontext.status); + varcontext.round = MPD_ROUND_FLOOR; + mpd_qdiv(lower, upper, &v, &varcontext, &varcontext.status); + varcontext.round = MPD_ROUND_TRUNC; + + if (cmp < 0) { + _mpd_ptrswap(&upper, &lower); + } + if (mpd_adjexp(upper) < mpd_etiny(ctx)) { + _settriple(z, (cmp<0), 1, mpd_etiny(ctx)-1); + goto postloop; + } + /* XXX optimization: t == 0 && mpd_adjexp(lower) < 0 */ + if (mpd_adjexp(lower) < 0) { + maxprec = maxprec - mpd_adjexp(lower); + } + } + + i = ln_schedule_prec(klist, maxprec, 2); + for (; i >= 0; i--) { + varcontext.prec = 2*klist[i]+3; + z->flags ^= MPD_NEG; + _mpd_qexp(&tmp, z, &varcontext, status); + z->flags ^= MPD_NEG; + + if (v.digits > varcontext.prec) { + shift = v.digits - varcontext.prec; + mpd_qshiftr(&vtmp, &v, shift, status); + vtmp.exp += shift; + mpd_qmul(&tmp, &vtmp, &tmp, &varcontext, status); + } + else { + mpd_qmul(&tmp, &v, &tmp, &varcontext, status); + } + + mpd_qsub(&tmp, &tmp, &one, &maxcontext, status); + mpd_qadd(z, z, &tmp, &maxcontext, status); + if (mpd_isspecial(z)) { + break; + } + } + +postloop: + mpd_qln10(&v, maxprec+2, status); + mpd_qmul_ssize(&tmp, &v, t, &maxcontext, status); + varcontext.prec = maxprec+2; + mpd_qadd(result, &tmp, z, &varcontext, status); + + +finish: + mpd_del(&v); + mpd_del(&vtmp); + mpd_del(&tmp); +} + +/* ln(a) */ +void +mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + mpd_ssize_t adjexp, t; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + mpd_setspecial(result, MPD_POS, MPD_INF); + return; + } + if (mpd_iszerocoeff(a)) { + mpd_setspecial(result, MPD_NEG, MPD_INF); + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (_mpd_cmp(a, &one) == 0) { + _settriple(result, MPD_POS, 0, 0); + return; + } + /* Check if the result will overflow. + * + * 1) adjexp(a) + 1 > log10(a) >= adjexp(a) + * + * 2) |log10(a)| >= adjexp(a), if adjexp(a) >= 0 + * |log10(a)| > -adjexp(a)-1, if adjexp(a) < 0 + * + * 3) |log(a)| > 2*|log10(a)| + */ + adjexp = mpd_adjexp(a); + t = (adjexp < 0) ? -adjexp-1 : adjexp; + t *= 2; + if (mpd_exp_digits(t)-1 > ctx->emax) { + *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded; + mpd_setspecial(result, (adjexp<0), MPD_INF); + return; + } + + workctx = *ctx; + workctx.round = MPD_ROUND_HALF_EVEN; + + if (ctx->allcr) { + MPD_NEW_STATIC(t1, 0,0,0,0); + MPD_NEW_STATIC(t2, 0,0,0,0); + MPD_NEW_STATIC(ulp, 0,0,0,0); + MPD_NEW_STATIC(aa, 0,0,0,0); + mpd_ssize_t prec; + + if (result == a) { + if (!mpd_qcopy(&aa, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + a = &aa; + } + + workctx.clamp = 0; + prec = ctx->prec + 3; + while (1) { + workctx.prec = prec; + _mpd_qln(result, a, &workctx, status); + _ssettriple(&ulp, MPD_POS, 1, + result->exp + result->digits-workctx.prec-1); + + workctx.prec = ctx->prec; + mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status); + mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status); + if (mpd_isspecial(result) || mpd_iszerocoeff(result) || + mpd_qcmp(&t1, &t2, status) == 0) { + workctx.clamp = ctx->clamp; + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + break; + } + prec += MPD_RDIGITS; + } + mpd_del(&t1); + mpd_del(&t2); + mpd_del(&ulp); + mpd_del(&aa); + } + else { + _mpd_qln(result, a, &workctx, status); + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + } +} + +/* Internal log10() function that does not check for specials, zero, ... */ +static void +_mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(ln10,0,0,0,0); + + mpd_maxcontext(&workctx); + workctx.prec = ctx->prec + 3; + _mpd_qln(result, a, &workctx, status); + mpd_qln10(&ln10, workctx.prec, status); + + workctx = *ctx; + workctx.round = MPD_ROUND_HALF_EVEN; + _mpd_qdiv(NO_IDEAL_EXP, result, result, &ln10, &workctx, status); + + mpd_del(&ln10); +} + +/* log10(a) */ +void +mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + mpd_ssize_t adjexp, t; + + workctx = *ctx; + workctx.round = MPD_ROUND_HALF_EVEN; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + mpd_setspecial(result, MPD_POS, MPD_INF); + return; + } + if (mpd_iszerocoeff(a)) { + mpd_setspecial(result, MPD_NEG, MPD_INF); + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_coeff_ispow10(a)) { + uint8_t sign = 0; + adjexp = mpd_adjexp(a); + if (adjexp < 0) { + sign = 1; + adjexp = -adjexp; + } + _settriple(result, sign, adjexp, 0); + mpd_qfinalize(result, &workctx, status); + return; + } + /* Check if the result will overflow. + * + * 1) adjexp(a) + 1 > log10(a) >= adjexp(a) + * + * 2) |log10(a)| >= adjexp(a), if adjexp(a) >= 0 + * |log10(a)| > -adjexp(a)-1, if adjexp(a) < 0 + */ + adjexp = mpd_adjexp(a); + t = (adjexp < 0) ? -adjexp-1 : adjexp; + if (mpd_exp_digits(t)-1 > ctx->emax) { + *status |= MPD_Overflow|MPD_Inexact|MPD_Rounded; + mpd_setspecial(result, (adjexp<0), MPD_INF); + return; + } + + if (ctx->allcr) { + MPD_NEW_STATIC(t1, 0,0,0,0); + MPD_NEW_STATIC(t2, 0,0,0,0); + MPD_NEW_STATIC(ulp, 0,0,0,0); + MPD_NEW_STATIC(aa, 0,0,0,0); + mpd_ssize_t prec; + + if (result == a) { + if (!mpd_qcopy(&aa, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + a = &aa; + } + + workctx.clamp = 0; + prec = ctx->prec + 3; + while (1) { + workctx.prec = prec; + _mpd_qlog10(result, a, &workctx, status); + _ssettriple(&ulp, MPD_POS, 1, + result->exp + result->digits-workctx.prec-1); + + workctx.prec = ctx->prec; + mpd_qadd(&t1, result, &ulp, &workctx, &workctx.status); + mpd_qsub(&t2, result, &ulp, &workctx, &workctx.status); + if (mpd_isspecial(result) || mpd_iszerocoeff(result) || + mpd_qcmp(&t1, &t2, status) == 0) { + workctx.clamp = ctx->clamp; + mpd_check_underflow(result, &workctx, status); + mpd_qfinalize(result, &workctx, status); + break; + } + prec += MPD_RDIGITS; + } + mpd_del(&t1); + mpd_del(&t2); + mpd_del(&ulp); + mpd_del(&aa); + } + else { + _mpd_qlog10(result, a, &workctx, status); + mpd_check_underflow(result, &workctx, status); + } +} + +/* + * Maximum of the two operands. Attention: If one operand is a quiet NaN and the + * other is numeric, the numeric operand is returned. This may not be what one + * expects. + */ +void +mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isqnan(a) && !mpd_isnan(b)) { + mpd_qcopy(result, b, status); + } + else if (mpd_isqnan(b) && !mpd_isnan(a)) { + mpd_qcopy(result, a, status); + } + else if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + else { + c = _mpd_cmp(a, b); + if (c == 0) { + c = _mpd_cmp_numequal(a, b); + } + + if (c < 0) { + mpd_qcopy(result, b, status); + } + else { + mpd_qcopy(result, a, status); + } + } + + mpd_qfinalize(result, ctx, status); +} + +/* + * Maximum magnitude: Same as mpd_max(), but compares the operands with their + * sign ignored. + */ +void +mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isqnan(a) && !mpd_isnan(b)) { + mpd_qcopy(result, b, status); + } + else if (mpd_isqnan(b) && !mpd_isnan(a)) { + mpd_qcopy(result, a, status); + } + else if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + else { + c = _mpd_cmp_abs(a, b); + if (c == 0) { + c = _mpd_cmp_numequal(a, b); + } + + if (c < 0) { + mpd_qcopy(result, b, status); + } + else { + mpd_qcopy(result, a, status); + } + } + + mpd_qfinalize(result, ctx, status); +} + +/* + * Minimum of the two operands. Attention: If one operand is a quiet NaN and the + * other is numeric, the numeric operand is returned. This may not be what one + * expects. + */ +void +mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isqnan(a) && !mpd_isnan(b)) { + mpd_qcopy(result, b, status); + } + else if (mpd_isqnan(b) && !mpd_isnan(a)) { + mpd_qcopy(result, a, status); + } + else if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + else { + c = _mpd_cmp(a, b); + if (c == 0) { + c = _mpd_cmp_numequal(a, b); + } + + if (c < 0) { + mpd_qcopy(result, a, status); + } + else { + mpd_qcopy(result, b, status); + } + } + + mpd_qfinalize(result, ctx, status); +} + +/* + * Minimum magnitude: Same as mpd_min(), but compares the operands with their + * sign ignored. + */ +void +mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isqnan(a) && !mpd_isnan(b)) { + mpd_qcopy(result, b, status); + } + else if (mpd_isqnan(b) && !mpd_isnan(a)) { + mpd_qcopy(result, a, status); + } + else if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + else { + c = _mpd_cmp_abs(a, b); + if (c == 0) { + c = _mpd_cmp_numequal(a, b); + } + + if (c < 0) { + mpd_qcopy(result, a, status); + } + else { + mpd_qcopy(result, b, status); + } + } + + mpd_qfinalize(result, ctx, status); +} + +/* Minimum space needed for the result array in _karatsuba_rec(). */ +static inline mpd_size_t +_kmul_resultsize(mpd_size_t la, mpd_size_t lb) +{ + mpd_size_t n, m; + + n = add_size_t(la, lb); + n = add_size_t(n, 1); + + m = (la+1)/2 + 1; + m = mul_size_t(m, 3); + + return (m > n) ? m : n; +} + +/* Work space needed in _karatsuba_rec(). lim >= 4 */ +static inline mpd_size_t +_kmul_worksize(mpd_size_t n, mpd_size_t lim) +{ + mpd_size_t m; + + if (n <= lim) { + return 0; + } + + m = (n+1)/2 + 1; + + return add_size_t(mul_size_t(m, 2), _kmul_worksize(m, lim)); +} + + +#define MPD_KARATSUBA_BASECASE 16 /* must be >= 4 */ + +/* + * Add the product of a and b to c. + * c must be _kmul_resultsize(la, lb) in size. + * w is used as a work array and must be _kmul_worksize(a, lim) in size. + * Roman E. Maeder, Storage Allocation for the Karatsuba Integer Multiplication + * Algorithm. In "Design and implementation of symbolic computation systems", + * Springer, 1993, ISBN 354057235X, 9783540572350. + */ +static void +_karatsuba_rec(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b, + mpd_uint_t *w, mpd_size_t la, mpd_size_t lb) +{ + mpd_size_t m, lt; + + assert(la >= lb && lb > 0); + assert(la <= MPD_KARATSUBA_BASECASE || w != NULL); + + if (la <= MPD_KARATSUBA_BASECASE) { + _mpd_basemul(c, a, b, la, lb); + return; + } + + m = (la+1)/2; // ceil(la/2) + + /* lb <= m < la */ + if (lb <= m) { + + /* lb can now be larger than la-m */ + if (lb > la-m) { + lt = lb + lb + 1; // space needed for result array + mpd_uint_zero(w, lt); // clear result array + _karatsuba_rec(w, b, a+m, w+lt, lb, la-m); // b*ah + } + else { + lt = (la-m) + (la-m) + 1; // space needed for result array + mpd_uint_zero(w, lt); // clear result array + _karatsuba_rec(w, a+m, b, w+lt, la-m, lb); // ah*b + } + _mpd_baseaddto(c+m, w, (la-m)+lb); // add ah*b*B**m + + lt = m + m + 1; // space needed for the result array + mpd_uint_zero(w, lt); // clear result array + _karatsuba_rec(w, a, b, w+lt, m, lb); // al*b + _mpd_baseaddto(c, w, m+lb); // add al*b + + return; + } + + /* la >= lb > m */ + memcpy(w, a, m * sizeof *w); + w[m] = 0; + _mpd_baseaddto(w, a+m, la-m); + + memcpy(w+(m+1), b, m * sizeof *w); + w[m+1+m] = 0; + _mpd_baseaddto(w+(m+1), b+m, lb-m); + + _karatsuba_rec(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1); + + lt = (la-m) + (la-m) + 1; + mpd_uint_zero(w, lt); + + _karatsuba_rec(w, a+m, b+m, w+lt, la-m, lb-m); + + _mpd_baseaddto(c+2*m, w, (la-m) + (lb-m)); + _mpd_basesubfrom(c+m, w, (la-m) + (lb-m)); + + lt = m + m + 1; + mpd_uint_zero(w, lt); + + _karatsuba_rec(w, a, b, w+lt, m, m); + _mpd_baseaddto(c, w, m+m); + _mpd_basesubfrom(c+m, w, m+m); + + return; +} + +/* + * Multiply u and v, using Karatsuba multiplication. Returns a pointer + * to the result or NULL in case of failure (malloc error). + * Conditions: ulen >= vlen, ulen >= 4 + */ +mpd_uint_t * +_mpd_kmul(const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t ulen, mpd_size_t vlen, + mpd_size_t *rsize) +{ + mpd_uint_t *result = NULL, *w = NULL; + mpd_size_t m; + + assert(ulen >= 4); + assert(ulen >= vlen); + + *rsize = _kmul_resultsize(ulen, vlen); + if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) { + return NULL; + } + + m = _kmul_worksize(ulen, MPD_KARATSUBA_BASECASE); + if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) { + mpd_free(result); + return NULL; + } + + _karatsuba_rec(result, u, v, w, ulen, vlen); + + + if (w) mpd_free(w); + return result; +} + + +/* Determine the minimum length for the number theoretic transform. */ +static inline mpd_size_t +_mpd_get_transform_len(mpd_size_t rsize) +{ + mpd_size_t log2rsize; + mpd_size_t x, step; + + assert(rsize >= 4); + log2rsize = mpd_bsr(rsize); + + if (rsize <= 1024) { + x = ((mpd_size_t)1)<>1; + x += step; + return (rsize <= x) ? x : x + step; + } + else if (rsize <= MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2) { + return MPD_MAXTRANSFORM_2N+MPD_MAXTRANSFORM_2N/2; + } + else if (rsize <= 3*MPD_MAXTRANSFORM_2N) { + return 3*MPD_MAXTRANSFORM_2N; + } + else { + return MPD_SIZE_MAX; + } +} + +#ifdef PPRO +#ifndef _MSC_VER +static inline unsigned short +_mpd_get_control87(void) +{ + unsigned short cw; + + __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); + return cw; +} + +static inline void +_mpd_set_control87(unsigned short cw) +{ + __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); +} +#endif + +unsigned int +mpd_set_fenv(void) +{ + unsigned int cw; +#ifdef _MSC_VER + unsigned int flags = + _EM_INVALID|_EM_DENORMAL|_EM_ZERODIVIDE|_EM_OVERFLOW| + _EM_UNDERFLOW|_EM_INEXACT|_RC_CHOP|_PC_64; + unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC; + unsigned int dummy; + + __control87_2(0, 0, &cw, NULL); + __control87_2(flags, mask, &dummy, NULL); +#else + cw = _mpd_get_control87(); + _mpd_set_control87(cw|0xF3F); +#endif + return cw; +} + +void +mpd_restore_fenv(unsigned int cw) +{ +#ifdef _MSC_VER + unsigned int mask = _MCW_EM|_MCW_RC|_MCW_PC; + unsigned int dummy; + + __control87_2(cw, mask, &dummy, NULL); +#else + _mpd_set_control87((unsigned short)cw); +#endif +} +#endif /* PPRO */ + +/* + * Multiply u and v, using the fast number theoretic transform. Returns + * a pointer to the result or NULL in case of failure (malloc error). + */ +mpd_uint_t * +_mpd_fntmul(const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t ulen, mpd_size_t vlen, + mpd_size_t *rsize) +{ + mpd_uint_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *vtmp = NULL; + mpd_size_t n; + +#ifdef PPRO + unsigned int cw; + cw = mpd_set_fenv(); +#endif + + *rsize = add_size_t(ulen, vlen); + if ((n = _mpd_get_transform_len(*rsize)) == MPD_SIZE_MAX) { + goto malloc_error; + } + + if ((c1 = mpd_calloc(sizeof *c1, n)) == NULL) { + goto malloc_error; + } + if ((c2 = mpd_calloc(sizeof *c2, n)) == NULL) { + goto malloc_error; + } + if ((c3 = mpd_calloc(sizeof *c3, n)) == NULL) { + goto malloc_error; + } + + memcpy(c1, u, ulen * (sizeof *c1)); + memcpy(c2, u, ulen * (sizeof *c2)); + memcpy(c3, u, ulen * (sizeof *c3)); + + if (u == v) { + if (!fnt_autoconvolute(c1, n, P1) || + !fnt_autoconvolute(c2, n, P2) || + !fnt_autoconvolute(c3, n, P3)) { + goto malloc_error; + } + } + else { + if ((vtmp = mpd_calloc(sizeof *vtmp, n)) == NULL) { + goto malloc_error; + } + + memcpy(vtmp, v, vlen * (sizeof *vtmp)); + if (!fnt_convolute(c1, vtmp, n, P1)) { + mpd_free(vtmp); + goto malloc_error; + } + + memcpy(vtmp, v, vlen * (sizeof *vtmp)); + mpd_uint_zero(vtmp+vlen, n-vlen); + if (!fnt_convolute(c2, vtmp, n, P2)) { + mpd_free(vtmp); + goto malloc_error; + } + + memcpy(vtmp, v, vlen * (sizeof *vtmp)); + mpd_uint_zero(vtmp+vlen, n-vlen); + if (!fnt_convolute(c3, vtmp, n, P3)) { + mpd_free(vtmp); + goto malloc_error; + } + + mpd_free(vtmp); + } + + crt3(c1, c2, c3, *rsize); + +out: +#ifdef PPRO + mpd_restore_fenv(cw); +#endif + if (c2) mpd_free(c2); + if (c3) mpd_free(c3); + return c1; + +malloc_error: + if (c1) mpd_free(c1); + c1 = NULL; + goto out; +} + + +/* + * Karatsuba multiplication with FNT/basemul as the base case. + */ +static int +_karatsuba_rec_fnt(mpd_uint_t *c, const mpd_uint_t *a, const mpd_uint_t *b, + mpd_uint_t *w, mpd_size_t la, mpd_size_t lb) +{ + mpd_size_t m, lt; + + assert(la >= lb && lb > 0); + assert(la <= 3*(MPD_MAXTRANSFORM_2N/2) || w != NULL); + + if (la <= 3*(MPD_MAXTRANSFORM_2N/2)) { + + if (lb <= 192) { + _mpd_basemul(c, b, a, lb, la); + } + else { + mpd_uint_t *result; + mpd_size_t dummy; + + if ((result = _mpd_fntmul(a, b, la, lb, &dummy)) == NULL) { + return 0; + } + memcpy(c, result, (la+lb) * (sizeof *result)); + mpd_free(result); + } + return 1; + } + + m = (la+1)/2; // ceil(la/2) + + /* lb <= m < la */ + if (lb <= m) { + + /* lb can now be larger than la-m */ + if (lb > la-m) { + lt = lb + lb + 1; // space needed for result array + mpd_uint_zero(w, lt); // clear result array + if (!_karatsuba_rec_fnt(w, b, a+m, w+lt, lb, la-m)) { // b*ah + return 0; /* GCOV_UNLIKELY */ + } + } + else { + lt = (la-m) + (la-m) + 1; // space needed for result array + mpd_uint_zero(w, lt); // clear result array + if (!_karatsuba_rec_fnt(w, a+m, b, w+lt, la-m, lb)) { // ah*b + return 0; /* GCOV_UNLIKELY */ + } + } + _mpd_baseaddto(c+m, w, (la-m)+lb); // add ah*b*B**m + + lt = m + m + 1; // space needed for the result array + mpd_uint_zero(w, lt); // clear result array + if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, lb)) { // al*b + return 0; /* GCOV_UNLIKELY */ + } + _mpd_baseaddto(c, w, m+lb); // add al*b + + return 1; + } + + /* la >= lb > m */ + memcpy(w, a, m * sizeof *w); + w[m] = 0; + _mpd_baseaddto(w, a+m, la-m); + + memcpy(w+(m+1), b, m * sizeof *w); + w[m+1+m] = 0; + _mpd_baseaddto(w+(m+1), b+m, lb-m); + + if (!_karatsuba_rec_fnt(c+m, w, w+(m+1), w+2*(m+1), m+1, m+1)) { + return 0; /* GCOV_UNLIKELY */ + } + + lt = (la-m) + (la-m) + 1; + mpd_uint_zero(w, lt); + + if (!_karatsuba_rec_fnt(w, a+m, b+m, w+lt, la-m, lb-m)) { + return 0; /* GCOV_UNLIKELY */ + } + + _mpd_baseaddto(c+2*m, w, (la-m) + (lb-m)); + _mpd_basesubfrom(c+m, w, (la-m) + (lb-m)); + + lt = m + m + 1; + mpd_uint_zero(w, lt); + + if (!_karatsuba_rec_fnt(w, a, b, w+lt, m, m)) { + return 0; /* GCOV_UNLIKELY */ + } + _mpd_baseaddto(c, w, m+m); + _mpd_basesubfrom(c+m, w, m+m); + + return 1; +} + +/* + * Multiply u and v, using Karatsuba multiplication with the FNT as the + * base case. Returns a pointer to the result or NULL in case of failure + * (malloc error). Conditions: ulen >= vlen, ulen >= 4. + */ +mpd_uint_t * +_mpd_kmul_fnt(const mpd_uint_t *u, const mpd_uint_t *v, + mpd_size_t ulen, mpd_size_t vlen, + mpd_size_t *rsize) +{ + mpd_uint_t *result = NULL, *w = NULL; + mpd_size_t m; + + assert(ulen >= 4); + assert(ulen >= vlen); + + *rsize = _kmul_resultsize(ulen, vlen); + if ((result = mpd_calloc(*rsize, sizeof *result)) == NULL) { + return NULL; + } + + m = _kmul_worksize(ulen, 3*(MPD_MAXTRANSFORM_2N/2)); + if (m && ((w = mpd_calloc(m, sizeof *w)) == NULL)) { + mpd_free(result); /* GCOV_UNLIKELY */ + return NULL; /* GCOV_UNLIKELY */ + } + + if (!_karatsuba_rec_fnt(result, u, v, w, ulen, vlen)) { + mpd_free(result); + result = NULL; + } + + + if (w) mpd_free(w); + return result; +} + + +/* Deal with the special cases of multiplying infinities. */ +static void +_mpd_qmul_inf(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status) +{ + if (mpd_isinfinite(a)) { + if (mpd_iszero(b)) { + mpd_seterror(result, MPD_Invalid_operation, status); + } + else { + mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF); + } + return; + } + assert(mpd_isinfinite(b)); + if (mpd_iszero(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + } + else { + mpd_setspecial(result, mpd_sign(a)^mpd_sign(b), MPD_INF); + } +} + +/* + * Internal function: Multiply a and b. _mpd_qmul deals with specials but + * does NOT finalize the result. This is for use in mpd_fma(). + */ +static inline void +_mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_t *big = (mpd_t *)a, *small = (mpd_t *)b; + mpd_uint_t *rdata = NULL; + mpd_uint_t rbuf[MPD_MINALLOC_MAX]; + mpd_size_t rsize, i; + + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + _mpd_qmul_inf(result, a, b, status); + return; + } + + if (small->len > big->len) { + _mpd_ptrswap(&big, &small); + } + + rsize = big->len + small->len; + + if (big->len == 1) { + _mpd_singlemul(result->data, big->data[0], small->data[0]); + goto finish; + } + if (rsize <= (mpd_size_t)MPD_MINALLOC_MAX) { + if (big->len == 2) { + _mpd_mul_2_le2(rbuf, big->data, small->data, small->len); + } + else { + mpd_uint_zero(rbuf, rsize); + if (small->len == 1) { + _mpd_shortmul(rbuf, big->data, big->len, small->data[0]); + } + else { + _mpd_basemul(rbuf, small->data, big->data, small->len, big->len); + } + } + if (!mpd_qresize(result, rsize, status)) { + return; + } + for(i = 0; i < rsize; i++) { + result->data[i] = rbuf[i]; + } + goto finish; + } + + + if (small->len == 1) { + if ((rdata = mpd_calloc(rsize, sizeof *rdata)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + _mpd_shortmul(rdata, big->data, big->len, small->data[0]); + } + else if (rsize <= 1024) { + rdata = _mpd_kmul(big->data, small->data, big->len, small->len, &rsize); + if (rdata == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + } + else if (rsize <= 3*MPD_MAXTRANSFORM_2N) { + rdata = _mpd_fntmul(big->data, small->data, big->len, small->len, &rsize); + if (rdata == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + } + else { + rdata = _mpd_kmul_fnt(big->data, small->data, big->len, small->len, &rsize); + if (rdata == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); /* GCOV_UNLIKELY */ + return; /* GCOV_UNLIKELY */ + } + } + + if (mpd_isdynamic_data(result)) { + mpd_free(result->data); + } + result->data = rdata; + result->alloc = rsize; + mpd_set_dynamic_data(result); + + +finish: + mpd_set_flags(result, mpd_sign(a)^mpd_sign(b)); + result->exp = big->exp + small->exp; + result->len = _mpd_real_size(result->data, rsize); + /* resize to smaller cannot fail */ + mpd_qresize(result, result->len, status); + mpd_setdigits(result); +} + +/* Multiply a and b. */ +void +mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + _mpd_qmul(result, a, b, ctx, status); + mpd_qfinalize(result, ctx, status); +} + +/* Multiply decimal and mpd_ssize_t. */ +void +mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_ssize(&bb, b, &maxcontext, status); + mpd_qmul(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +/* Multiply decimal and mpd_uint_t. */ +void +mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(bb,0,0,0,0); + + mpd_maxcontext(&maxcontext); + mpd_qsset_uint(&bb, b, &maxcontext, status); + mpd_qmul(result, a, &bb, ctx, status); + mpd_del(&bb); +} + +void +mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qmul_ssize(result, a, b, ctx, status); +} + +void +mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qmul_uint(result, a, b, ctx, status); +} + +#ifdef CONFIG_64 +void +mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qmul_ssize(result, a, b, ctx, status); +} + +void +mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_qmul_uint(result, a, b, ctx, status); +} +#endif + +/* Like the minus operator. */ +void +mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + } + + if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) { + mpd_qcopy_abs(result, a, status); + } + else { + mpd_qcopy_negate(result, a, status); + } + + mpd_qfinalize(result, ctx, status); +} + +/* Like the plus operator. */ +void +mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + } + + if (mpd_iszero(a) && ctx->round != MPD_ROUND_FLOOR) { + mpd_qcopy_abs(result, a, status); + } + else { + mpd_qcopy(result, a, status); + } + + mpd_qfinalize(result, ctx, status); +} + +/* The largest representable number that is smaller than the operand. */ +void +mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; /* function context */ + MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1); + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isinfinite(a)) { + if (mpd_isnegative(a)) { + mpd_qcopy(result, a, status); + return; + } + else { + mpd_clear_flags(result); + mpd_qmaxcoeff(result, ctx, status); + if (mpd_isnan(result)) { + return; + } + result->exp = ctx->emax - ctx->prec + 1; + return; + } + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + + mpd_workcontext(&workctx, ctx); + workctx.round = MPD_ROUND_FLOOR; + + if (!mpd_qcopy(result, a, status)) { + return; + } + + mpd_qfinalize(result, &workctx, &workctx.status); + if (workctx.status&(MPD_Inexact|MPD_Errors)) { + *status |= (workctx.status&MPD_Errors); + return; + } + + workctx.status = 0; + mpd_qsub(result, a, &tiny, &workctx, &workctx.status); + *status |= (workctx.status&MPD_Errors); +} + +/* The smallest representable number that is larger than the operand. */ +void +mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_CONST(tiny,MPD_POS,mpd_etiny(ctx)-1,1,1,1,1); + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isinfinite(a)) { + if (mpd_ispositive(a)) { + mpd_qcopy(result, a, status); + } + else { + mpd_clear_flags(result); + mpd_qmaxcoeff(result, ctx, status); + if (mpd_isnan(result)) { + return; + } + mpd_set_flags(result, MPD_NEG); + result->exp = mpd_etop(ctx); + } + return; + } + } + + mpd_workcontext(&workctx, ctx); + workctx.round = MPD_ROUND_CEILING; + + if (!mpd_qcopy(result, a, status)) { + return; + } + + mpd_qfinalize(result, &workctx, &workctx.status); + if (workctx.status & (MPD_Inexact|MPD_Errors)) { + *status |= (workctx.status&MPD_Errors); + return; + } + + workctx.status = 0; + mpd_qadd(result, a, &tiny, &workctx, &workctx.status); + *status |= (workctx.status&MPD_Errors); +} + +/* + * The number closest to the first operand that is in the direction towards + * the second operand. + */ +void +mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + int c; + + if (mpd_isnan(a) || mpd_isnan(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) + return; + } + + c = _mpd_cmp(a, b); + if (c == 0) { + mpd_qcopy_sign(result, a, b, status); + return; + } + + if (c < 0) { + mpd_qnext_plus(result, a, ctx, status); + } + else { + mpd_qnext_minus(result, a, ctx, status); + } + + if (mpd_isinfinite(result)) { + *status |= (MPD_Overflow|MPD_Rounded|MPD_Inexact); + } + else if (mpd_adjexp(result) < ctx->emin) { + *status |= (MPD_Underflow|MPD_Subnormal|MPD_Rounded|MPD_Inexact); + if (mpd_iszero(result)) { + *status |= MPD_Clamped; + } + } +} + +/* + * Internal function: Integer power with mpd_uint_t exponent, base is modified! + * Function can fail with MPD_Malloc_error. + */ +static inline void +_mpd_qpow_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_uint_t n; + + if (exp == 0) { + _settriple(result, resultsign, 1, 0); /* GCOV_NOT_REACHED */ + return; /* GCOV_NOT_REACHED */ + } + + if (!mpd_qcopy(result, base, status)) { + return; + } + + n = mpd_bits[mpd_bsr(exp)]; + while (n >>= 1) { + mpd_qmul(result, result, result, ctx, &workstatus); + if (exp & n) { + mpd_qmul(result, result, base, ctx, &workstatus); + } + if (workstatus & (MPD_Overflow|MPD_Clamped)) { + break; + } + } + + *status |= workstatus; + mpd_set_sign(result, resultsign); +} + +/* + * Internal function: Integer power with mpd_t exponent, tbase and texp + * are modified!! Function can fail with MPD_Malloc_error. + */ +static inline void +_mpd_qpow_mpd(mpd_t *result, mpd_t *tbase, mpd_t *texp, uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_context_t maxctx; + MPD_NEW_CONST(two,0,0,1,1,1,2); + + + mpd_maxcontext(&maxctx); + + /* resize to smaller cannot fail */ + mpd_qcopy(result, &one, status); + + while (!mpd_iszero(texp)) { + if (mpd_isodd(texp)) { + mpd_qmul(result, result, tbase, ctx, &workstatus); + *status |= workstatus; + if (workstatus & (MPD_Overflow|MPD_Clamped)) { + break; + } + } + mpd_qmul(tbase, tbase, tbase, ctx, &workstatus); + mpd_qdivint(texp, texp, &two, &maxctx, &workstatus); + if (mpd_isnan(tbase) || mpd_isnan(texp)) { + mpd_seterror(result, workstatus&MPD_Errors, status); + return; + } + } + mpd_set_sign(result, resultsign); +} + +/* + * The power function for integer exponents. + */ +static void +_mpd_qpow_int(mpd_t *result, const mpd_t *base, const mpd_t *exp, + uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(tbase,0,0,0,0); + MPD_NEW_STATIC(texp,0,0,0,0); + mpd_ssize_t n; + + + mpd_workcontext(&workctx, ctx); + workctx.prec += (exp->digits + exp->exp + 2); + workctx.round = MPD_ROUND_HALF_EVEN; + workctx.clamp = 0; + if (mpd_isnegative(exp)) { + mpd_qdiv(&tbase, &one, base, &workctx, status); + if (*status&MPD_Errors) { + mpd_setspecial(result, MPD_POS, MPD_NAN); + goto finish; + } + } + else { + if (!mpd_qcopy(&tbase, base, status)) { + mpd_setspecial(result, MPD_POS, MPD_NAN); + goto finish; + } + } + + n = mpd_qabs_uint(exp, &workctx.status); + if (workctx.status&MPD_Invalid_operation) { + if (!mpd_qcopy(&texp, exp, status)) { + mpd_setspecial(result, MPD_POS, MPD_NAN); /* GCOV_UNLIKELY */ + goto finish; /* GCOV_UNLIKELY */ + } + _mpd_qpow_mpd(result, &tbase, &texp, resultsign, &workctx, status); + } + else { + _mpd_qpow_uint(result, &tbase, n, resultsign, &workctx, status); + } + + if (mpd_isinfinite(result)) { + /* for ROUND_DOWN, ROUND_FLOOR, etc. */ + _settriple(result, resultsign, 1, MPD_EXP_INF); + } + +finish: + mpd_del(&tbase); + mpd_del(&texp); + mpd_qfinalize(result, ctx, status); +} + +/* + * This is an internal function that does not check for NaNs. + */ +static int +_qcheck_pow_one_inf(mpd_t *result, const mpd_t *base, uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t shift; + int cmp; + + if ((cmp = _mpd_cmp(base, &one)) == 0) { + shift = ctx->prec-1; + mpd_qshiftl(result, &one, shift, status); + result->exp = -shift; + mpd_set_flags(result, resultsign); + *status |= (MPD_Inexact|MPD_Rounded); + } + + return cmp; +} + +/* + * If base equals one, calculate the correct power of one result. + * Otherwise, result is undefined. Return the value of the comparison + * against 1. + * + * This is an internal function that does not check for specials. + */ +static int +_qcheck_pow_one(mpd_t *result, const mpd_t *base, const mpd_t *exp, + uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_ssize_t shift; + int cmp; + + if ((cmp = _mpd_cmp_abs(base, &one)) == 0) { + if (_mpd_isint(exp)) { + if (mpd_isnegative(exp)) { + _settriple(result, resultsign, 1, 0); + return 0; + } + /* 1.000**3 = 1.000000000 */ + mpd_qmul_ssize(result, exp, -base->exp, ctx, &workstatus); + if (workstatus&MPD_Errors) { + *status |= (workstatus&MPD_Errors); + return 0; + } + /* digits-1 after exponentiation */ + shift = mpd_qget_ssize(result, &workstatus); + /* shift is MPD_SSIZE_MAX if result is too large */ + if (shift > ctx->prec-1) { + shift = ctx->prec-1; + *status |= MPD_Rounded; + } + } + else if (mpd_ispositive(base)) { + shift = ctx->prec-1; + *status |= (MPD_Inexact|MPD_Rounded); + } + else { + return -2; /* GCOV_NOT_REACHED */ + } + if (!mpd_qshiftl(result, &one, shift, status)) { + return 0; + } + result->exp = -shift; + mpd_set_flags(result, resultsign); + } + + return cmp; +} + +/* + * Detect certain over/underflow of x**y. + * ACL2 proof: pow_bounds.lisp. + * + * Symbols: + * + * e: EXP_INF or EXP_CLAMP + * x: base + * y: exponent + * + * omega(e) = log10(abs(e)) + * zeta(x) = log10(abs(log10(x))) + * theta(y) = log10(abs(y)) + * + * Upper and lower bounds: + * + * ub_omega(e) = ceil(log10(abs(e))) + * lb_theta(y) = floor(log10(abs(y))) + * + * | floor(log10(floor(abs(log10(x))))) if x < 1/10 or x >= 10 + * lb_zeta(x) = | floor(log10(abs(x-1)/10)) if 1/10 <= x < 1 + * | floor(log10(abs((x-1)/100))) if 1 < x < 10 + * + * ub_omega(e) and lb_theta(y) are obviously upper and lower bounds + * for omega(e) and theta(y). + * + * lb_zeta is a lower bound for zeta(x): + * + * x < 1/10 or x >= 10: + * + * abs(log10(x)) >= 1, so the outer log10 is well defined. Since log10 + * is strictly increasing, the end result is a lower bound. + * + * 1/10 <= x < 1: + * + * We use: log10(x) <= (x-1)/log(10) + * abs(log10(x)) >= abs(x-1)/log(10) + * abs(log10(x)) >= abs(x-1)/10 + * + * 1 < x < 10: + * + * We use: (x-1)/(x*log(10)) < log10(x) + * abs((x-1)/100) < abs(log10(x)) + * + * XXX: abs((x-1)/10) would work, need ACL2 proof. + * + * + * Let (0 < x < 1 and y < 0) or (x > 1 and y > 0). (H1) + * Let ub_omega(exp_inf) < lb_zeta(x) + lb_theta(y) (H2) + * + * Then: + * log10(abs(exp_inf)) < log10(abs(log10(x))) + log10(abs(y)). (1) + * exp_inf < log10(x) * y (2) + * 10**exp_inf < x**y (3) + * + * Let (0 < x < 1 and y > 0) or (x > 1 and y < 0). (H3) + * Let ub_omega(exp_clamp) < lb_zeta(x) + lb_theta(y) (H4) + * + * Then: + * log10(abs(exp_clamp)) < log10(abs(log10(x))) + log10(abs(y)). (4) + * log10(x) * y < exp_clamp (5) + * x**y < 10**exp_clamp (6) + * + */ +static mpd_ssize_t +_lower_bound_zeta(const mpd_t *x, uint32_t *status) +{ + mpd_context_t maxctx; + MPD_NEW_STATIC(scratch,0,0,0,0); + mpd_ssize_t t, u; + + t = mpd_adjexp(x); + if (t > 0) { + /* x >= 10 -> floor(log10(floor(abs(log10(x))))) */ + return mpd_exp_digits(t) - 1; + } + else if (t < -1) { + /* x < 1/10 -> floor(log10(floor(abs(log10(x))))) */ + return mpd_exp_digits(t+1) - 1; + } + else { + mpd_maxcontext(&maxctx); + mpd_qsub(&scratch, x, &one, &maxctx, status); + if (mpd_isspecial(&scratch)) { + mpd_del(&scratch); + return MPD_SSIZE_MAX; + } + u = mpd_adjexp(&scratch); + mpd_del(&scratch); + + /* t == -1, 1/10 <= x < 1 -> floor(log10(abs(x-1)/10)) + * t == 0, 1 < x < 10 -> floor(log10(abs(x-1)/100)) */ + return (t == 0) ? u-2 : u-1; + } +} + +/* + * Detect cases of certain overflow/underflow in the power function. + * Assumptions: x != 1, y != 0. The proof above is for positive x. + * If x is negative and y is an odd integer, x**y == -(abs(x)**y), + * so the analysis does not change. + */ +static int +_qcheck_pow_bounds(mpd_t *result, const mpd_t *x, const mpd_t *y, + uint8_t resultsign, + const mpd_context_t *ctx, uint32_t *status) +{ + MPD_NEW_SHARED(abs_x, x); + mpd_ssize_t ub_omega, lb_zeta, lb_theta; + uint8_t sign; + + mpd_set_positive(&abs_x); + + lb_theta = mpd_adjexp(y); + lb_zeta = _lower_bound_zeta(&abs_x, status); + if (lb_zeta == MPD_SSIZE_MAX) { + mpd_seterror(result, MPD_Malloc_error, status); + return 1; + } + + sign = (mpd_adjexp(&abs_x) < 0) ^ mpd_sign(y); + if (sign == 0) { + /* (0 < |x| < 1 and y < 0) or (|x| > 1 and y > 0) */ + ub_omega = mpd_exp_digits(ctx->emax); + if (ub_omega < lb_zeta + lb_theta) { + _settriple(result, resultsign, 1, MPD_EXP_INF); + mpd_qfinalize(result, ctx, status); + return 1; + } + } + else { + /* (0 < |x| < 1 and y > 0) or (|x| > 1 and y < 0). */ + ub_omega = mpd_exp_digits(mpd_etiny(ctx)); + if (ub_omega < lb_zeta + lb_theta) { + _settriple(result, resultsign, 1, mpd_etiny(ctx)-1); + mpd_qfinalize(result, ctx, status); + return 1; + } + } + + return 0; +} + +/* + * TODO: Implement algorithm for computing exact powers from decimal.py. + * In order to prevent infinite loops, this has to be called before + * using Ziv's strategy for correct rounding. + */ +/* +static int +_mpd_qpow_exact(mpd_t *result, const mpd_t *base, const mpd_t *exp, + const mpd_context_t *ctx, uint32_t *status) +{ + return 0; +} +*/ + +/* The power function for real exponents */ +static void +_mpd_qpow_real(mpd_t *result, const mpd_t *base, const mpd_t *exp, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(texp,0,0,0,0); + + if (!mpd_qcopy(&texp, exp, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + + mpd_maxcontext(&workctx); + workctx.prec = (base->digits > ctx->prec) ? base->digits : ctx->prec; + workctx.prec += (4 + MPD_EXPDIGITS); + workctx.round = MPD_ROUND_HALF_EVEN; + workctx.allcr = ctx->allcr; + + mpd_qln(result, base, &workctx, &workctx.status); + mpd_qmul(result, result, &texp, &workctx, &workctx.status); + mpd_qexp(result, result, &workctx, status); + + mpd_del(&texp); + *status |= (workctx.status&MPD_Errors); + *status |= (MPD_Inexact|MPD_Rounded); +} + +/* The power function: base**exp */ +void +mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp, + const mpd_context_t *ctx, uint32_t *status) +{ + uint8_t resultsign = 0; + int intexp = 0; + int cmp; + + if (mpd_isspecial(base) || mpd_isspecial(exp)) { + if (mpd_qcheck_nans(result, base, exp, ctx, status)) { + return; + } + } + if (mpd_isinteger(exp)) { + intexp = 1; + resultsign = mpd_isnegative(base) && mpd_isodd(exp); + } + + if (mpd_iszero(base)) { + if (mpd_iszero(exp)) { + mpd_seterror(result, MPD_Invalid_operation, status); + } + else if (mpd_isnegative(exp)) { + mpd_setspecial(result, resultsign, MPD_INF); + } + else { + _settriple(result, resultsign, 0, 0); + } + return; + } + if (mpd_isnegative(base)) { + if (!intexp || mpd_isinfinite(exp)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + } + if (mpd_isinfinite(exp)) { + /* power of one */ + cmp = _qcheck_pow_one_inf(result, base, resultsign, ctx, status); + if (cmp == 0) { + return; + } + else { + cmp *= mpd_arith_sign(exp); + if (cmp < 0) { + _settriple(result, resultsign, 0, 0); + } + else { + mpd_setspecial(result, resultsign, MPD_INF); + } + } + return; + } + if (mpd_isinfinite(base)) { + if (mpd_iszero(exp)) { + _settriple(result, resultsign, 1, 0); + } + else if (mpd_isnegative(exp)) { + _settriple(result, resultsign, 0, 0); + } + else { + mpd_setspecial(result, resultsign, MPD_INF); + } + return; + } + if (mpd_iszero(exp)) { + _settriple(result, resultsign, 1, 0); + return; + } + if (_qcheck_pow_one(result, base, exp, resultsign, ctx, status) == 0) { + return; + } + if (_qcheck_pow_bounds(result, base, exp, resultsign, ctx, status)) { + return; + } + + if (intexp) { + _mpd_qpow_int(result, base, exp, resultsign, ctx, status); + } + else { + _mpd_qpow_real(result, base, exp, ctx, status); + if (!mpd_isspecial(result) && _mpd_cmp(result, &one) == 0) { + mpd_ssize_t shift = ctx->prec-1; + mpd_qshiftl(result, &one, shift, status); + result->exp = -shift; + } + if (mpd_isinfinite(result)) { + /* for ROUND_DOWN, ROUND_FLOOR, etc. */ + _settriple(result, MPD_POS, 1, MPD_EXP_INF); + } + mpd_qfinalize(result, ctx, status); + } +} + +/* + * Internal function: Integer powmod with mpd_uint_t exponent, base is modified! + * Function can fail with MPD_Malloc_error. + */ +static inline void +_mpd_qpowmod_uint(mpd_t *result, mpd_t *base, mpd_uint_t exp, + mpd_t *mod, uint32_t *status) +{ + mpd_context_t maxcontext; + + mpd_maxcontext(&maxcontext); + + /* resize to smaller cannot fail */ + mpd_qcopy(result, &one, status); + + while (exp > 0) { + if (exp & 1) { + mpd_qmul(result, result, base, &maxcontext, status); + mpd_qrem(result, result, mod, &maxcontext, status); + } + mpd_qmul(base, base, base, &maxcontext, status); + mpd_qrem(base, base, mod, &maxcontext, status); + exp >>= 1; + } +} + +/* The powmod function: (base**exp) % mod */ +void +mpd_qpowmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, + const mpd_t *mod, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxcontext; + MPD_NEW_STATIC(tbase,0,0,0,0); + MPD_NEW_STATIC(texp,0,0,0,0); + MPD_NEW_STATIC(tmod,0,0,0,0); + MPD_NEW_STATIC(tmp,0,0,0,0); + MPD_NEW_CONST(two,0,0,1,1,1,2); + mpd_ssize_t tbase_exp, texp_exp; + mpd_ssize_t i; + mpd_t t; + mpd_uint_t r; + uint8_t sign; + + + if (mpd_isspecial(base) || mpd_isspecial(exp) || mpd_isspecial(mod)) { + if (mpd_qcheck_3nans(result, base, exp, mod, ctx, status)) { + return; + } + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + + if (!_mpd_isint(base) || !_mpd_isint(exp) || !_mpd_isint(mod)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_iszerocoeff(mod)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mod->digits+mod->exp > ctx->prec) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + sign = (mpd_isnegative(base)) && (mpd_isodd(exp)); + if (mpd_iszerocoeff(exp)) { + if (mpd_iszerocoeff(base)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + r = (_mpd_cmp_abs(mod, &one)==0) ? 0 : 1; + _settriple(result, sign, r, 0); + return; + } + if (mpd_isnegative(exp)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (mpd_iszerocoeff(base)) { + _settriple(result, sign, 0, 0); + return; + } + + if (!mpd_qcopy(&tmod, mod, status)) { + goto mpd_errors; + } + mpd_set_positive(&tmod); + + mpd_maxcontext(&maxcontext); + + mpd_qround_to_int(&tbase, base, &maxcontext, status); + mpd_qround_to_int(&texp, exp, &maxcontext, status); + mpd_qround_to_int(&tmod, &tmod, &maxcontext, status); + + tbase_exp = tbase.exp; + tbase.exp = 0; + texp_exp = texp.exp; + texp.exp = 0; + + /* base = (base.int % modulo * pow(10, base.exp, modulo)) % modulo */ + mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status); + _settriple(result, MPD_POS, 1, tbase_exp); + mpd_qrem(result, result, &tmod, &maxcontext, status); + mpd_qmul(&tbase, &tbase, result, &maxcontext, status); + mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status); + if (mpd_isspecial(&tbase) || + mpd_isspecial(&texp) || + mpd_isspecial(&tmod)) { + goto mpd_errors; + } + + for (i = 0; i < texp_exp; i++) { + _mpd_qpowmod_uint(&tmp, &tbase, 10, &tmod, status); + t = tmp; + tmp = tbase; + tbase = t; + } + if (mpd_isspecial(&tbase)) { + goto mpd_errors; /* GCOV_UNLIKELY */ + } + + /* resize to smaller cannot fail */ + mpd_qcopy(result, &one, status); + while (mpd_isfinite(&texp) && !mpd_iszero(&texp)) { + if (mpd_isodd(&texp)) { + mpd_qmul(result, result, &tbase, &maxcontext, status); + mpd_qrem(result, result, &tmod, &maxcontext, status); + } + mpd_qmul(&tbase, &tbase, &tbase, &maxcontext, status); + mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status); + mpd_qdivint(&texp, &texp, &two, &maxcontext, status); + } + if (mpd_isspecial(&texp) || mpd_isspecial(&tbase) || + mpd_isspecial(&tmod) || mpd_isspecial(result)) { + /* MPD_Malloc_error */ + goto mpd_errors; + } + else { + mpd_set_sign(result, sign); + } + +out: + mpd_del(&tbase); + mpd_del(&texp); + mpd_del(&tmod); + mpd_del(&tmp); + mpd_qfinalize(result, ctx, status); + return; + +mpd_errors: + mpd_setspecial(result, MPD_POS, MPD_NAN); + goto out; +} + +void +mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_ssize_t b_exp = b->exp; + mpd_ssize_t expdiff, shift; + mpd_uint_t rnd; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(result, a, b, ctx, status)) { + return; + } + if (mpd_isinfinite(a) && mpd_isinfinite(b)) { + mpd_qcopy(result, a, status); + return; + } + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + if (b->exp > ctx->emax || b->exp < mpd_etiny(ctx)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + if (mpd_iszero(a)) { + _settriple(result, mpd_sign(a), 0, b->exp); + mpd_qfinalize(result, ctx, status); + return; + } + + + expdiff = a->exp - b->exp; + if (a->digits + expdiff > ctx->prec) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + if (expdiff >= 0) { + shift = expdiff; + if (!mpd_qshiftl(result, a, shift, status)) { + return; + } + result->exp = b_exp; + } + else { + /* At this point expdiff < 0 and a->digits+expdiff <= prec, + * so the shift before an increment will fit in prec. */ + shift = -expdiff; + rnd = mpd_qshiftr(result, a, shift, status); + if (rnd == MPD_UINT_MAX) { + return; + } + result->exp = b_exp; + if (!_mpd_apply_round_fit(result, rnd, ctx, status)) { + return; + } + workstatus |= MPD_Rounded; + if (rnd) { + workstatus |= MPD_Inexact; + } + } + + if (mpd_adjexp(result) > ctx->emax || + mpd_adjexp(result) < mpd_etiny(ctx)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + *status |= workstatus; + mpd_qfinalize(result, ctx, status); +} + +void +mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_ssize_t shift, maxexp, maxshift; + uint8_t sign_a = mpd_sign(a); + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + mpd_qcopy(result, a, status); + return; + } + + if (!mpd_qcopy(result, a, status)) { + return; + } + mpd_qfinalize(result, ctx, status); + if (mpd_isspecial(result)) { + return; + } + if (mpd_iszero(result)) { + _settriple(result, sign_a, 0, 0); + return; + } + + shift = mpd_trail_zeros(result); + maxexp = (ctx->clamp) ? mpd_etop(ctx) : ctx->emax; + /* After the finalizing above result->exp <= maxexp. */ + maxshift = maxexp - result->exp; + shift = (shift > maxshift) ? maxshift : shift; + + mpd_qshiftr_inplace(result, shift); + result->exp += shift; +} + +void +mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, + uint32_t *status) +{ + MPD_NEW_STATIC(q,0,0,0,0); + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(r, a, b, ctx, status)) { + return; + } + if (mpd_isinfinite(a)) { + mpd_seterror(r, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(b)) { + mpd_qcopy(r, a, status); + mpd_qfinalize(r, ctx, status); + return; + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_seterror(r, MPD_Division_undefined, status); + } + else { + mpd_seterror(r, MPD_Invalid_operation, status); + } + return; + } + + _mpd_qdivmod(&q, r, a, b, ctx, status); + mpd_del(&q); + mpd_qfinalize(r, ctx, status); +} + +void +mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t workctx; + MPD_NEW_STATIC(btmp,0,0,0,0); + MPD_NEW_STATIC(q,0,0,0,0); + mpd_ssize_t expdiff, floordigits; + int cmp, isodd, allnine; + + if (mpd_isspecial(a) || mpd_isspecial(b)) { + if (mpd_qcheck_nans(r, a, b, ctx, status)) { + return; + } + if (mpd_isinfinite(a)) { + mpd_seterror(r, MPD_Invalid_operation, status); + return; + } + if (mpd_isinfinite(b)) { + mpd_qcopy(r, a, status); + mpd_qfinalize(r, ctx, status); + return; + } + /* debug */ + abort(); /* GCOV_NOT_REACHED */ + } + if (mpd_iszerocoeff(b)) { + if (mpd_iszerocoeff(a)) { + mpd_seterror(r, MPD_Division_undefined, status); + } + else { + mpd_seterror(r, MPD_Invalid_operation, status); + } + return; + } + + if (r == b) { + if (!mpd_qcopy(&btmp, b, status)) { + mpd_seterror(r, MPD_Malloc_error, status); + return; + } + b = &btmp; + } + + workctx = *ctx; + workctx.prec = a->digits; + workctx.prec = (workctx.prec > ctx->prec) ? workctx.prec : ctx->prec; + + _mpd_qdivmod(&q, r, a, b, &workctx, status); + if (mpd_isnan(&q) || mpd_isnan(r) || q.digits > ctx->prec) { + mpd_seterror(r, MPD_Division_impossible, status); + goto finish; + } + if (mpd_iszerocoeff(r)) { + goto finish; + } + + /* Deal with cases like rmnx078: + * remaindernear 999999999.5 1 -> NaN Division_impossible */ + expdiff = mpd_adjexp(b) - mpd_adjexp(r); + if (-1 <= expdiff && expdiff <= 1) { + + mpd_qtrunc(&q, &q, &workctx, &workctx.status); + allnine = mpd_coeff_isallnine(&q); + floordigits = q.digits; + isodd = mpd_isodd(&q); + + mpd_maxcontext(&workctx); + if (mpd_sign(a) == mpd_sign(b)) { + _mpd_qsub(&q, r, b, &workctx, &workctx.status); + if (workctx.status&MPD_Errors) { + mpd_seterror(r, workctx.status&MPD_Errors, status); + goto finish; + } + } + else { + _mpd_qadd(&q, r, b, &workctx, &workctx.status); + if (workctx.status&MPD_Errors) { + mpd_seterror(r, workctx.status&MPD_Errors, status); + goto finish; + } + } + + cmp = mpd_cmp_total_mag(&q, r); + if (cmp < 0 || (cmp == 0 && isodd)) { + if (allnine && floordigits == ctx->prec) { + mpd_seterror(r, MPD_Division_impossible, status); + goto finish; + } + mpd_qcopy(r, &q, status); + *status &= ~MPD_Rounded; + } + } + + +finish: + mpd_del(&btmp); + mpd_del(&q); + mpd_qfinalize(r, ctx, status); +} + +static void +_mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_ssize_t expdiff, shift; + mpd_uint_t rnd; + + if (mpd_isspecial(a)) { + mpd_qcopy(result, a, status); + return; + } + + if (mpd_iszero(a)) { + _settriple(result, mpd_sign(a), 0, exp); + return; + } + + expdiff = a->exp - exp; + if (expdiff >= 0) { + shift = expdiff; + if (a->digits + shift > MPD_MAX_PREC+1) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (!mpd_qshiftl(result, a, shift, status)) { + return; + } + result->exp = exp; + } + else { + shift = -expdiff; + rnd = mpd_qshiftr(result, a, shift, status); + if (rnd == MPD_UINT_MAX) { + return; + } + result->exp = exp; + _mpd_apply_round_excess(result, rnd, ctx, status); + *status |= MPD_Rounded; + if (rnd) { + *status |= MPD_Inexact; + } + } + + if (mpd_issubnormal(result, ctx)) { + *status |= MPD_Subnormal; + } +} + +/* + * Rescale a number so that it has exponent 'exp'. Does not regard context + * precision, emax, emin, but uses the rounding mode. Special numbers are + * quietly copied. Restrictions: + * + * MPD_MIN_ETINY <= exp <= MPD_MAX_EMAX+1 + * result->digits <= MPD_MAX_PREC+1 + */ +void +mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, + const mpd_context_t *ctx, uint32_t *status) +{ + if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + _mpd_qrescale(result, a, exp, ctx, status); +} + +/* + * Same as mpd_qrescale, but with relaxed restrictions. The result of this + * function should only be used for formatting a number and never as input + * for other operations. + * + * MPD_MIN_ETINY-MPD_MAX_PREC <= exp <= MPD_MAX_EMAX+1 + * result->digits <= MPD_MAX_PREC+1 + */ +void +mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, + const mpd_context_t *ctx, uint32_t *status) +{ + if (exp > MPD_MAX_EMAX+1 || exp < MPD_MIN_ETINY-MPD_MAX_PREC) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + _mpd_qrescale(result, a, exp, ctx, status); +} + +/* Round to an integer according to 'action' and ctx->round. */ +enum {TO_INT_EXACT, TO_INT_SILENT, TO_INT_TRUNC}; +static void +_mpd_qround_to_integral(int action, mpd_t *result, const mpd_t *a, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t rnd; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + mpd_qcopy(result, a, status); + return; + } + if (a->exp >= 0) { + mpd_qcopy(result, a, status); + return; + } + if (mpd_iszerocoeff(a)) { + _settriple(result, mpd_sign(a), 0, 0); + return; + } + + rnd = mpd_qshiftr(result, a, -a->exp, status); + if (rnd == MPD_UINT_MAX) { + return; + } + result->exp = 0; + + if (action == TO_INT_EXACT || action == TO_INT_SILENT) { + _mpd_apply_round_excess(result, rnd, ctx, status); + if (action == TO_INT_EXACT) { + *status |= MPD_Rounded; + if (rnd) { + *status |= MPD_Inexact; + } + } + } +} + +void +mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + (void)_mpd_qround_to_integral(TO_INT_EXACT, result, a, ctx, status); +} + +void +mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a, ctx, status); +} + +void +mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + (void)_mpd_qround_to_integral(TO_INT_TRUNC, result, a, ctx, status); +} + +void +mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx = *ctx; + workctx.round = MPD_ROUND_FLOOR; + (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a, + &workctx, status); +} + +void +mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t workctx = *ctx; + workctx.round = MPD_ROUND_CEILING; + (void)_mpd_qround_to_integral(TO_INT_SILENT, result, a, + &workctx, status); +} + +int +mpd_same_quantum(const mpd_t *a, const mpd_t *b) +{ + if (mpd_isspecial(a) || mpd_isspecial(b)) { + return ((mpd_isnan(a) && mpd_isnan(b)) || + (mpd_isinfinite(a) && mpd_isinfinite(b))); + } + + return a->exp == b->exp; +} + +/* Schedule the increase in precision for the Newton iteration. */ +static inline int +recpr_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], + mpd_ssize_t maxprec, mpd_ssize_t initprec) +{ + mpd_ssize_t k; + int i; + + assert(maxprec > 0 && initprec > 0); + if (maxprec <= initprec) return -1; + + i = 0; k = maxprec; + do { + k = (k+1) / 2; + klist[i++] = k; + } while (k > initprec); + + return i-1; +} + +/* + * Initial approximation for the reciprocal. Result has MPD_RDIGITS-2 + * significant digits. + */ +static void +_mpd_qreciprocal_approx(mpd_t *z, const mpd_t *v, uint32_t *status) +{ + mpd_uint_t p10data[2] = {0, mpd_pow10[MPD_RDIGITS-2]}; /* 10**(2*MPD_RDIGITS-2) */ + mpd_uint_t dummy, word; + int n; + + _mpd_get_msdigits(&dummy, &word, v, MPD_RDIGITS); + n = mpd_word_digits(word); + word *= mpd_pow10[MPD_RDIGITS-n]; + + mpd_qresize(z, 2, status); + (void)_mpd_shortdiv(z->data, p10data, 2, word); + + mpd_clear_flags(z); + z->exp = -(v->exp + v->digits) - (MPD_RDIGITS-2); + z->len = (z->data[1] == 0) ? 1 : 2; + mpd_setdigits(z); +} + +/* Reciprocal, calculated with Newton's Method. Assumption: result != a. */ +static void +_mpd_qreciprocal(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + mpd_context_t varcontext, maxcontext; + mpd_t *z = result; /* current approximation */ + mpd_t *v; /* a, normalized to a number between 0.1 and 1 */ + MPD_NEW_SHARED(vtmp, a); /* by default v will share data with a */ + MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */ + MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */ + MPD_NEW_CONST(two,0,0,1,1,1,2); /* const 2 */ + mpd_ssize_t klist[MPD_MAX_PREC_LOG2]; + mpd_ssize_t adj, maxprec, initprec; + uint8_t sign = mpd_sign(a); + int i; + + v = &vtmp; + assert(result != a); + + mpd_clear_flags(v); + adj = v->digits + v->exp; + v->exp = -v->digits; + + /* initial approximation */ + _mpd_qreciprocal_approx(z, v, status); + + mpd_maxcontext(&varcontext); + mpd_maxcontext(&maxcontext); + varcontext.round = MPD_ROUND_TRUNC; + maxcontext.round = MPD_ROUND_TRUNC; + + maxprec = (v->digits > ctx->prec) ? v->digits : ctx->prec; + maxprec += 2; + initprec = MPD_RDIGITS-3; + + i = recpr_schedule_prec(klist, maxprec, initprec); + for (; i >= 0; i--) { + mpd_qmul(&s, z, z, &maxcontext, status); + varcontext.prec = 2*klist[i] + 5; + if (v->digits > varcontext.prec) { + mpd_qshiftr(&t, v, v->digits-varcontext.prec, status); + t.exp = -varcontext.prec; + mpd_qmul(&t, &t, &s, &varcontext, status); + } + else { + mpd_qmul(&t, v, &s, &varcontext, status); + } + mpd_qmul(&s, z, &two, &maxcontext, status); + mpd_qsub(z, &s, &t, &maxcontext, status); + } + + if (!mpd_isspecial(z)) { + z->exp -= adj; + mpd_set_flags(z, sign); + } + + mpd_del(&s); + mpd_del(&t); + mpd_qfinalize(z, ctx, status); +} + +/* + * Integer division with remainder of the coefficients: coeff(a) / coeff(b). + * This function is for large numbers where it is faster to divide by + * multiplying the dividend by the reciprocal of the divisor. + * The inexact result is fixed by a small loop, which should not take + * more than 2 iterations. + */ +static void +_mpd_qbarrett_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, + uint32_t *status) +{ + mpd_context_t workctx; + mpd_t *qq = q, *rr = r; + mpd_t aa, bb; + int k; + + mpd_maxcontext(&workctx); + _mpd_copy_shared(&aa, a); + _mpd_copy_shared(&bb, b); + + mpd_set_positive(&aa); + mpd_set_positive(&bb); + aa.exp = 0; + bb.exp = 0; + + if (q == a || q == b) { + if ((qq = mpd_qnew()) == NULL) { + *status |= MPD_Malloc_error; + goto nanresult; + } + } + if (r == a || r == b) { + if ((rr = mpd_qnew()) == NULL) { + *status |= MPD_Malloc_error; + goto nanresult; + } + } + + /* maximum length of q + 3 digits */ + workctx.prec = aa.digits - bb.digits + 1 + 3; + /* we get the reciprocal with precision maxlen(q) + 3 */ + _mpd_qreciprocal(rr, &bb, &workctx, &workctx.status); + + mpd_qmul(qq, &aa, rr, &workctx, &workctx.status); + mpd_qtrunc(qq, qq, &workctx, &workctx.status); + + workctx.prec = aa.digits + 3; + /* get the remainder */ + mpd_qmul(rr, &bb, qq, &workctx, &workctx.status); + mpd_qsub(rr, &aa, rr, &workctx, &workctx.status); + + /* Fix the result. Algorithm from: Karl Hasselstrom, Fast Division of Large Integers */ + for (k = 0;; k++) { + if (mpd_isspecial(rr)) { + *status |= (workctx.status&MPD_Errors); + goto nanresult; + } + if (k > 2) { + mpd_err_warn("libmpdec: internal error in " /* GCOV_NOT_REACHED */ + "_mpd_qbarrett_divmod: please report"); /* GCOV_NOT_REACHED */ + *status |= MPD_Invalid_operation; /* GCOV_NOT_REACHED */ + goto nanresult; /* GCOV_NOT_REACHED */ + } + else if (_mpd_cmp(&zero, rr) == 1) { + mpd_qadd(rr, rr, &bb, &workctx, &workctx.status); + mpd_qadd(qq, qq, &minus_one, &workctx, &workctx.status); + } + else if (_mpd_cmp(rr, &bb) == -1) { + break; + } + else { + mpd_qsub(rr, rr, &bb, &workctx, &workctx.status); + mpd_qadd(qq, qq, &one, &workctx, &workctx.status); + } + } + + if (qq != q) { + if (!mpd_qcopy(q, qq, status)) { + goto nanresult; /* GCOV_UNLIKELY */ + } + mpd_del(qq); + } + if (rr != r) { + if (!mpd_qcopy(r, rr, status)) { + goto nanresult; /* GCOV_UNLIKELY */ + } + mpd_del(rr); + } + + *status |= (workctx.status&MPD_Errors); + return; + + +nanresult: + if (qq && qq != q) mpd_del(qq); + if (rr && rr != r) mpd_del(rr); + mpd_setspecial(q, MPD_POS, MPD_NAN); + mpd_setspecial(r, MPD_POS, MPD_NAN); +} + +static inline int +invroot_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], + mpd_ssize_t maxprec, mpd_ssize_t initprec) +{ + mpd_ssize_t k; + int i; + + assert(maxprec >= 3 && initprec >= 3); + if (maxprec <= initprec) return -1; + + i = 0; k = maxprec; + do { + k = (k+3) / 2; + klist[i++] = k; + } while (k > initprec); + + return i-1; +} + +/* + * Initial approximation for the inverse square root. + * + * Input: + * v := 7 or 8 decimal digits with an implicit exponent of 10**-6, + * representing a number 1 <= x < 100. + * + * Output: + * An approximation to 1/sqrt(v) + */ +static inline void +_invroot_init_approx(mpd_t *z, mpd_uint_t v) +{ + mpd_uint_t lo = 1000; + mpd_uint_t hi = 10000; + mpd_uint_t a, sq; + + assert(v >= lo*lo && v < (hi+1)*(hi+1)); + + for(;;) { + a = (lo + hi) / 2; + sq = a * a; + if (v >= sq) { + if (v < sq + 2*a + 1) { + break; + } + lo = a + 1; + } + else { + hi = a - 1; + } + } + + /* At this point a/1000 is an approximation to sqrt(v). */ + mpd_minalloc(z); + mpd_clear_flags(z); + z->data[0] = 1000000000UL / a; + z->len = 1; + z->exp = -6; + mpd_setdigits(z); +} + +static void +_mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_context_t varcontext, maxcontext; + mpd_t *z = result; /* current approximation */ + mpd_t *v; /* a, normalized to a number between 1 and 100 */ + MPD_NEW_SHARED(vtmp, a); /* by default v will share data with a */ + MPD_NEW_STATIC(s,0,0,0,0); /* temporary variable */ + MPD_NEW_STATIC(t,0,0,0,0); /* temporary variable */ + MPD_NEW_CONST(one_half,0,-1,1,1,1,5); + MPD_NEW_CONST(three,0,0,1,1,1,3); + mpd_ssize_t klist[MPD_MAX_PREC_LOG2]; + mpd_ssize_t ideal_exp, shift; + mpd_ssize_t adj, tz; + mpd_ssize_t maxprec, fracdigits; + mpd_uint_t x, dummy; + int i, n; + + + ideal_exp = -(a->exp - (a->exp & 1)) / 2; + + v = &vtmp; + if (result == a) { + if ((v = mpd_qncopy(a)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + } + + /* normalize a to 1 <= v < 100 */ + if ((v->digits+v->exp) & 1) { + fracdigits = v->digits - 1; + v->exp = -fracdigits; + n = (v->digits > 7) ? 7 : (int)v->digits; + _mpd_get_msdigits(&dummy, &x, v, n); + if (n < 7) { + x *= mpd_pow10[7-n]; + } + } + else { + fracdigits = v->digits - 2; + v->exp = -fracdigits; + n = (v->digits > 8) ? 8 : (int)v->digits; + _mpd_get_msdigits(&dummy, &x, v, n); + if (n < 8) { + x *= mpd_pow10[8-n]; + } + } + adj = (a->exp-v->exp) / 2; + + /* initial approximation */ + _invroot_init_approx(z, x); + + mpd_maxcontext(&maxcontext); + mpd_maxcontext(&varcontext); + varcontext.round = MPD_ROUND_TRUNC; + maxprec = ctx->prec + 2; + + i = invroot_schedule_prec(klist, maxprec, 3); + for (; i >= 0; i--) { + varcontext.prec = 2*klist[i]+2; + mpd_qmul(&s, z, z, &maxcontext, &workstatus); + if (v->digits > varcontext.prec) { + shift = v->digits - varcontext.prec; + mpd_qshiftr(&t, v, shift, &workstatus); + t.exp += shift; + mpd_qmul(&t, &t, &s, &varcontext, &workstatus); + } + else { + mpd_qmul(&t, v, &s, &varcontext, &workstatus); + } + mpd_qsub(&t, &three, &t, &maxcontext, &workstatus); + mpd_qmul(z, z, &t, &varcontext, &workstatus); + mpd_qmul(z, z, &one_half, &maxcontext, &workstatus); + } + + z->exp -= adj; + + tz = mpd_trail_zeros(result); + shift = ideal_exp - result->exp; + shift = (tz > shift) ? shift : tz; + if (shift > 0) { + mpd_qshiftr_inplace(result, shift); + result->exp += shift; + } + + + mpd_del(&s); + mpd_del(&t); + if (v != &vtmp) mpd_del(v); + *status |= (workstatus&MPD_Errors); + varcontext = *ctx; + varcontext.round = MPD_ROUND_HALF_EVEN; + mpd_qfinalize(result, &varcontext, status); +} + +void +mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + /* positive infinity */ + _settriple(result, MPD_POS, 0, mpd_etiny(ctx)); + *status |= MPD_Clamped; + return; + } + if (mpd_iszero(a)) { + mpd_setspecial(result, mpd_sign(a), MPD_INF); + *status |= MPD_Division_by_zero; + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + _mpd_qinvroot(result, a, ctx, status); +} + +/* + * Ensure correct rounding. Algorithm after Hull & Abrham, "Properly Rounded + * Variable Precision Square Root", ACM Transactions on Mathematical Software, + * Vol. 11, No. 3. + */ +static void +_mpd_fix_sqrt(mpd_t *result, const mpd_t *a, mpd_t *tmp, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_context_t maxctx; + MPD_NEW_CONST(u,0,0,1,1,1,5); + + mpd_maxcontext(&maxctx); + u.exp = u.digits - ctx->prec + result->exp - 1; + + _mpd_qsub(tmp, result, &u, &maxctx, status); + if (*status&MPD_Errors) goto nanresult; + + _mpd_qmul(tmp, tmp, tmp, &maxctx, status); + if (*status&MPD_Errors) goto nanresult; + + if (_mpd_cmp(tmp, a) == 1) { + u.exp += 1; + u.data[0] = 1; + _mpd_qsub(result, result, &u, &maxctx, status); + } + else { + _mpd_qadd(tmp, result, &u, &maxctx, status); + if (*status&MPD_Errors) goto nanresult; + + _mpd_qmul(tmp, tmp, tmp, &maxctx, status); + if (*status&MPD_Errors) goto nanresult; + + if (_mpd_cmp(tmp, a) == -1) { + u.exp += 1; + u.data[0] = 1; + _mpd_qadd(result, result, &u, &maxctx, status); + } + } + + return; + +nanresult: + mpd_setspecial(result, MPD_POS, MPD_NAN); +} + +void +mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, + uint32_t *status) +{ + uint32_t workstatus = 0; + mpd_context_t varcontext; + mpd_t *z = result; /* current approximation */ + MPD_NEW_STATIC(v,0,0,0,0); /* a, normalized to a number between 1 and 10 */ + MPD_NEW_STATIC(vtmp,0,0,0,0); + MPD_NEW_STATIC(tmp,0,0,0,0); + mpd_ssize_t ideal_exp, shift; + mpd_ssize_t target_prec, fracdigits; + mpd_ssize_t a_exp, a_digits; + mpd_ssize_t adj, tz; + mpd_uint_t dummy, t; + int exact = 0; + + + varcontext = *ctx; + varcontext.round = MPD_ROUND_HALF_EVEN; + ideal_exp = (a->exp - (a->exp & 1)) / 2; + + if (mpd_isspecial(a)) { + if (mpd_qcheck_nan(result, a, ctx, status)) { + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + mpd_setspecial(result, MPD_POS, MPD_INF); + return; + } + if (mpd_iszero(a)) { + _settriple(result, mpd_sign(a), 0, ideal_exp); + mpd_qfinalize(result, ctx, status); + return; + } + if (mpd_isnegative(a)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + + if (!mpd_qcopy(&v, a, status)) { + mpd_seterror(result, MPD_Malloc_error, status); + goto finish; + } + + a_exp = a->exp; + a_digits = a->digits; + + /* normalize a to 1 <= v < 100 */ + if ((v.digits+v.exp) & 1) { + fracdigits = v.digits - 1; + v.exp = -fracdigits; + _mpd_get_msdigits(&dummy, &t, &v, 3); + t = t < 100 ? t*10 : t; + t = t < 100 ? t*10 : t; + } + else { + fracdigits = v.digits - 2; + v.exp = -fracdigits; + _mpd_get_msdigits(&dummy, &t, &v, 4); + t = t < 1000 ? t*10 : t; + t = t < 1000 ? t*10 : t; + t = t < 1000 ? t*10 : t; + } + adj = (a_exp-v.exp) / 2; + + + /* use excess digits */ + target_prec = (a_digits > ctx->prec) ? a_digits : ctx->prec; + target_prec += 2; + varcontext.prec = target_prec + 3; + + /* invroot is much faster for large numbers */ + _mpd_qinvroot(&tmp, &v, &varcontext, &workstatus); + + varcontext.prec = target_prec; + _mpd_qdiv(NO_IDEAL_EXP, z, &one, &tmp, &varcontext, &workstatus); + + + tz = mpd_trail_zeros(result); + if ((result->digits-tz)*2-1 <= v.digits) { + _mpd_qmul(&tmp, result, result, &varcontext, &workstatus); + if (workstatus&MPD_Errors) { + mpd_seterror(result, workstatus&MPD_Errors, status); + goto finish; + } + exact = (_mpd_cmp(&tmp, &v) == 0); + } + *status |= (workstatus&MPD_Errors); + + if (!exact && !mpd_isspecial(result) && !mpd_iszero(result)) { + _mpd_fix_sqrt(result, &v, &tmp, &varcontext, status); + if (mpd_isspecial(result)) goto finish; + *status |= (MPD_Rounded|MPD_Inexact); + } + + result->exp += adj; + if (exact) { + shift = ideal_exp - result->exp; + shift = (tz > shift) ? shift : tz; + if (shift > 0) { + mpd_qshiftr_inplace(result, shift); + result->exp += shift; + } + } + + +finish: + mpd_del(&v); + mpd_del(&vtmp); + mpd_del(&tmp); + varcontext.prec = ctx->prec; + mpd_qfinalize(result, &varcontext, status); +} + + +/******************************************************************************/ +/* Base conversions */ +/******************************************************************************/ + +/* + * Returns the space needed to represent an integer mpd_t in base 'base'. + * The result is undefined for non-integers. + * + * Max space needed: + * + * base^n >= 10^(digits+exp) + * n >= log10(10^(digits+exp))/log10(base) = (digits+exp) / log10(base) + */ +size_t +mpd_sizeinbase(mpd_t *a, uint32_t base) +{ + size_t x; + + assert(mpd_isinteger(a)); + if (mpd_iszero(a)) { + return 1; + } + + x = a->digits+a->exp; + +#ifdef CONFIG_64 + #ifdef USE_80BIT_LONG_DOUBLE + return (long double)x / log10(base) + 3; + #else + /* x > floor(((1ULL<<53)-3) * log10(2)) */ + if (x > 2711437152599294ULL) { + return SIZE_MAX; + } + return (double)x / log10(base) + 3; + #endif +#else /* CONFIG_32 */ +{ + double y = x / log10(base) + 3; + return (y > SIZE_MAX) ? SIZE_MAX : (size_t)y; +} +#endif +} + +/* + * Returns the space needed to import a base 'base' integer of length 'srclen'. + */ +static inline mpd_ssize_t +_mpd_importsize(size_t srclen, uint32_t base) +{ +#if SIZE_MAX == UINT64_MAX + #ifdef USE_80BIT_LONG_DOUBLE + long double x = (long double)srclen * (log10(base)/MPD_RDIGITS) + 3; + #else + double x; + if (srclen > (1ULL<<53)) { + return MPD_SSIZE_MAX; + } + x = (double)srclen * (log10(base)/MPD_RDIGITS) + 3; + #endif +#else + double x = srclen * (log10(base)/MPD_RDIGITS) + 3; +#endif + return (x > MPD_MAXIMPORT) ? MPD_SSIZE_MAX : (mpd_ssize_t)x; +} + + +static inline size_t +_to_base_u16(uint16_t *w, size_t wlen, mpd_uint_t wbase, + mpd_uint_t *u, mpd_ssize_t ulen) +{ + size_t n = 0; + + assert(wlen > 0 && ulen > 0); + + do { + w[n++] = (uint16_t)_mpd_shortdiv(u, u, ulen, wbase); + /* ulen will be at least 1. u[ulen-1] can only be zero if ulen == 1 */ + ulen = _mpd_real_size(u, ulen); + + } while (u[ulen-1] != 0 && n < wlen); + + /* proper termination condition */ + assert(u[ulen-1] == 0); + + return n; +} + +static inline void +_from_base_u16(mpd_uint_t *w, mpd_ssize_t wlen, + const mpd_uint_t *u, size_t ulen, uint32_t ubase) +{ + mpd_ssize_t m = 1; + mpd_uint_t carry; + + assert(wlen > 0 && ulen > 0); + + w[0] = u[--ulen]; + while (--ulen != SIZE_MAX && m < wlen) { + _mpd_shortmul(w, w, m, ubase); + m = _mpd_real_size(w, m+1); + carry = _mpd_shortadd(w, m, u[ulen]); + if (carry) w[m++] = carry; + } + + /* proper termination condition */ + assert(ulen == SIZE_MAX); +} + +/* target base wbase <= source base ubase */ +static inline size_t +_baseconv_to_smaller(uint32_t *w, size_t wlen, mpd_uint_t wbase, + mpd_uint_t *u, mpd_ssize_t ulen, mpd_uint_t ubase) +{ + size_t n = 0; + + assert(wlen > 0 && ulen > 0); + + do { + w[n++] = (uint32_t)_mpd_shortdiv_b(u, u, ulen, wbase, ubase); + /* ulen will be at least 1. u[ulen-1] can only be zero if ulen == 1 */ + ulen = _mpd_real_size(u, ulen); + + } while (u[ulen-1] != 0 && n < wlen); + + /* proper termination condition */ + assert(u[ulen-1] == 0); + + return n; +} + +/* target base wbase >= source base ubase */ +static inline void +_baseconv_to_larger(mpd_uint_t *w, mpd_ssize_t wlen, mpd_uint_t wbase, + const mpd_uint_t *u, size_t ulen, mpd_uint_t ubase) +{ + mpd_ssize_t m = 1; + mpd_uint_t carry; + + assert(wlen > 0 && ulen > 0); + + w[0] = u[--ulen]; + while (--ulen != SIZE_MAX && m < wlen) { + _mpd_shortmul_b(w, w, m, ubase, wbase); + m = _mpd_real_size(w, m+1); + carry = _mpd_shortadd_b(w, m, u[ulen], wbase); + if (carry) w[m++] = carry; + } + + /* proper termination condition */ + assert(ulen == SIZE_MAX); +} + + +/* + * Converts an integer mpd_t to a multiprecision integer with + * base <= UINT16_MAX+1. The least significant word of the result + * is rdata[0]. + */ +size_t +mpd_qexport_u16(uint16_t *rdata, size_t rlen, uint32_t rbase, + const mpd_t *src, uint32_t *status) +{ + mpd_t *tsrc; + size_t n; + + assert(rbase <= (1U<<16)); + assert(rlen <= SIZE_MAX/(sizeof *rdata)); + + if (mpd_isspecial(src) || !_mpd_isint(src)) { + *status |= MPD_Invalid_operation; + return SIZE_MAX; + } + + memset(rdata, 0, rlen * (sizeof *rdata)); + + if (mpd_iszero(src)) { + return 1; + } + + if ((tsrc = mpd_qnew()) == NULL) { + *status |= MPD_Malloc_error; + return SIZE_MAX; + } + + if (src->exp >= 0) { + if (!mpd_qshiftl(tsrc, src, src->exp, status)) { + mpd_del(tsrc); + return SIZE_MAX; + } + } + else { + if (mpd_qshiftr(tsrc, src, -src->exp, status) == MPD_UINT_MAX) { + mpd_del(tsrc); + return SIZE_MAX; + } + } + + n = _to_base_u16(rdata, rlen, rbase, tsrc->data, tsrc->len); + + mpd_del(tsrc); + return n; +} + +/* + * Converts an integer mpd_t to a multiprecision integer with + * base <= UINT32_MAX. The least significant word of the result + * is rdata[0]. + */ +size_t +mpd_qexport_u32(uint32_t *rdata, size_t rlen, uint32_t rbase, + const mpd_t *src, uint32_t *status) +{ + mpd_t *tsrc; + size_t n; + + if (mpd_isspecial(src) || !_mpd_isint(src)) { + *status |= MPD_Invalid_operation; + return SIZE_MAX; + } +#if MPD_SIZE_MAX < SIZE_MAX + if (rlen > MPD_SSIZE_MAX) { + *status |= MPD_Invalid_operation; + return SIZE_MAX; + } +#endif + + assert(rlen <= SIZE_MAX/(sizeof *rdata)); + memset(rdata, 0, rlen * (sizeof *rdata)); + + if (mpd_iszero(src)) { + return 1; + } + + if ((tsrc = mpd_qnew()) == NULL) { + *status |= MPD_Malloc_error; + return SIZE_MAX; + } + + if (src->exp >= 0) { + if (!mpd_qshiftl(tsrc, src, src->exp, status)) { + mpd_del(tsrc); + return SIZE_MAX; + } + } + else { + if (mpd_qshiftr(tsrc, src, -src->exp, status) == MPD_UINT_MAX) { + mpd_del(tsrc); + return SIZE_MAX; + } + } + +#ifdef CONFIG_64 + n = _baseconv_to_smaller(rdata, rlen, rbase, + tsrc->data, tsrc->len, MPD_RADIX); +#else + if (rbase <= MPD_RADIX) { + n = _baseconv_to_smaller(rdata, rlen, rbase, + tsrc->data, tsrc->len, MPD_RADIX); + } + else { + _baseconv_to_larger(rdata, (mpd_ssize_t)rlen, rbase, + tsrc->data, tsrc->len, MPD_RADIX); + n = _mpd_real_size(rdata, (mpd_ssize_t)rlen); + } +#endif + + mpd_del(tsrc); + return n; +} + + +/* + * Converts a multiprecision integer with base <= UINT16_MAX+1 to an mpd_t. + * The least significant word of the source is srcdata[0]. + */ +void +mpd_qimport_u16(mpd_t *result, + const uint16_t *srcdata, size_t srclen, + uint8_t srcsign, uint32_t srcbase, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t *usrc; /* uint16_t src copied to an mpd_uint_t array */ + mpd_ssize_t rlen; /* length of the result */ + size_t n = 0; + + assert(srclen > 0); + assert(srcbase <= (1U<<16)); + + if ((rlen = _mpd_importsize(srclen, srcbase)) == MPD_SSIZE_MAX) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (srclen > MPD_SIZE_MAX/(sizeof *usrc)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if ((usrc = mpd_alloc((mpd_size_t)srclen, sizeof *usrc)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + for (n = 0; n < srclen; n++) { + usrc[n] = srcdata[n]; + } + + /* result->data is initialized to zero */ + if (!mpd_qresize_zero(result, rlen, status)) { + goto finish; + } + + _from_base_u16(result->data, rlen, usrc, srclen, srcbase); + + mpd_set_flags(result, srcsign); + result->exp = 0; + result->len = _mpd_real_size(result->data, rlen); + mpd_setdigits(result); + + mpd_qresize(result, result->len, status); + mpd_qfinalize(result, ctx, status); + + +finish: + mpd_free(usrc); +} + +/* + * Converts a multiprecision integer with base <= UINT32_MAX to an mpd_t. + * The least significant word of the source is srcdata[0]. + */ +void +mpd_qimport_u32(mpd_t *result, + const uint32_t *srcdata, size_t srclen, + uint8_t srcsign, uint32_t srcbase, + const mpd_context_t *ctx, uint32_t *status) +{ + mpd_uint_t *usrc; /* uint32_t src copied to an mpd_uint_t array */ + mpd_ssize_t rlen; /* length of the result */ + size_t n = 0; + + assert(srclen > 0); + + if ((rlen = _mpd_importsize(srclen, srcbase)) == MPD_SSIZE_MAX) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if (srclen > MPD_SIZE_MAX/(sizeof *usrc)) { + mpd_seterror(result, MPD_Invalid_operation, status); + return; + } + if ((usrc = mpd_alloc((mpd_size_t)srclen, sizeof *usrc)) == NULL) { + mpd_seterror(result, MPD_Malloc_error, status); + return; + } + for (n = 0; n < srclen; n++) { + usrc[n] = srcdata[n]; + } + + /* result->data is initialized to zero */ + if (!mpd_qresize_zero(result, rlen, status)) { + goto finish; + } + +#ifdef CONFIG_64 + _baseconv_to_larger(result->data, rlen, MPD_RADIX, + usrc, srclen, srcbase); +#else + if (srcbase <= MPD_RADIX) { + _baseconv_to_larger(result->data, rlen, MPD_RADIX, + usrc, srclen, srcbase); + } + else { + _baseconv_to_smaller(result->data, rlen, MPD_RADIX, + usrc, (mpd_ssize_t)srclen, srcbase); + } +#endif + + mpd_set_flags(result, srcsign); + result->exp = 0; + result->len = _mpd_real_size(result->data, rlen); + mpd_setdigits(result); + + mpd_qresize(result, result->len, status); + mpd_qfinalize(result, ctx, status); + + +finish: + mpd_free(usrc); +} + + + diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/mpdecimal.h @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef MPDECIMAL_H +#define MPDECIMAL_H + + +#ifdef __cplusplus +extern "C" { +#define __STDC_LIMIT_MACROS +#endif + + +#ifndef _MSC_VER + #include "pyconfig.h" +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER + #include "vccompat.h" + #ifndef UNUSED + #define UNUSED + #endif + #define EXTINLINE extern inline +#else + #ifdef HAVE_STDINT_H + #include + #endif + #ifdef HAVE_INTTYPES_H + #include + #endif + #ifndef __GNUC_STDC_INLINE__ + #define __GNUC_STDC_INLINE__ + #endif + #if defined(__GNUC__) && !defined(__INTEL_COMPILER) + #define UNUSED __attribute__((unused)) + #else + #define UNUSED + #endif + #define EXTINLINE +#endif + + +#if !defined(LEGACY_COMPILER) + #if !defined(UINT64_MAX) + /* The following #error is just a warning. If the compiler indeed does + * not have uint64_t, it is perfectly safe to comment out the #error. */ + #error "Warning: Compiler without uint64_t. Comment out this line." + #define LEGACY_COMPILER + #endif +#endif + + +/******************************************************************************/ +/* Configuration */ +/******************************************************************************/ + +#if defined(UNIVERSAL) + #if defined(CONFIG_64) || defined(CONFIG_32) + #error "cannot use CONFIG_64 or CONFIG_32 with UNIVERSAL." + #endif + #if defined(__ppc__) + #define CONFIG_32 + #define ANSI + #elif defined(__ppc64__) + #define CONFIG_64 + #define ANSI + #elif defined(__i386__) + #define CONFIG_32 + #define ANSI + #elif defined(__x86_64__) + #define CONFIG_64 + #define ASM + #else + #error "unknown architecture for universal build." + #endif +#endif + + +/* BEGIN CONFIG_64 */ +#if defined(CONFIG_64) +/* types for modular and base arithmetic */ +#define MPD_UINT_MAX UINT64_MAX +#define MPD_BITS_PER_UINT 64 +typedef uint64_t mpd_uint_t; /* unsigned mod type */ + +#define MPD_SIZE_MAX SIZE_MAX +typedef size_t mpd_size_t; /* unsigned size type */ + +/* type for exp, digits, len, prec */ +#define MPD_SSIZE_MAX INT64_MAX +#define MPD_SSIZE_MIN INT64_MIN +typedef int64_t mpd_ssize_t; +#define _mpd_strtossize strtoll + +/* decimal arithmetic */ +#define MPD_RADIX 10000000000000000000ULL /* 10**19 */ +#define MPD_RDIGITS 19 +#define MPD_MAX_POW10 19 +#define MPD_EXPDIGITS 19 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */ + +#define MPD_MAXTRANSFORM_2N 4294967296ULL /* 2**32 */ +#define MPD_MAX_PREC 999999999999999999LL +#define MPD_MAX_PREC_LOG2 64 +#define MPD_ELIMIT 1000000000000000000LL +#define MPD_MAX_EMAX 999999999999999999LL /* ELIMIT-1 */ +#define MPD_MIN_EMIN (-999999999999999999LL) /* -EMAX */ +#define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1)) +#define MPD_EXP_INF 2000000000000000001LL +#define MPD_EXP_CLAMP (-4000000000000000001LL) +#define MPD_MAXIMPORT 105263157894736842L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */ + +/* conversion specifiers */ +#define PRI_mpd_uint_t PRIu64 +#define PRI_mpd_ssize_t PRIi64 +/* END CONFIG_64 */ + + +/* BEGIN CONFIG_32 */ +#elif defined(CONFIG_32) +/* types for modular and base arithmetic */ +#define MPD_UINT_MAX UINT32_MAX +#define MPD_BITS_PER_UINT 32 +typedef uint32_t mpd_uint_t; /* unsigned mod type */ + +#ifndef LEGACY_COMPILER +#define MPD_UUINT_MAX UINT64_MAX +typedef uint64_t mpd_uuint_t; /* double width unsigned mod type */ +#endif + +#define MPD_SIZE_MAX SIZE_MAX +typedef size_t mpd_size_t; /* unsigned size type */ + +/* type for dec->len, dec->exp, ctx->prec */ +#define MPD_SSIZE_MAX INT32_MAX +#define MPD_SSIZE_MIN INT32_MIN +typedef int32_t mpd_ssize_t; +#define _mpd_strtossize strtol + +/* decimal arithmetic */ +#define MPD_RADIX 1000000000UL /* 10**9 */ +#define MPD_RDIGITS 9 +#define MPD_MAX_POW10 9 +#define MPD_EXPDIGITS 10 /* MPD_EXPDIGITS <= MPD_RDIGITS+1 */ + +#define MPD_MAXTRANSFORM_2N 33554432UL /* 2**25 */ +#define MPD_MAX_PREC 425000000L +#define MPD_MAX_PREC_LOG2 32 +#define MPD_ELIMIT 425000001L +#define MPD_MAX_EMAX 425000000L /* ELIMIT-1 */ +#define MPD_MIN_EMIN (-425000000L) /* -EMAX */ +#define MPD_MIN_ETINY (MPD_MIN_EMIN-(MPD_MAX_PREC-1)) +#define MPD_EXP_INF 1000000001L /* allows for emax=999999999 in the tests */ +#define MPD_EXP_CLAMP (-2000000001L) /* allows for emin=-999999999 in the tests */ +#define MPD_MAXIMPORT 94444445L /* ceil((2*MPD_MAX_PREC)/MPD_RDIGITS) */ + +/* conversion specifiers */ +#define PRI_mpd_uint_t PRIu32 +#define PRI_mpd_ssize_t PRIi32 +/* END CONFIG_32 */ + +#else + #error "define CONFIG_64 or CONFIG_32" +#endif +/* END CONFIG */ + + +#if MPD_SIZE_MAX != MPD_UINT_MAX + #error "unsupported platform: need mpd_size_t == mpd_uint_t" +#endif + + +/******************************************************************************/ +/* Context */ +/******************************************************************************/ + +enum { + MPD_ROUND_UP, /* round away from 0 */ + MPD_ROUND_DOWN, /* round toward 0 (truncate) */ + MPD_ROUND_CEILING, /* round toward +infinity */ + MPD_ROUND_FLOOR, /* round toward -infinity */ + MPD_ROUND_HALF_UP, /* 0.5 is rounded up */ + MPD_ROUND_HALF_DOWN, /* 0.5 is rounded down */ + MPD_ROUND_HALF_EVEN, /* 0.5 is rounded to even */ + MPD_ROUND_05UP, /* round zero or five away from 0 */ + MPD_ROUND_TRUNC, /* truncate, but set infinity */ + MPD_ROUND_GUARD +}; + +enum { MPD_CLAMP_DEFAULT, MPD_CLAMP_IEEE_754, MPD_CLAMP_GUARD }; + +extern const char *mpd_round_string[MPD_ROUND_GUARD]; +extern const char *mpd_clamp_string[MPD_CLAMP_GUARD]; + + +typedef struct { + mpd_ssize_t prec; /* precision */ + mpd_ssize_t emax; /* max positive exp */ + mpd_ssize_t emin; /* min negative exp */ + uint32_t traps; /* status events that should be trapped */ + uint32_t status; /* status flags */ + uint32_t newtrap; /* set by mpd_addstatus_raise() */ + int round; /* rounding mode */ + int clamp; /* clamp mode */ + int allcr; /* all functions correctly rounded */ +} mpd_context_t; + + +/* Status flags */ +#define MPD_Clamped 0x00000001U +#define MPD_Conversion_syntax 0x00000002U +#define MPD_Division_by_zero 0x00000004U +#define MPD_Division_impossible 0x00000008U +#define MPD_Division_undefined 0x00000010U +#define MPD_Fpu_error 0x00000020U +#define MPD_Inexact 0x00000040U +#define MPD_Invalid_context 0x00000080U +#define MPD_Invalid_operation 0x00000100U +#define MPD_Malloc_error 0x00000200U +#define MPD_Not_implemented 0x00000400U +#define MPD_Overflow 0x00000800U +#define MPD_Rounded 0x00001000U +#define MPD_Subnormal 0x00002000U +#define MPD_Underflow 0x00004000U +#define MPD_Max_status (0x00008000U-1U) + +/* Conditions that result in an IEEE 754 exception */ +#define MPD_IEEE_Invalid_operation (MPD_Conversion_syntax | \ + MPD_Division_impossible | \ + MPD_Division_undefined | \ + MPD_Fpu_error | \ + MPD_Invalid_context | \ + MPD_Invalid_operation | \ + MPD_Malloc_error) \ + +/* Errors that require the result of an operation to be set to NaN */ +#define MPD_Errors (MPD_IEEE_Invalid_operation | \ + MPD_Division_by_zero) + +/* Default traps */ +#define MPD_Traps (MPD_IEEE_Invalid_operation | \ + MPD_Division_by_zero | \ + MPD_Overflow | \ + MPD_Underflow) + +/* Official name */ +#define MPD_Insufficient_storage MPD_Malloc_error + +/* IEEE 754 interchange format contexts */ +#define MPD_IEEE_CONTEXT_MAX_BITS 512 /* 16*(log2(MPD_MAX_EMAX / 3)-3) */ +#define MPD_DECIMAL32 32 +#define MPD_DECIMAL64 64 +#define MPD_DECIMAL128 128 + + +#define MPD_MINALLOC_MIN 2 +#define MPD_MINALLOC_MAX 64 +extern mpd_ssize_t MPD_MINALLOC; +extern void (* mpd_traphandler)(mpd_context_t *); +void mpd_dflt_traphandler(mpd_context_t *); + +void mpd_setminalloc(mpd_ssize_t n); +void mpd_init(mpd_context_t *ctx, mpd_ssize_t prec); + +void mpd_maxcontext(mpd_context_t *ctx); +void mpd_defaultcontext(mpd_context_t *ctx); +void mpd_basiccontext(mpd_context_t *ctx); +int mpd_ieee_context(mpd_context_t *ctx, int bits); + +mpd_ssize_t mpd_getprec(const mpd_context_t *ctx); +mpd_ssize_t mpd_getemax(const mpd_context_t *ctx); +mpd_ssize_t mpd_getemin(const mpd_context_t *ctx); +int mpd_getround(const mpd_context_t *ctx); +uint32_t mpd_gettraps(const mpd_context_t *ctx); +uint32_t mpd_getstatus(const mpd_context_t *ctx); +int mpd_getclamp(const mpd_context_t *ctx); +int mpd_getcr(const mpd_context_t *ctx); + +int mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec); +int mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax); +int mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin); +int mpd_qsetround(mpd_context_t *ctx, int newround); +int mpd_qsettraps(mpd_context_t *ctx, uint32_t flags); +int mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags); +int mpd_qsetclamp(mpd_context_t *ctx, int c); +int mpd_qsetcr(mpd_context_t *ctx, int c); +void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags); + + +/******************************************************************************/ +/* Decimal Arithmetic */ +/******************************************************************************/ + +/* mpd_t flags */ +#define MPD_POS ((uint8_t)0) +#define MPD_NEG ((uint8_t)1) +#define MPD_INF ((uint8_t)2) +#define MPD_NAN ((uint8_t)4) +#define MPD_SNAN ((uint8_t)8) +#define MPD_SPECIAL (MPD_INF|MPD_NAN|MPD_SNAN) +#define MPD_STATIC ((uint8_t)16) +#define MPD_STATIC_DATA ((uint8_t)32) +#define MPD_SHARED_DATA ((uint8_t)64) +#define MPD_CONST_DATA ((uint8_t)128) +#define MPD_DATAFLAGS (MPD_STATIC_DATA|MPD_SHARED_DATA|MPD_CONST_DATA) + +/* mpd_t */ +typedef struct { + uint8_t flags; + mpd_ssize_t exp; + mpd_ssize_t digits; + mpd_ssize_t len; + mpd_ssize_t alloc; + mpd_uint_t *data; +} mpd_t; + + +typedef unsigned char uchar; + + +/******************************************************************************/ +/* Quiet, thread-safe functions */ +/******************************************************************************/ + +/* format specification */ +typedef struct { + mpd_ssize_t min_width; /* minimum field width */ + mpd_ssize_t prec; /* fraction digits or significant digits */ + char type; /* conversion specifier */ + char align; /* alignment */ + char sign; /* sign printing/alignment */ + char fill[5]; /* fill character */ + const char *dot; /* decimal point */ + const char *sep; /* thousands separator */ + const char *grouping; /* grouping of digits */ +} mpd_spec_t; + +/* output to a string */ +char *mpd_to_sci(const mpd_t *dec, int fmt); +char *mpd_to_eng(const mpd_t *dec, int fmt); +mpd_ssize_t mpd_to_sci_size(char **res, const mpd_t *dec, int fmt); +mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt); +int mpd_validate_lconv(mpd_spec_t *spec); +int mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps); +char * mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status); +char *mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, uint32_t *status); + +#define MPD_NUM_FLAGS 15 +#define MPD_MAX_FLAG_STRING 208 +#define MPD_MAX_FLAG_LIST (MPD_MAX_FLAG_STRING+18) +#define MPD_MAX_SIGNAL_LIST 121 +int mpd_snprint_flags(char *dest, int nmemb, uint32_t flags); +int mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[]); +int mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[]); + +/* output to a file */ +void mpd_fprint(FILE *file, const mpd_t *dec); +void mpd_print(const mpd_t *dec); + +/* assignment from a string */ +void mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx, uint32_t *status); + +/* set to NaN with error flags */ +void mpd_seterror(mpd_t *result, uint32_t flags, uint32_t *status); +/* set a special with sign and type */ +void mpd_setspecial(mpd_t *dec, uint8_t sign, uint8_t type); +/* set coefficient to zero or all nines */ +void mpd_zerocoeff(mpd_t *result); +void mpd_qmaxcoeff(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); + +/* quietly assign a C integer type to an mpd_t */ +void mpd_qset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); +#ifndef LEGACY_COMPILER +void mpd_qset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); +#endif + +/* quietly assign a C integer type to an mpd_t with a static coefficient */ +void mpd_qsset_ssize(mpd_t *result, mpd_ssize_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsset_i32(mpd_t *result, int32_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsset_uint(mpd_t *result, mpd_uint_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsset_u32(mpd_t *result, uint32_t a, const mpd_context_t *ctx, uint32_t *status); + +/* quietly get a C integer type from an mpd_t */ +mpd_ssize_t mpd_qget_ssize(const mpd_t *dec, uint32_t *status); +mpd_uint_t mpd_qget_uint(const mpd_t *dec, uint32_t *status); +mpd_uint_t mpd_qabs_uint(const mpd_t *dec, uint32_t *status); + + +/* quiet functions */ +int mpd_qcheck_nan(mpd_t *nanresult, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +int mpd_qcheck_nans(mpd_t *nanresult, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); + +const char * mpd_class(const mpd_t *a, const mpd_context_t *ctx); + +int mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status); +mpd_t *mpd_qncopy(const mpd_t *a); +int mpd_qcopy_abs(mpd_t *result, const mpd_t *a, uint32_t *status); +int mpd_qcopy_negate(mpd_t *result, const mpd_t *a, uint32_t *status); +int mpd_qcopy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, uint32_t *status); + +void mpd_qand(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qinvert(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qlogb(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qscaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qxor(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +int mpd_same_quantum(const mpd_t *a, const mpd_t *b); + +void mpd_qrotate(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +int mpd_qshiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); +mpd_uint_t mpd_qshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, uint32_t *status); +mpd_uint_t mpd_qshiftr_inplace(mpd_t *result, mpd_ssize_t n); +void mpd_qshift(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qshiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, const mpd_context_t *ctx, uint32_t *status); + +int mpd_qcmp(const mpd_t *a, const mpd_t *b, uint32_t *status); +int mpd_qcompare(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +int mpd_qcompare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +int mpd_cmp_total(const mpd_t *a, const mpd_t *b); +int mpd_cmp_total_mag(const mpd_t *a, const mpd_t *b); +int mpd_compare_total(mpd_t *result, const mpd_t *a, const mpd_t *b); +int mpd_compare_total_mag(mpd_t *result, const mpd_t *a, const mpd_t *b); + +void mpd_qround_to_intx(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qround_to_int(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qtrunc(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qfloor(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qceil(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); + +void mpd_qabs(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmax(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmax_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmin(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmin_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qminus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qplus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qnext_minus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qnext_plus(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qnext_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qquantize(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qrescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); +void mpd_qrescale_fmt(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, const mpd_context_t *ctx, uint32_t *status); +void mpd_qreduce(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qfma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_i32(mpd_t *result, const mpd_t *a, int32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_u32(mpd_t *result, const mpd_t *a, uint32_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdivint(mpd_t *q, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qrem(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qrem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdivmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qpow(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_context_t *ctx, uint32_t *status); +void mpd_qpowmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, const mpd_context_t *ctx, uint32_t *status); +void mpd_qexp(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qln10(mpd_t *result, mpd_ssize_t prec, uint32_t *status); +void mpd_qln(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qlog10(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status); + + +size_t mpd_sizeinbase(mpd_t *a, uint32_t base); +void mpd_qimport_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, + uint8_t srcsign, uint32_t srcbase, + const mpd_context_t *ctx, uint32_t *status); +void mpd_qimport_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, + uint8_t srcsign, uint32_t srcbase, + const mpd_context_t *ctx, uint32_t *status); +size_t mpd_qexport_u16(uint16_t *rdata, size_t rlen, uint32_t base, + const mpd_t *src, uint32_t *status); +size_t mpd_qexport_u32(uint32_t *rdata, size_t rlen, uint32_t base, + const mpd_t *src, uint32_t *status); + + +/******************************************************************************/ +/* Signalling functions */ +/******************************************************************************/ + +char * mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx); +void mpd_import_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); +void mpd_import_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); +size_t mpd_export_u16(uint16_t *rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); +size_t mpd_export_u32(uint32_t *rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); +void mpd_finalize(mpd_t *result, mpd_context_t *ctx); +int mpd_check_nan(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +int mpd_check_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_set_string(mpd_t *result, const char *s, mpd_context_t *ctx); +void mpd_maxcoeff(mpd_t *result, mpd_context_t *ctx); +void mpd_sset_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); +void mpd_sset_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); +void mpd_sset_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); +void mpd_sset_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); +void mpd_set_ssize(mpd_t *result, mpd_ssize_t a, mpd_context_t *ctx); +void mpd_set_i32(mpd_t *result, int32_t a, mpd_context_t *ctx); +void mpd_set_uint(mpd_t *result, mpd_uint_t a, mpd_context_t *ctx); +void mpd_set_u32(mpd_t *result, uint32_t a, mpd_context_t *ctx); +#ifndef LEGACY_COMPILER +void mpd_set_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); +void mpd_set_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); +#endif +mpd_ssize_t mpd_get_ssize(const mpd_t *a, mpd_context_t *ctx); +mpd_uint_t mpd_get_uint(const mpd_t *a, mpd_context_t *ctx); +mpd_uint_t mpd_abs_uint(const mpd_t *a, mpd_context_t *ctx); +void mpd_and(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_canonical(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_copy_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_copy_negate(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_copy_sign(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_invert(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_logb(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_or(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_rotate(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_scaleb(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_shiftl(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); +mpd_uint_t mpd_shiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); +void mpd_shiftn(mpd_t *result, const mpd_t *a, mpd_ssize_t n, mpd_context_t *ctx); +void mpd_shift(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_xor(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_abs(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +int mpd_cmp(const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +int mpd_compare(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +int mpd_compare_signal(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_add(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_add_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); +void mpd_add_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); +void mpd_add_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); +void mpd_add_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); +void mpd_sub(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_sub_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); +void mpd_sub_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); +void mpd_sub_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); +void mpd_sub_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); +void mpd_div(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_div_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); +void mpd_div_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); +void mpd_div_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); +void mpd_div_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); +void mpd_divmod(mpd_t *q, mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_divint(mpd_t *q, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_exp(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_fma(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, mpd_context_t *ctx); +void mpd_ln(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_log10(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_max(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_max_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_min(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_min_mag(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_mul(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_mul_ssize(mpd_t *result, const mpd_t *a, mpd_ssize_t b, mpd_context_t *ctx); +void mpd_mul_i32(mpd_t *result, const mpd_t *a, int32_t b, mpd_context_t *ctx); +void mpd_mul_uint(mpd_t *result, const mpd_t *a, mpd_uint_t b, mpd_context_t *ctx); +void mpd_mul_u32(mpd_t *result, const mpd_t *a, uint32_t b, mpd_context_t *ctx); +void mpd_next_minus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_next_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_next_toward(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_plus(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_pow(mpd_t *result, const mpd_t *base, const mpd_t *exp, mpd_context_t *ctx); +void mpd_powmod(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_t *mod, mpd_context_t *ctx); +void mpd_quantize(mpd_t *result, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_rescale(mpd_t *result, const mpd_t *a, mpd_ssize_t exp, mpd_context_t *ctx); +void mpd_reduce(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_rem(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_rem_near(mpd_t *r, const mpd_t *a, const mpd_t *b, mpd_context_t *ctx); +void mpd_round_to_intx(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_round_to_int(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_trunc(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_floor(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_ceil(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_sqrt(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); +void mpd_invroot(mpd_t *result, const mpd_t *a, mpd_context_t *ctx); + + +/******************************************************************************/ +/* Configuration specific */ +/******************************************************************************/ + +#ifdef CONFIG_64 +void mpd_qsset_i64(mpd_t *result, int64_t a, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsset_u64(mpd_t *result, uint64_t a, const mpd_context_t *ctx, uint32_t *status); +int64_t mpd_qget_i64(const mpd_t *dec, uint32_t *status); +uint64_t mpd_qget_u64(const mpd_t *dec, uint32_t *status); + +void mpd_qadd_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qadd_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qsub_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qmul_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_i64(mpd_t *result, const mpd_t *a, int64_t b, const mpd_context_t *ctx, uint32_t *status); +void mpd_qdiv_u64(mpd_t *result, const mpd_t *a, uint64_t b, const mpd_context_t *ctx, uint32_t *status); + +void mpd_sset_i64(mpd_t *result, int64_t a, mpd_context_t *ctx); +void mpd_sset_u64(mpd_t *result, uint64_t a, mpd_context_t *ctx); +int64_t mpd_get_i64(const mpd_t *a, mpd_context_t *ctx); +uint64_t mpd_get_u64(const mpd_t *a, mpd_context_t *ctx); + +void mpd_add_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); +void mpd_add_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); +void mpd_sub_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); +void mpd_sub_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); +void mpd_div_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); +void mpd_div_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); +void mpd_mul_i64(mpd_t *result, const mpd_t *a, int64_t b, mpd_context_t *ctx); +void mpd_mul_u64(mpd_t *result, const mpd_t *a, uint64_t b, mpd_context_t *ctx); +#else +int32_t mpd_qget_i32(const mpd_t *dec, uint32_t *status); +uint32_t mpd_qget_u32(const mpd_t *dec, uint32_t *status); +int32_t mpd_get_i32(const mpd_t *a, mpd_context_t *ctx); +uint32_t mpd_get_u32(const mpd_t *a, mpd_context_t *ctx); +#endif + + +/******************************************************************************/ +/* Get attributes of a decimal */ +/******************************************************************************/ + +EXTINLINE mpd_ssize_t mpd_adjexp(const mpd_t *dec); +EXTINLINE mpd_ssize_t mpd_etiny(const mpd_context_t *ctx); +EXTINLINE mpd_ssize_t mpd_etop(const mpd_context_t *ctx); +EXTINLINE mpd_uint_t mpd_msword(const mpd_t *dec); +EXTINLINE int mpd_word_digits(mpd_uint_t word); +/* most significant digit of a word */ +EXTINLINE mpd_uint_t mpd_msd(mpd_uint_t word); +/* least significant digit of a word */ +EXTINLINE mpd_uint_t mpd_lsd(mpd_uint_t word); +/* coefficient size needed to store 'digits' */ +EXTINLINE mpd_ssize_t mpd_digits_to_size(mpd_ssize_t digits); +/* number of digits in the exponent, undefined for MPD_SSIZE_MIN */ +EXTINLINE int mpd_exp_digits(mpd_ssize_t exp); +EXTINLINE int mpd_iscanonical(const mpd_t *dec UNUSED); +EXTINLINE int mpd_isfinite(const mpd_t *dec); +EXTINLINE int mpd_isinfinite(const mpd_t *dec); +EXTINLINE int mpd_isinteger(const mpd_t *dec); +EXTINLINE int mpd_isnan(const mpd_t *dec); +EXTINLINE int mpd_isnegative(const mpd_t *dec); +EXTINLINE int mpd_ispositive(const mpd_t *dec); +EXTINLINE int mpd_isqnan(const mpd_t *dec); +EXTINLINE int mpd_issigned(const mpd_t *dec); +EXTINLINE int mpd_issnan(const mpd_t *dec); +EXTINLINE int mpd_isspecial(const mpd_t *dec); +EXTINLINE int mpd_iszero(const mpd_t *dec); +/* undefined for special numbers */ +EXTINLINE int mpd_iszerocoeff(const mpd_t *dec); +EXTINLINE int mpd_isnormal(const mpd_t *dec, const mpd_context_t *ctx); +EXTINLINE int mpd_issubnormal(const mpd_t *dec, const mpd_context_t *ctx); +/* odd word */ +EXTINLINE int mpd_isoddword(mpd_uint_t word); +/* odd coefficient */ +EXTINLINE int mpd_isoddcoeff(const mpd_t *dec); +/* odd decimal, only defined for integers */ +int mpd_isodd(const mpd_t *dec); +/* even decimal, only defined for integers */ +int mpd_iseven(const mpd_t *dec); +/* 0 if dec is positive, 1 if dec is negative */ +EXTINLINE uint8_t mpd_sign(const mpd_t *dec); +/* 1 if dec is positive, -1 if dec is negative */ +EXTINLINE int mpd_arith_sign(const mpd_t *dec); +EXTINLINE long mpd_radix(void); +EXTINLINE int mpd_isdynamic(mpd_t *dec); +EXTINLINE int mpd_isstatic(mpd_t *dec); +EXTINLINE int mpd_isdynamic_data(mpd_t *dec); +EXTINLINE int mpd_isstatic_data(mpd_t *dec); +EXTINLINE int mpd_isshared_data(mpd_t *dec); +EXTINLINE int mpd_isconst_data(mpd_t *dec); +EXTINLINE mpd_ssize_t mpd_trail_zeros(const mpd_t *dec); + + +/******************************************************************************/ +/* Set attributes of a decimal */ +/******************************************************************************/ + +/* set number of decimal digits in the coefficient */ +EXTINLINE void mpd_setdigits(mpd_t *result); +EXTINLINE void mpd_set_sign(mpd_t *result, uint8_t sign); +/* copy sign from another decimal */ +EXTINLINE void mpd_signcpy(mpd_t *result, mpd_t *a); +EXTINLINE void mpd_set_infinity(mpd_t *result); +EXTINLINE void mpd_set_qnan(mpd_t *result); +EXTINLINE void mpd_set_snan(mpd_t *result); +EXTINLINE void mpd_set_negative(mpd_t *result); +EXTINLINE void mpd_set_positive(mpd_t *result); +EXTINLINE void mpd_set_dynamic(mpd_t *result); +EXTINLINE void mpd_set_static(mpd_t *result); +EXTINLINE void mpd_set_dynamic_data(mpd_t *result); +EXTINLINE void mpd_set_static_data(mpd_t *result); +EXTINLINE void mpd_set_shared_data(mpd_t *result); +EXTINLINE void mpd_set_const_data(mpd_t *result); +EXTINLINE void mpd_clear_flags(mpd_t *result); +EXTINLINE void mpd_set_flags(mpd_t *result, uint8_t flags); +EXTINLINE void mpd_copy_flags(mpd_t *result, const mpd_t *a); + + +/******************************************************************************/ +/* Error Macros */ +/******************************************************************************/ + +#define mpd_err_fatal(...) \ + do {fprintf(stderr, "%s:%d: error: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ + exit(1); \ + } while (0) +#define mpd_err_warn(...) \ + do {fprintf(stderr, "%s:%d: warning: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ + } while (0) + + +/******************************************************************************/ +/* Memory handling */ +/******************************************************************************/ + +extern void *(* mpd_mallocfunc)(size_t size); +extern void *(* mpd_callocfunc)(size_t nmemb, size_t size); +extern void *(* mpd_reallocfunc)(void *ptr, size_t size); +extern void (* mpd_free)(void *ptr); + +void *mpd_callocfunc_em(size_t nmemb, size_t size); + +void *mpd_alloc(mpd_size_t nmemb, mpd_size_t size); +void *mpd_calloc(mpd_size_t nmemb, mpd_size_t size); +void *mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err); +void *mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size); + +mpd_t *mpd_qnew(void); +mpd_t *mpd_new(mpd_context_t *ctx); +mpd_t *mpd_qnew_size(mpd_ssize_t size); +void mpd_del(mpd_t *dec); + +void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len); +int mpd_qresize(mpd_t *result, mpd_ssize_t size, uint32_t *status); +int mpd_qresize_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status); +void mpd_minalloc(mpd_t *result); + +int mpd_resize(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx); +int mpd_resize_zero(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx); + + +#ifdef __cplusplus +} /* END extern "C" */ +#endif + + +#endif /* MPDECIMAL_H */ + + + diff --git a/Modules/_decimal/libmpdec/numbertheory.c b/Modules/_decimal/libmpdec/numbertheory.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/numbertheory.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include "bits.h" +#include "umodarith.h" +#include "numbertheory.h" + + +/* Bignum: Initialize the Number Theoretic Transform. */ + + +/* + * Return the nth root of unity in F(p). This corresponds to e**((2*pi*i)/n) + * in the Fourier transform. We have w**n == 1 (mod p). + * n := transform length. + * sign := -1 for forward transform, 1 for backward transform. + * modnum := one of {P1, P2, P3}. + */ +mpd_uint_t +_mpd_getkernel(mpd_uint_t n, int sign, int modnum) +{ + mpd_uint_t umod, p, r, xi; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + + SETMODULUS(modnum); + r = mpd_roots[modnum]; /* primitive root of F(p) */ + p = umod; + xi = (p-1) / n; + + if (sign == -1) + return POWMOD(r, (p-1-xi)); + else + return POWMOD(r, xi); +} + +/* + * Initialize and return transform parameters. + * n := transform length. + * sign := -1 for forward transform, 1 for backward transform. + * modnum := one of {P1, P2, P3}. + */ +struct fnt_params * +_mpd_init_fnt_params(mpd_size_t n, int sign, int modnum) +{ + struct fnt_params *tparams; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t kernel, w; + mpd_uint_t i; + mpd_size_t nhalf; + + assert(ispower2(n)); + assert(sign == -1 || sign == 1); + assert(P1 <= modnum && modnum <= P3); + + nhalf = n/2; + tparams = mpd_sh_alloc(sizeof *tparams, nhalf, sizeof (mpd_uint_t)); + if (tparams == NULL) { + return NULL; + } + + SETMODULUS(modnum); + kernel = _mpd_getkernel(n, sign, modnum); + + tparams->modnum = modnum; + tparams->modulus = umod; + tparams->kernel = kernel; + + /* wtable[] := w**0, w**1, ..., w**(nhalf-1) */ + w = 1; + for (i = 0; i < nhalf; i++) { + tparams->wtable[i] = w; + w = MULMOD(w, kernel); + } + + return tparams; +} + +/* Initialize wtable of size three. */ +void +_mpd_init_w3table(mpd_uint_t w3table[3], int sign, int modnum) +{ + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t kernel; + + SETMODULUS(modnum); + kernel = _mpd_getkernel(3, sign, modnum); + + w3table[0] = 1; + w3table[1] = kernel; + w3table[2] = POWMOD(kernel, 2); +} + + diff --git a/Modules/_decimal/libmpdec/numbertheory.h b/Modules/_decimal/libmpdec/numbertheory.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/numbertheory.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef NUMBER_THEORY_H +#define NUMBER_THEORY_H + + +#include "constants.h" +#include "mpdecimal.h" + + +/* transform parameters */ +struct fnt_params { + int modnum; + mpd_uint_t modulus; + mpd_uint_t kernel; + mpd_uint_t wtable[]; +}; + + +mpd_uint_t _mpd_getkernel(mpd_uint_t n, int sign, int modnum); +struct fnt_params *_mpd_init_fnt_params(mpd_size_t n, int sign, int modnum); +void _mpd_init_w3table(mpd_uint_t w3table[3], int sign, int modnum); + + +#ifdef PPRO +static inline void +ppro_setmodulus(int modnum, mpd_uint_t *umod, double *dmod, uint32_t dinvmod[3]) +{ + *dmod = *umod = mpd_moduli[modnum]; + dinvmod[0] = mpd_invmoduli[modnum][0]; + dinvmod[1] = mpd_invmoduli[modnum][1]; + dinvmod[2] = mpd_invmoduli[modnum][2]; +} +#else +static inline void +std_setmodulus(int modnum, mpd_uint_t *umod) +{ + *umod = mpd_moduli[modnum]; +} +#endif + + +#endif + + diff --git a/Modules/_decimal/libmpdec/sixstep.c b/Modules/_decimal/libmpdec/sixstep.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/sixstep.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include "bits.h" +#include "difradix2.h" +#include "numbertheory.h" +#include "transpose.h" +#include "umodarith.h" +#include "sixstep.h" + + +/* Bignum: Cache efficient Matrix Fourier Transform for arrays of the + form 2**n (See literature/six-step.txt). */ + + +/* forward transform with sign = -1 */ +int +six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + struct fnt_params *tparams; + mpd_size_t log2n, C, R; + mpd_uint_t kernel; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t *x, w0, w1, wstep; + mpd_size_t i, k; + + + assert(ispower2(n)); + assert(n >= 16); + assert(n <= MPD_MAXTRANSFORM_2N); + + log2n = mpd_bsr(n); + C = ((mpd_size_t)1) << (log2n / 2); /* number of columns */ + R = ((mpd_size_t)1) << (log2n - (log2n / 2)); /* number of rows */ + + + /* Transpose the matrix. */ + if (!transpose_pow2(a, R, C)) { + return 0; + } + + /* Length R transform on the rows. */ + if ((tparams = _mpd_init_fnt_params(R, -1, modnum)) == NULL) { + return 0; + } + for (x = a; x < a+n; x += R) { + fnt_dif2(x, R, tparams); + } + + /* Transpose the matrix. */ + if (!transpose_pow2(a, C, R)) { + mpd_free(tparams); + return 0; + } + + /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */ + SETMODULUS(modnum); + kernel = _mpd_getkernel(n, -1, modnum); + for (i = 1; i < R; i++) { + w0 = 1; /* r**(i*0): initial value for k=0 */ + w1 = POWMOD(kernel, i); /* r**(i*1): initial value for k=1 */ + wstep = MULMOD(w1, w1); /* r**(2*i) */ + for (k = 0; k < C; k += 2) { + mpd_uint_t x0 = a[i*C+k]; + mpd_uint_t x1 = a[i*C+k+1]; + MULMOD2(&x0, w0, &x1, w1); + MULMOD2C(&w0, &w1, wstep); /* r**(i*(k+2)) = r**(i*k) * r**(2*i) */ + a[i*C+k] = x0; + a[i*C+k+1] = x1; + } + } + + /* Length C transform on the rows. */ + if (C != R) { + mpd_free(tparams); + if ((tparams = _mpd_init_fnt_params(C, -1, modnum)) == NULL) { + return 0; + } + } + for (x = a; x < a+n; x += C) { + fnt_dif2(x, C, tparams); + } + mpd_free(tparams); + +#if 0 /* An unordered transform is sufficient for convolution. */ + /* Transpose the matrix. */ + if (!transpose_pow2(a, R, C)) { + return 0; + } +#endif + + return 1; +} + + +/* reverse transform, sign = 1 */ +int +inv_six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum) +{ + struct fnt_params *tparams; + mpd_size_t log2n, C, R; + mpd_uint_t kernel; + mpd_uint_t umod; +#ifdef PPRO + double dmod; + uint32_t dinvmod[3]; +#endif + mpd_uint_t *x, w0, w1, wstep; + mpd_size_t i, k; + + + assert(ispower2(n)); + assert(n >= 16); + assert(n <= MPD_MAXTRANSFORM_2N); + + log2n = mpd_bsr(n); + C = ((mpd_size_t)1) << (log2n / 2); /* number of columns */ + R = ((mpd_size_t)1) << (log2n - (log2n / 2)); /* number of rows */ + + +#if 0 /* An unordered transform is sufficient for convolution. */ + /* Transpose the matrix, producing an R*C matrix. */ + if (!transpose_pow2(a, C, R)) { + return 0; + } +#endif + + /* Length C transform on the rows. */ + if ((tparams = _mpd_init_fnt_params(C, 1, modnum)) == NULL) { + return 0; + } + for (x = a; x < a+n; x += C) { + fnt_dif2(x, C, tparams); + } + + /* Multiply each matrix element (addressed by i*C+k) by r**(i*k). */ + SETMODULUS(modnum); + kernel = _mpd_getkernel(n, 1, modnum); + for (i = 1; i < R; i++) { + w0 = 1; + w1 = POWMOD(kernel, i); + wstep = MULMOD(w1, w1); + for (k = 0; k < C; k += 2) { + mpd_uint_t x0 = a[i*C+k]; + mpd_uint_t x1 = a[i*C+k+1]; + MULMOD2(&x0, w0, &x1, w1); + MULMOD2C(&w0, &w1, wstep); + a[i*C+k] = x0; + a[i*C+k+1] = x1; + } + } + + /* Transpose the matrix. */ + if (!transpose_pow2(a, R, C)) { + mpd_free(tparams); + return 0; + } + + /* Length R transform on the rows. */ + if (R != C) { + mpd_free(tparams); + if ((tparams = _mpd_init_fnt_params(R, 1, modnum)) == NULL) { + return 0; + } + } + for (x = a; x < a+n; x += R) { + fnt_dif2(x, R, tparams); + } + mpd_free(tparams); + + /* Transpose the matrix. */ + if (!transpose_pow2(a, C, R)) { + return 0; + } + + return 1; +} + + diff --git a/Modules/_decimal/libmpdec/sixstep.h b/Modules/_decimal/libmpdec/sixstep.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/sixstep.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef SIX_STEP_H +#define SIX_STEP_H + + +#include "mpdecimal.h" +#include + + +int six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); +int inv_six_step_fnt(mpd_uint_t *a, mpd_size_t n, int modnum); + + +#endif diff --git a/Modules/_decimal/libmpdec/transpose.c b/Modules/_decimal/libmpdec/transpose.c new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/transpose.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include +#include +#include +#include +#include +#include "bits.h" +#include "constants.h" +#include "typearith.h" +#include "transpose.h" + + +#define BUFSIZE 4096 +#define SIDE 128 + + +/* Bignum: The transpose functions are used for very large transforms + in sixstep.c and fourstep.c. */ + + +/* Definition of the matrix transpose */ +void +std_trans(mpd_uint_t dest[], mpd_uint_t src[], mpd_size_t rows, mpd_size_t cols) +{ + mpd_size_t idest, isrc; + mpd_size_t r, c; + + for (r = 0; r < rows; r++) { + isrc = r * cols; + idest = r; + for (c = 0; c < cols; c++) { + dest[idest] = src[isrc]; + isrc += 1; + idest += rows; + } + } +} + +/* + * Swap half-rows of 2^n * (2*2^n) matrix. + * FORWARD_CYCLE: even/odd permutation of the halfrows. + * BACKWARD_CYCLE: reverse the even/odd permutation. + */ +static int +swap_halfrows_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols, int dir) +{ + mpd_uint_t buf1[BUFSIZE]; + mpd_uint_t buf2[BUFSIZE]; + mpd_uint_t *readbuf, *writebuf, *hp; + mpd_size_t *done, dbits; + mpd_size_t b = BUFSIZE, stride; + mpd_size_t hn, hmax; /* halfrow number */ + mpd_size_t m, r=0; + mpd_size_t offset; + mpd_size_t next; + + + assert(cols == mul_size_t(2, rows)); + + if (dir == FORWARD_CYCLE) { + r = rows; + } + else if (dir == BACKWARD_CYCLE) { + r = 2; + } + else { + abort(); /* GCOV_NOT_REACHED */ + } + + m = cols - 1; + hmax = rows; /* cycles start at odd halfrows */ + dbits = 8 * sizeof *done; + if ((done = mpd_calloc(hmax/(sizeof *done) + 1, sizeof *done)) == NULL) { + return 0; + } + + for (hn = 1; hn <= hmax; hn += 2) { + + if (done[hn/dbits] & mpd_bits[hn%dbits]) { + continue; + } + + readbuf = buf1; writebuf = buf2; + + for (offset = 0; offset < cols/2; offset += b) { + + stride = (offset + b < cols/2) ? b : cols/2-offset; + + hp = matrix + hn*cols/2; + memcpy(readbuf, hp+offset, stride*(sizeof *readbuf)); + pointerswap(&readbuf, &writebuf); + + next = mulmod_size_t(hn, r, m); + hp = matrix + next*cols/2; + + while (next != hn) { + + memcpy(readbuf, hp+offset, stride*(sizeof *readbuf)); + memcpy(hp+offset, writebuf, stride*(sizeof *writebuf)); + pointerswap(&readbuf, &writebuf); + + done[next/dbits] |= mpd_bits[next%dbits]; + + next = mulmod_size_t(next, r, m); + hp = matrix + next*cols/2; + + } + + memcpy(hp+offset, writebuf, stride*(sizeof *writebuf)); + + done[hn/dbits] |= mpd_bits[hn%dbits]; + } + } + + mpd_free(done); + return 1; +} + +/* In-place transpose of a square matrix */ +static inline void +squaretrans(mpd_uint_t *buf, mpd_size_t cols) +{ + mpd_uint_t tmp; + mpd_size_t idest, isrc; + mpd_size_t r, c; + + for (r = 0; r < cols; r++) { + c = r+1; + isrc = r*cols + c; + idest = c*cols + r; + for (c = r+1; c < cols; c++) { + tmp = buf[isrc]; + buf[isrc] = buf[idest]; + buf[idest] = tmp; + isrc += 1; + idest += cols; + } + } +} + +/* + * Transpose 2^n * 2^n matrix. For cache efficiency, the matrix is split into + * square blocks with side length 'SIDE'. First, the blocks are transposed, + * then a square tranposition is done on each individual block. + */ +static void +squaretrans_pow2(mpd_uint_t *matrix, mpd_size_t size) +{ + mpd_uint_t buf1[SIDE*SIDE]; + mpd_uint_t buf2[SIDE*SIDE]; + mpd_uint_t *to, *from; + mpd_size_t b = size; + mpd_size_t r, c; + mpd_size_t i; + + while (b > SIDE) b >>= 1; + + for (r = 0; r < size; r += b) { + + for (c = r; c < size; c += b) { + + from = matrix + r*size + c; + to = buf1; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += size; + to += b; + } + squaretrans(buf1, b); + + if (r == c) { + to = matrix + r*size + c; + from = buf1; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += b; + to += size; + } + continue; + } + else { + from = matrix + c*size + r; + to = buf2; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += size; + to += b; + } + squaretrans(buf2, b); + + to = matrix + c*size + r; + from = buf1; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += b; + to += size; + } + + to = matrix + r*size + c; + from = buf2; + for (i = 0; i < b; i++) { + memcpy(to, from, b*(sizeof *to)); + from += b; + to += size; + } + } + } + } + +} + +/* + * In-place transposition of a 2^n x 2^n or a 2^n x (2*2^n) + * or a (2*2^n) x 2^n matrix. + */ +int +transpose_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols) +{ + mpd_size_t size = mul_size_t(rows, cols); + + assert(ispower2(rows)); + assert(ispower2(cols)); + + if (cols == rows) { + squaretrans_pow2(matrix, rows); + } + else if (cols == mul_size_t(2, rows)) { + if (!swap_halfrows_pow2(matrix, rows, cols, FORWARD_CYCLE)) { + return 0; + } + squaretrans_pow2(matrix, rows); + squaretrans_pow2(matrix+(size/2), rows); + } + else if (rows == mul_size_t(2, cols)) { + squaretrans_pow2(matrix, cols); + squaretrans_pow2(matrix+(size/2), cols); + if (!swap_halfrows_pow2(matrix, cols, rows, BACKWARD_CYCLE)) { + return 0; + } + } + else { + abort(); /* GCOV_NOT_REACHED */ + } + + return 1; +} + + diff --git a/Modules/_decimal/libmpdec/transpose.h b/Modules/_decimal/libmpdec/transpose.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/transpose.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef TRANSPOSE_H +#define TRANSPOSE_H + + +#include "mpdecimal.h" +#include + + +enum {FORWARD_CYCLE, BACKWARD_CYCLE}; + + +void std_trans(mpd_uint_t dest[], mpd_uint_t src[], mpd_size_t rows, mpd_size_t cols); +int transpose_pow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols); +void transpose_3xpow2(mpd_uint_t *matrix, mpd_size_t rows, mpd_size_t cols); + + +static inline void pointerswap(mpd_uint_t **a, mpd_uint_t **b) +{ + mpd_uint_t *tmp; + + tmp = *b; + *b = *a; + *a = tmp; +} + + +#endif diff --git a/Modules/_decimal/libmpdec/typearith.h b/Modules/_decimal/libmpdec/typearith.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/typearith.h @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef TYPEARITH_H +#define TYPEARITH_H + + +#include "mpdecimal.h" + + +/*****************************************************************************/ +/* Low level native arithmetic on basic types */ +/*****************************************************************************/ + + +/** ------------------------------------------------------------ + ** Double width multiplication and division + ** ------------------------------------------------------------ + */ + +#if defined(CONFIG_64) +#if defined(ANSI) +#if defined(HAVE_UINT128_T) +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + __uint128_t hl; + + hl = (__uint128_t)a * b; + + *hi = hl >> 64; + *lo = (mpd_uint_t)hl; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + __uint128_t hl; + + hl = ((__uint128_t)hi<<64) + lo; + *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */ + *r = (mpd_uint_t)(hl - (__uint128_t)(*q) * d); +} +#else +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + uint32_t w[4], carry; + uint32_t ah, al, bh, bl; + uint64_t hl; + + ah = (uint32_t)(a>>32); al = (uint32_t)a; + bh = (uint32_t)(b>>32); bl = (uint32_t)b; + + hl = (uint64_t)al * bl; + w[0] = (uint32_t)hl; + carry = (uint32_t)(hl>>32); + + hl = (uint64_t)ah * bl + carry; + w[1] = (uint32_t)hl; + w[2] = (uint32_t)(hl>>32); + + hl = (uint64_t)al * bh + w[1]; + w[1] = (uint32_t)hl; + carry = (uint32_t)(hl>>32); + + hl = ((uint64_t)ah * bh + w[2]) + carry; + w[2] = (uint32_t)hl; + w[3] = (uint32_t)(hl>>32); + + *hi = ((uint64_t)w[3]<<32) + w[2]; + *lo = ((uint64_t)w[1]<<32) + w[0]; +} + +/* + * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt + * http://www.hackersdelight.org/permissions.htm: + * "You are free to use, copy, and distribute any of the code on this web + * site, whether modified by you or not. You need not give attribution." + * + * Slightly modified, comments are mine. + */ +static inline int +nlz(uint64_t x) +{ + int n; + + if (x == 0) return(64); + + n = 0; + if (x <= 0x00000000FFFFFFFF) {n = n +32; x = x <<32;} + if (x <= 0x0000FFFFFFFFFFFF) {n = n +16; x = x <<16;} + if (x <= 0x00FFFFFFFFFFFFFF) {n = n + 8; x = x << 8;} + if (x <= 0x0FFFFFFFFFFFFFFF) {n = n + 4; x = x << 4;} + if (x <= 0x3FFFFFFFFFFFFFFF) {n = n + 2; x = x << 2;} + if (x <= 0x7FFFFFFFFFFFFFFF) {n = n + 1;} + + return n; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0, + mpd_uint_t v) +{ + const mpd_uint_t b = 4294967296; + mpd_uint_t un1, un0, + vn1, vn0, + q1, q0, + un32, un21, un10, + rhat, t; + int s; + + assert(u1 < v); + + s = nlz(v); + v = v << s; + vn1 = v >> 32; + vn0 = v & 0xFFFFFFFF; + + t = (s == 0) ? 0 : u0 >> (64 - s); + un32 = (u1 << s) | t; + un10 = u0 << s; + + un1 = un10 >> 32; + un0 = un10 & 0xFFFFFFFF; + + q1 = un32 / vn1; + rhat = un32 - q1*vn1; +again1: + if (q1 >= b || q1*vn0 > b*rhat + un1) { + q1 = q1 - 1; + rhat = rhat + vn1; + if (rhat < b) goto again1; + } + + /* + * Before again1 we had: + * (1) q1*vn1 + rhat = un32 + * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1 + * + * The statements inside the if-clause do not change the value + * of the left-hand side of (2), and the loop is only exited + * if q1*vn0 <= rhat*b + un1, so: + * + * (3) q1*vn1*b + q1*vn0 <= un32*b + un1 + * (4) q1*v <= un32*b + un1 + * (5) 0 <= un32*b + un1 - q1*v + * + * By (5) we are certain that the possible add-back step from + * Knuth's algorithm D is never required. + * + * Since the final quotient is less than 2**64, the following + * must be true: + * + * (6) un32*b + un1 - q1*v <= UINT64_MAX + * + * This means that in the following line, the high words + * of un32*b and q1*v can be discarded without any effect + * on the result. + */ + un21 = un32*b + un1 - q1*v; + + q0 = un21 / vn1; + rhat = un21 - q0*vn1; +again2: + if (q0 >= b || q0*vn0 > b*rhat + un0) { + q0 = q0 - 1; + rhat = rhat + vn1; + if (rhat < b) goto again2; + } + + *q = q1*b + q0; + *r = (un21*b + un0 - q0*v) >> s; +} +#endif + +/* END ANSI */ +#elif defined(ASM) +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + mpd_uint_t h, l; + + asm ( "mulq %3\n\t" + : "=d" (h), "=a" (l) + : "%a" (a), "rm" (b) + : "cc" + ); + + *hi = h; + *lo = l; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + mpd_uint_t qq, rr; + + asm ( "divq %4\n\t" + : "=a" (qq), "=d" (rr) + : "a" (lo), "d" (hi), "rm" (d) + : "cc" + ); + + *q = qq; + *r = rr; +} +/* END GCC ASM */ +#elif defined(MASM) +#include +#pragma intrinsic(_umul128) + +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + *lo = _umul128(a, b, hi); +} + +void _mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d); + +/* END MASM (_MSC_VER) */ +#else + #error "need platform specific 128 bit multiplication and division" +#endif + +#define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d +static inline void +_mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp) +{ + assert(exp <= 19); + + if (exp <= 9) { + if (exp <= 4) { + switch (exp) { + case 0: *q = v; *r = 0; break; + case 1: DIVMOD(q, r, v, 10UL); break; + case 2: DIVMOD(q, r, v, 100UL); break; + case 3: DIVMOD(q, r, v, 1000UL); break; + case 4: DIVMOD(q, r, v, 10000UL); break; + } + } + else { + switch (exp) { + case 5: DIVMOD(q, r, v, 100000UL); break; + case 6: DIVMOD(q, r, v, 1000000UL); break; + case 7: DIVMOD(q, r, v, 10000000UL); break; + case 8: DIVMOD(q, r, v, 100000000UL); break; + case 9: DIVMOD(q, r, v, 1000000000UL); break; + } + } + } + else { + if (exp <= 14) { + switch (exp) { + case 10: DIVMOD(q, r, v, 10000000000ULL); break; + case 11: DIVMOD(q, r, v, 100000000000ULL); break; + case 12: DIVMOD(q, r, v, 1000000000000ULL); break; + case 13: DIVMOD(q, r, v, 10000000000000ULL); break; + case 14: DIVMOD(q, r, v, 100000000000000ULL); break; + } + } + else { + switch (exp) { + case 15: DIVMOD(q, r, v, 1000000000000000ULL); break; + case 16: DIVMOD(q, r, v, 10000000000000000ULL); break; + case 17: DIVMOD(q, r, v, 100000000000000000ULL); break; + case 18: DIVMOD(q, r, v, 1000000000000000000ULL); break; + case 19: DIVMOD(q, r, v, 10000000000000000000ULL); break; /* GCOV_NOT_REACHED */ + } + } + } +} + +/* END CONFIG_64 */ +#elif defined(CONFIG_32) +#if defined(ANSI) +#if !defined(LEGACY_COMPILER) +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + mpd_uuint_t hl; + + hl = (mpd_uuint_t)a * b; + + *hi = hl >> 32; + *lo = (mpd_uint_t)hl; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + mpd_uuint_t hl; + + hl = ((mpd_uuint_t)hi<<32) + lo; + *q = (mpd_uint_t)(hl / d); /* quotient is known to fit */ + *r = (mpd_uint_t)(hl - (mpd_uuint_t)(*q) * d); +} +/* END ANSI + uint64_t */ +#else +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + uint16_t w[4], carry; + uint16_t ah, al, bh, bl; + uint32_t hl; + + ah = (uint16_t)(a>>16); al = (uint16_t)a; + bh = (uint16_t)(b>>16); bl = (uint16_t)b; + + hl = (uint32_t)al * bl; + w[0] = (uint16_t)hl; + carry = (uint16_t)(hl>>16); + + hl = (uint32_t)ah * bl + carry; + w[1] = (uint16_t)hl; + w[2] = (uint16_t)(hl>>16); + + hl = (uint32_t)al * bh + w[1]; + w[1] = (uint16_t)hl; + carry = (uint16_t)(hl>>16); + + hl = ((uint32_t)ah * bh + w[2]) + carry; + w[2] = (uint16_t)hl; + w[3] = (uint16_t)(hl>>16); + + *hi = ((uint32_t)w[3]<<16) + w[2]; + *lo = ((uint32_t)w[1]<<16) + w[0]; +} + +/* + * By Henry S. Warren: http://www.hackersdelight.org/HDcode/divlu.c.txt + * http://www.hackersdelight.org/permissions.htm: + * "You are free to use, copy, and distribute any of the code on this web + * site, whether modified by you or not. You need not give attribution." + * + * Slightly modified, comments are mine. + */ +static inline int +nlz(uint32_t x) +{ + int n; + + if (x == 0) return(32); + + n = 0; + if (x <= 0x0000FFFF) {n = n +16; x = x <<16;} + if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;} + if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;} + if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;} + if (x <= 0x7FFFFFFF) {n = n + 1;} + + return n; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t u1, mpd_uint_t u0, + mpd_uint_t v) +{ + const mpd_uint_t b = 65536; + mpd_uint_t un1, un0, + vn1, vn0, + q1, q0, + un32, un21, un10, + rhat, t; + int s; + + assert(u1 < v); + + s = nlz(v); + v = v << s; + vn1 = v >> 16; + vn0 = v & 0xFFFF; + + t = (s == 0) ? 0 : u0 >> (32 - s); + un32 = (u1 << s) | t; + un10 = u0 << s; + + un1 = un10 >> 16; + un0 = un10 & 0xFFFF; + + q1 = un32 / vn1; + rhat = un32 - q1*vn1; +again1: + if (q1 >= b || q1*vn0 > b*rhat + un1) { + q1 = q1 - 1; + rhat = rhat + vn1; + if (rhat < b) goto again1; + } + + /* + * Before again1 we had: + * (1) q1*vn1 + rhat = un32 + * (2) q1*vn1*b + rhat*b + un1 = un32*b + un1 + * + * The statements inside the if-clause do not change the value + * of the left-hand side of (2), and the loop is only exited + * if q1*vn0 <= rhat*b + un1, so: + * + * (3) q1*vn1*b + q1*vn0 <= un32*b + un1 + * (4) q1*v <= un32*b + un1 + * (5) 0 <= un32*b + un1 - q1*v + * + * By (5) we are certain that the possible add-back step from + * Knuth's algorithm D is never required. + * + * Since the final quotient is less than 2**32, the following + * must be true: + * + * (6) un32*b + un1 - q1*v <= UINT32_MAX + * + * This means that in the following line, the high words + * of un32*b and q1*v can be discarded without any effect + * on the result. + */ + un21 = un32*b + un1 - q1*v; + + q0 = un21 / vn1; + rhat = un21 - q0*vn1; +again2: + if (q0 >= b || q0*vn0 > b*rhat + un0) { + q0 = q0 - 1; + rhat = rhat + vn1; + if (rhat < b) goto again2; + } + + *q = q1*b + q0; + *r = (un21*b + un0 - q0*v) >> s; +} +#endif /* END ANSI + LEGACY_COMPILER */ + +/* END ANSI */ +#elif defined(ASM) +static inline void +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + mpd_uint_t h, l; + + asm ( "mull %3\n\t" + : "=d" (h), "=a" (l) + : "%a" (a), "rm" (b) + : "cc" + ); + + *hi = h; + *lo = l; +} + +static inline void +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + mpd_uint_t qq, rr; + + asm ( "divl %4\n\t" + : "=a" (qq), "=d" (rr) + : "a" (lo), "d" (hi), "rm" (d) + : "cc" + ); + + *q = qq; + *r = rr; +} +/* END GCC ASM */ +#elif defined(MASM) +static inline void __cdecl +_mpd_mul_words(mpd_uint_t *hi, mpd_uint_t *lo, mpd_uint_t a, mpd_uint_t b) +{ + mpd_uint_t h, l; + + __asm { + mov eax, a + mul b + mov h, edx + mov l, eax + } + + *hi = h; + *lo = l; +} + +static inline void __cdecl +_mpd_div_words(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t hi, mpd_uint_t lo, + mpd_uint_t d) +{ + mpd_uint_t qq, rr; + + __asm { + mov eax, lo + mov edx, hi + div d + mov qq, eax + mov rr, edx + } + + *q = qq; + *r = rr; +} +/* END MASM (_MSC_VER) */ +#else + #error "need platform specific 64 bit multiplication and division" +#endif + +#define DIVMOD(q, r, v, d) *q = v / d; *r = v - *q * d +static inline void +_mpd_divmod_pow10(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t exp) +{ + assert(exp <= 9); + + if (exp <= 4) { + switch (exp) { + case 0: *q = v; *r = 0; break; + case 1: DIVMOD(q, r, v, 10UL); break; + case 2: DIVMOD(q, r, v, 100UL); break; + case 3: DIVMOD(q, r, v, 1000UL); break; + case 4: DIVMOD(q, r, v, 10000UL); break; + } + } + else { + switch (exp) { + case 5: DIVMOD(q, r, v, 100000UL); break; + case 6: DIVMOD(q, r, v, 1000000UL); break; + case 7: DIVMOD(q, r, v, 10000000UL); break; + case 8: DIVMOD(q, r, v, 100000000UL); break; + case 9: DIVMOD(q, r, v, 1000000000UL); break; /* GCOV_NOT_REACHED */ + } + } +} +/* END CONFIG_32 */ + +/* NO CONFIG */ +#else + #error "define CONFIG_64 or CONFIG_32" +#endif /* CONFIG */ + + +static inline void +_mpd_div_word(mpd_uint_t *q, mpd_uint_t *r, mpd_uint_t v, mpd_uint_t d) +{ + *q = v / d; + *r = v - *q * d; +} + +static inline void +_mpd_idiv_word(mpd_ssize_t *q, mpd_ssize_t *r, mpd_ssize_t v, mpd_ssize_t d) +{ + *q = v / d; + *r = v - *q * d; +} + + +/** ------------------------------------------------------------ + ** Arithmetic with overflow checking + ** ------------------------------------------------------------ + */ + +/* The following macros do call exit() in case of an overflow. + If the library is used correctly (i.e. with valid context + parameters), such overflows cannot occur. The macros are used + as sanity checks in a couple of strategic places and should + be viewed as a handwritten version of gcc's -ftrapv option. */ + +static inline mpd_size_t +add_size_t(mpd_size_t a, mpd_size_t b) +{ + if (a > MPD_SIZE_MAX - b) { + mpd_err_fatal("add_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */ + } + return a + b; +} + +static inline mpd_size_t +sub_size_t(mpd_size_t a, mpd_size_t b) +{ + if (b > a) { + mpd_err_fatal("sub_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */ + } + return a - b; +} + +#if MPD_SIZE_MAX != MPD_UINT_MAX + #error "adapt mul_size_t() and mulmod_size_t()" +#endif + +static inline mpd_size_t +mul_size_t(mpd_size_t a, mpd_size_t b) +{ + mpd_uint_t hi, lo; + + _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b); + if (hi) { + mpd_err_fatal("mul_size_t(): overflow: check the context"); /* GCOV_NOT_REACHED */ + } + return lo; +} + +static inline mpd_size_t +add_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow) +{ + mpd_size_t ret; + + *overflow = 0; + ret = a + b; + if (ret < a) *overflow = 1; + return ret; +} + +static inline mpd_size_t +mul_size_t_overflow(mpd_size_t a, mpd_size_t b, mpd_size_t *overflow) +{ + mpd_uint_t lo; + + _mpd_mul_words((mpd_uint_t *)overflow, &lo, (mpd_uint_t)a, + (mpd_uint_t)b); + return lo; +} + +static inline mpd_ssize_t +mod_mpd_ssize_t(mpd_ssize_t a, mpd_ssize_t m) +{ + mpd_ssize_t r = a % m; + return (r < 0) ? r + m : r; +} + +static inline mpd_size_t +mulmod_size_t(mpd_size_t a, mpd_size_t b, mpd_size_t m) +{ + mpd_uint_t hi, lo; + mpd_uint_t q, r; + + _mpd_mul_words(&hi, &lo, (mpd_uint_t)a, (mpd_uint_t)b); + _mpd_div_words(&q, &r, hi, lo, (mpd_uint_t)m); + + return r; +} + + +#endif /* TYPEARITH_H */ + + + diff --git a/Modules/_decimal/libmpdec/umodarith.h b/Modules/_decimal/libmpdec/umodarith.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/umodarith.h @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef UMODARITH_H +#define UMODARITH_H + + +#include "constants.h" +#include "mpdecimal.h" +#include "typearith.h" + + +/* Bignum: Low level routines for unsigned modular arithmetic. These are + used in the fast convolution functions for very large coefficients. */ + + +/**************************************************************************/ +/* ANSI modular arithmetic */ +/**************************************************************************/ + + +/* + * Restrictions: a < m and b < m + * ACL2 proof: umodarith.lisp: addmod-correct + */ +static inline mpd_uint_t +addmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t s; + + s = a + b; + s = (s < a) ? s - m : s; + s = (s >= m) ? s - m : s; + + return s; +} + +/* + * Restrictions: a < m and b < m + * ACL2 proof: umodarith.lisp: submod-2-correct + */ +static inline mpd_uint_t +submod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t d; + + d = a - b; + d = (a < b) ? d + m : d; + + return d; +} + +/* + * Restrictions: a < 2m and b < 2m + * ACL2 proof: umodarith.lisp: section ext-submod + */ +static inline mpd_uint_t +ext_submod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t d; + + a = (a >= m) ? a - m : a; + b = (b >= m) ? b - m : b; + + d = a - b; + d = (a < b) ? d + m : d; + + return d; +} + +/* + * Reduce double word modulo m. + * Restrictions: m != 0 + * ACL2 proof: umodarith.lisp: section dw-reduce + */ +static inline mpd_uint_t +dw_reduce(mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t m) +{ + mpd_uint_t r1, r2, w; + + _mpd_div_word(&w, &r1, hi, m); + _mpd_div_words(&w, &r2, r1, lo, m); + + return r2; +} + +/* + * Subtract double word from a. + * Restrictions: a < m + * ACL2 proof: umodarith.lisp: section dw-submod + */ +static inline mpd_uint_t +dw_submod(mpd_uint_t a, mpd_uint_t hi, mpd_uint_t lo, mpd_uint_t m) +{ + mpd_uint_t d, r; + + r = dw_reduce(hi, lo, m); + d = a - r; + d = (a < r) ? d + m : d; + + return d; +} + +#ifdef CONFIG_64 + +/**************************************************************************/ +/* 64-bit modular arithmetic */ +/**************************************************************************/ + +/* + * A proof of the algorithm is in literature/mulmod-64.txt. An ACL2 + * proof is in umodarith.lisp: section "Fast modular reduction". + * + * Algorithm: calculate (a * b) % p: + * + * a) hi, lo <- a * b # Calculate a * b. + * + * b) hi, lo <- R(hi, lo) # Reduce modulo p. + * + * c) Repeat step b) until 0 <= hi * 2**64 + lo < 2*p. + * + * d) If the result is less than p, return lo. Otherwise return lo - p. + */ + +static inline mpd_uint_t +x64_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t hi, lo, x, y; + + + _mpd_mul_words(&hi, &lo, a, b); + + if (m & (1ULL<<32)) { /* P1 */ + + /* first reduction */ + x = y = hi; + hi >>= 32; + + x = lo - x; + if (x > lo) hi--; + + y <<= 32; + lo = y + x; + if (lo < y) hi++; + + /* second reduction */ + x = y = hi; + hi >>= 32; + + x = lo - x; + if (x > lo) hi--; + + y <<= 32; + lo = y + x; + if (lo < y) hi++; + + return (hi || lo >= m ? lo - m : lo); + } + else if (m & (1ULL<<34)) { /* P2 */ + + /* first reduction */ + x = y = hi; + hi >>= 30; + + x = lo - x; + if (x > lo) hi--; + + y <<= 34; + lo = y + x; + if (lo < y) hi++; + + /* second reduction */ + x = y = hi; + hi >>= 30; + + x = lo - x; + if (x > lo) hi--; + + y <<= 34; + lo = y + x; + if (lo < y) hi++; + + /* third reduction */ + x = y = hi; + hi >>= 30; + + x = lo - x; + if (x > lo) hi--; + + y <<= 34; + lo = y + x; + if (lo < y) hi++; + + return (hi || lo >= m ? lo - m : lo); + } + else { /* P3 */ + + /* first reduction */ + x = y = hi; + hi >>= 24; + + x = lo - x; + if (x > lo) hi--; + + y <<= 40; + lo = y + x; + if (lo < y) hi++; + + /* second reduction */ + x = y = hi; + hi >>= 24; + + x = lo - x; + if (x > lo) hi--; + + y <<= 40; + lo = y + x; + if (lo < y) hi++; + + /* third reduction */ + x = y = hi; + hi >>= 24; + + x = lo - x; + if (x > lo) hi--; + + y <<= 40; + lo = y + x; + if (lo < y) hi++; + + return (hi || lo >= m ? lo - m : lo); + } +} + +static inline void +x64_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m) +{ + *a = x64_mulmod(*a, w, m); + *b = x64_mulmod(*b, w, m); +} + +static inline void +x64_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + mpd_uint_t m) +{ + *a0 = x64_mulmod(*a0, b0, m); + *a1 = x64_mulmod(*a1, b1, m); +} + +static inline mpd_uint_t +x64_powmod(mpd_uint_t base, mpd_uint_t exp, mpd_uint_t umod) +{ + mpd_uint_t r = 1; + + while (exp > 0) { + if (exp & 1) + r = x64_mulmod(r, base, umod); + base = x64_mulmod(base, base, umod); + exp >>= 1; + } + + return r; +} + +/* END CONFIG_64 */ +#else /* CONFIG_32 */ + + +/**************************************************************************/ +/* 32-bit modular arithmetic */ +/**************************************************************************/ + +#if defined(ANSI) +#if !defined(LEGACY_COMPILER) +/* HAVE_UINT64_T */ +static inline mpd_uint_t +std_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + return ((mpd_uuint_t) a * b) % m; +} + +static inline void +std_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m) +{ + *a = ((mpd_uuint_t) *a * w) % m; + *b = ((mpd_uuint_t) *b * w) % m; +} + +static inline void +std_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + mpd_uint_t m) +{ + *a0 = ((mpd_uuint_t) *a0 * b0) % m; + *a1 = ((mpd_uuint_t) *a1 * b1) % m; +} +/* END HAVE_UINT64_T */ +#else +/* LEGACY_COMPILER */ +static inline mpd_uint_t +std_mulmod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) +{ + mpd_uint_t hi, lo, q, r; + _mpd_mul_words(&hi, &lo, a, b); + _mpd_div_words(&q, &r, hi, lo, m); + return r; +} + +static inline void +std_mulmod2c(mpd_uint_t *a, mpd_uint_t *b, mpd_uint_t w, mpd_uint_t m) +{ + *a = std_mulmod(*a, w, m); + *b = std_mulmod(*b, w, m); +} + +static inline void +std_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + mpd_uint_t m) +{ + *a0 = std_mulmod(*a0, b0, m); + *a1 = std_mulmod(*a1, b1, m); +} +/* END LEGACY_COMPILER */ +#endif + +static inline mpd_uint_t +std_powmod(mpd_uint_t base, mpd_uint_t exp, mpd_uint_t umod) +{ + mpd_uint_t r = 1; + + while (exp > 0) { + if (exp & 1) + r = std_mulmod(r, base, umod); + base = std_mulmod(base, base, umod); + exp >>= 1; + } + + return r; +} +#endif /* ANSI CONFIG_32 */ + + +/**************************************************************************/ +/* Pentium Pro modular arithmetic */ +/**************************************************************************/ + +/* + * A proof of the algorithm is in literature/mulmod-ppro.txt. The FPU + * control word must be set to 64-bit precision and truncation mode + * prior to using these functions. + * + * Algorithm: calculate (a * b) % p: + * + * p := prime < 2**31 + * pinv := (long double)1.0 / p (precalculated) + * + * a) n = a * b # Calculate exact product. + * b) qest = n * pinv # Calculate estimate for q = n / p. + * c) q = (qest+2**63)-2**63 # Truncate qest to the exact quotient. + * d) r = n - q * p # Calculate remainder. + * + * Remarks: + * + * - p = dmod and pinv = dinvmod. + * - dinvmod points to an array of three uint32_t, which is interpreted + * as an 80 bit long double by fldt. + * - Intel compilers prior to version 11 do not seem to handle the + * __GNUC__ inline assembly correctly. + * - random tests are provided in tests/extended/ppro_mulmod.c + */ + +#if defined(PPRO) +#if defined(ASM) + +/* Return (a * b) % dmod */ +static inline mpd_uint_t +ppro_mulmod(mpd_uint_t a, mpd_uint_t b, double *dmod, uint32_t *dinvmod) +{ + mpd_uint_t retval; + + asm ( + "fildl %2\n\t" + "fildl %1\n\t" + "fmulp %%st, %%st(1)\n\t" + "fldt (%4)\n\t" + "fmul %%st(1), %%st\n\t" + "flds %5\n\t" + "fadd %%st, %%st(1)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fldl (%3)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fistpl %0\n\t" + : "=m" (retval) + : "m" (a), "m" (b), "r" (dmod), "r" (dinvmod), "m" (MPD_TWO63) + : "st", "memory" + ); + + return retval; +} + +/* + * Two modular multiplications in parallel: + * *a0 = (*a0 * w) % dmod + * *a1 = (*a1 * w) % dmod + */ +static inline void +ppro_mulmod2c(mpd_uint_t *a0, mpd_uint_t *a1, mpd_uint_t w, + double *dmod, uint32_t *dinvmod) +{ + asm ( + "fildl %2\n\t" + "fildl (%1)\n\t" + "fmul %%st(1), %%st\n\t" + "fxch %%st(1)\n\t" + "fildl (%0)\n\t" + "fmulp %%st, %%st(1) \n\t" + "fldt (%4)\n\t" + "flds %5\n\t" + "fld %%st(2)\n\t" + "fmul %%st(2)\n\t" + "fadd %%st(1)\n\t" + "fsub %%st(1)\n\t" + "fmull (%3)\n\t" + "fsubrp %%st, %%st(3)\n\t" + "fxch %%st(2)\n\t" + "fistpl (%0)\n\t" + "fmul %%st(2)\n\t" + "fadd %%st(1)\n\t" + "fsubp %%st, %%st(1)\n\t" + "fmull (%3)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fistpl (%1)\n\t" + : : "r" (a0), "r" (a1), "m" (w), + "r" (dmod), "r" (dinvmod), + "m" (MPD_TWO63) + : "st", "memory" + ); +} + +/* + * Two modular multiplications in parallel: + * *a0 = (*a0 * b0) % dmod + * *a1 = (*a1 * b1) % dmod + */ +static inline void +ppro_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + double *dmod, uint32_t *dinvmod) +{ + asm ( + "fildl %3\n\t" + "fildl (%2)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fildl %1\n\t" + "fildl (%0)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fldt (%5)\n\t" + "fld %%st(2)\n\t" + "fmul %%st(1), %%st\n\t" + "fxch %%st(1)\n\t" + "fmul %%st(2), %%st\n\t" + "flds %6\n\t" + "fldl (%4)\n\t" + "fxch %%st(3)\n\t" + "fadd %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fadd %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fsub %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fsubp %%st, %%st(1)\n\t" + "fxch %%st(1)\n\t" + "fmul %%st(2), %%st\n\t" + "fxch %%st(1)\n\t" + "fmulp %%st, %%st(2)\n\t" + "fsubrp %%st, %%st(3)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fxch %%st(1)\n\t" + "fistpl (%2)\n\t" + "fistpl (%0)\n\t" + : : "r" (a0), "m" (b0), "r" (a1), "m" (b1), + "r" (dmod), "r" (dinvmod), + "m" (MPD_TWO63) + : "st", "memory" + ); +} +/* END PPRO GCC ASM */ +#elif defined(MASM) + +/* Return (a * b) % dmod */ +static inline mpd_uint_t __cdecl +ppro_mulmod(mpd_uint_t a, mpd_uint_t b, double *dmod, uint32_t *dinvmod) +{ + mpd_uint_t retval; + + __asm { + mov eax, dinvmod + mov edx, dmod + fild b + fild a + fmulp st(1), st + fld TBYTE PTR [eax] + fmul st, st(1) + fld MPD_TWO63 + fadd st(1), st + fsubp st(1), st + fld QWORD PTR [edx] + fmulp st(1), st + fsubp st(1), st + fistp retval + } + + return retval; +} + +/* + * Two modular multiplications in parallel: + * *a0 = (*a0 * w) % dmod + * *a1 = (*a1 * w) % dmod + */ +static inline mpd_uint_t __cdecl +ppro_mulmod2c(mpd_uint_t *a0, mpd_uint_t *a1, mpd_uint_t w, + double *dmod, uint32_t *dinvmod) +{ + __asm { + mov ecx, dmod + mov edx, a1 + mov ebx, dinvmod + mov eax, a0 + fild w + fild DWORD PTR [edx] + fmul st, st(1) + fxch st(1) + fild DWORD PTR [eax] + fmulp st(1), st + fld TBYTE PTR [ebx] + fld MPD_TWO63 + fld st(2) + fmul st, st(2) + fadd st, st(1) + fsub st, st(1) + fmul QWORD PTR [ecx] + fsubp st(3), st + fxch st(2) + fistp DWORD PTR [eax] + fmul st, st(2) + fadd st, st(1) + fsubrp st(1), st + fmul QWORD PTR [ecx] + fsubp st(1), st + fistp DWORD PTR [edx] + } +} + +/* + * Two modular multiplications in parallel: + * *a0 = (*a0 * b0) % dmod + * *a1 = (*a1 * b1) % dmod + */ +static inline void __cdecl +ppro_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, + double *dmod, uint32_t *dinvmod) +{ + __asm { + mov ecx, dmod + mov edx, a1 + mov ebx, dinvmod + mov eax, a0 + fild b1 + fild DWORD PTR [edx] + fmulp st(1), st + fild b0 + fild DWORD PTR [eax] + fmulp st(1), st + fld TBYTE PTR [ebx] + fld st(2) + fmul st, st(1) + fxch st(1) + fmul st, st(2) + fld DWORD PTR MPD_TWO63 + fld QWORD PTR [ecx] + fxch st(3) + fadd st, st(1) + fxch st(2) + fadd st, st(1) + fxch st(2) + fsub st, st(1) + fxch st(2) + fsubrp st(1), st + fxch st(1) + fmul st, st(2) + fxch st(1) + fmulp st(2), st + fsubp st(3), st + fsubp st(1), st + fxch st(1) + fistp DWORD PTR [edx] + fistp DWORD PTR [eax] + } +} +#endif /* PPRO MASM (_MSC_VER) */ + + +/* Return (base ** exp) % dmod */ +static inline mpd_uint_t +ppro_powmod(mpd_uint_t base, mpd_uint_t exp, double *dmod, uint32_t *dinvmod) +{ + mpd_uint_t r = 1; + + while (exp > 0) { + if (exp & 1) + r = ppro_mulmod(r, base, dmod, dinvmod); + base = ppro_mulmod(base, base, dmod, dinvmod); + exp >>= 1; + } + + return r; +} +#endif /* PPRO */ +#endif /* CONFIG_32 */ + + +#endif /* UMODARITH_H */ + + + diff --git a/Modules/_decimal/libmpdec/vccompat.h b/Modules/_decimal/libmpdec/vccompat.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/vccompat.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef VCCOMPAT_H +#define VCCOMPAT_H + + +/* Visual C fixes: no stdint.h, no snprintf ... */ +#ifdef _MSC_VER + #include "vcstdint.h" + #undef inline + #define inline __inline + #undef random + #define random rand + #undef srandom + #define srandom srand + #undef snprintf + #define snprintf sprintf_s + #define HAVE_SNPRINTF + #undef strncasecmp + #define strncasecmp _strnicmp + #undef strcasecmp + #define strcasecmp _stricmp + #undef strtoll + #define strtoll _strtoi64 + #define strdup _strdup + #define PRIi64 "I64i" + #define PRIu64 "I64u" + #define PRIi32 "I32i" + #define PRIu32 "I32u" +#endif + + +#endif /* VCCOMPAT_H */ + + + diff --git a/Modules/_decimal/libmpdec/vcdiv64.asm b/Modules/_decimal/libmpdec/vcdiv64.asm new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/vcdiv64.asm @@ -0,0 +1,48 @@ +; +; Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; 1. Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; +; 2. Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in the +; documentation and/or other materials provided with the distribution. +; +; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +; SUCH DAMAGE. +; + + +PUBLIC _mpd_div_words +_TEXT SEGMENT +q$ = 8 +r$ = 16 +hi$ = 24 +lo$ = 32 +d$ = 40 +_mpd_div_words PROC + mov r10, rdx + mov rdx, r8 + mov rax, r9 + div QWORD PTR d$[rsp] + mov QWORD PTR [r10], rdx + mov QWORD PTR [rcx], rax + ret 0 +_mpd_div_words ENDP +_TEXT ENDS +END + + diff --git a/Modules/_decimal/libmpdec/vcstdint.h b/Modules/_decimal/libmpdec/vcstdint.h new file mode 100644 --- /dev/null +++ b/Modules/_decimal/libmpdec/vcstdint.h @@ -0,0 +1,232 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#if (_MSC_VER < 1300) && defined(__cplusplus) + extern "C++" { +#endif +# include +#if (_MSC_VER < 1300) && defined(__cplusplus) + } +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/Modules/_decimal/tests/README.txt b/Modules/_decimal/tests/README.txt new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/README.txt @@ -0,0 +1,15 @@ + + +This directory contains extended tests and a benchmark against decimal.py: + + bench.py -> Benchmark for small and large precisions. + Usage: ../../../python bench.py + + formathelper.py -> + randdec.py -> Generate test cases for deccheck.py. + randfloat.py -> + + deccheck.py -> Run extended tests. + Usage: ../../../python deccheck.py [--short|--medium|--long|--all] + + diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/bench.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python + +# +# Copyright (C) 2001-2012 Python Software Foundation. All Rights Reserved. +# Modified and extended by Stefan Krah. +# + +# Usage: ../../../python bench.py + + +import time +from math import log, ceil +from test.support import import_fresh_module + +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) + + +# Pi function from the decimal.py documentation +def pi_float(prec): + """native float""" + lasts, t, s, n, na, d, da = 0, 3.0, 3, 1, 0, 0, 24 + while s != lasts: + lasts = s + n, na = n+na, na+8 + d, da = d+da, da+32 + t = (t * n) / d + s += t + return s + +def pi_cdecimal(prec): + """cdecimal""" + C.getcontext().prec = prec + D = C.Decimal + lasts, t, s, n, na, d, da = D(0), D(3), D(3), D(1), D(0), D(0), D(24) + while s != lasts: + lasts = s + n, na = n+na, na+8 + d, da = d+da, da+32 + t = (t * n) / d + s += t + return s + +def pi_decimal(prec): + """decimal""" + P.getcontext().prec = prec + D = P.Decimal + lasts, t, s, n, na, d, da = D(0), D(3), D(3), D(1), D(0), D(0), D(24) + while s != lasts: + lasts = s + n, na = n+na, na+8 + d, da = d+da, da+32 + t = (t * n) / d + s += t + return s + +def factorial(n, m): + if (n > m): + return factorial(m, n) + elif m == 0: + return 1 + elif n == m: + return n + else: + return factorial(n, (n+m)//2) * factorial((n+m)//2 + 1, m) + + +print("\n# ======================================================================") +print("# Calculating pi, 10000 iterations") +print("# ======================================================================\n") + +for prec in [9, 19]: + print("\nPrecision: %d decimal digits\n" % prec) + for func in [pi_float, pi_cdecimal, pi_decimal]: + start = time.time() + for i in range(10000): + x = func(prec) + print("%s:" % func.__name__.replace("pi_", "")) + print("result: %s" % str(x)) + print("time: %fs\n" % (time.time()-start)) + + +print("\n# ======================================================================") +print("# Factorial") +print("# ======================================================================\n") + +C.getcontext().prec = C.MAX_PREC + +for n in [100000, 1000000]: + + print("n = %d\n" % n) + + # C version of decimal + start_calc = time.time() + x = factorial(C.Decimal(n), 0) + end_calc = time.time() + start_conv = time.time() + sx = str(x) + end_conv = time.time() + print("cdecimal:") + print("calculation time: %fs" % (end_calc-start_calc)) + print("conversion time: %fs\n" % (end_conv-start_conv)) + + # Python integers + start_calc = time.time() + y = factorial(n, 0) + end_calc = time.time() + start_conv = time.time() + sy = str(y) + end_conv = time.time() + + print("int:") + print("calculation time: %fs" % (end_calc-start_calc)) + print("conversion time: %fs\n\n" % (end_conv-start_conv)) + + assert(sx == sy) diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/deccheck.py @@ -0,0 +1,1074 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# +# Usage: python deccheck.py [--short|--medium|--long|--all] +# + +import sys, random +from copy import copy +from collections import defaultdict +from test.support import import_fresh_module +from randdec import randfloat, all_unary, all_binary, all_ternary +from formathelper import rand_format, rand_locale + +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) +EXIT_STATUS = 0 + + +# Contains all categories of Decimal methods. +Functions = { + # Plain unary: + 'unary': ( + '__abs__', '__bool__', '__ceil__', '__complex__', '__copy__', + '__floor__', '__float__', '__hash__', '__int__', '__neg__', + '__pos__', '__reduce__', '__repr__', '__str__', '__trunc__', + 'adjusted', 'as_tuple', 'canonical', 'conjugate', 'copy_abs', + 'copy_negate', 'is_canonical', 'is_finite', 'is_infinite', + 'is_nan', 'is_qnan', 'is_signed', 'is_snan', 'is_zero', 'radix' + ), + # Unary with optional context: + 'unary_ctx': ( + 'exp', 'is_normal', 'is_subnormal', 'ln', 'log10', 'logb', + 'logical_invert', 'next_minus', 'next_plus', 'normalize', + 'number_class', 'sqrt', 'to_eng_string' + ), + # Unary with optional rounding mode and context: + 'unary_rnd_ctx': ('to_integral', 'to_integral_exact', 'to_integral_value'), + # Plain binary: + 'binary': ( + '__add__', '__divmod__', '__eq__', '__floordiv__', '__ge__', '__gt__', + '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__pow__', + '__radd__', '__rdivmod__', '__rfloordiv__', '__rmod__', '__rmul__', + '__rpow__', '__rsub__', '__rtruediv__', '__sub__', '__truediv__', + 'compare_total', 'compare_total_mag', 'copy_sign', 'quantize', + 'same_quantum' + ), + # Binary with optional context: + 'binary_ctx': ( + 'compare', 'compare_signal', 'logical_and', 'logical_or', 'logical_xor', + 'max', 'max_mag', 'min', 'min_mag', 'next_toward', 'remainder_near', + 'rotate', 'scaleb', 'shift' + ), + # Plain ternary: + 'ternary': ('__pow__',), + # Ternary with optional context: + 'ternary_ctx': ('fma',), + # Special: + 'special': ('__format__', '__reduce_ex__', '__round__', 'from_float', + 'quantize'), + # Properties: + 'property': ('real', 'imag') +} + +# Contains all categories of Context methods. The n-ary classification +# applies to the number of Decimal arguments. +ContextFunctions = { + # Plain nullary: + 'nullary': ('context.__hash__', 'context.__reduce__', 'context.radix'), + # Plain unary: + 'unary': ('context.abs', 'context.canonical', 'context.copy_abs', + 'context.copy_decimal', 'context.copy_negate', + 'context.create_decimal', 'context.exp', 'context.is_canonical', + 'context.is_finite', 'context.is_infinite', 'context.is_nan', + 'context.is_normal', 'context.is_qnan', 'context.is_signed', + 'context.is_snan', 'context.is_subnormal', 'context.is_zero', + 'context.ln', 'context.log10', 'context.logb', + 'context.logical_invert', 'context.minus', 'context.next_minus', + 'context.next_plus', 'context.normalize', 'context.number_class', + 'context.plus', 'context.sqrt', 'context.to_eng_string', + 'context.to_integral', 'context.to_integral_exact', + 'context.to_integral_value', 'context.to_sci_string' + ), + # Plain binary: + 'binary': ('context.add', 'context.compare', 'context.compare_signal', + 'context.compare_total', 'context.compare_total_mag', + 'context.copy_sign', 'context.divide', 'context.divide_int', + 'context.divmod', 'context.logical_and', 'context.logical_or', + 'context.logical_xor', 'context.max', 'context.max_mag', + 'context.min', 'context.min_mag', 'context.multiply', + 'context.next_toward', 'context.power', 'context.quantize', + 'context.remainder', 'context.remainder_near', 'context.rotate', + 'context.same_quantum', 'context.scaleb', 'context.shift', + 'context.subtract' + ), + # Plain ternary: + 'ternary': ('context.fma', 'context.power'), + # Special: + 'special': ('context.__reduce_ex__', 'context.create_decimal_from_float') +} + +# Functions that require a restricted exponent range for reasonable runtimes. +UnaryRestricted = [ + '__ceil__', '__floor__', '__int__', '__long__', '__trunc__', + 'to_integral', 'to_integral_value' +] + +BinaryRestricted = ['__round__'] + +TernaryRestricted = ['__pow__', 'context.power'] + + +# ====================================================================== +# Unified Context +# ====================================================================== + +# Translate symbols. +CondMap = { + C.Clamped: P.Clamped, + C.ConversionSyntax: P.ConversionSyntax, + C.DivisionByZero: P.DivisionByZero, + C.DivisionImpossible: P.InvalidOperation, + C.DivisionUndefined: P.DivisionUndefined, + C.Inexact: P.Inexact, + C.InvalidContext: P.InvalidContext, + C.InvalidOperation: P.InvalidOperation, + C.Overflow: P.Overflow, + C.Rounded: P.Rounded, + C.Subnormal: P.Subnormal, + C.Underflow: P.Underflow, + C.FloatOperation: P.FloatOperation, +} + +RoundMap = { + C.ROUND_UP: P.ROUND_UP, + C.ROUND_DOWN: P.ROUND_DOWN, + C.ROUND_CEILING: P.ROUND_CEILING, + C.ROUND_FLOOR: P.ROUND_FLOOR, + C.ROUND_HALF_UP: P.ROUND_HALF_UP, + C.ROUND_HALF_DOWN: P.ROUND_HALF_DOWN, + C.ROUND_HALF_EVEN: P.ROUND_HALF_EVEN, + C.ROUND_05UP: P.ROUND_05UP +} +RoundModes = RoundMap.items() + + +class Context(object): + """Provides a convenient way of syncing the C and P contexts""" + + __slots__ = ['c', 'p'] + + def __init__(self, c_ctx=None, p_ctx=None): + """Initialization is from the C context""" + self.c = C.getcontext() if c_ctx is None else c_ctx + self.p = P.getcontext() if p_ctx is None else p_ctx + self.p.prec = self.c.prec + self.p.Emin = self.c.Emin + self.p.Emax = self.c.Emax + self.p.rounding = RoundMap[self.c.rounding] + self.p.capitals = self.c.capitals + self.settraps([sig for sig in self.c.traps if self.c.traps[sig]]) + self.setstatus([sig for sig in self.c.flags if self.c.flags[sig]]) + self.p.clamp = self.c.clamp + + def __str__(self): + return str(self.c) + '\n' + str(self.p) + + def getprec(self): + assert(self.c.prec == self.p.prec) + return self.c.prec + + def setprec(self, val): + self.c.prec = val + self.p.prec = val + + def getemin(self): + assert(self.c.Emin == self.p.Emin) + return self.c.Emin + + def setemin(self, val): + self.c.Emin = val + self.p.Emin = val + + def getemax(self): + assert(self.c.Emax == self.p.Emax) + return self.c.Emax + + def setemax(self, val): + self.c.Emax = val + self.p.Emax = val + + def getround(self): + assert(self.c.rounding == RoundMap[self.p.rounding]) + return self.c.rounding + + def setround(self, val): + self.c.rounding = val + self.p.rounding = RoundMap[val] + + def getcapitals(self): + assert(self.c.capitals == self.p.capitals) + return self.c.capitals + + def setcapitals(self, val): + self.c.capitals = val + self.p.capitals = val + + def getclamp(self): + assert(self.c.clamp == self.p.clamp) + return self.c.clamp + + def setclamp(self, val): + self.c.clamp = val + self.p.clamp = val + + prec = property(getprec, setprec) + Emin = property(getemin, setemin) + Emax = property(getemax, setemax) + rounding = property(getround, setround) + clamp = property(getclamp, setclamp) + capitals = property(getcapitals, setcapitals) + + def clear_traps(self): + self.c.clear_traps() + for trap in self.p.traps: + self.p.traps[trap] = False + + def clear_status(self): + self.c.clear_flags() + self.p.clear_flags() + + def settraps(self, lst): + """lst: C signal list""" + self.clear_traps() + for signal in lst: + self.c.traps[signal] = True + self.p.traps[CondMap[signal]] = True + + def setstatus(self, lst): + """lst: C signal list""" + self.clear_status() + for signal in lst: + self.c.flags[signal] = True + self.p.flags[CondMap[signal]] = True + + def assert_eq_status(self): + """assert equality of C and P status""" + for signal in self.c.flags: + if self.c.flags[signal] == (not self.p.flags[CondMap[signal]]): + return False + return True + + +# We don't want exceptions so that we can compare the status flags. +context = Context() +context.Emin = C.MIN_EMIN +context.Emax = C.MAX_EMAX +context.clear_traps() + +# When creating decimals, _decimal is ultimately limited by the maximum +# context values. We emulate this restriction for decimal.py. +maxcontext = P.Context( + prec=C.MAX_PREC, + Emin=C.MIN_EMIN, + Emax=C.MAX_EMAX, + rounding=P.ROUND_HALF_UP, + capitals=1 +) +maxcontext.clamp = 0 + +def RestrictedDecimal(value): + maxcontext.traps = copy(context.p.traps) + maxcontext.clear_flags() + if isinstance(value, str): + value = value.strip() + dec = maxcontext.create_decimal(value) + if maxcontext.flags[P.Inexact] or \ + maxcontext.flags[P.Rounded] or \ + maxcontext.flags[P.InvalidOperation]: + return context.p._raise_error(P.InvalidOperation) + if maxcontext.flags[P.FloatOperation]: + context.p.flags[P.FloatOperation] = True + return dec + + +# ====================================================================== +# TestSet: Organize data and events during a single test case +# ====================================================================== + +class RestrictedList(list): + """List that can only be modified by appending items.""" + def __getattribute__(self, name): + if name != 'append': + raise AttributeError("unsupported operation") + return list.__getattribute__(self, name) + def unsupported(self, *_): + raise AttributeError("unsupported operation") + __add__ = __delattr__ = __delitem__ = __iadd__ = __imul__ = unsupported + __mul__ = __reversed__ = __rmul__ = __setattr__ = __setitem__ = unsupported + +class TestSet(object): + """A TestSet contains the original input operands, converted operands, + Python exceptions that occurred either during conversion or during + execution of the actual function, and the final results. + + For safety, most attributes are lists that only support the append + operation. + + If a function name is prefixed with 'context.', the corresponding + context method is called. + """ + def __init__(self, funcname, operands): + if funcname.startswith("context."): + self.funcname = funcname.replace("context.", "") + self.contextfunc = True + else: + self.funcname = funcname + self.contextfunc = False + self.op = operands # raw operand tuple + self.context = context # context used for the operation + self.cop = RestrictedList() # converted C.Decimal operands + self.cex = RestrictedList() # Python exceptions for C.Decimal + self.cresults = RestrictedList() # C.Decimal results + self.pop = RestrictedList() # converted P.Decimal operands + self.pex = RestrictedList() # Python exceptions for P.Decimal + self.presults = RestrictedList() # P.Decimal results + + +# ====================================================================== +# SkipHandler: skip known discrepancies +# ====================================================================== + +class SkipHandler: + """Handle known discrepancies between decimal.py and _decimal.so. + These are either ULP differences in the power function or + extremely minor issues.""" + + def __init__(self): + self.ulpdiff = 0 + self.powmod_zeros = 0 + self.maxctx = P.Context(Emax=10**18, Emin=-10**18) + + def default(self, t): + return False + __ge__ = __gt__ = __le__ = __lt__ = __ne__ = __eq__ = default + __reduce__ = __format__ = __repr__ = __str__ = default + + def harrison_ulp(self, dec): + """ftp://ftp.inria.fr/INRIA/publication/publi-pdf/RR/RR-5504.pdf""" + a = dec.next_plus() + b = dec.next_minus() + return abs(a - b) + + def standard_ulp(self, dec, prec): + return P._dec_from_triple(0, '1', dec._exp+len(dec._int)-prec) + + def rounding_direction(self, x, mode): + """Determine the effective direction of the rounding when + the exact result x is rounded according to mode. + Return -1 for downwards, 0 for undirected, 1 for upwards, + 2 for ROUND_05UP.""" + cmp = 1 if x.compare_total(P.Decimal("+0")) >= 0 else -1 + + if mode in (P.ROUND_HALF_EVEN, P.ROUND_HALF_UP, P.ROUND_HALF_DOWN): + return 0 + elif mode == P.ROUND_CEILING: + return 1 + elif mode == P.ROUND_FLOOR: + return -1 + elif mode == P.ROUND_UP: + return cmp + elif mode == P.ROUND_DOWN: + return -cmp + elif mode == P.ROUND_05UP: + return 2 + else: + raise ValueError("Unexpected rounding mode: %s" % mode) + + def check_ulpdiff(self, exact, rounded): + # current precision + p = context.p.prec + + # Convert infinities to the largest representable number + 1. + x = exact + if exact.is_infinite(): + x = P._dec_from_triple(exact._sign, '10', context.p.Emax) + y = rounded + if rounded.is_infinite(): + y = P._dec_from_triple(rounded._sign, '10', context.p.Emax) + + # err = (rounded - exact) / ulp(rounded) + self.maxctx.prec = p * 2 + t = self.maxctx.subtract(y, x) + if context.c.flags[C.Clamped] or \ + context.c.flags[C.Underflow]: + # The standard ulp does not work in Underflow territory. + ulp = self.harrison_ulp(y) + else: + ulp = self.standard_ulp(y, p) + # Error in ulps. + err = self.maxctx.divide(t, ulp) + + dir = self.rounding_direction(x, context.p.rounding) + if dir == 0: + if P.Decimal("-0.6") < err < P.Decimal("0.6"): + return True + elif dir == 1: # directed, upwards + if P.Decimal("-0.1") < err < P.Decimal("1.1"): + return True + elif dir == -1: # directed, downwards + if P.Decimal("-1.1") < err < P.Decimal("0.1"): + return True + else: # ROUND_05UP + if P.Decimal("-1.1") < err < P.Decimal("1.1"): + return True + + print("ulp: %s error: %s exact: %s c_rounded: %s" + % (ulp, err, exact, rounded)) + return False + + def bin_resolve_ulp(self, t): + """Check if results of _decimal's power function are within the + allowed ulp ranges.""" + # NaNs are beyond repair. + if t.rc.is_nan() or t.rp.is_nan(): + return False + + # "exact" result, double precision, half_even + self.maxctx.prec = context.p.prec * 2 + + op1, op2 = t.pop[0], t.pop[1] + if t.contextfunc: + exact = getattr(self.maxctx, t.funcname)(op1, op2) + else: + exact = getattr(op1, t.funcname)(op2, context=self.maxctx) + + # _decimal's rounded result + rounded = P.Decimal(t.cresults[0]) + + self.ulpdiff += 1 + return self.check_ulpdiff(exact, rounded) + + ############################ Correct rounding ############################# + def resolve_underflow(self, t): + """In extremely rare cases where the infinite precision result is just + below etiny, cdecimal does not set Subnormal/Underflow. Example: + + setcontext(Context(prec=21, rounding=ROUND_UP, Emin=-55, Emax=85)) + Decimal("1.00000000000000000000000000000000000000000000000" + "0000000100000000000000000000000000000000000000000" + "0000000000000025").ln() + """ + if t.cresults != t.presults: + return False # Results must be identical. + if context.c.flags[C.Rounded] and \ + context.c.flags[C.Inexact] and \ + context.p.flags[P.Rounded] and \ + context.p.flags[P.Inexact]: + return True # Subnormal/Underflow may be missing. + return False + + def exp(self, t): + """Resolve Underflow or ULP difference.""" + return self.resolve_underflow(t) + + def log10(self, t): + """Resolve Underflow or ULP difference.""" + return self.resolve_underflow(t) + + def ln(self, t): + """Resolve Underflow or ULP difference.""" + return self.resolve_underflow(t) + + def __pow__(self, t): + """Always calls the resolve function. C.Decimal does not have correct + rounding for the power function.""" + if context.c.flags[C.Rounded] and \ + context.c.flags[C.Inexact] and \ + context.p.flags[P.Rounded] and \ + context.p.flags[P.Inexact]: + return self.bin_resolve_ulp(t) + else: + return False + power = __rpow__ = __pow__ + + ############################## Technicalities ############################# + def __float__(self, t): + """NaN comparison in the verify() function obviously gives an + incorrect answer: nan == nan -> False""" + if t.cop[0].is_nan() and t.pop[0].is_nan(): + return True + return False + __complex__ = __float__ + + def __radd__(self, t): + """decimal.py gives precedence to the first NaN; this is + not important, as __radd__ will not be called for + two decimal arguments.""" + if t.rc.is_nan() and t.rp.is_nan(): + return True + return False + __rmul__ = __radd__ + + ################################ Various ################################## + def __round__(self, t): + """Exception: Decimal('1').__round__(-100000000000000000000000000) + Should it really be InvalidOperation?""" + if t.rc is None and t.rp.is_nan(): + return True + return False + +shandler = SkipHandler() +def skip_error(t): + return getattr(shandler, t.funcname, shandler.default)(t) + + +# ====================================================================== +# Handling verification errors +# ====================================================================== + +class VerifyError(Exception): + """Verification failed.""" + pass + +def function_as_string(t): + if t.contextfunc: + cargs = t.cop + pargs = t.pop + cfunc = "c_func: %s(" % t.funcname + pfunc = "p_func: %s(" % t.funcname + else: + cself, cargs = t.cop[0], t.cop[1:] + pself, pargs = t.pop[0], t.pop[1:] + cfunc = "c_func: %s.%s(" % (repr(cself), t.funcname) + pfunc = "p_func: %s.%s(" % (repr(pself), t.funcname) + + err = cfunc + for arg in cargs: + err += "%s, " % repr(arg) + err = err.rstrip(", ") + err += ")\n" + + err += pfunc + for arg in pargs: + err += "%s, " % repr(arg) + err = err.rstrip(", ") + err += ")" + + return err + +def raise_error(t): + global EXIT_STATUS + + if skip_error(t): + return + EXIT_STATUS = 1 + + err = "Error in %s:\n\n" % t.funcname + err += "input operands: %s\n\n" % (t.op,) + err += function_as_string(t) + err += "\n\nc_result: %s\np_result: %s\n\n" % (t.cresults, t.presults) + err += "c_exceptions: %s\np_exceptions: %s\n\n" % (t.cex, t.pex) + err += "%s\n\n" % str(t.context) + + raise VerifyError(err) + + +# ====================================================================== +# Main testing functions +# +# The procedure is always (t is the TestSet): +# +# convert(t) -> Initialize the TestSet as necessary. +# +# Return 0 for early abortion (e.g. if a TypeError +# occurs during conversion, there is nothing to test). +# +# Return 1 for continuing with the test case. +# +# callfuncs(t) -> Call the relevant function for each implementation +# and record the results in the TestSet. +# +# verify(t) -> Verify the results. If verification fails, details +# are printed to stdout. +# ====================================================================== + +def convert(t, convstr=True): + """ t is the testset. At this stage the testset contains a tuple of + operands t.op of various types. For decimal methods the first + operand (self) is always converted to Decimal. If 'convstr' is + true, string operands are converted as well. + + Context operands are of type deccheck.Context, rounding mode + operands are given as a tuple (C.rounding, P.rounding). + + Other types (float, int, etc.) are left unchanged. + """ + for i, op in enumerate(t.op): + + context.clear_status() + + if not t.contextfunc and i == 0 or \ + convstr and isinstance(op, str): + try: + c = C.Decimal(op) + cex = None + except (TypeError, ValueError, OverflowError) as e: + c = None + cex = e.__class__ + + try: + p = RestrictedDecimal(op) + pex = None + except (TypeError, ValueError, OverflowError) as e: + p = None + pex = e.__class__ + + t.cop.append(c) + t.cex.append(cex) + t.pop.append(p) + t.pex.append(pex) + + if cex is pex: + if str(c) != str(p) or not context.assert_eq_status(): + raise_error(t) + if cex and pex: + # nothing to test + return 0 + else: + raise_error(t) + + elif isinstance(op, Context): + t.context = op + t.cop.append(op.c) + t.pop.append(op.p) + + elif op in RoundModes: + t.cop.append(op[0]) + t.pop.append(op[1]) + + else: + t.cop.append(op) + t.pop.append(op) + + return 1 + +def callfuncs(t): + """ t is the testset. At this stage the testset contains operand lists + t.cop and t.pop for the C and Python versions of decimal. + For Decimal methods, the first operands are of type C.Decimal and + P.Decimal respectively. The remaining operands can have various types. + For Context methods, all operands can have any type. + + t.rc and t.rp are the results of the operation. + """ + context.clear_status() + + try: + if t.contextfunc: + cargs = t.cop + t.rc = getattr(context.c, t.funcname)(*cargs) + else: + cself = t.cop[0] + cargs = t.cop[1:] + t.rc = getattr(cself, t.funcname)(*cargs) + t.cex.append(None) + except (TypeError, ValueError, OverflowError, MemoryError) as e: + t.rc = None + t.cex.append(e.__class__) + + try: + if t.contextfunc: + pargs = t.pop + t.rp = getattr(context.p, t.funcname)(*pargs) + else: + pself = t.pop[0] + pargs = t.pop[1:] + t.rp = getattr(pself, t.funcname)(*pargs) + t.pex.append(None) + except (TypeError, ValueError, OverflowError, MemoryError) as e: + t.rp = None + t.pex.append(e.__class__) + +def verify(t, stat): + """ t is the testset. At this stage the testset contains the following + tuples: + + t.op: original operands + t.cop: C.Decimal operands (see convert for details) + t.pop: P.Decimal operands (see convert for details) + t.rc: C result + t.rp: Python result + + t.rc and t.rp can have various types. + """ + t.cresults.append(str(t.rc)) + t.presults.append(str(t.rp)) + if isinstance(t.rc, C.Decimal) and isinstance(t.rp, P.Decimal): + # General case: both results are Decimals. + t.cresults.append(t.rc.to_eng_string()) + t.cresults.append(t.rc.as_tuple()) + t.cresults.append(str(t.rc.imag)) + t.cresults.append(str(t.rc.real)) + t.presults.append(t.rp.to_eng_string()) + t.presults.append(t.rp.as_tuple()) + t.presults.append(str(t.rp.imag)) + t.presults.append(str(t.rp.real)) + + nc = t.rc.number_class().lstrip('+-s') + stat[nc] += 1 + else: + # Results from e.g. __divmod__ can only be compared as strings. + if not isinstance(t.rc, tuple) and not isinstance(t.rp, tuple): + if t.rc != t.rp: + raise_error(t) + stat[type(t.rc).__name__] += 1 + + # The return value lists must be equal. + if t.cresults != t.presults: + raise_error(t) + # The Python exception lists (TypeError, etc.) must be equal. + if t.cex != t.pex: + raise_error(t) + # The context flags must be equal. + if not t.context.assert_eq_status(): + raise_error(t) + + +# ====================================================================== +# Main test loops +# +# test_method(method, testspecs, testfunc) -> +# +# Loop through various context settings. The degree of +# thoroughness is determined by 'testspec'. For each +# setting, call 'testfunc'. Generally, 'testfunc' itself +# a loop, iterating through many test cases generated +# by the functions in randdec.py. +# +# test_n-ary(method, prec, exp_range, restricted_range, itr, stat) -> +# +# 'test_unary', 'test_binary' and 'test_ternary' are the +# main test functions passed to 'test_method'. They deal +# with the regular cases. The thoroughness of testing is +# determined by 'itr'. +# +# 'prec', 'exp_range' and 'restricted_range' are passed +# to the test-generating functions and limit the generated +# values. In some cases, for reasonable run times a +# maximum exponent of 9999 is required. +# +# The 'stat' parameter is passed down to the 'verify' +# function, which records statistics for the result values. +# ====================================================================== + +def log(fmt, args=None): + if args: + sys.stdout.write(''.join((fmt, '\n')) % args) + else: + sys.stdout.write(''.join((str(fmt), '\n'))) + sys.stdout.flush() + +def test_method(method, testspecs, testfunc): + """Iterate a test function through many context settings.""" + log("testing %s ...", method) + stat = defaultdict(int) + for spec in testspecs: + if 'samples' in spec: + spec['prec'] = sorted(random.sample(range(1, 101), + spec['samples'])) + for prec in spec['prec']: + context.prec = prec + for expts in spec['expts']: + emin, emax = expts + if emin == 'rand': + context.Emin = random.randrange(-1000, 0) + context.Emax = random.randrange(prec, 1000) + else: + context.Emin, context.Emax = emin, emax + if prec > context.Emax: continue + log(" prec: %d emin: %d emax: %d", + (context.prec, context.Emin, context.Emax)) + restr_range = 9999 if context.Emax > 9999 else context.Emax+99 + for rounding in sorted(RoundMap): + context.rounding = rounding + context.capitals = random.randrange(2) + if spec['clamp'] == 'rand': + context.clamp = random.randrange(2) + else: + context.clamp = spec['clamp'] + exprange = context.c.Emax + testfunc(method, prec, exprange, restr_range, + spec['iter'], stat) + log(" result types: %s" % sorted([t for t in stat.items()])) + +def test_unary(method, prec, exp_range, restricted_range, itr, stat): + """Iterate a unary function through many test cases.""" + if method in UnaryRestricted: + exp_range = restricted_range + for op in all_unary(prec, exp_range, itr): + t = TestSet(method, op) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_binary(method, prec, exp_range, restricted_range, itr, stat): + """Iterate a binary function through many test cases.""" + if method in BinaryRestricted: + exp_range = restricted_range + for op in all_binary(prec, exp_range, itr): + t = TestSet(method, op) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_ternary(method, prec, exp_range, restricted_range, itr, stat): + """Iterate a ternary function through many test cases.""" + if method in TernaryRestricted: + exp_range = restricted_range + for op in all_ternary(prec, exp_range, itr): + t = TestSet(method, op) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_format(method, prec, exp_range, restricted_range, itr, stat): + """Iterate the __format__ method through many test cases.""" + for op in all_unary(prec, exp_range, itr): + fmt1 = rand_format(chr(random.randrange(32, 128)), 'EeGgn') + fmt2 = rand_locale() + for fmt in (fmt1, fmt2): + fmtop = (op[0], fmt) + t = TestSet(method, fmtop) + try: + if not convert(t, convstr=False): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + for op in all_unary(prec, 9999, itr): + fmt1 = rand_format(chr(random.randrange(32, 128)), 'Ff%') + fmt2 = rand_locale() + for fmt in (fmt1, fmt2): + fmtop = (op[0], fmt) + t = TestSet(method, fmtop) + try: + if not convert(t, convstr=False): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_round(method, prec, exprange, restricted_range, itr, stat): + """Iterate the __round__ method through many test cases.""" + for op in all_unary(prec, 9999, itr): + n = random.randrange(10) + roundop = (op[0], n) + t = TestSet(method, roundop) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def test_from_float(method, prec, exprange, restricted_range, itr, stat): + """Iterate the __float__ method through many test cases.""" + for rounding in sorted(RoundMap): + context.rounding = rounding + for i in range(1000): + f = randfloat() + op = (f,) if method.startswith("context.") else ("sNaN", f) + t = TestSet(method, op) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + +def randcontext(exprange): + c = Context(C.Context(), P.Context()) + c.Emax = random.randrange(1, exprange+1) + c.Emin = random.randrange(-exprange, 0) + maxprec = 100 if c.Emax >= 100 else c.Emax + c.prec = random.randrange(1, maxprec+1) + c.clamp = random.randrange(2) + c.clear_traps() + return c + +def test_quantize_api(method, prec, exprange, restricted_range, itr, stat): + """Iterate the 'quantize' method through many test cases, using + the optional arguments.""" + for op in all_binary(prec, restricted_range, itr): + for rounding in RoundModes: + c = randcontext(exprange) + quantizeop = (op[0], op[1], rounding, c) + t = TestSet(method, quantizeop) + try: + if not convert(t): + continue + callfuncs(t) + verify(t, stat) + except VerifyError as err: + log(err) + + +def check_untested(funcdict, c_cls, p_cls): + """Determine untested, C-only and Python-only attributes. + Uncomment print lines for debugging.""" + c_attr = set(dir(c_cls)) + p_attr = set(dir(p_cls)) + intersect = c_attr & p_attr + + funcdict['c_only'] = tuple(sorted(c_attr-intersect)) + funcdict['p_only'] = tuple(sorted(p_attr-intersect)) + + tested = set() + for lst in funcdict.values(): + for v in lst: + v = v.replace("context.", "") if c_cls == C.Context else v + tested.add(v) + + funcdict['untested'] = tuple(sorted(intersect-tested)) + + #for key in ('untested', 'c_only', 'p_only'): + # s = 'Context' if c_cls == C.Context else 'Decimal' + # print("\n%s %s:\n%s" % (s, key, funcdict[key])) + + +if __name__ == '__main__': + + import time + + randseed = int(time.time()) + random.seed(randseed) + + # Set up the testspecs list. A testspec is simply a dictionary + # that determines the amount of different contexts that 'test_method' + # will generate. + base_expts = [(C.MIN_EMIN, C.MAX_EMAX)] + if C.MAX_EMAX == 999999999999999999: + base_expts.append((-999999999, 999999999)) + + # Basic contexts. + base = { + 'expts': base_expts, + 'prec': [], + 'clamp': 'rand', + 'iter': None, + 'samples': None, + } + # Contexts with small values for prec, emin, emax. + small = { + 'prec': [1, 2, 3, 4, 5], + 'expts': [(-1, 1), (-2, 2), (-3, 3), (-4, 4), (-5, 5)], + 'clamp': 'rand', + 'iter': None + } + # IEEE interchange format. + ieee = [ + # DECIMAL32 + {'prec': [7], 'expts': [(-95, 96)], 'clamp': 1, 'iter': None}, + # DECIMAL64 + {'prec': [16], 'expts': [(-383, 384)], 'clamp': 1, 'iter': None}, + # DECIMAL128 + {'prec': [34], 'expts': [(-6143, 6144)], 'clamp': 1, 'iter': None} + ] + + if '--medium' in sys.argv: + base['expts'].append(('rand', 'rand')) + # 5 random precisions + base['samples'] = 5 + testspecs = [small] + ieee + [base] + if '--long' in sys.argv: + base['expts'].append(('rand', 'rand')) + # 10 random precisions + base['samples'] = 10 + testspecs = [small] + ieee + [base] + elif '--all' in sys.argv: + base['expts'].append(('rand', 'rand')) + # All precisions in [1, 100] + base['samples'] = 100 + testspecs = [small] + ieee + [base] + else: # --short + rand_ieee = random.choice(ieee) + base['iter'] = small['iter'] = rand_ieee['iter'] = 1 + # 1 random precision and exponent pair + base['samples'] = 1 + base['expts'] = [random.choice(base_expts)] + # 1 random precision and exponent pair + prec = random.randrange(1, 6) + small['prec'] = [prec] + small['expts'] = [(-prec, prec)] + testspecs = [small, rand_ieee, base] + + check_untested(Functions, C.Decimal, P.Decimal) + check_untested(ContextFunctions, C.Context, P.Context) + + + log("\n\nRandom seed: %d\n\n", randseed) + + # Decimal methods: + for method in Functions['unary'] + Functions['unary_ctx'] + \ + Functions['unary_rnd_ctx']: + test_method(method, testspecs, test_unary) + + for method in Functions['binary'] + Functions['binary_ctx']: + test_method(method, testspecs, test_binary) + + for method in Functions['ternary'] + Functions['ternary_ctx']: + test_method(method, testspecs, test_ternary) + + test_method('__format__', testspecs, test_format) + test_method('__round__', testspecs, test_round) + test_method('from_float', testspecs, test_from_float) + test_method('quantize', testspecs, test_quantize_api) + + # Context methods: + for method in ContextFunctions['unary']: + test_method(method, testspecs, test_unary) + + for method in ContextFunctions['binary']: + test_method(method, testspecs, test_binary) + + for method in ContextFunctions['ternary']: + test_method(method, testspecs, test_ternary) + + test_method('context.create_decimal_from_float', testspecs, test_from_float) + + + sys.exit(EXIT_STATUS) diff --git a/Modules/_decimal/tests/formathelper.py b/Modules/_decimal/tests/formathelper.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/formathelper.py @@ -0,0 +1,344 @@ +# +# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + + +# Generate PEP-3101 format strings. + + +import os, sys, locale, random +import platform, subprocess +from test.support import import_fresh_module +from distutils.spawn import find_executable + +C = import_fresh_module('decimal', fresh=['_decimal']) +P = import_fresh_module('decimal', blocked=['_decimal']) + + +windows_lang_strings = [ + "chinese", "chinese-simplified", "chinese-traditional", "czech", "danish", + "dutch", "belgian", "english", "australian", "canadian", "english-nz", + "english-uk", "english-us", "finnish", "french", "french-belgian", + "french-canadian", "french-swiss", "german", "german-austrian", + "german-swiss", "greek", "hungarian", "icelandic", "italian", "italian-swiss", + "japanese", "korean", "norwegian", "norwegian-bokmal", "norwegian-nynorsk", + "polish", "portuguese", "portuguese-brazil", "russian", "slovak", "spanish", + "spanish-mexican", "spanish-modern", "swedish", "turkish", +] + +preferred_encoding = { + 'cs_CZ': 'ISO8859-2', + 'cs_CZ.iso88592': 'ISO8859-2', + 'czech': 'ISO8859-2', + 'eesti': 'ISO8859-1', + 'estonian': 'ISO8859-1', + 'et_EE': 'ISO8859-15', + 'et_EE.ISO-8859-15': 'ISO8859-15', + 'et_EE.iso885915': 'ISO8859-15', + 'et_EE.iso88591': 'ISO8859-1', + 'fi_FI.iso88591': 'ISO8859-1', + 'fi_FI': 'ISO8859-15', + 'fi_FI at euro': 'ISO8859-15', + 'fi_FI.iso885915 at euro': 'ISO8859-15', + 'finnish': 'ISO8859-1', + 'lv_LV': 'ISO8859-13', + 'lv_LV.iso885913': 'ISO8859-13', + 'nb_NO': 'ISO8859-1', + 'nb_NO.iso88591': 'ISO8859-1', + 'bokmal': 'ISO8859-1', + 'nn_NO': 'ISO8859-1', + 'nn_NO.iso88591': 'ISO8859-1', + 'no_NO': 'ISO8859-1', + 'norwegian': 'ISO8859-1', + 'nynorsk': 'ISO8859-1', + 'ru_RU': 'ISO8859-5', + 'ru_RU.iso88595': 'ISO8859-5', + 'russian': 'ISO8859-5', + 'ru_RU.KOI8-R': 'KOI8-R', + 'ru_RU.koi8r': 'KOI8-R', + 'ru_RU.CP1251': 'CP1251', + 'ru_RU.cp1251': 'CP1251', + 'sk_SK': 'ISO8859-2', + 'sk_SK.iso88592': 'ISO8859-2', + 'slovak': 'ISO8859-2', + 'sv_FI': 'ISO8859-1', + 'sv_FI.iso88591': 'ISO8859-1', + 'sv_FI at euro': 'ISO8859-15', + 'sv_FI.iso885915 at euro': 'ISO8859-15', + 'uk_UA': 'KOI8-U', + 'uk_UA.koi8u': 'KOI8-U' +} + +integers = [ + "", + "1", + "12", + "123", + "1234", + "12345", + "123456", + "1234567", + "12345678", + "123456789", + "1234567890", + "12345678901", + "123456789012", + "1234567890123", + "12345678901234", + "123456789012345", + "1234567890123456", + "12345678901234567", + "123456789012345678", + "1234567890123456789", + "12345678901234567890", + "123456789012345678901", + "1234567890123456789012", +] + +numbers = [ + "0", "-0", "+0", + "0.0", "-0.0", "+0.0", + "0e0", "-0e0", "+0e0", + ".0", "-.0", + ".1", "-.1", + "1.1", "-1.1", + "1e1", "-1e1" +] + +# Get the list of available locales. +if platform.system() == 'Windows': + locale_list = windows_lang_strings +else: + locale_list = ['C'] + if os.path.isfile("/var/lib/locales/supported.d/local"): + # On Ubuntu, `locale -a` gives the wrong case for some locales, + # so we get the correct names directly: + with open("/var/lib/locales/supported.d/local") as f: + locale_list = [loc.split()[0] for loc in f.readlines() \ + if not loc.startswith('#')] + elif find_executable('locale'): + locale_list = subprocess.Popen(["locale", "-a"], + stdout=subprocess.PIPE).communicate()[0] + try: + locale_list = locale_list.decode() + except UnicodeDecodeError: + # Some distributions insist on using latin-1 characters + # in their locale names. + locale_list = locale_list.decode('latin-1') + locale_list = locale_list.split('\n') +try: + locale_list.remove('') +except ValueError: + pass + +# Debian +if os.path.isfile("/etc/locale.alias"): + with open("/etc/locale.alias") as f: + while 1: + try: + line = f.readline() + except UnicodeDecodeError: + continue + if line == "": + break + if line.startswith('#'): + continue + x = line.split() + if len(x) == 2: + if x[0] in locale_list: + locale_list.remove(x[0]) + +# FreeBSD +if platform.system() == 'FreeBSD': + # http://www.freebsd.org/cgi/query-pr.cgi?pr=142173 + # en_GB.US-ASCII has 163 as the currency symbol. + for loc in ['it_CH.ISO8859-1', 'it_CH.ISO8859-15', 'it_CH.UTF-8', + 'it_IT.ISO8859-1', 'it_IT.ISO8859-15', 'it_IT.UTF-8', + 'sl_SI.ISO8859-2', 'sl_SI.UTF-8', + 'en_GB.US-ASCII']: + try: + locale_list.remove(loc) + except ValueError: + pass + +# Print a testcase in the format of the IBM tests (for runtest.c): +def get_preferred_encoding(): + loc = locale.setlocale(locale.LC_CTYPE) + if loc in preferred_encoding: + return preferred_encoding[loc] + else: + return locale.getpreferredencoding() + +def printit(testno, s, fmt, encoding=None): + if not encoding: + encoding = get_preferred_encoding() + try: + result = format(P.Decimal(s), fmt) + fmt = str(fmt.encode(encoding))[2:-1] + result = str(result.encode(encoding))[2:-1] + if "'" in result: + sys.stdout.write("xfmt%d format %s '%s' -> \"%s\"\n" + % (testno, s, fmt, result)) + else: + sys.stdout.write("xfmt%d format %s '%s' -> '%s'\n" + % (testno, s, fmt, result)) + except Exception as err: + sys.stderr.write("%s %s %s\n" % (err, s, fmt)) + + +# Check if an integer can be converted to a valid fill character. +def check_fillchar(i): + try: + c = chr(i) + c.encode('utf-8').decode() + format(P.Decimal(0), c + '<19g') + if c in ("'", '"', '\\'): + return None + return c + except: + return None + +# Generate all unicode characters that are accepted as +# fill characters by decimal.py. +def all_fillchars(): + for i in range(32, 0x110002): + c = check_fillchar(i) + if c: yield c + +# Return random fill character. +def rand_fillchar(): + while 1: + i = random.randrange(32, 0x110002) + c = check_fillchar(i) + if c: return c + +# Generate random format strings +# [[fill]align][sign][#][0][width][.precision][type] +def rand_format(fill, typespec='EeGgFfn%'): + active = sorted(random.sample(range(7), random.randrange(8))) + have_align = 0 + s = '' + for elem in active: + if elem == 0: # fill+align + s += fill + s += random.choice('<>=^') + have_align = 1 + elif elem == 1: # sign + s += random.choice('+- ') + elif elem == 2 and not have_align: # zeropad + s += '0' + elif elem == 3: # width + s += str(random.randrange(1, 100)) + elif elem == 4: # thousands separator + s += ',' + elif elem == 5: # prec + s += '.' + s += str(random.randrange(100)) + elif elem == 6: + if 4 in active: c = typespec.replace('n', '') + else: c = typespec + s += random.choice(c) + return s + +# Partially brute force all possible format strings containing a thousands +# separator. Fall back to random where the runtime would become excessive. +# [[fill]align][sign][#][0][width][,][.precision][type] +def all_format_sep(): + for align in ('', '<', '>', '=', '^'): + for fill in ('', 'x'): + if align == '': fill = '' + for sign in ('', '+', '-', ' '): + for zeropad in ('', '0'): + if align != '': zeropad = '' + for width in ['']+[str(y) for y in range(1, 15)]+['101']: + for prec in ['']+['.'+str(y) for y in range(15)]: + # for type in ('', 'E', 'e', 'G', 'g', 'F', 'f', '%'): + type = random.choice(('', 'E', 'e', 'G', 'g', 'F', 'f', '%')) + yield ''.join((fill, align, sign, zeropad, width, ',', prec, type)) + +# Partially brute force all possible format strings with an 'n' specifier. +# [[fill]align][sign][#][0][width][,][.precision][type] +def all_format_loc(): + for align in ('', '<', '>', '=', '^'): + for fill in ('', 'x'): + if align == '': fill = '' + for sign in ('', '+', '-', ' '): + for zeropad in ('', '0'): + if align != '': zeropad = '' + for width in ['']+[str(y) for y in range(1, 20)]+['101']: + for prec in ['']+['.'+str(y) for y in range(1, 20)]: + yield ''.join((fill, align, sign, zeropad, width, prec, 'n')) + +# Generate random format strings with a unicode fill character +# [[fill]align][sign][#][0][width][,][.precision][type] +def randfill(fill): + active = sorted(random.sample(range(5), random.randrange(6))) + s = '' + s += str(fill) + s += random.choice('<>=^') + for elem in active: + if elem == 0: # sign + s += random.choice('+- ') + elif elem == 1: # width + s += str(random.randrange(1, 100)) + elif elem == 2: # thousands separator + s += ',' + elif elem == 3: # prec + s += '.' + s += str(random.randrange(100)) + elif elem == 4: + if 2 in active: c = 'EeGgFf%' + else: c = 'EeGgFfn%' + s += random.choice(c) + return s + +# Generate random format strings with random locale setting +# [[fill]align][sign][#][0][width][,][.precision][type] +def rand_locale(): + try: + loc = random.choice(locale_list) + locale.setlocale(locale.LC_ALL, loc) + except locale.Error as err: + pass + active = sorted(random.sample(range(5), random.randrange(6))) + s = '' + have_align = 0 + for elem in active: + if elem == 0: # fill+align + s += chr(random.randrange(32, 128)) + s += random.choice('<>=^') + have_align = 1 + elif elem == 1: # sign + s += random.choice('+- ') + elif elem == 2 and not have_align: # zeropad + s += '0' + elif elem == 3: # width + s += str(random.randrange(1, 100)) + elif elem == 4: # prec + s += '.' + s += str(random.randrange(100)) + s += 'n' + return s diff --git a/Modules/_decimal/tests/randdec.py b/Modules/_decimal/tests/randdec.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/randdec.py @@ -0,0 +1,559 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2008-2012 Stefan Krah. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + + +# Generate test cases for deccheck.py. + + +# +# Grammar from http://speleotrove.com/decimal/daconvs.html +# +# sign ::= '+' | '-' +# digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | +# '8' | '9' +# indicator ::= 'e' | 'E' +# digits ::= digit [digit]... +# decimal-part ::= digits '.' [digits] | ['.'] digits +# exponent-part ::= indicator [sign] digits +# infinity ::= 'Infinity' | 'Inf' +# nan ::= 'NaN' [digits] | 'sNaN' [digits] +# numeric-value ::= decimal-part [exponent-part] | infinity +# numeric-string ::= [sign] numeric-value | [sign] nan +# + + +from random import randrange, sample +from fractions import Fraction +from randfloat import un_randfloat, bin_randfloat, tern_randfloat + + +def sign(): + if randrange(2): + if randrange(2): return '+' + return '' + return '-' + +def indicator(): + return "eE"[randrange(2)] + +def digits(maxprec): + if maxprec == 0: return '' + return str(randrange(10**maxprec)) + +def dot(): + if randrange(2): return '.' + return '' + +def decimal_part(maxprec): + if randrange(100) > 60: # integers + return digits(maxprec) + if randrange(2): + intlen = randrange(1, maxprec+1) + fraclen = maxprec-intlen + intpart = digits(intlen) + fracpart = digits(fraclen) + return ''.join((intpart, '.', fracpart)) + else: + return ''.join((dot(), digits(maxprec))) + +def expdigits(maxexp): + return str(randrange(maxexp)) + +def exponent_part(maxexp): + return ''.join((indicator(), sign(), expdigits(maxexp))) + +def infinity(): + if randrange(2): return 'Infinity' + return 'Inf' + +def nan(): + d = '' + if randrange(2): + d = digits(randrange(99)) + if randrange(2): + return ''.join(('NaN', d)) + else: + return ''.join(('sNaN', d)) + +def numeric_value(maxprec, maxexp): + if randrange(100) > 90: + return infinity() + exp_part = '' + if randrange(100) > 60: + exp_part = exponent_part(maxexp) + return ''.join((decimal_part(maxprec), exp_part)) + +def numeric_string(maxprec, maxexp): + if randrange(100) > 95: + return ''.join((sign(), nan())) + else: + return ''.join((sign(), numeric_value(maxprec, maxexp))) + +def randdec(maxprec, maxexp): + return numeric_string(maxprec, maxexp) + +def rand_adjexp(maxprec, maxadjexp): + d = digits(maxprec) + maxexp = maxadjexp-len(d)+1 + if maxexp == 0: maxexp = 1 + exp = str(randrange(maxexp-2*(abs(maxexp)), maxexp)) + return ''.join((sign(), d, 'E', exp)) + + +def ndigits(n): + if n < 1: return 0 + return randrange(10**(n-1), 10**n) + +def randtuple(maxprec, maxexp): + n = randrange(100) + sign = randrange(2) + coeff = ndigits(maxprec) + if n >= 95: + coeff = () + exp = 'F' + elif n >= 85: + coeff = tuple(map(int, str(ndigits(maxprec)))) + exp = "nN"[randrange(2)] + else: + coeff = tuple(map(int, str(ndigits(maxprec)))) + exp = randrange(-maxexp, maxexp) + return (sign, coeff, exp) + +def from_triple(sign, coeff, exp): + return ''.join((str(sign*coeff), indicator(), str(exp))) + + +# Close to 10**n +def un_close_to_pow10(prec, maxexp, itr=None): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + nines = [10**n - 1 for n in lst] + pow10 = [10**n for n in lst] + for coeff in nines: + yield coeff + yield -coeff + yield from_triple(1, coeff, randrange(2*maxexp)) + yield from_triple(-1, coeff, randrange(2*maxexp)) + for coeff in pow10: + yield coeff + yield -coeff + +# Close to 10**n +def bin_close_to_pow10(prec, maxexp, itr=None): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + nines = [10**n - 1 for n in lst] + pow10 = [10**n for n in lst] + for coeff in nines: + yield coeff, 1 + yield -coeff, -1 + yield 1, coeff + yield -1, -coeff + yield from_triple(1, coeff, randrange(2*maxexp)), 1 + yield from_triple(-1, coeff, randrange(2*maxexp)), -1 + yield 1, from_triple(1, coeff, -randrange(2*maxexp)) + yield -1, from_triple(-1, coeff, -randrange(2*maxexp)) + for coeff in pow10: + yield coeff, -1 + yield -coeff, 1 + yield 1, -coeff + yield -coeff, 1 + +# Close to 1: +def close_to_one_greater(prec, emax, emin): + rprec = 10**prec + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)))) + +def close_to_one_less(prec, emax, emin): + rprec = 10**prec + return ''.join(("0.9", '9'*randrange(prec), + str(randrange(rprec)))) + +# Close to 0: +def close_to_zero_greater(prec, emax, emin): + rprec = 10**prec + return ''.join(("0.", '0'*randrange(prec), + str(randrange(rprec)))) + +def close_to_zero_less(prec, emax, emin): + rprec = 10**prec + return ''.join(("-0.", '0'*randrange(prec), + str(randrange(rprec)))) + +# Close to emax: +def close_to_emax_less(prec, emax, emin): + rprec = 10**prec + return ''.join(("9.", '9'*randrange(prec), + str(randrange(rprec)), "E", str(emax))) + +def close_to_emax_greater(prec, emax, emin): + rprec = 10**prec + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)), "E", str(emax+1))) + +# Close to emin: +def close_to_emin_greater(prec, emax, emin): + rprec = 10**prec + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)), "E", str(emin))) + +def close_to_emin_less(prec, emax, emin): + rprec = 10**prec + return ''.join(("9.", '9'*randrange(prec), + str(randrange(rprec)), "E", str(emin-1))) + +# Close to etiny: +def close_to_etiny_greater(prec, emax, emin): + rprec = 10**prec + etiny = emin - (prec - 1) + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)), "E", str(etiny))) + +def close_to_etiny_less(prec, emax, emin): + rprec = 10**prec + etiny = emin - (prec - 1) + return ''.join(("9.", '9'*randrange(prec), + str(randrange(rprec)), "E", str(etiny-1))) + + +def close_to_min_etiny_greater(prec, max_prec, min_emin): + rprec = 10**prec + etiny = min_emin - (max_prec - 1) + return ''.join(("1.", '0'*randrange(prec), + str(randrange(rprec)), "E", str(etiny))) + +def close_to_min_etiny_less(prec, max_prec, min_emin): + rprec = 10**prec + etiny = min_emin - (max_prec - 1) + return ''.join(("9.", '9'*randrange(prec), + str(randrange(rprec)), "E", str(etiny-1))) + + +close_funcs = [ + close_to_one_greater, close_to_one_less, close_to_zero_greater, + close_to_zero_less, close_to_emax_less, close_to_emax_greater, + close_to_emin_greater, close_to_emin_less, close_to_etiny_greater, + close_to_etiny_less, close_to_min_etiny_greater, close_to_min_etiny_less +] + + +def un_close_numbers(prec, emax, emin, itr=None): + if itr is None: + itr = 1000 + for _ in range(itr): + for func in close_funcs: + yield func(prec, emax, emin) + +def bin_close_numbers(prec, emax, emin, itr=None): + if itr is None: + itr = 1000 + for _ in range(itr): + for func1 in close_funcs: + for func2 in close_funcs: + yield func1(prec, emax, emin), func2(prec, emax, emin) + for func in close_funcs: + yield randdec(prec, emax), func(prec, emax, emin) + yield func(prec, emax, emin), randdec(prec, emax) + +def tern_close_numbers(prec, emax, emin, itr): + if itr is None: + itr = 1000 + for _ in range(itr): + for func1 in close_funcs: + for func2 in close_funcs: + for func3 in close_funcs: + yield (func1(prec, emax, emin), func2(prec, emax, emin), + func3(prec, emax, emin)) + for func in close_funcs: + yield (randdec(prec, emax), func(prec, emax, emin), + func(prec, emax, emin)) + yield (func(prec, emax, emin), randdec(prec, emax), + func(prec, emax, emin)) + yield (func(prec, emax, emin), func(prec, emax, emin), + randdec(prec, emax)) + for func in close_funcs: + yield (randdec(prec, emax), randdec(prec, emax), + func(prec, emax, emin)) + yield (randdec(prec, emax), func(prec, emax, emin), + randdec(prec, emax)) + yield (func(prec, emax, emin), randdec(prec, emax), + randdec(prec, emax)) + + +# If itr == None, test all digit lengths up to prec + 30 +def un_incr_digits(prec, maxexp, itr): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + for m in lst: + yield from_triple(1, ndigits(m), 0) + yield from_triple(-1, ndigits(m), 0) + yield from_triple(1, ndigits(m), randrange(maxexp)) + yield from_triple(-1, ndigits(m), randrange(maxexp)) + +# If itr == None, test all digit lengths up to prec + 30 +# Also output decimals im tuple form. +def un_incr_digits_tuple(prec, maxexp, itr): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + for m in lst: + yield from_triple(1, ndigits(m), 0) + yield from_triple(-1, ndigits(m), 0) + yield from_triple(1, ndigits(m), randrange(maxexp)) + yield from_triple(-1, ndigits(m), randrange(maxexp)) + # test from tuple + yield (0, tuple(map(int, str(ndigits(m)))), 0) + yield (1, tuple(map(int, str(ndigits(m)))), 0) + yield (0, tuple(map(int, str(ndigits(m)))), randrange(maxexp)) + yield (1, tuple(map(int, str(ndigits(m)))), randrange(maxexp)) + +# If itr == None, test all combinations of digit lengths up to prec + 30 +def bin_incr_digits(prec, maxexp, itr): + if itr is None: + lst1 = range(prec+30) + lst2 = range(prec+30) + else: + lst1 = sample(range(prec+30), itr) + lst2 = sample(range(prec+30), itr) + for m in lst1: + x = from_triple(1, ndigits(m), 0) + yield x, x + x = from_triple(-1, ndigits(m), 0) + yield x, x + x = from_triple(1, ndigits(m), randrange(maxexp)) + yield x, x + x = from_triple(-1, ndigits(m), randrange(maxexp)) + yield x, x + for m in lst1: + for n in lst2: + x = from_triple(1, ndigits(m), 0) + y = from_triple(1, ndigits(n), 0) + yield x, y + x = from_triple(-1, ndigits(m), 0) + y = from_triple(1, ndigits(n), 0) + yield x, y + x = from_triple(1, ndigits(m), 0) + y = from_triple(-1, ndigits(n), 0) + yield x, y + x = from_triple(-1, ndigits(m), 0) + y = from_triple(-1, ndigits(n), 0) + yield x, y + x = from_triple(1, ndigits(m), randrange(maxexp)) + y = from_triple(1, ndigits(n), randrange(maxexp)) + yield x, y + x = from_triple(-1, ndigits(m), randrange(maxexp)) + y = from_triple(1, ndigits(n), randrange(maxexp)) + yield x, y + x = from_triple(1, ndigits(m), randrange(maxexp)) + y = from_triple(-1, ndigits(n), randrange(maxexp)) + yield x, y + x = from_triple(-1, ndigits(m), randrange(maxexp)) + y = from_triple(-1, ndigits(n), randrange(maxexp)) + yield x, y + + +def randsign(): + return (1, -1)[randrange(2)] + +# If itr == None, test all combinations of digit lengths up to prec + 30 +def tern_incr_digits(prec, maxexp, itr): + if itr is None: + lst1 = range(prec+30) + lst2 = range(prec+30) + lst3 = range(prec+30) + else: + lst1 = sample(range(prec+30), itr) + lst2 = sample(range(prec+30), itr) + lst3 = sample(range(prec+30), itr) + for m in lst1: + for n in lst2: + for p in lst3: + x = from_triple(randsign(), ndigits(m), 0) + y = from_triple(randsign(), ndigits(n), 0) + z = from_triple(randsign(), ndigits(p), 0) + yield x, y, z + + +# Tests for the 'logical' functions +def bindigits(prec): + z = 0 + for i in range(prec): + z += randrange(2) * 10**i + return z + +def logical_un_incr_digits(prec, itr): + if itr is None: + lst = range(prec+30) + else: + lst = sample(range(prec+30), itr) + for m in lst: + yield from_triple(1, bindigits(m), 0) + +def logical_bin_incr_digits(prec, itr): + if itr is None: + lst1 = range(prec+30) + lst2 = range(prec+30) + else: + lst1 = sample(range(prec+30), itr) + lst2 = sample(range(prec+30), itr) + for m in lst1: + x = from_triple(1, bindigits(m), 0) + yield x, x + for m in lst1: + for n in lst2: + x = from_triple(1, bindigits(m), 0) + y = from_triple(1, bindigits(n), 0) + yield x, y + + +def randint(): + p = randrange(1, 100) + return ndigits(p) * (1,-1)[randrange(2)] + +def randfloat(): + p = randrange(1, 100) + s = numeric_value(p, 383) + try: + f = float(numeric_value(p, 383)) + except ValueError: + f = 0.0 + return f + +def randcomplex(): + real = randfloat() + if randrange(100) > 30: + imag = 0.0 + else: + imag = randfloat() + return complex(real, imag) + +def randfraction(): + num = randint() + denom = randint() + if denom == 0: + denom = 1 + return Fraction(num, denom) + +number_funcs = [randint, randfloat, randcomplex, randfraction] + +def un_random_mixed_op(itr=None): + if itr is None: + itr = 1000 + for _ in range(itr): + for func in number_funcs: + yield func() + # Test garbage input + for x in (['x'], ('y',), {'z'}, {1:'z'}): + yield x + +def bin_random_mixed_op(prec, emax, emin, itr=None): + if itr is None: + itr = 1000 + for _ in range(itr): + for func in number_funcs: + yield randdec(prec, emax), func() + yield func(), randdec(prec, emax) + for number in number_funcs: + for dec in close_funcs: + yield dec(prec, emax, emin), number() + # Test garbage input + for x in (['x'], ('y',), {'z'}, {1:'z'}): + for y in (['x'], ('y',), {'z'}, {1:'z'}): + yield x, y + +def tern_random_mixed_op(prec, emax, emin, itr): + if itr is None: + itr = 1000 + for _ in range(itr): + for func in number_funcs: + yield randdec(prec, emax), randdec(prec, emax), func() + yield randdec(prec, emax), func(), func() + yield func(), func(), func() + # Test garbage input + for x in (['x'], ('y',), {'z'}, {1:'z'}): + for y in (['x'], ('y',), {'z'}, {1:'z'}): + for z in (['x'], ('y',), {'z'}, {1:'z'}): + yield x, y, z + +def all_unary(prec, exp_range, itr): + for a in un_close_to_pow10(prec, exp_range, itr): + yield (a,) + for a in un_close_numbers(prec, exp_range, -exp_range, itr): + yield (a,) + for a in un_incr_digits_tuple(prec, exp_range, itr): + yield (a,) + for a in un_randfloat(): + yield (a,) + for a in un_random_mixed_op(itr): + yield (a,) + for a in logical_un_incr_digits(prec, itr): + yield (a,) + for _ in range(100): + yield (randdec(prec, exp_range),) + for _ in range(100): + yield (randtuple(prec, exp_range),) + +def all_binary(prec, exp_range, itr): + for a, b in bin_close_to_pow10(prec, exp_range, itr): + yield a, b + for a, b in bin_close_numbers(prec, exp_range, -exp_range, itr): + yield a, b + for a, b in bin_incr_digits(prec, exp_range, itr): + yield a, b + for a, b in bin_randfloat(): + yield a, b + for a, b in bin_random_mixed_op(prec, exp_range, -exp_range, itr): + yield a, b + for a, b in logical_bin_incr_digits(prec, itr): + yield a, b + for _ in range(100): + yield randdec(prec, exp_range), randdec(prec, exp_range) + +def all_ternary(prec, exp_range, itr): + for a, b, c in tern_close_numbers(prec, exp_range, -exp_range, itr): + yield a, b, c + for a, b, c in tern_incr_digits(prec, exp_range, itr): + yield a, b, c + for a, b, c in tern_randfloat(): + yield a, b, c + for a, b, c in tern_random_mixed_op(prec, exp_range, -exp_range, itr): + yield a, b, c + for _ in range(100): + a = randdec(prec, 2*exp_range) + b = randdec(prec, 2*exp_range) + c = randdec(prec, 2*exp_range) + yield a, b, c diff --git a/Modules/_decimal/tests/randfloat.py b/Modules/_decimal/tests/randfloat.py new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/randfloat.py @@ -0,0 +1,250 @@ +# Copyright (c) 2010 Python Software Foundation. All Rights Reserved. +# Adapted from Python's Lib/test/test_strtod.py (by Mark Dickinson) + +# More test cases for deccheck.py. + +import random + +TEST_SIZE = 2 + + +def test_short_halfway_cases(): + # exact halfway cases with a small number of significant digits + for k in 0, 5, 10, 15, 20: + # upper = smallest integer >= 2**54/5**k + upper = -(-2**54//5**k) + # lower = smallest odd number >= 2**53/5**k + lower = -(-2**53//5**k) + if lower % 2 == 0: + lower += 1 + for i in range(10 * TEST_SIZE): + # Select a random odd n in [2**53/5**k, + # 2**54/5**k). Then n * 10**k gives a halfway case + # with small number of significant digits. + n, e = random.randrange(lower, upper, 2), k + + # Remove any additional powers of 5. + while n % 5 == 0: + n, e = n // 5, e + 1 + assert n % 10 in (1, 3, 7, 9) + + # Try numbers of the form n * 2**p2 * 10**e, p2 >= 0, + # until n * 2**p2 has more than 20 significant digits. + digits, exponent = n, e + while digits < 10**20: + s = '{}e{}'.format(digits, exponent) + yield s + # Same again, but with extra trailing zeros. + s = '{}e{}'.format(digits * 10**40, exponent - 40) + yield s + digits *= 2 + + # Try numbers of the form n * 5**p2 * 10**(e - p5), p5 + # >= 0, with n * 5**p5 < 10**20. + digits, exponent = n, e + while digits < 10**20: + s = '{}e{}'.format(digits, exponent) + yield s + # Same again, but with extra trailing zeros. + s = '{}e{}'.format(digits * 10**40, exponent - 40) + yield s + digits *= 5 + exponent -= 1 + +def test_halfway_cases(): + # test halfway cases for the round-half-to-even rule + for i in range(1000): + for j in range(TEST_SIZE): + # bit pattern for a random finite positive (or +0.0) float + bits = random.randrange(2047*2**52) + + # convert bit pattern to a number of the form m * 2**e + e, m = divmod(bits, 2**52) + if e: + m, e = m + 2**52, e - 1 + e -= 1074 + + # add 0.5 ulps + m, e = 2*m + 1, e - 1 + + # convert to a decimal string + if e >= 0: + digits = m << e + exponent = 0 + else: + # m * 2**e = (m * 5**-e) * 10**e + digits = m * 5**-e + exponent = e + s = '{}e{}'.format(digits, exponent) + yield s + +def test_boundaries(): + # boundaries expressed as triples (n, e, u), where + # n*10**e is an approximation to the boundary value and + # u*10**e is 1ulp + boundaries = [ + (10000000000000000000, -19, 1110), # a power of 2 boundary (1.0) + (17976931348623159077, 289, 1995), # overflow boundary (2.**1024) + (22250738585072013831, -327, 4941), # normal/subnormal (2.**-1022) + (0, -327, 4941), # zero + ] + for n, e, u in boundaries: + for j in range(1000): + for i in range(TEST_SIZE): + digits = n + random.randrange(-3*u, 3*u) + exponent = e + s = '{}e{}'.format(digits, exponent) + yield s + n *= 10 + u *= 10 + e -= 1 + +def test_underflow_boundary(): + # test values close to 2**-1075, the underflow boundary; similar + # to boundary_tests, except that the random error doesn't scale + # with n + for exponent in range(-400, -320): + base = 10**-exponent // 2**1075 + for j in range(TEST_SIZE): + digits = base + random.randrange(-1000, 1000) + s = '{}e{}'.format(digits, exponent) + yield s + +def test_bigcomp(): + for ndigs in 5, 10, 14, 15, 16, 17, 18, 19, 20, 40, 41, 50: + dig10 = 10**ndigs + for i in range(100 * TEST_SIZE): + digits = random.randrange(dig10) + exponent = random.randrange(-400, 400) + s = '{}e{}'.format(digits, exponent) + yield s + +def test_parsing(): + # make '0' more likely to be chosen than other digits + digits = '000000123456789' + signs = ('+', '-', '') + + # put together random short valid strings + # \d*[.\d*]?e + for i in range(1000): + for j in range(TEST_SIZE): + s = random.choice(signs) + intpart_len = random.randrange(5) + s += ''.join(random.choice(digits) for _ in range(intpart_len)) + if random.choice([True, False]): + s += '.' + fracpart_len = random.randrange(5) + s += ''.join(random.choice(digits) + for _ in range(fracpart_len)) + else: + fracpart_len = 0 + if random.choice([True, False]): + s += random.choice(['e', 'E']) + s += random.choice(signs) + exponent_len = random.randrange(1, 4) + s += ''.join(random.choice(digits) + for _ in range(exponent_len)) + + if intpart_len + fracpart_len: + yield s + +test_particular = [ + # squares + '1.00000000100000000025', + '1.0000000000000000000000000100000000000000000000000' #... + '00025', + '1.0000000000000000000000000000000000000000000010000' #... + '0000000000000000000000000000000000000000025', + '1.0000000000000000000000000000000000000000000000000' #... + '000001000000000000000000000000000000000000000000000' #... + '000000000025', + '0.99999999900000000025', + '0.9999999999999999999999999999999999999999999999999' #... + '999000000000000000000000000000000000000000000000000' #... + '000025', + '0.9999999999999999999999999999999999999999999999999' #... + '999999999999999999999999999999999999999999999999999' #... + '999999999999999999999999999999999999999990000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '0000000000000000000000000000025', + + '1.0000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '100000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000001', + '1.0000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '500000000000000000000000000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000005', + '1.0000000000000000000000000000000000000000000000000' #... + '000000000100000000000000000000000000000000000000000' #... + '000000000000000000250000000000000002000000000000000' #... + '000000000000000000000000000000000000000000010000000' #... + '000000000000000000000000000000000000000000000000000' #... + '0000000000000000001', + '1.0000000000000000000000000000000000000000000000000' #... + '000000000100000000000000000000000000000000000000000' #... + '000000000000000000249999999999999999999999999999999' #... + '999999999999979999999999999999999999999999999999999' #... + '999999999999999999999900000000000000000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '00000000000000000000000001', + + '0.9999999999999999999999999999999999999999999999999' #... + '999999999900000000000000000000000000000000000000000' #... + '000000000000000000249999999999999998000000000000000' #... + '000000000000000000000000000000000000000000010000000' #... + '000000000000000000000000000000000000000000000000000' #... + '0000000000000000001', + '0.9999999999999999999999999999999999999999999999999' #... + '999999999900000000000000000000000000000000000000000' #... + '000000000000000000250000001999999999999999999999999' #... + '999999999999999999999999999999999990000000000000000' #... + '000000000000000000000000000000000000000000000000000' #... + '1', + + # tough cases for ln etc. + '1.000000000000000000000000000000000000000000000000' #... + '00000000000000000000000000000000000000000000000000' #... + '00100000000000000000000000000000000000000000000000' #... + '00000000000000000000000000000000000000000000000000' #... + '0001', + '0.999999999999999999999999999999999999999999999999' #... + '99999999999999999999999999999999999999999999999999' #... + '99899999999999999999999999999999999999999999999999' #... + '99999999999999999999999999999999999999999999999999' #... + '99999999999999999999999999999999999999999999999999' #... + '9999' + ] + + +TESTCASES = [ + [x for x in test_short_halfway_cases()], + [x for x in test_halfway_cases()], + [x for x in test_boundaries()], + [x for x in test_underflow_boundary()], + [x for x in test_bigcomp()], + [x for x in test_parsing()], + test_particular +] + +def un_randfloat(): + for i in range(1000): + l = random.choice(TESTCASES[:6]) + yield random.choice(l) + for v in test_particular: + yield v + +def bin_randfloat(): + for i in range(1000): + l1 = random.choice(TESTCASES) + l2 = random.choice(TESTCASES) + yield random.choice(l1), random.choice(l2) + +def tern_randfloat(): + for i in range(1000): + l1 = random.choice(TESTCASES) + l2 = random.choice(TESTCASES) + l3 = random.choice(TESTCASES) + yield random.choice(l1), random.choice(l2), random.choice(l3) diff --git a/Modules/_decimal/tests/runall-memorydebugger.sh b/Modules/_decimal/tests/runall-memorydebugger.sh new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/runall-memorydebugger.sh @@ -0,0 +1,175 @@ +#!/bin/sh + +# +# Purpose: test with and without threads, all machine configurations, pydebug, +# refleaks, release build and release build with valgrind. +# +# Synopsis: ./runall-memorydebugger.sh [--all-configs64 | --all-configs32] +# +# Requirements: valgrind +# + +# Set additional CFLAGS for ./configure +ADD_CFLAGS= + + +CONFIGS_64="x64 uint128 ansi64 universal" +CONFIGS_32="ppro ansi32 ansi-legacy universal" + +VALGRIND="valgrind --tool=memcheck --leak-resolution=high \ + --db-attach=yes --suppressions=Misc/valgrind-python.supp" + +# Get args +case $@ in + *--all-configs64*) + CONFIGS=$CONFIGS_64 + ;; + *--all-configs32*) + CONFIGS=$CONFIGS_32 + ;; + *) + CONFIGS="auto" + ;; +esac + +# gmake required +GMAKE=`which gmake` +if [ X"$GMAKE" = X"" ]; then + GMAKE=make +fi + +# Pretty print configurations +print_config () +{ + len=`echo $@ | wc -c` + margin="#%"`expr \( 74 - $len \) / 2`"s" + + echo "" + echo "# ========================================================================" + printf $margin "" + echo $@ + echo "# ========================================================================" + echo "" +} + + +cd .. + +# test_decimal: refleak, regular and Valgrind tests +for args in "--without-threads" ""; do + for config in $CONFIGS; do + + unset PYTHON_DECIMAL_WITH_MACHINE + libmpdec_config=$config + if [ X"$config" != X"auto" ]; then + PYTHON_DECIMAL_WITH_MACHINE=$config + export PYTHON_DECIMAL_WITH_MACHINE + else + libmpdec_config="" + fi + + ############ refleak tests ########### + print_config "refleak tests: config=$config" $args + printf "\nbuilding python ...\n\n" + + cd ../../ + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== refleak tests ===========================\n\n" + ./python -m test -uall -R 2:2 test_decimal + + + ############ regular tests ########### + print_config "regular tests: config=$config" $args + printf "\nbuilding python ...\n\n" + + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== regular tests ===========================\n\n" + ./python -m test -uall test_decimal + + + ########### valgrind tests ########### + valgrind=$VALGRIND + case "$config" in + # Valgrind has no support for 80 bit long double arithmetic. + ppro) valgrind= ;; + auto) case `uname -m` in + i386|i486|i586|i686) valgrind= ;; + esac + esac + + print_config "valgrind tests: config=$config" $args + printf "\nbuilding python ...\n\n" + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== valgrind tests ===========================\n\n" + $valgrind ./python -m test -uall test_decimal + + cd Modules/_decimal + done +done + +# deccheck +cd ../../ +for config in $CONFIGS; do + for args in "--without-threads" ""; do + + unset PYTHON_DECIMAL_WITH_MACHINE + if [ X"$config" != X"auto" ]; then + PYTHON_DECIMAL_WITH_MACHINE=$config + export PYTHON_DECIMAL_WITH_MACHINE + fi + + ############ debug ############ + print_config "deccheck: config=$config --with-pydebug" $args + printf "\nbuilding python ...\n\n" + + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ========================== debug ===========================\n\n" + ./python Modules/_decimal/tests/deccheck.py + + ########### regular ########### + print_config "deccheck: config=$config " $args + printf "\nbuilding python ...\n\n" + + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== regular ===========================\n\n" + ./python Modules/_decimal/tests/deccheck.py + + ########### valgrind ########### + valgrind=$VALGRIND + case "$config" in + # Valgrind has no support for 80 bit long double arithmetic. + ppro) valgrind= ;; + auto) case `uname -m` in + i386|i486|i586|i686) valgrind= ;; + esac + esac + + print_config "valgrind deccheck: config=$config " $args + printf "\nbuilding python ...\n\n" + + $GMAKE distclean > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1 + $GMAKE | grep _decimal + + printf "\n\n# ======================== valgrind ==========================\n\n" + $valgrind ./python Modules/_decimal/tests/deccheck.py + done +done + + + diff --git a/Modules/_decimal/tests/runall.bat b/Modules/_decimal/tests/runall.bat new file mode 100644 --- /dev/null +++ b/Modules/_decimal/tests/runall.bat @@ -0,0 +1,121 @@ + at ECHO OFF + +rem Test all machine configurations, pydebug, refleaks, release build. + +cd .. + +call vcvarsall x64 +echo. +echo # ====================================================================== +echo # test_decimal: platform=x64 +echo # ====================================================================== +echo. + +cd ..\..\PCbuild +echo # ==================== refleak tests ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Debug|x64" > NUL 2>&1 +amd64\python_d.exe -m test -uall -R 2:2 test_decimal +echo. + +echo # ==================== regular tests ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Release|x64" > NUL 2>&1 +amd64\python.exe -m test -uall test_decimal +echo. +echo. + + +call vcvarsall x86 +echo. +echo # ====================================================================== +echo # test_decimal: platform=x86 +echo # ====================================================================== +echo. + +echo # ==================== refleak tests ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Debug|win32" > NUL 2>&1 +python_d.exe -m test -uall -R 2:2 test_decimal +echo. + +echo # ==================== regular tests ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Release|win32" > NUL 2>&1 +python.exe -m test -uall test_decimal +echo. +echo. + + +call vcvarsall x64 +echo. +echo # ====================================================================== +echo # deccheck: platform=x64 +echo # ====================================================================== +echo. +echo. +echo # ==================== debug build ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Debug|x64" > NUL 2>&1 +amd64\python_d.exe ..\Modules\_decimal\tests\deccheck.py +echo. +echo. + +echo # =================== release build ====================== +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Release|x64" > NUL 2>&1 +amd64\python.exe ..\Modules\_decimal\tests\deccheck.py +echo. +echo. + + +call vcvarsall x86 +echo. +echo # ====================================================================== +echo # deccheck: platform=x86 +echo # ====================================================================== +echo. +echo. +echo # ==================== debug build ======================= +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Debug|win32" > NUL 2>&1 +python_d.exe ..\Modules\_decimal\tests\deccheck.py +echo. +echo. + +echo # =================== release build ====================== +echo. +echo building python ... +echo. +vcbuild /clean pcbuild.sln > NUL 2>&1 +vcbuild pcbuild.sln "Release|win32" > NUL 2>&1 +python.exe ..\Modules\_decimal\tests\deccheck.py +echo. +echo. + + +cd ..\Modules\_decimal\tests + + + diff --git a/PCbuild/_decimal.vcproj b/PCbuild/_decimal.vcproj new file mode 100644 --- /dev/null +++ b/PCbuild/_decimal.vcproj @@ -0,0 +1,743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -38,6 +38,11 @@ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_decimal", "_decimal.vcproj", "{0E9791DB-593A-465F-98BC-681011311617}" + ProjectSection(ProjectDependencies) = postProject + {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_ctypes", "_ctypes.vcproj", "{0E9791DB-593A-465F-98BC-681011311618}" ProjectSection(ProjectDependencies) = postProject {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} @@ -271,6 +276,22 @@ {28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|Win32.Build.0 = Release|Win32 {28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.ActiveCfg = Release|x64 {28B5D777-DDF2-4B6B-B34F-31D938813856}.Release|x64.Build.0 = Release|x64 + {0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.ActiveCfg = Debug|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.Build.0 = Debug|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.ActiveCfg = Debug|x64 + {0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.Build.0 = Debug|x64 + {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.Build.0 = PGInstrument|x64 + {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {0E9791DB-593A-465F-98BC-681011311617}.PGUpdate|x64.Build.0 = PGUpdate|x64 + {0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.ActiveCfg = Release|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.Release|Win32.Build.0 = Release|Win32 + {0E9791DB-593A-465F-98BC-681011311617}.Release|x64.ActiveCfg = Release|x64 + {0E9791DB-593A-465F-98BC-681011311617}.Release|x64.Build.0 = Release|x64 {0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.ActiveCfg = Debug|Win32 {0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.Build.0 = Debug|Win32 {0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/PCbuild/pythoncore.vcproj b/PCbuild/pythoncore.vcproj --- a/PCbuild/pythoncore.vcproj +++ b/PCbuild/pythoncore.vcproj @@ -735,10 +735,6 @@ > - - diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6863,6 +6863,13 @@ fi +ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "$ac_includes_default" +if test "x$ac_cv_type___uint128_t" = xyes; then : + +$as_echo "#define HAVE_GCC_UINT128_T 1" >>confdefs.h + +fi + # Sizes of various common basic types # ANSI C requires sizeof(char) == 1, so no need to check it @@ -12034,6 +12041,40 @@ fi +# ************************************** +# * Check for gcc x64 inline assembler * +# ************************************** + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x64 gcc inline assembler" >&5 +$as_echo_n "checking for x64 gcc inline assembler... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + __asm__ __volatile__ ("movq %rcx, %rax"); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_gcc_asm_for_x64=yes +else + have_gcc_asm_for_x64=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_asm_for_x64" >&5 +$as_echo "$have_gcc_asm_for_x64" >&6; } +if test "$have_gcc_asm_for_x64" = yes +then + +$as_echo "#define HAVE_GCC_ASM_FOR_X64 1" >>confdefs.h + +fi + # ************************************************** # * Check for various properties of floating point * # ************************************************** @@ -14228,6 +14269,136 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } +# Availability of -O2: +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -O2" >&5 +$as_echo_n "checking for -O2... " >&6; } +saved_cflags="$CFLAGS" +CFLAGS="-O2" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_O2=yes +else + have_O2=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_O2" >&5 +$as_echo "$have_O2" >&6; } +CFLAGS="$saved_cflags" + +# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: +# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc _FORTIFY_SOURCE/memmove bug" >&5 +$as_echo_n "checking for glibc _FORTIFY_SOURCE/memmove bug... " >&6; } +saved_cflags="$CFLAGS" +CFLAGS="-O2 -D_FORTIFY_SOURCE=2" +if test "$have_O2" = no; then + CFLAGS="" +fi +if test "$cross_compiling" = yes; then : + have_glibc_memmove_bug=undefined +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +void foo(void *p, void *q) { memmove(p, q, 19); } +int main() { + char a[32] = "123456789000000000"; + foo(&a[9], a); + if (strcmp(a, "123456789123456789000000000") != 0) + return 1; + foo(a, &a[9]); + if (strcmp(a, "123456789000000000") != 0) + return 1; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + have_glibc_memmove_bug=no +else + have_glibc_memmove_bug=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +CFLAGS="$saved_cflags" +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_glibc_memmove_bug" >&5 +$as_echo "$have_glibc_memmove_bug" >&6; } +if test "$have_glibc_memmove_bug" = yes; then + +$as_echo "#define HAVE_GLIBC_MEMMOVE_BUG 1" >>confdefs.h + +fi + +if test "$have_gcc_asm_for_x87" = yes; then + # Some versions of gcc miscompile inline asm: + # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 + # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html + case $CC in + *gcc*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc ipa-pure-const bug" >&5 +$as_echo_n "checking for gcc ipa-pure-const bug... " >&6; } + saved_cflags="$CFLAGS" + CFLAGS="-O2" + if test "$cross_compiling" = yes; then : + have_ipa_pure_const_bug=undefined +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + __attribute__((noinline)) int + foo(int *p) { + int r; + asm ( "movl \$6, (%1)\n\t" + "xorl %0, %0\n\t" + : "=r" (r) : "r" (p) : "memory" + ); + return r; + } + int main() { + int p = 8; + if ((foo(&p) ? : p) != 6) + return 1; + return 0; + } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + have_ipa_pure_const_bug=no +else + have_ipa_pure_const_bug=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$saved_cflags" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ipa_pure_const_bug" >&5 +$as_echo "$have_ipa_pure_const_bug" >&6; } + if test "$have_ipa_pure_const_bug" = yes; then + +$as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h + + fi + ;; + esac +fi + # generate output files ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc" diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1483,6 +1483,8 @@ AC_TYPE_INT64_T AC_CHECK_TYPE(ssize_t, AC_DEFINE(HAVE_SSIZE_T, 1, [Define if your compiler provides ssize_t]),,) +AC_CHECK_TYPE(__uint128_t, + AC_DEFINE(HAVE_GCC_UINT128_T, 1, [Define if your compiler provides __uint128_t]),,) # Sizes of various common basic types # ANSI C requires sizeof(char) == 1, so no need to check it @@ -3329,6 +3331,21 @@ fi], [AC_MSG_RESULT(default LIBC="$LIBC")]) +# ************************************** +# * Check for gcc x64 inline assembler * +# ************************************** + +AC_MSG_CHECKING(for x64 gcc inline assembler) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ + __asm__ __volatile__ ("movq %rcx, %rax"); +]])],[have_gcc_asm_for_x64=yes],[have_gcc_asm_for_x64=no]) +AC_MSG_RESULT($have_gcc_asm_for_x64) +if test "$have_gcc_asm_for_x64" = yes +then + AC_DEFINE(HAVE_GCC_ASM_FOR_X64, 1, + [Define if we can use x64 gcc inline assembler]) +fi + # ************************************************** # * Check for various properties of floating point * # ************************************************** @@ -4333,6 +4350,89 @@ done AC_MSG_RESULT(done) +# Availability of -O2: +AC_MSG_CHECKING(for -O2) +saved_cflags="$CFLAGS" +CFLAGS="-O2" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ +]])],[have_O2=yes],[have_O2=no]) +AC_MSG_RESULT($have_O2) +CFLAGS="$saved_cflags" + +# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: +# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html +AC_MSG_CHECKING(for glibc _FORTIFY_SOURCE/memmove bug) +saved_cflags="$CFLAGS" +CFLAGS="-O2 -D_FORTIFY_SOURCE=2" +if test "$have_O2" = no; then + CFLAGS="" +fi +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#include +#include +void foo(void *p, void *q) { memmove(p, q, 19); } +int main() { + char a[32] = "123456789000000000"; + foo(&a[9], a); + if (strcmp(a, "123456789123456789000000000") != 0) + return 1; + foo(a, &a[9]); + if (strcmp(a, "123456789000000000") != 0) + return 1; + return 0; +} +]])], +[have_glibc_memmove_bug=no], +[have_glibc_memmove_bug=yes], +[have_glibc_memmove_bug=undefined]) +CFLAGS="$saved_cflags" +AC_MSG_RESULT($have_glibc_memmove_bug) +if test "$have_glibc_memmove_bug" = yes; then + AC_DEFINE(HAVE_GLIBC_MEMMOVE_BUG, 1, + [Define if glibc has incorrect _FORTIFY_SOURCE wrappers + for memmove and bcopy.]) +fi + +if test "$have_gcc_asm_for_x87" = yes; then + # Some versions of gcc miscompile inline asm: + # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 + # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html + case $CC in + *gcc*) + AC_MSG_CHECKING(for gcc ipa-pure-const bug) + saved_cflags="$CFLAGS" + CFLAGS="-O2" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + __attribute__((noinline)) int + foo(int *p) { + int r; + asm ( "movl \$6, (%1)\n\t" + "xorl %0, %0\n\t" + : "=r" (r) : "r" (p) : "memory" + ); + return r; + } + int main() { + int p = 8; + if ((foo(&p) ? : p) != 6) + return 1; + return 0; + } + ]])], + [have_ipa_pure_const_bug=no], + [have_ipa_pure_const_bug=yes], + [have_ipa_pure_const_bug=undefined]) + CFLAGS="$saved_cflags" + AC_MSG_RESULT($have_ipa_pure_const_bug) + if test "$have_ipa_pure_const_bug" = yes; then + AC_DEFINE(HAVE_IPA_PURE_CONST_BUG, 1, + [Define if gcc has the ipa-pure-const bug.]) + fi + ;; + esac +fi + # generate output files AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc) AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix]) diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -304,10 +304,16 @@ /* Define to 1 if you have the `gamma' function. */ #undef HAVE_GAMMA +/* Define if we can use x64 gcc inline assembler */ +#undef HAVE_GCC_ASM_FOR_X64 + /* Define if we can use gcc inline assembler to get and set x87 control word */ #undef HAVE_GCC_ASM_FOR_X87 +/* Define if your compiler provides __uint128_t */ +#undef HAVE_GCC_UINT128_T + /* Define if you have the getaddrinfo function. */ #undef HAVE_GETADDRINFO @@ -392,6 +398,10 @@ /* Define to 1 if you have the `getwd' function. */ #undef HAVE_GETWD +/* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and + bcopy. */ +#undef HAVE_GLIBC_MEMMOVE_BUG + /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H @@ -422,6 +432,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_IO_H +/* Define if gcc has the ipa-pure-const bug. */ +#undef HAVE_IPA_PURE_CONST_BUG + /* Define to 1 if you have the `kill' function. */ #undef HAVE_KILL diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -1342,6 +1342,9 @@ exts.append(Extension('_codecs_%s' % loc, ['cjkcodecs/_codecs_%s.c' % loc])) + # Stefan Krah's _decimal module + exts.append(self._decimal_ext()) + # Thomas Heller's _ctypes module self.detect_ctypes(inc_dirs, lib_dirs) @@ -1792,6 +1795,116 @@ ext.libraries.append(ffi_lib) self.use_system_libffi = True + def _decimal_ext(self): + sources = [ + '_decimal/_decimal.c', + '_decimal/libmpdec/basearith.c', + '_decimal/libmpdec/constants.c', + '_decimal/libmpdec/context.c', + '_decimal/libmpdec/convolute.c', + '_decimal/libmpdec/crt.c', + '_decimal/libmpdec/difradix2.c', + '_decimal/libmpdec/fnt.c', + '_decimal/libmpdec/fourstep.c', + '_decimal/libmpdec/io.c', + '_decimal/libmpdec/memory.c', + '_decimal/libmpdec/mpdecimal.c', + '_decimal/libmpdec/numbertheory.c', + '_decimal/libmpdec/sixstep.c', + '_decimal/libmpdec/transpose.c', + ] + depends = [ + '_decimal/docstrings.h', + '_decimal/libmpdec/basearith.h', + '_decimal/libmpdec/bits.h', + '_decimal/libmpdec/constants.h', + '_decimal/libmpdec/convolute.h', + '_decimal/libmpdec/crt.h', + '_decimal/libmpdec/difradix2.h', + '_decimal/libmpdec/fnt.h', + '_decimal/libmpdec/fourstep.h', + '_decimal/libmpdec/io.h', + '_decimal/libmpdec/memory.h', + '_decimal/libmpdec/mpdecimal.h', + '_decimal/libmpdec/numbertheory.h', + '_decimal/libmpdec/sixstep.h', + '_decimal/libmpdec/transpose.h', + '_decimal/libmpdec/typearith.h', + '_decimal/libmpdec/umodarith.h', + ] + config = { + 'x64': [('CONFIG_64','1'), ('ASM','1')], + 'uint128': [('CONFIG_64','1'), ('ANSI','1'), ('HAVE_UINT128_T','1')], + 'ansi64': [('CONFIG_64','1'), ('ANSI','1')], + 'ppro': [('CONFIG_32','1'), ('PPRO','1'), ('ASM','1')], + 'ansi32': [('CONFIG_32','1'), ('ANSI','1')], + 'ansi-legacy': [('CONFIG_32','1'), ('ANSI','1'), + ('LEGACY_COMPILER','1')], + 'universal': [('UNIVERSAL','1')] + } + + include_dirs = ['./Modules/_decimal/libmpdec'] + extra_compile_args = [] + undef_macros=['NDEBUG'] + + platform = self.get_platform() + cc = sysconfig.get_config_var('CC') + sizeof_size_t = sysconfig.get_config_var('SIZEOF_SIZE_T') + machine = os.environ.get('PYTHON_DECIMAL_WITH_MACHINE') + + if machine: + # Override automatic configuration to facilitate testing. + define_macros = config[machine] + elif platform == 'darwin': + # Universal here means: build with the same options Python + # was built with. + define_macros = config['universal'] + elif sizeof_size_t == 8: + if sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X64'): + define_macros = config['x64'] + elif sysconfig.get_config_var('HAVE_GCC_UINT128_T'): + define_macros = config['uint128'] + else: + define_macros = config['ansi64'] + elif sizeof_size_t == 4: + ppro = sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X87') + if ppro and ('gcc' in cc or 'clang' in cc) and \ + not 'sunos' in platform: + # solaris: problems with register allocation. + # icc >= 11.0 works as well. + define_macros = config['ppro'] + else: + define_macros = config['ansi32'] + else: + raise DistutilsError("_decimal: unsupported architecture") + + # Workarounds for toolchain bugs: + if sysconfig.get_config_var('HAVE_IPA_PURE_CONST_BUG'): + # Some versions of gcc miscompile inline asm: + # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 + # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html + extra_compile_args.append('-fno-ipa-pure-const') + if sysconfig.get_config_var('HAVE_GLIBC_MEMMOVE_BUG'): + # _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: + # http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html + undef_macros.append('_FORTIFY_SOURCE') + + # Faster version without thread local contexts: + if not sysconfig.get_config_var('WITH_THREAD'): + define_macros.append(('WITHOUT_THREADS', 1)) + + # Uncomment for extra functionality: + #define_macros.append(('EXTRA_FUNCTIONALITY', 1)) + ext = Extension ( + '_decimal', + include_dirs=include_dirs, + define_macros=define_macros, + undef_macros=undef_macros, + extra_compile_args=extra_compile_args, + sources=sources, + depends=depends + ) + return ext class PyBuildInstall(install): # Suppress the warning about installation into the lib_dynload -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 19:51:49 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 21 Mar 2012 19:51:49 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_rewrite_this_function=2C_wh?= =?utf8?q?ich_was_still_accounting_for_classic_classes?= Message-ID: http://hg.python.org/cpython/rev/006e4a3a4b29 changeset: 75856:006e4a3a4b29 user: Benjamin Peterson date: Wed Mar 21 14:38:11 2012 -0400 summary: rewrite this function, which was still accounting for classic classes files: Objects/abstract.c | 36 +++++++++++---------------------- 1 files changed, 12 insertions(+), 24 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1271,34 +1271,22 @@ PyObject * _PyNumber_ConvertIntegralToInt(PyObject *integral, const char* error_format) { - static PyObject *int_name = NULL; - if (int_name == NULL) { - int_name = PyUnicode_InternFromString("__int__"); - if (int_name == NULL) + PyNumberMethods *nb; + if (PyLong_Check(integral)) + return integral; + nb = Py_TYPE(integral)->tp_as_number; + if (nb->nb_int) { + PyObject *as_int = nb->nb_int(integral); + Py_DECREF(integral); + if (!as_int) return NULL; + if (PyLong_Check(as_int)) + return as_int; + Py_DECREF(as_int); } - - if (integral && !PyLong_Check(integral)) { - /* Don't go through tp_as_number->nb_int to avoid - hitting the classic class fallback to __trunc__. */ - PyObject *int_func = PyObject_GetAttr(integral, int_name); - if (int_func == NULL) { - PyErr_Clear(); /* Raise a different error. */ - goto non_integral_error; - } - Py_DECREF(integral); - integral = PyEval_CallObject(int_func, NULL); - Py_DECREF(int_func); - if (integral && !PyLong_Check(integral)) { - goto non_integral_error; - } - } - return integral; - -non_integral_error: PyErr_Format(PyExc_TypeError, error_format, Py_TYPE(integral)->tp_name); Py_DECREF(integral); - return NULL; + return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 19:51:51 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 21 Mar 2012 19:51:51 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_make_=5FPyNumber=5FConvertI?= =?utf8?q?ntegralToInt_static=2C_since_it=27s_only_used_in_abstract=2Ec?= Message-ID: http://hg.python.org/cpython/rev/1e89e2c86df0 changeset: 75857:1e89e2c86df0 user: Benjamin Peterson date: Wed Mar 21 14:44:43 2012 -0400 summary: make _PyNumber_ConvertIntegralToInt static, since it's only used in abstract.c files: Include/abstract.h | 15 --------------- Objects/abstract.c | 14 ++++++++++---- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/Include/abstract.h b/Include/abstract.h --- a/Include/abstract.h +++ b/Include/abstract.h @@ -773,21 +773,6 @@ PyAPI_FUNC(Py_ssize_t) PyNumber_AsSsize_t(PyObject *o, PyObject *exc); /* - Returns the Integral instance converted to an int. The - instance is expected to be int or long or have an __int__ - method. Steals integral's reference. error_format will be - used to create the TypeError if integral isn't actually an - Integral instance. error_format should be a format string - that can accept a char* naming integral's type. - */ - -#ifndef Py_LIMITED_API - PyAPI_FUNC(PyObject *) _PyNumber_ConvertIntegralToInt( - PyObject *integral, - const char* error_format); -#endif - - /* Returns the object converted to Py_ssize_t by going through PyNumber_Index first. If an overflow error occurs while converting the int-or-long to Py_ssize_t, then the second argument diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1268,8 +1268,15 @@ } -PyObject * -_PyNumber_ConvertIntegralToInt(PyObject *integral, const char* error_format) +/* + Returns the Integral instance converted to an int. The instance is expected + to be an int or have an __int__ method. Steals integral's + reference. error_format will be used to create the TypeError if integral + isn't actually an Integral instance. error_format should be a format string + that can accept a char* naming integral's type. +*/ +static PyObject * +convert_integral_to_int(PyObject *integral, const char *error_format) { PyNumberMethods *nb; if (PyLong_Check(integral)) @@ -1345,8 +1352,7 @@ Py_DECREF(trunc_func); /* __trunc__ is specified to return an Integral type, but long() needs to return a long. */ - int_instance = _PyNumber_ConvertIntegralToInt( - truncated, + int_instance = convert_integral_to_int(truncated, "__trunc__ returned non-Integral (type %.200s)"); return int_instance; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 19:52:01 2012 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 21 Mar 2012 19:52:01 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbjogbG9uZygpIC0+IGludCgp?= Message-ID: http://hg.python.org/cpython/rev/bd4243dc0741 changeset: 75858:bd4243dc0741 user: Benjamin Peterson date: Wed Mar 21 14:51:14 2012 -0400 summary: long() -> int() files: Objects/abstract.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1351,7 +1351,7 @@ PyObject *int_instance; Py_DECREF(trunc_func); /* __trunc__ is specified to return an Integral type, - but long() needs to return a long. */ + but int() needs to return a int. */ int_instance = convert_integral_to_int(truncated, "__trunc__ returned non-Integral (type %.200s)"); return int_instance; @@ -1361,7 +1361,7 @@ if (PyBytes_Check(o)) /* need to do extra error checking that PyLong_FromString() - * doesn't do. In particular long('9.5') must raise an + * doesn't do. In particular int('9.5') must raise an * exception, not truncate the float. */ return long_from_string(PyBytes_AS_STRING(o), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 20:02:42 2012 From: python-checkins at python.org (r.david.murray) Date: Wed, 21 Mar 2012 20:02:42 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzEyNzU3OiBNYWtl?= =?utf8?q?_doctest_skipping_in_-OO_mode_work_with_unittest/regrtest_-v?= Message-ID: http://hg.python.org/cpython/rev/64f1b8ad9214 changeset: 75859:64f1b8ad9214 branch: 3.2 parent: 75846:a95b19b3b4cd user: R David Murray date: Wed Mar 21 14:53:42 2012 -0400 summary: #12757: Make doctest skipping in -OO mode work with unittest/regrtest -v files: Lib/doctest.py | 10 +++++++--- Misc/NEWS | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/doctest.py b/Lib/doctest.py --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -2266,7 +2266,8 @@ return "Doctest: " + self._dt_test.name class SkipDocTestCase(DocTestCase): - def __init__(self): + def __init__(self, module): + self.module = module DocTestCase.__init__(self, None) def setUp(self): @@ -2276,7 +2277,10 @@ pass def shortDescription(self): - return "Skipping tests from %s" % module.__name__ + return "Skipping tests from %s" % self.module.__name__ + + __str__ = shortDescription + def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, **options): @@ -2324,7 +2328,7 @@ if not tests and sys.flags.optimize >=2: # Skip doctests when running with -O2 suite = unittest.TestSuite() - suite.addTest(SkipDocTestCase()) + suite.addTest(SkipDocTestCase(module)) return suite elif not tests: # Why do we want to do this? Because it reveals a bug that might diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,9 @@ Library ------- +- Issue #12757: Fix the skipping of doctests when python is run with -OO so + that it works in unittest's verbose mode as well as non-verbose mode. + - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)) (Patch by Guilherme Polo) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 20:02:43 2012 From: python-checkins at python.org (r.david.murray) Date: Wed, 21 Mar 2012 20:02:43 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2312757=3A_Make_doctest_skipping_in_-OO_mode_work_wit?= =?utf8?q?h_unittest/regrtest_-v?= Message-ID: http://hg.python.org/cpython/rev/ff7957aa01a1 changeset: 75860:ff7957aa01a1 parent: 75858:bd4243dc0741 parent: 75859:64f1b8ad9214 user: R David Murray date: Wed Mar 21 14:55:04 2012 -0400 summary: Merge #12757: Make doctest skipping in -OO mode work with unittest/regrtest -v files: Lib/doctest.py | 10 +++++++--- Misc/NEWS | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/doctest.py b/Lib/doctest.py --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -2267,7 +2267,8 @@ return "Doctest: " + self._dt_test.name class SkipDocTestCase(DocTestCase): - def __init__(self): + def __init__(self, module): + self.module = module DocTestCase.__init__(self, None) def setUp(self): @@ -2277,7 +2278,10 @@ pass def shortDescription(self): - return "Skipping tests from %s" % module.__name__ + return "Skipping tests from %s" % self.module.__name__ + + __str__ = shortDescription + def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, **options): @@ -2325,7 +2329,7 @@ if not tests and sys.flags.optimize >=2: # Skip doctests when running with -O2 suite = unittest.TestSuite() - suite.addTest(SkipDocTestCase()) + suite.addTest(SkipDocTestCase(module)) return suite elif not tests: # Why do we want to do this? Because it reveals a bug that might diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,9 @@ Library ------- +- Issue #12757: Fix the skipping of doctests when python is run with -OO so + that it works in unittest's verbose mode as well as non-verbose mode. + - Issue #7652: Integrate the decimal floating point libmpdec library to speed up the decimal module. Performance gains of the new C implementation are between 12x and 80x, depending on the application. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 20:02:44 2012 From: python-checkins at python.org (r.david.murray) Date: Wed, 21 Mar 2012 20:02:44 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzEyNzU3OiBNYWtl?= =?utf8?q?_doctest_skipping_in_-OO_mode_work_with_unittest/regrtest_-v?= Message-ID: http://hg.python.org/cpython/rev/c50db3d06116 changeset: 75861:c50db3d06116 branch: 2.7 parent: 75848:a9be863e5734 user: R David Murray date: Wed Mar 21 15:02:30 2012 -0400 summary: #12757: Make doctest skipping in -OO mode work with unittest/regrtest -v files: Lib/doctest.py | 10 +++++++--- Misc/NEWS | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/doctest.py b/Lib/doctest.py --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -2314,7 +2314,8 @@ return "Doctest: " + self._dt_test.name class SkipDocTestCase(DocTestCase): - def __init__(self): + def __init__(self, module): + self.module = module DocTestCase.__init__(self, None) def setUp(self): @@ -2324,7 +2325,10 @@ pass def shortDescription(self): - return "Skipping tests from %s" % module.__name__ + return "Skipping tests from %s" % self.module.__name__ + + __str__ = shortDescription + def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, **options): @@ -2372,7 +2376,7 @@ if not tests and sys.flags.optimize >=2: # Skip doctests when running with -O2 suite = unittest.TestSuite() - suite.addTest(SkipDocTestCase()) + suite.addTest(SkipDocTestCase(module)) return suite elif not tests: # Why do we want to do this? Because it reveals a bug that might diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ Library ------- +- Issue #12757: Fix the skipping of doctests when python is run with -OO so + that it works in unittest's verbose mode as well as non-verbose mode. + - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)) (Patch by Guilherme Polo) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 20:29:18 2012 From: python-checkins at python.org (stefan.krah) Date: Wed, 21 Mar 2012 20:29:18 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Whitespace=2E?= Message-ID: http://hg.python.org/cpython/rev/82bef37f579d changeset: 75862:82bef37f579d parent: 75851:3d5ef57742d3 user: Stefan Krah date: Wed Mar 21 20:21:20 2012 +0100 summary: Whitespace. files: Modules/_decimal/_decimal.c | 4 +- Modules/_decimal/libmpdec/context.c | 230 +++++++------- Modules/_decimal/libmpdec/io.c | 48 +- Modules/_decimal/libmpdec/mpdecimal.c | 2 +- Modules/_decimal/libmpdec/mpdecimal.h | 14 +- Modules/_decimal/libmpdec/typearith.h | 32 +- 6 files changed, 165 insertions(+), 165 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -1585,14 +1585,14 @@ #define CURRENT_CONTEXT(ctxobj) \ ctxobj = current_context(); \ if (ctxobj == NULL) { \ - return NULL; \ + return NULL; \ } /* ctx := pointer to the mpd_context_t struct of the current context */ #define CURRENT_CONTEXT_ADDR(ctx) { \ PyObject *_c_t_x_o_b_j = current_context(); \ if (_c_t_x_o_b_j == NULL) { \ - return NULL; \ + return NULL; \ } \ ctx = CTX(_c_t_x_o_b_j); \ } diff --git a/Modules/_decimal/libmpdec/context.c b/Modules/_decimal/libmpdec/context.c --- a/Modules/_decimal/libmpdec/context.c +++ b/Modules/_decimal/libmpdec/context.c @@ -35,7 +35,7 @@ void mpd_dflt_traphandler(mpd_context_t *ctx UNUSED) { - raise(SIGFPE); + raise(SIGFPE); } void (* mpd_traphandler)(mpd_context_t *) = mpd_dflt_traphandler; @@ -48,239 +48,239 @@ void mpd_setminalloc(mpd_ssize_t n) { - static int minalloc_is_set = 0; + static int minalloc_is_set = 0; - if (minalloc_is_set) { - mpd_err_warn("mpd_setminalloc: ignoring request to set " - "MPD_MINALLOC a second time\n"); - return; - } - if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) { - mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */ - } - MPD_MINALLOC = n; - minalloc_is_set = 1; + if (minalloc_is_set) { + mpd_err_warn("mpd_setminalloc: ignoring request to set " + "MPD_MINALLOC a second time\n"); + return; + } + if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) { + mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */ + } + MPD_MINALLOC = n; + minalloc_is_set = 1; } void mpd_init(mpd_context_t *ctx, mpd_ssize_t prec) { - mpd_ssize_t ideal_minalloc; + mpd_ssize_t ideal_minalloc; - mpd_defaultcontext(ctx); + mpd_defaultcontext(ctx); - if (!mpd_qsetprec(ctx, prec)) { - mpd_addstatus_raise(ctx, MPD_Invalid_context); - return; - } + if (!mpd_qsetprec(ctx, prec)) { + mpd_addstatus_raise(ctx, MPD_Invalid_context); + return; + } - ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS); - if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN; - if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX; + ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS); + if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN; + if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX; - mpd_setminalloc(ideal_minalloc); + mpd_setminalloc(ideal_minalloc); } void mpd_maxcontext(mpd_context_t *ctx) { - ctx->prec=MPD_MAX_PREC; - ctx->emax=MPD_MAX_EMAX; - ctx->emin=MPD_MIN_EMIN; - ctx->round=MPD_ROUND_HALF_EVEN; - ctx->traps=MPD_Traps; - ctx->status=0; - ctx->newtrap=0; - ctx->clamp=0; - ctx->allcr=1; + ctx->prec=MPD_MAX_PREC; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_EVEN; + ctx->traps=MPD_Traps; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; } void mpd_defaultcontext(mpd_context_t *ctx) { - ctx->prec=2*MPD_RDIGITS; - ctx->emax=MPD_MAX_EMAX; - ctx->emin=MPD_MIN_EMIN; - ctx->round=MPD_ROUND_HALF_UP; - ctx->traps=MPD_Traps; - ctx->status=0; - ctx->newtrap=0; - ctx->clamp=0; - ctx->allcr=1; + ctx->prec=2*MPD_RDIGITS; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_UP; + ctx->traps=MPD_Traps; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; } void mpd_basiccontext(mpd_context_t *ctx) { - ctx->prec=9; - ctx->emax=MPD_MAX_EMAX; - ctx->emin=MPD_MIN_EMIN; - ctx->round=MPD_ROUND_HALF_UP; - ctx->traps=MPD_Traps|MPD_Clamped; - ctx->status=0; - ctx->newtrap=0; - ctx->clamp=0; - ctx->allcr=1; + ctx->prec=9; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_UP; + ctx->traps=MPD_Traps|MPD_Clamped; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; } int mpd_ieee_context(mpd_context_t *ctx, int bits) { - if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) { - return -1; - } + if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) { + return -1; + } - ctx->prec = 9 * (bits/32) - 2; - ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3)); - ctx->emin = 1 - ctx->emax; - ctx->round=MPD_ROUND_HALF_EVEN; - ctx->traps=0; - ctx->status=0; - ctx->newtrap=0; - ctx->clamp=1; - ctx->allcr=1; + ctx->prec = 9 * (bits/32) - 2; + ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3)); + ctx->emin = 1 - ctx->emax; + ctx->round=MPD_ROUND_HALF_EVEN; + ctx->traps=0; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=1; + ctx->allcr=1; - return 0; + return 0; } mpd_ssize_t mpd_getprec(const mpd_context_t *ctx) { - return ctx->prec; + return ctx->prec; } mpd_ssize_t mpd_getemax(const mpd_context_t *ctx) { - return ctx->emax; + return ctx->emax; } mpd_ssize_t mpd_getemin(const mpd_context_t *ctx) { - return ctx->emin; + return ctx->emin; } int mpd_getround(const mpd_context_t *ctx) { - return ctx->round; + return ctx->round; } uint32_t mpd_gettraps(const mpd_context_t *ctx) { - return ctx->traps; + return ctx->traps; } uint32_t mpd_getstatus(const mpd_context_t *ctx) { - return ctx->status; + return ctx->status; } int mpd_getclamp(const mpd_context_t *ctx) { - return ctx->clamp; + return ctx->clamp; } int mpd_getcr(const mpd_context_t *ctx) { - return ctx->allcr; + return ctx->allcr; } int mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec) { - if (prec <= 0 || prec > MPD_MAX_PREC) { - return 0; - } - ctx->prec = prec; - return 1; + if (prec <= 0 || prec > MPD_MAX_PREC) { + return 0; + } + ctx->prec = prec; + return 1; } int mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax) { - if (emax < 0 || emax > MPD_MAX_EMAX) { - return 0; - } - ctx->emax = emax; - return 1; + if (emax < 0 || emax > MPD_MAX_EMAX) { + return 0; + } + ctx->emax = emax; + return 1; } int mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin) { - if (emin > 0 || emin < MPD_MIN_EMIN) { - return 0; - } - ctx->emin = emin; - return 1; + if (emin > 0 || emin < MPD_MIN_EMIN) { + return 0; + } + ctx->emin = emin; + return 1; } int mpd_qsetround(mpd_context_t *ctx, int round) { - if (!(0 <= round && round < MPD_ROUND_GUARD)) { - return 0; - } - ctx->round = round; - return 1; + if (!(0 <= round && round < MPD_ROUND_GUARD)) { + return 0; + } + ctx->round = round; + return 1; } int mpd_qsettraps(mpd_context_t *ctx, uint32_t traps) { - if (traps > MPD_Max_status) { - return 0; - } - ctx->traps = traps; - return 1; + if (traps > MPD_Max_status) { + return 0; + } + ctx->traps = traps; + return 1; } int mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags) { - if (flags > MPD_Max_status) { - return 0; - } - ctx->status = flags; - return 1; + if (flags > MPD_Max_status) { + return 0; + } + ctx->status = flags; + return 1; } int mpd_qsetclamp(mpd_context_t *ctx, int c) { - if (c != 0 && c != 1) { - return 0; - } - ctx->clamp = c; - return 1; + if (c != 0 && c != 1) { + return 0; + } + ctx->clamp = c; + return 1; } int mpd_qsetcr(mpd_context_t *ctx, int c) { - if (c != 0 && c != 1) { - return 0; - } - ctx->allcr = c; - return 1; + if (c != 0 && c != 1) { + return 0; + } + ctx->allcr = c; + return 1; } void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags) { - ctx->status |= flags; - if (flags&ctx->traps) { - ctx->newtrap = (flags&ctx->traps); - mpd_traphandler(ctx); - } + ctx->status |= flags; + if (flags&ctx->traps) { + ctx->newtrap = (flags&ctx->traps); + mpd_traphandler(ctx); + } } diff --git a/Modules/_decimal/libmpdec/io.c b/Modules/_decimal/libmpdec/io.c --- a/Modules/_decimal/libmpdec/io.c +++ b/Modules/_decimal/libmpdec/io.c @@ -328,33 +328,33 @@ static inline char * word_to_string(char *s, mpd_uint_t x, int n, char *dot) { - switch(n) { + switch(n) { #ifdef CONFIG_64 - case 20: EXTRACT_DIGIT(s, x, 10000000000000000000ULL, dot); /* GCOV_NOT_REACHED */ - case 19: EXTRACT_DIGIT(s, x, 1000000000000000000ULL, dot); - case 18: EXTRACT_DIGIT(s, x, 100000000000000000ULL, dot); - case 17: EXTRACT_DIGIT(s, x, 10000000000000000ULL, dot); - case 16: EXTRACT_DIGIT(s, x, 1000000000000000ULL, dot); - case 15: EXTRACT_DIGIT(s, x, 100000000000000ULL, dot); - case 14: EXTRACT_DIGIT(s, x, 10000000000000ULL, dot); - case 13: EXTRACT_DIGIT(s, x, 1000000000000ULL, dot); - case 12: EXTRACT_DIGIT(s, x, 100000000000ULL, dot); - case 11: EXTRACT_DIGIT(s, x, 10000000000ULL, dot); + case 20: EXTRACT_DIGIT(s, x, 10000000000000000000ULL, dot); /* GCOV_NOT_REACHED */ + case 19: EXTRACT_DIGIT(s, x, 1000000000000000000ULL, dot); + case 18: EXTRACT_DIGIT(s, x, 100000000000000000ULL, dot); + case 17: EXTRACT_DIGIT(s, x, 10000000000000000ULL, dot); + case 16: EXTRACT_DIGIT(s, x, 1000000000000000ULL, dot); + case 15: EXTRACT_DIGIT(s, x, 100000000000000ULL, dot); + case 14: EXTRACT_DIGIT(s, x, 10000000000000ULL, dot); + case 13: EXTRACT_DIGIT(s, x, 1000000000000ULL, dot); + case 12: EXTRACT_DIGIT(s, x, 100000000000ULL, dot); + case 11: EXTRACT_DIGIT(s, x, 10000000000ULL, dot); #endif - case 10: EXTRACT_DIGIT(s, x, 1000000000UL, dot); - case 9: EXTRACT_DIGIT(s, x, 100000000UL, dot); - case 8: EXTRACT_DIGIT(s, x, 10000000UL, dot); - case 7: EXTRACT_DIGIT(s, x, 1000000UL, dot); - case 6: EXTRACT_DIGIT(s, x, 100000UL, dot); - case 5: EXTRACT_DIGIT(s, x, 10000UL, dot); - case 4: EXTRACT_DIGIT(s, x, 1000UL, dot); - case 3: EXTRACT_DIGIT(s, x, 100UL, dot); - case 2: EXTRACT_DIGIT(s, x, 10UL, dot); - default: if (s == dot) *s++ = '.'; *s++ = '0' + (char)x; - } + case 10: EXTRACT_DIGIT(s, x, 1000000000UL, dot); + case 9: EXTRACT_DIGIT(s, x, 100000000UL, dot); + case 8: EXTRACT_DIGIT(s, x, 10000000UL, dot); + case 7: EXTRACT_DIGIT(s, x, 1000000UL, dot); + case 6: EXTRACT_DIGIT(s, x, 100000UL, dot); + case 5: EXTRACT_DIGIT(s, x, 10000UL, dot); + case 4: EXTRACT_DIGIT(s, x, 1000UL, dot); + case 3: EXTRACT_DIGIT(s, x, 100UL, dot); + case 2: EXTRACT_DIGIT(s, x, 10UL, dot); + default: if (s == dot) *s++ = '.'; *s++ = '0' + (char)x; + } - *s = '\0'; - return s; + *s = '\0'; + return s; } /* Print exponent x to string s. Undefined for MPD_SSIZE_MIN. */ diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c --- a/Modules/_decimal/libmpdec/mpdecimal.c +++ b/Modules/_decimal/libmpdec/mpdecimal.c @@ -6192,7 +6192,7 @@ mpd_qdivint(&texp, &texp, &two, &maxcontext, status); } if (mpd_isspecial(&texp) || mpd_isspecial(&tbase) || - mpd_isspecial(&tmod) || mpd_isspecial(result)) { + mpd_isspecial(&tmod) || mpd_isspecial(result)) { /* MPD_Malloc_error */ goto mpd_errors; } diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h --- a/Modules/_decimal/libmpdec/mpdecimal.h +++ b/Modules/_decimal/libmpdec/mpdecimal.h @@ -749,14 +749,14 @@ /******************************************************************************/ #define mpd_err_fatal(...) \ - do {fprintf(stderr, "%s:%d: error: ", __FILE__, __LINE__); \ - fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ - exit(1); \ - } while (0) + do {fprintf(stderr, "%s:%d: error: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ + exit(1); \ + } while (0) #define mpd_err_warn(...) \ - do {fprintf(stderr, "%s:%d: warning: ", __FILE__, __LINE__); \ - fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ - } while (0) + do {fprintf(stderr, "%s:%d: warning: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ + } while (0) /******************************************************************************/ diff --git a/Modules/_decimal/libmpdec/typearith.h b/Modules/_decimal/libmpdec/typearith.h --- a/Modules/_decimal/libmpdec/typearith.h +++ b/Modules/_decimal/libmpdec/typearith.h @@ -207,10 +207,10 @@ { mpd_uint_t h, l; - asm ( "mulq %3\n\t" - : "=d" (h), "=a" (l) - : "%a" (a), "rm" (b) - : "cc" + asm ( "mulq %3\n\t" + : "=d" (h), "=a" (l) + : "%a" (a), "rm" (b) + : "cc" ); *hi = h; @@ -223,10 +223,10 @@ { mpd_uint_t qq, rr; - asm ( "divq %4\n\t" - : "=a" (qq), "=d" (rr) - : "a" (lo), "d" (hi), "rm" (d) - : "cc" + asm ( "divq %4\n\t" + : "=a" (qq), "=d" (rr) + : "a" (lo), "d" (hi), "rm" (d) + : "cc" ); *q = qq; @@ -464,10 +464,10 @@ { mpd_uint_t h, l; - asm ( "mull %3\n\t" - : "=d" (h), "=a" (l) - : "%a" (a), "rm" (b) - : "cc" + asm ( "mull %3\n\t" + : "=d" (h), "=a" (l) + : "%a" (a), "rm" (b) + : "cc" ); *hi = h; @@ -480,10 +480,10 @@ { mpd_uint_t qq, rr; - asm ( "divl %4\n\t" - : "=a" (qq), "=d" (rr) - : "a" (lo), "d" (hi), "rm" (d) - : "cc" + asm ( "divl %4\n\t" + : "=a" (qq), "=d" (rr) + : "a" (lo), "d" (hi), "rm" (d) + : "cc" ); *q = qq; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 20:29:19 2012 From: python-checkins at python.org (stefan.krah) Date: Wed, 21 Mar 2012 20:29:19 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?b?KTogTWVyZ2Uu?= Message-ID: http://hg.python.org/cpython/rev/8af880dd216e changeset: 75863:8af880dd216e parent: 75862:82bef37f579d parent: 75860:ff7957aa01a1 user: Stefan Krah date: Wed Mar 21 20:27:33 2012 +0100 summary: Merge. files: Include/abstract.h | 15 ---- Lib/doctest.py | 10 ++- Lib/test/test_descr.py | 1 + Misc/NEWS | 3 + Objects/abstract.c | 92 +++++++++++------------------ Python/ceval.c | 3 +- 6 files changed, 47 insertions(+), 77 deletions(-) diff --git a/Include/abstract.h b/Include/abstract.h --- a/Include/abstract.h +++ b/Include/abstract.h @@ -773,21 +773,6 @@ PyAPI_FUNC(Py_ssize_t) PyNumber_AsSsize_t(PyObject *o, PyObject *exc); /* - Returns the Integral instance converted to an int. The - instance is expected to be int or long or have an __int__ - method. Steals integral's reference. error_format will be - used to create the TypeError if integral isn't actually an - Integral instance. error_format should be a format string - that can accept a char* naming integral's type. - */ - -#ifndef Py_LIMITED_API - PyAPI_FUNC(PyObject *) _PyNumber_ConvertIntegralToInt( - PyObject *integral, - const char* error_format); -#endif - - /* Returns the object converted to Py_ssize_t by going through PyNumber_Index first. If an overflow error occurs while converting the int-or-long to Py_ssize_t, then the second argument diff --git a/Lib/doctest.py b/Lib/doctest.py --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -2267,7 +2267,8 @@ return "Doctest: " + self._dt_test.name class SkipDocTestCase(DocTestCase): - def __init__(self): + def __init__(self, module): + self.module = module DocTestCase.__init__(self, None) def setUp(self): @@ -2277,7 +2278,10 @@ pass def shortDescription(self): - return "Skipping tests from %s" % module.__name__ + return "Skipping tests from %s" % self.module.__name__ + + __str__ = shortDescription + def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, **options): @@ -2325,7 +2329,7 @@ if not tests and sys.flags.optimize >=2: # Skip doctests when running with -O2 suite = unittest.TestSuite() - suite.addTest(SkipDocTestCase()) + suite.addTest(SkipDocTestCase(module)) return suite elif not tests: # Why do we want to do this? Because it reveals a bug that might diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1770,6 +1770,7 @@ ("__format__", format, format_impl, set(), {}), ("__floor__", math.floor, zero, set(), {}), ("__trunc__", math.trunc, zero, set(), {}), + ("__trunc__", int, zero, set(), {}), ("__ceil__", math.ceil, zero, set(), {}), ("__dir__", dir, empty_seq, set(), {}), ] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,9 @@ Library ------- +- Issue #12757: Fix the skipping of doctests when python is run with -OO so + that it works in unittest's verbose mode as well as non-verbose mode. + - Issue #7652: Integrate the decimal floating point libmpdec library to speed up the decimal module. Performance gains of the new C implementation are between 12x and 80x, depending on the application. diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1268,37 +1268,32 @@ } -PyObject * -_PyNumber_ConvertIntegralToInt(PyObject *integral, const char* error_format) +/* + Returns the Integral instance converted to an int. The instance is expected + to be an int or have an __int__ method. Steals integral's + reference. error_format will be used to create the TypeError if integral + isn't actually an Integral instance. error_format should be a format string + that can accept a char* naming integral's type. +*/ +static PyObject * +convert_integral_to_int(PyObject *integral, const char *error_format) { - static PyObject *int_name = NULL; - if (int_name == NULL) { - int_name = PyUnicode_InternFromString("__int__"); - if (int_name == NULL) + PyNumberMethods *nb; + if (PyLong_Check(integral)) + return integral; + nb = Py_TYPE(integral)->tp_as_number; + if (nb->nb_int) { + PyObject *as_int = nb->nb_int(integral); + Py_DECREF(integral); + if (!as_int) return NULL; + if (PyLong_Check(as_int)) + return as_int; + Py_DECREF(as_int); } - - if (integral && !PyLong_Check(integral)) { - /* Don't go through tp_as_number->nb_int to avoid - hitting the classic class fallback to __trunc__. */ - PyObject *int_func = PyObject_GetAttr(integral, int_name); - if (int_func == NULL) { - PyErr_Clear(); /* Raise a different error. */ - goto non_integral_error; - } - Py_DECREF(integral); - integral = PyEval_CallObject(int_func, NULL); - Py_DECREF(int_func); - if (integral && !PyLong_Check(integral)) { - goto non_integral_error; - } - } - return integral; - -non_integral_error: PyErr_Format(PyExc_TypeError, error_format, Py_TYPE(integral)->tp_name); Py_DECREF(integral); - return NULL; + return NULL; } @@ -1325,16 +1320,10 @@ PyNumber_Long(PyObject *o) { PyNumberMethods *m; - static PyObject *trunc_name = NULL; PyObject *trunc_func; const char *buffer; Py_ssize_t buffer_len; - - if (trunc_name == NULL) { - trunc_name = PyUnicode_InternFromString("__trunc__"); - if (trunc_name == NULL) - return NULL; - } + _Py_IDENTIFIER(__trunc__); if (o == NULL) return null_error(); @@ -1356,23 +1345,23 @@ } if (PyLong_Check(o)) /* An int subclass without nb_int */ return _PyLong_Copy((PyLongObject *)o); - trunc_func = PyObject_GetAttr(o, trunc_name); + trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__); if (trunc_func) { PyObject *truncated = PyEval_CallObject(trunc_func, NULL); PyObject *int_instance; Py_DECREF(trunc_func); /* __trunc__ is specified to return an Integral type, - but long() needs to return a long. */ - int_instance = _PyNumber_ConvertIntegralToInt( - truncated, + but int() needs to return a int. */ + int_instance = convert_integral_to_int(truncated, "__trunc__ returned non-Integral (type %.200s)"); return int_instance; } - PyErr_Clear(); /* It's not an error if o.__trunc__ doesn't exist. */ + if (PyErr_Occurred()) + return NULL; if (PyBytes_Check(o)) /* need to do extra error checking that PyLong_FromString() - * doesn't do. In particular long('9.5') must raise an + * doesn't do. In particular int('9.5') must raise an * exception, not truncate the float. */ return long_from_string(PyBytes_AS_STRING(o), @@ -2411,10 +2400,8 @@ /* isinstance(), issubclass() */ -/* abstract_get_bases() has logically 4 return states, with a sort of 0th - * state that will almost never happen. +/* abstract_get_bases() has logically 4 return states: * - * 0. creating the __bases__ static string could get a MemoryError * 1. getattr(cls, '__bases__') could raise an AttributeError * 2. getattr(cls, '__bases__') could raise some other exception * 3. getattr(cls, '__bases__') could return a tuple @@ -2440,16 +2427,11 @@ static PyObject * abstract_get_bases(PyObject *cls) { - static PyObject *__bases__ = NULL; + _Py_IDENTIFIER(__bases__); PyObject *bases; - if (__bases__ == NULL) { - __bases__ = PyUnicode_InternFromString("__bases__"); - if (__bases__ == NULL) - return NULL; - } Py_ALLOW_RECURSION - bases = PyObject_GetAttr(cls, __bases__); + bases = _PyObject_GetAttrId(cls, &PyId___bases__); Py_END_ALLOW_RECURSION if (bases == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) @@ -2519,19 +2501,13 @@ recursive_isinstance(PyObject *inst, PyObject *cls) { PyObject *icls; - static PyObject *__class__ = NULL; int retval = 0; - - if (__class__ == NULL) { - __class__ = PyUnicode_InternFromString("__class__"); - if (__class__ == NULL) - return -1; - } + _Py_IDENTIFIER(__class__); if (PyType_Check(cls)) { retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls); if (retval == 0) { - PyObject *c = PyObject_GetAttr(inst, __class__); + PyObject *c = _PyObject_GetAttrId(inst, &PyId___class__); if (c == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) PyErr_Clear(); @@ -2552,7 +2528,7 @@ if (!check_class(cls, "isinstance() arg 2 must be a type or tuple of types")) return -1; - icls = PyObject_GetAttr(inst, __class__); + icls = _PyObject_GetAttrId(inst, &PyId___class__); if (icls == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) PyErr_Clear(); diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1837,10 +1837,11 @@ if (PyGen_CheckExact(x)) { retval = _PyGen_Send((PyGenObject *)x, u); } else { + _Py_IDENTIFIER(send); if (u == Py_None) retval = PyIter_Next(x); else - retval = PyObject_CallMethod(x, "send", "O", u); + retval = _PyObject_CallMethodId(x, &PyId_send, "O", u); } Py_DECREF(u); if (!retval) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 21 22:53:11 2012 From: python-checkins at python.org (andrew.svetlov) Date: Wed, 21 Mar 2012 22:53:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=233035=3A_Unused_fun?= =?utf8?q?ctions_from_tkinter_are_marked_as_pending_peprecated=2E?= Message-ID: http://hg.python.org/cpython/rev/d42f264f291e changeset: 75864:d42f264f291e user: Andrew Svetlov date: Wed Mar 21 23:52:59 2012 +0200 summary: Issue #3035: Unused functions from tkinter are marked as pending peprecated. files: Lib/tkinter/__init__.py | 24 ++++++++++++++++++++++++ Misc/NEWS | 2 ++ 2 files changed, 26 insertions(+), 0 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -34,10 +34,14 @@ if sys.platform == "win32": # Attempt to configure Tcl/Tk without requiring PATH from tkinter import _fix + +import warnings + import _tkinter # If this fails your Python may not be configured for Tk TclError = _tkinter.TclError from tkinter.constants import * + wantobjects = 1 TkVersion = float(_tkinter.TK_VERSION) @@ -2118,25 +2122,45 @@ """ return self.tk.call(self._w, 'invoke') + # Indices: # XXX I don't like these -- take them away def AtEnd(): + warnings.warn("tkinter.AtEnd will be removed in 3.5", + PendingDeprecationWarning, stacklevel=2) return 'end' + + def AtInsert(*args): + warnings.warn("tkinter.AtInsert will be removed in 3.5", + PendingDeprecationWarning, stacklevel=2) s = 'insert' for a in args: if a: s = s + (' ' + a) return s + + def AtSelFirst(): + warnings.warn("tkinter.AtSelFirst will be removed in 3.5", + PendingDeprecationWarning, stacklevel=2) return 'sel.first' + + def AtSelLast(): + warnings.warn("tkinter.AtSelLast will be removed in 3.5", + PendingDeprecationWarning, stacklevel=2) return 'sel.last' + + def At(x, y=None): + warnings.warn("tkinter.At will be removed in 3.5", + PendingDeprecationWarning, stacklevel=2) if y is None: return '@%r' % (x,) else: return '@%r,%r' % (x, y) + class Canvas(Widget, XView, YView): """Canvas widget to display graphical elements like lines or text.""" def __init__(self, master=None, cnf={}, **kw): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,8 @@ Library ------- +- Issue #3035: Unused functions from tkinter are marked as pending peprecated. + - Issue #12757: Fix the skipping of doctests when python is run with -OO so that it works in unittest's verbose mode as well as non-verbose mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 00:34:40 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 22 Mar 2012 00:34:40 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314204=3A_The_ssl_m?= =?utf8?q?odule_now_has_support_for_the_Next_Protocol_Negotiation?= Message-ID: http://hg.python.org/cpython/rev/2514a4e2b3ce changeset: 75865:2514a4e2b3ce user: Antoine Pitrou date: Thu Mar 22 00:23:03 2012 +0100 summary: Issue #14204: The ssl module now has support for the Next Protocol Negotiation extension, if available in the underlying OpenSSL library. Patch by Colin Marc. files: Doc/library/ssl.rst | 35 +++++++++- Lib/ssl.py | 27 ++++++- Lib/test/test_ssl.py | 54 +++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 4 + Modules/_ssl.c | 115 +++++++++++++++++++++++++++++++ 6 files changed, 228 insertions(+), 8 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -470,6 +470,16 @@ .. versionadded:: 3.2 +.. data:: HAS_NPN + + Whether the OpenSSL library has built-in support for *Next Protocol + Negotiation* as described in the `NPN draft specification + `_. When true, + you can use the :meth:`SSLContext.set_npn_protocols` method to advertise + which protocols you want to support. + + .. versionadded:: 3.3 + .. data:: CHANNEL_BINDING_TYPES List of supported TLS channel binding types. Strings in this list @@ -609,6 +619,15 @@ .. versionadded:: 3.3 +.. method:: SSLSocket.selected_npn_protocol() + + Returns the protocol that was selected during the TLS/SSL handshake. If + :meth:`SSLContext.set_npn_protocols` was not called, or if the other party + does not support NPN, or if the handshake has not yet happened, this will + return ``None``. + + .. versionadded:: 3.3 + .. method:: SSLSocket.unwrap() Performs the SSL shutdown handshake, which removes the TLS layer from the @@ -617,7 +636,6 @@ returned socket should always be used for further communication with the other side of the connection, rather than the original socket. - .. attribute:: SSLSocket.context The :class:`SSLContext` object this SSL socket is tied to. If the SSL @@ -715,6 +733,21 @@ when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will give the currently selected cipher. +.. method:: SSLContext.set_npn_protocols(protocols) + + Specify which protocols the socket should avertise during the SSL/TLS + handshake. It should be a list of strings, like ``['http/1.1', 'spdy/2']``, + ordered by preference. The selection of a protocol will happen during the + handshake, and will play out according to the `NPN draft specification + `_. After a + successful handshake, the :meth:`SSLSocket.selected_npn_protocol` method will + return the agreed-upon protocol. + + This method will raise :exc:`NotImplementedError` if :data:`HAS_NPN` is + False. + + .. versionadded:: 3.3 + .. method:: SSLContext.load_dh_params(dhfile) Load the key generation parameters for Diffie-Helman (DH) key exchange. diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -90,7 +90,7 @@ SSL_ERROR_EOF, SSL_ERROR_INVALID_ERROR_CODE, ) -from _ssl import HAS_SNI, HAS_ECDH +from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN from _ssl import (PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1) from _ssl import _OPENSSL_API_VERSION @@ -209,6 +209,17 @@ server_hostname=server_hostname, _context=self) + def set_npn_protocols(self, npn_protocols): + protos = bytearray() + for protocol in npn_protocols: + b = bytes(protocol, 'ascii') + if len(b) == 0 or len(b) > 255: + raise SSLError('NPN protocols must be 1 to 255 in length') + protos.append(len(b)) + protos.extend(b) + + self._set_npn_protocols(protos) + class SSLSocket(socket): """This class implements a subtype of socket.socket that wraps @@ -220,7 +231,7 @@ ssl_version=PROTOCOL_SSLv23, ca_certs=None, do_handshake_on_connect=True, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None, - suppress_ragged_eofs=True, ciphers=None, + suppress_ragged_eofs=True, npn_protocols=None, ciphers=None, server_hostname=None, _context=None): @@ -240,6 +251,8 @@ self.context.load_verify_locations(ca_certs) if certfile: self.context.load_cert_chain(certfile, keyfile) + if npn_protocols: + self.context.set_npn_protocols(npn_protocols) if ciphers: self.context.set_ciphers(ciphers) self.keyfile = keyfile @@ -340,6 +353,13 @@ self._checkClosed() return self._sslobj.peer_certificate(binary_form) + def selected_npn_protocol(self): + self._checkClosed() + if not self._sslobj or not _ssl.HAS_NPN: + return None + else: + return self._sslobj.selected_npn_protocol() + def cipher(self): self._checkClosed() if not self._sslobj: @@ -568,7 +588,8 @@ server_side=False, cert_reqs=CERT_NONE, ssl_version=PROTOCOL_SSLv23, ca_certs=None, do_handshake_on_connect=True, - suppress_ragged_eofs=True, ciphers=None): + suppress_ragged_eofs=True, + ciphers=None): return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile, server_side=server_side, cert_reqs=cert_reqs, diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -879,6 +879,7 @@ try: self.sslconn = self.server.context.wrap_socket( self.sock, server_side=True) + self.server.selected_protocols.append(self.sslconn.selected_npn_protocol()) except ssl.SSLError as e: # XXX Various errors can have happened here, for example # a mismatching protocol version, an invalid certificate, @@ -901,6 +902,8 @@ cipher = self.sslconn.cipher() if support.verbose and self.server.chatty: sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n") + sys.stdout.write(" server: selected protocol is now " + + str(self.sslconn.selected_npn_protocol()) + "\n") return True def read(self): @@ -979,7 +982,7 @@ def __init__(self, certificate=None, ssl_version=None, certreqs=None, cacerts=None, chatty=True, connectionchatty=False, starttls_server=False, - ciphers=None, context=None): + npn_protocols=None, ciphers=None, context=None): if context: self.context = context else: @@ -992,6 +995,8 @@ self.context.load_verify_locations(cacerts) if certificate: self.context.load_cert_chain(certificate) + if npn_protocols: + self.context.set_npn_protocols(npn_protocols) if ciphers: self.context.set_ciphers(ciphers) self.chatty = chatty @@ -1001,6 +1006,7 @@ self.port = support.bind_port(self.sock) self.flag = None self.active = False + self.selected_protocols = [] self.conn_errors = [] threading.Thread.__init__(self) self.daemon = True @@ -1195,6 +1201,7 @@ Launch a server, connect a client to it and try various reads and writes. """ + stats = {} server = ThreadedEchoServer(context=server_context, chatty=chatty, connectionchatty=False) @@ -1220,12 +1227,14 @@ if connectionchatty: if support.verbose: sys.stdout.write(" client: closing connection.\n") - stats = { + stats.update({ 'compression': s.compression(), 'cipher': s.cipher(), - } + 'client_npn_protocol': s.selected_npn_protocol() + }) s.close() - return stats + stats['server_npn_protocols'] = server.selected_protocols + return stats def try_protocol_combo(server_protocol, client_protocol, expect_success, certsreqs=None, server_options=0, client_options=0): @@ -1853,6 +1862,43 @@ if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts: self.fail("Non-DH cipher: " + cipher[0]) + def test_selected_npn_protocol(self): + # selected_npn_protocol() is None unless NPN is used + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context.load_cert_chain(CERTFILE) + stats = server_params_test(context, context, + chatty=True, connectionchatty=True) + self.assertIs(stats['client_npn_protocol'], None) + + @unittest.skipUnless(ssl.HAS_NPN, "NPN support needed for this test") + def test_npn_protocols(self): + server_protocols = ['http/1.1', 'spdy/2'] + protocol_tests = [ + (['http/1.1', 'spdy/2'], 'http/1.1'), + (['spdy/2', 'http/1.1'], 'http/1.1'), + (['spdy/2', 'test'], 'spdy/2'), + (['abc', 'def'], 'abc') + ] + for client_protocols, expected in protocol_tests: + server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + server_context.load_cert_chain(CERTFILE) + server_context.set_npn_protocols(server_protocols) + client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + client_context.load_cert_chain(CERTFILE) + client_context.set_npn_protocols(client_protocols) + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True) + + msg = "failed trying %s (s) and %s (c).\n" \ + "was expecting %s, but got %%s from the %%s" \ + % (str(server_protocols), str(client_protocols), + str(expected)) + client_result = stats['client_npn_protocol'] + self.assertEqual(client_result, expected, msg % (client_result, "client")) + server_result = stats['server_npn_protocols'][-1] \ + if len(stats['server_npn_protocols']) else 'nothing' + self.assertEqual(server_result, expected, msg % (server_result, "server")) + def test_main(verbose=False): if support.verbose: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -644,6 +644,7 @@ David Malcolm Ken Manheimer Vladimir Marangozov +Colin Marc David Marek Doug Marien Sven Marnach diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,10 @@ Library ------- +- Issue #14204: The ssl module now has support for the Next Protocol + Negotiation extension, if available in the underlying OpenSSL library. + Patch by Colin Marc. + - Issue #3035: Unused functions from tkinter are marked as pending peprecated. - Issue #12757: Fix the skipping of doctests when python is run with -OO so diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -159,6 +159,10 @@ typedef struct { PyObject_HEAD SSL_CTX *ctx; +#ifdef OPENSSL_NPN_NEGOTIATED + char *npn_protocols; + int npn_protocols_len; +#endif } PySSLContext; typedef struct { @@ -1015,6 +1019,20 @@ return NULL; } +#ifdef OPENSSL_NPN_NEGOTIATED +static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) { + const unsigned char *out; + unsigned int outlen; + + SSL_get0_next_proto_negotiated(self->ssl, + &out, &outlen); + + if (out == NULL) + Py_RETURN_NONE; + return PyUnicode_FromStringAndSize((char *) out, outlen); +} +#endif + static PyObject *PySSL_compression(PySSLSocket *self) { #ifdef OPENSSL_NO_COMP Py_RETURN_NONE; @@ -1487,6 +1505,9 @@ {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, PySSL_peercert_doc}, {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, +#ifdef OPENSSL_NPN_NEGOTIATED + {"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS}, +#endif {"compression", (PyCFunction)PySSL_compression, METH_NOARGS}, {"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS, PySSL_SSLshutdown_doc}, @@ -1597,6 +1618,9 @@ context_dealloc(PySSLContext *self) { SSL_CTX_free(self->ctx); +#ifdef OPENSSL_NPN_NEGOTIATED + PyMem_Free(self->npn_protocols); +#endif Py_TYPE(self)->tp_free(self); } @@ -1621,6 +1645,87 @@ Py_RETURN_NONE; } +#ifdef OPENSSL_NPN_NEGOTIATED +/* this callback gets passed to SSL_CTX_set_next_protos_advertise_cb */ +static int +_advertiseNPN_cb(SSL *s, + const unsigned char **data, unsigned int *len, + void *args) +{ + PySSLContext *ssl_ctx = (PySSLContext *) args; + + if (ssl_ctx->npn_protocols == NULL) { + *data = (unsigned char *) ""; + *len = 0; + } else { + *data = (unsigned char *) ssl_ctx->npn_protocols; + *len = ssl_ctx->npn_protocols_len; + } + + return SSL_TLSEXT_ERR_OK; +} +/* this callback gets passed to SSL_CTX_set_next_proto_select_cb */ +static int +_selectNPN_cb(SSL *s, + unsigned char **out, unsigned char *outlen, + const unsigned char *server, unsigned int server_len, + void *args) +{ + PySSLContext *ssl_ctx = (PySSLContext *) args; + + unsigned char *client = (unsigned char *) ssl_ctx->npn_protocols; + int client_len; + + if (client == NULL) { + client = (unsigned char *) ""; + client_len = 0; + } else { + client_len = ssl_ctx->npn_protocols_len; + } + + SSL_select_next_proto(out, outlen, + server, server_len, + client, client_len); + + return SSL_TLSEXT_ERR_OK; +} +#endif + +static PyObject * +_set_npn_protocols(PySSLContext *self, PyObject *args) +{ +#ifdef OPENSSL_NPN_NEGOTIATED + Py_buffer protos; + + if (!PyArg_ParseTuple(args, "y*:set_npn_protocols", &protos)) + return NULL; + + self->npn_protocols = PyMem_Malloc(protos.len); + if (self->npn_protocols == NULL) { + PyBuffer_Release(&protos); + return PyErr_NoMemory(); + } + memcpy(self->npn_protocols, protos.buf, protos.len); + self->npn_protocols_len = (int) protos.len; + + /* set both server and client callbacks, because the context can + * be used to create both types of sockets */ + SSL_CTX_set_next_protos_advertised_cb(self->ctx, + _advertiseNPN_cb, + self); + SSL_CTX_set_next_proto_select_cb(self->ctx, + _selectNPN_cb, + self); + + PyBuffer_Release(&protos); + Py_RETURN_NONE; +#else + PyErr_SetString(PyExc_NotImplementedError, + "The NPN extension requires OpenSSL 1.0.1 or later."); + return NULL; +#endif +} + static PyObject * get_verify_mode(PySSLContext *self, void *c) { @@ -2097,6 +2202,8 @@ METH_VARARGS | METH_KEYWORDS, NULL}, {"set_ciphers", (PyCFunction) set_ciphers, METH_VARARGS, NULL}, + {"_set_npn_protocols", (PyCFunction) _set_npn_protocols, + METH_VARARGS, NULL}, {"load_cert_chain", (PyCFunction) load_cert_chain, METH_VARARGS | METH_KEYWORDS, NULL}, {"load_dh_params", (PyCFunction) load_dh_params, @@ -2590,6 +2697,14 @@ Py_INCREF(r); PyModule_AddObject(m, "HAS_ECDH", r); +#ifdef OPENSSL_NPN_NEGOTIATED + r = Py_True; +#else + r = Py_False; +#endif + Py_INCREF(r); + PyModule_AddObject(m, "HAS_NPN", r); + /* OpenSSL version */ /* SSLeay() gives us the version of the library linked against, which could be different from the headers version. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 00:47:34 2012 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 22 Mar 2012 00:47:34 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Reject_PEP_416_=28frozendict?= =?utf8?q?=29_with_reasons_why=2E?= Message-ID: http://hg.python.org/peps/rev/372f8123c1bd changeset: 4143:372f8123c1bd user: Guido van Rossum date: Wed Mar 21 16:47:27 2012 -0700 summary: Reject PEP 416 (frozendict) with reasons why. files: pep-0416.txt | 32 ++++++++++++++++++++++++++++++-- 1 files changed, 30 insertions(+), 2 deletions(-) diff --git a/pep-0416.txt b/pep-0416.txt --- a/pep-0416.txt +++ b/pep-0416.txt @@ -3,13 +3,40 @@ Version: $Revision$ Last-Modified: $Date$ Author: Victor Stinner -Status: Draft +Status: Rejected Type: Standards Track Content-Type: text/x-rst Created: 29-February-2012 Python-Version: 3.3 +Rejection Notice +================ + +I'm rejecting this PEP. A number of reasons (not exhaustive): + + * According to Raymond Hettinger, use of frozendict is low. Those + that do use it tend to use it as a hint only, such as declaring + global or class-level "constants": they aren't really immutable, + since anyone can still assign to the name. + * There are existing idioms for avoiding mutable default values. + * The potential of optimizing code using frozendict in PyPy is + unsure; a lot of other things would have to change first. The same + holds for compile-time lookups in general. + * Multiple threads can agree by convention not to mutate a shared + dict, there's no great need for enforcement. Multiple processes + can't share dicts. + * Adding a security sandbox written in Python, even with a limited + scope, is frowned upon by many, due to the inherent difficulty with + ever proving that the sandbox is actually secure. Because of this + we won't be adding one to the stdlib any time soon, so this use + case falls outside the scope of a PEP. + +On the other hand, exposing the existing read-only dict proxy as a +built-in type sounds good to me. (It would need to be changed to +allow calling the constructor.) + + Abstract ======== @@ -26,7 +53,8 @@ Use cases: * Immutable global variable like a default configuration. - * Default value of a function parameter. Avoid the issue of mutable default arguments. + * Default value of a function parameter. Avoid the issue of mutable default + arguments. * Implement a cache: frozendict can be used to store function keywords. frozendict can be used as a key of a mapping or as a member of set. * frozendict avoids the need of a lock when the frozendict is shared -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 22 02:09:39 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 22 Mar 2012 02:09:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Micro-optimize_PyObject=5FG?= =?utf8?q?etAttrString=28=29?= Message-ID: http://hg.python.org/cpython/rev/059489cec7b9 changeset: 75866:059489cec7b9 user: Victor Stinner date: Thu Mar 22 02:09:08 2012 +0100 summary: Micro-optimize PyObject_GetAttrString() w cannot be NULL so use Py_DECREF() instead of Py_XDECREF(). files: Objects/object.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -820,7 +820,7 @@ if (w == NULL) return NULL; res = PyObject_GetAttr(v, w); - Py_XDECREF(w); + Py_DECREF(w); return res; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 03:02:34 2012 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 22 Mar 2012 03:02:34 +0100 Subject: [Python-checkins] =?utf8?q?peps=3A_Sign_rejection_notices=2E?= Message-ID: http://hg.python.org/peps/rev/8da98543ae43 changeset: 4144:8da98543ae43 user: Guido van Rossum date: Wed Mar 21 19:02:27 2012 -0700 summary: Sign rejection notices. files: pep-0340.txt | 2 +- pep-0416.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0340.txt b/pep-0340.txt --- a/pep-0340.txt +++ b/pep-0340.txt @@ -36,7 +36,7 @@ Rejection Notice I am rejecting this PEP in favor of PEP 343. See the motivational - section in that PEP for the reasoning behind this rejection. + section in that PEP for the reasoning behind this rejection. GvR. Motivation and Summary diff --git a/pep-0416.txt b/pep-0416.txt --- a/pep-0416.txt +++ b/pep-0416.txt @@ -34,7 +34,7 @@ On the other hand, exposing the existing read-only dict proxy as a built-in type sounds good to me. (It would need to be changed to -allow calling the constructor.) +allow calling the constructor.) GvR. Abstract -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Thu Mar 22 05:46:21 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 22 Mar 2012 05:46:21 +0100 Subject: [Python-checkins] Daily reference leaks (059489cec7b9): sum=0 Message-ID: results for 059489cec7b9 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogiVEBSS', '-x'] From python-checkins at python.org Thu Mar 22 07:42:35 2012 From: python-checkins at python.org (georg.brandl) Date: Thu, 22 Mar 2012 07:42:35 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_typo=2E?= Message-ID: http://hg.python.org/cpython/rev/7c52a59f1409 changeset: 75867:7c52a59f1409 user: Georg Brandl date: Thu Mar 22 07:42:31 2012 +0100 summary: Fix typo. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,7 +34,7 @@ Negotiation extension, if available in the underlying OpenSSL library. Patch by Colin Marc. -- Issue #3035: Unused functions from tkinter are marked as pending peprecated. +- Issue #3035: Unused functions from tkinter are marked as pending deprecated. - Issue #12757: Fix the skipping of doctests when python is run with -OO so that it works in unittest's verbose mode as well as non-verbose mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 13:19:58 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 13:19:58 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_check_by_equali?= =?utf8?q?ty_for_=5F=5Ffuture=5F=5F_not_identity_=28closes_=2314378=29?= Message-ID: http://hg.python.org/cpython/rev/f57cbcefde34 changeset: 75868:f57cbcefde34 branch: 3.2 parent: 75859:64f1b8ad9214 user: Benjamin Peterson date: Thu Mar 22 08:19:04 2012 -0400 summary: check by equality for __future__ not identity (closes #14378) files: Lib/test/test_ast.py | 6 ++++++ Misc/NEWS | 3 +++ Python/future.c | 10 ++-------- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -218,6 +218,12 @@ im = ast.parse("from . import y").body[0] self.assertIsNone(im.module) + def test_non_interned_future_from_ast(self): + mod = ast.parse("from __future__ import division") + self.assertIsInstance(mod.body[0], ast.ImportFrom) + mod.body[0].module = " __future__ ".strip() + compile(mod, "", "exec") + def test_base_classes(self): self.assertTrue(issubclass(ast.For, ast.stmt)) self.assertTrue(issubclass(ast.Name, ast.expr)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #14378: Fix compiling ast.ImportFrom nodes with a "__future__" string as + the module name that was not interned. + - Issue #14331: Use significantly less stack space when importing modules by allocating path buffers on the heap instead of the stack. diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -60,13 +60,6 @@ { int i, found_docstring = 0, done = 0, prev_line = 0; - static PyObject *future; - if (!future) { - future = PyUnicode_InternFromString("__future__"); - if (!future) - return 0; - } - if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) return 1; @@ -93,7 +86,8 @@ */ if (s->kind == ImportFrom_kind) { - if (s->v.ImportFrom.module == future) { + PyObject *modname = s->v.ImportFrom.module; + if (!PyUnicode_CompareWithASCIIString(modname, "__future__")) { if (done) { PyErr_SetString(PyExc_SyntaxError, ERR_LATE_FUTURE); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 13:20:01 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 13:20:01 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?b?OiBtZXJnZSAzLjIgKCMxNDM3OCk=?= Message-ID: http://hg.python.org/cpython/rev/9d793be3b4eb changeset: 75869:9d793be3b4eb parent: 75867:7c52a59f1409 parent: 75868:f57cbcefde34 user: Benjamin Peterson date: Thu Mar 22 08:19:50 2012 -0400 summary: merge 3.2 (#14378) files: Lib/test/test_ast.py | 6 ++++++ Misc/NEWS | 6 +++++- Python/future.c | 10 ++-------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -226,6 +226,12 @@ im = ast.parse("from . import y").body[0] self.assertIsNone(im.module) + def test_non_interned_future_from_ast(self): + mod = ast.parse("from __future__ import division") + self.assertIsInstance(mod.body[0], ast.ImportFrom) + mod.body[0].module = " __future__ ".strip() + compile(mod, "", "exec") + def test_base_classes(self): self.assertTrue(issubclass(ast.For, ast.stmt)) self.assertTrue(issubclass(ast.Name, ast.expr)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,7 +13,11 @@ - Issue #1683368: object.__new__ and object.__init__ raise a TypeError if they are passed arguments and their complementary method is not overridden. -- Give the ast.AST class a __dict__. +- Issue #14378: Fix compiling ast.ImportFrom nodes with a "__future__" string as + the module name that was not interned. + +- Issue #14331: Use significantly less stack space when importing modules by + allocating path buffers on the heap instead of the stack. - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not passed strings. diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -60,13 +60,6 @@ { int i, found_docstring = 0, done = 0, prev_line = 0; - static PyObject *future; - if (!future) { - future = PyUnicode_InternFromString("__future__"); - if (!future) - return 0; - } - if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) return 1; @@ -93,7 +86,8 @@ */ if (s->kind == ImportFrom_kind) { - if (s->v.ImportFrom.module == future) { + PyObject *modname = s->v.ImportFrom.module; + if (!PyUnicode_CompareWithASCIIString(modname, "__future__")) { if (done) { PyErr_SetString(PyExc_SyntaxError, ERR_LATE_FUTURE); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 13:58:03 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 13:58:03 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_check_for_NULL?= Message-ID: http://hg.python.org/cpython/rev/1b467efb9b27 changeset: 75870:1b467efb9b27 branch: 3.2 parent: 75868:f57cbcefde34 user: Benjamin Peterson date: Thu Mar 22 08:56:15 2012 -0400 summary: check for NULL files: Python/future.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -87,7 +87,8 @@ if (s->kind == ImportFrom_kind) { PyObject *modname = s->v.ImportFrom.module; - if (!PyUnicode_CompareWithASCIIString(modname, "__future__")) { + if (modname && + !PyUnicode_CompareWithASCIIString(modname, "__future__")) { if (done) { PyErr_SetString(PyExc_SyntaxError, ERR_LATE_FUTURE); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 13:58:05 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 13:58:05 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/db154e62ac03 changeset: 75871:db154e62ac03 parent: 75869:9d793be3b4eb parent: 75870:1b467efb9b27 user: Benjamin Peterson date: Thu Mar 22 08:56:27 2012 -0400 summary: merge 3.2 files: Python/future.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -87,7 +87,8 @@ if (s->kind == ImportFrom_kind) { PyObject *modname = s->v.ImportFrom.module; - if (!PyUnicode_CompareWithASCIIString(modname, "__future__")) { + if (modname && + !PyUnicode_CompareWithASCIIString(modname, "__future__")) { if (done) { PyErr_SetString(PyExc_SyntaxError, ERR_LATE_FUTURE); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 13:58:06 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 13:58:06 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_check_by_equali?= =?utf8?q?ty_for_=5F=5Ffuture=5F=5F_not_identity_=28closes_=2314378=29?= Message-ID: http://hg.python.org/cpython/rev/1729ec440bb6 changeset: 75872:1729ec440bb6 branch: 2.7 parent: 75838:44a8385a8241 user: Benjamin Peterson date: Thu Mar 22 08:19:04 2012 -0400 summary: check by equality for __future__ not identity (closes #14378) files: Lib/test/test_ast.py | 6 ++++++ Misc/NEWS | 3 +++ Python/future.c | 11 +++-------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -231,6 +231,12 @@ im = ast.parse("from . import y").body[0] self.assertIsNone(im.module) + def test_non_interned_future_from_ast(self): + mod = ast.parse("from __future__ import division") + self.assertIsInstance(mod.body[0], ast.ImportFrom) + mod.body[0].module = " __future__ ".strip() + compile(mod, "", "exec") + def test_base_classes(self): self.assertTrue(issubclass(ast.For, ast.stmt)) self.assertTrue(issubclass(ast.Name, ast.expr)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #14378: Fix compiling ast.ImportFrom nodes with a "__future__" string as + the module name that was not interned. + - Issue #14331: Use significantly less stack space when importing modules by allocating path buffers on the heap instead of the stack. diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -59,13 +59,6 @@ { int i, found_docstring = 0, done = 0, prev_line = 0; - static PyObject *future; - if (!future) { - future = PyString_InternFromString("__future__"); - if (!future) - return 0; - } - if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) return 1; @@ -92,7 +85,9 @@ */ if (s->kind == ImportFrom_kind) { - if (s->v.ImportFrom.module == future) { + PyObject *modname = s->v.ImportFrom.module; + if (PyString_GET_SIZE(modname) == 10 && + !strcmp(PyString_AS_STRING(modname), "__future__")) { if (done) { PyErr_SetString(PyExc_SyntaxError, ERR_LATE_FUTURE); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 13:58:11 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 13:58:11 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_check_for_NULL?= Message-ID: http://hg.python.org/cpython/rev/ad5e93ae22ef changeset: 75873:ad5e93ae22ef branch: 2.7 user: Benjamin Peterson date: Thu Mar 22 08:56:15 2012 -0400 summary: check for NULL files: Python/future.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -86,7 +86,7 @@ if (s->kind == ImportFrom_kind) { PyObject *modname = s->v.ImportFrom.module; - if (PyString_GET_SIZE(modname) == 10 && + if (modname && PyString_GET_SIZE(modname) == 10 && !strcmp(PyString_AS_STRING(modname), "__future__")) { if (done) { PyErr_SetString(PyExc_SyntaxError, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 13:58:14 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 13:58:14 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/c2d0bf94615d changeset: 75874:c2d0bf94615d branch: 2.7 parent: 75873:ad5e93ae22ef parent: 75861:c50db3d06116 user: Benjamin Peterson date: Thu Mar 22 08:57:56 2012 -0400 summary: merge heads files: Lib/asyncore.py | 1 + Lib/doctest.py | 10 +++++++--- Lib/idlelib/NEWS.txt | 7 +++++++ Lib/idlelib/PyShell.py | 6 ++++-- Misc/NEWS | 9 +++++++++ 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -345,6 +345,7 @@ err = self.socket.connect_ex(address) if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ or err == EINVAL and os.name in ('nt', 'ce'): + self.addr = address return if err in (0, EISCONN): self.addr = address diff --git a/Lib/doctest.py b/Lib/doctest.py --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -2314,7 +2314,8 @@ return "Doctest: " + self._dt_test.name class SkipDocTestCase(DocTestCase): - def __init__(self): + def __init__(self, module): + self.module = module DocTestCase.__init__(self, None) def setUp(self): @@ -2324,7 +2325,10 @@ pass def shortDescription(self): - return "Skipping tests from %s" % module.__name__ + return "Skipping tests from %s" % self.module.__name__ + + __str__ = shortDescription + def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, **options): @@ -2372,7 +2376,7 @@ if not tests and sys.flags.optimize >=2: # Skip doctests when running with -O2 suite = unittest.TestSuite() - suite.addTest(SkipDocTestCase()) + suite.addTest(SkipDocTestCase(module)) return suite elif not tests: # Why do we want to do this? Because it reveals a bug that might diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,3 +1,10 @@ +What's New in IDLE 2.7.3? +======================= + +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)). + + What's New in IDLE 2.7.2? ======================= diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1412,8 +1412,10 @@ if enable_edit: if not (cmd or script): - for filename in args: - flist.open(filename) + for filename in args[:]: + if flist.open(filename) is None: + # filename is a directory actually, disconsider it + args.remove(filename) if not args: flist.new() if enable_shell: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,15 @@ Library ------- +- Issue #12757: Fix the skipping of doctests when python is run with -OO so + that it works in unittest's verbose mode as well as non-verbose mode. + +- Issue #3573: IDLE hangs when passing invalid command line args + (directory(ies) instead of file(s)) (Patch by Guilherme Polo) + +- Issue #13694: asynchronous connect in asyncore.dispatcher does not set addr + attribute. + - Issue #10484: Fix the CGIHTTPServer's PATH_INFO handling problem. - Issue #11199: Fix the with urllib which hangs on particular ftp urls. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 14:48:53 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 22 Mar 2012 14:48:53 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0Mzg3?= =?utf8?q?=3A_Do_not_include_accu=2Eh_from_Python=2Eh=2E?= Message-ID: http://hg.python.org/cpython/rev/f34ac2e9d5cf changeset: 75875:f34ac2e9d5cf branch: 3.2 parent: 75870:1b467efb9b27 user: Antoine Pitrou date: Thu Mar 22 14:38:16 2012 +0100 summary: Issue #14387: Do not include accu.h from Python.h. files: Include/Python.h | 1 - Misc/NEWS | 2 ++ Objects/accu.c | 1 + Objects/listobject.c | 1 + Objects/tupleobject.c | 1 + 5 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Include/Python.h b/Include/Python.h --- a/Include/Python.h +++ b/Include/Python.h @@ -100,7 +100,6 @@ #include "warnings.h" #include "weakrefobject.h" #include "structseq.h" -#include "accu.h" #include "codecs.h" #include "pyerrors.h" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -93,6 +93,8 @@ Build ----- +- Issue #14387: Do not include accu.h from Python.h. + - Issue #14359: Only use O_CLOEXEC in _posixmodule.c if it is defined. Based on patch from Herv? Coatanhay. diff --git a/Objects/accu.c b/Objects/accu.c --- a/Objects/accu.c +++ b/Objects/accu.c @@ -1,6 +1,7 @@ /* Accumulator struct implementation */ #include "Python.h" +#include "accu.h" static PyObject * join_list_unicode(PyObject *lst) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1,6 +1,7 @@ /* List object implementation */ #include "Python.h" +#include "accu.h" #ifdef STDC_HEADERS #include diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -2,6 +2,7 @@ /* Tuple object implementation */ #include "Python.h" +#include "accu.h" /* Speed optimization to avoid frequent malloc/free of small tuples */ #ifndef PyTuple_MAXSAVESIZE -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 14:48:55 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 22 Mar 2012 14:48:55 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314387=3A_Do_not_include_accu=2Eh_from_Python=2Eh=2E?= Message-ID: http://hg.python.org/cpython/rev/5fe7d19ec49a changeset: 75876:5fe7d19ec49a parent: 75871:db154e62ac03 parent: 75875:f34ac2e9d5cf user: Antoine Pitrou date: Thu Mar 22 14:42:18 2012 +0100 summary: Issue #14387: Do not include accu.h from Python.h. files: Include/Python.h | 1 - Misc/NEWS | 2 ++ Modules/_io/stringio.c | 1 + Modules/_json.c | 2 ++ Objects/accu.c | 1 + Objects/listobject.c | 1 + Objects/stringlib/unicode_format.h | 1 + Objects/tupleobject.c | 1 + 8 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Include/Python.h b/Include/Python.h --- a/Include/Python.h +++ b/Include/Python.h @@ -101,7 +101,6 @@ #include "warnings.h" #include "weakrefobject.h" #include "structseq.h" -#include "accu.h" #include "codecs.h" #include "pyerrors.h" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -155,6 +155,8 @@ Build ----- +- Issue #14387: Do not include accu.h from Python.h. + - Issue #14359: Only use O_CLOEXEC in _posixmodule.c if it is defined. Based on patch from Herv? Coatanhay. diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -1,6 +1,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "structmember.h" +#include "accu.h" #include "_iomodule.h" /* Implementation note: the buffer is always at least one character longer diff --git a/Modules/_json.c b/Modules/_json.c --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1,5 +1,7 @@ #include "Python.h" #include "structmember.h" +#include "accu.h" + #if PY_VERSION_HEX < 0x02060000 && !defined(Py_TYPE) #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #endif diff --git a/Objects/accu.c b/Objects/accu.c --- a/Objects/accu.c +++ b/Objects/accu.c @@ -1,6 +1,7 @@ /* Accumulator struct implementation */ #include "Python.h" +#include "accu.h" static PyObject * join_list_unicode(PyObject *lst) diff --git a/Objects/listobject.c b/Objects/listobject.c --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1,6 +1,7 @@ /* List object implementation */ #include "Python.h" +#include "accu.h" #ifdef STDC_HEADERS #include diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -2,6 +2,7 @@ unicode_format.h -- implementation of str.format(). */ +#include "accu.h" /* Defines for more efficiently reallocating the string buffer */ #define INITIAL_SIZE_INCREMENT 100 diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -2,6 +2,7 @@ /* Tuple object implementation */ #include "Python.h" +#include "accu.h" /* Speed optimization to avoid frequent malloc/free of small tuples */ #ifndef PyTuple_MAXSAVESIZE -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 15:40:29 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 15:40:29 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_this_should_tec?= =?utf8?q?hnicaly_be_identifier?= Message-ID: http://hg.python.org/cpython/rev/79422b3684f1 changeset: 75877:79422b3684f1 branch: 3.2 parent: 75875:f34ac2e9d5cf user: Benjamin Peterson date: Thu Mar 22 10:39:16 2012 -0400 summary: this should technicaly be identifier files: Python/future.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -86,7 +86,7 @@ */ if (s->kind == ImportFrom_kind) { - PyObject *modname = s->v.ImportFrom.module; + identifier *modname = s->v.ImportFrom.module; if (modname && !PyUnicode_CompareWithASCIIString(modname, "__future__")) { if (done) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 15:40:30 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 15:40:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_this_should_tec?= =?utf8?q?hnicaly_be_identifier?= Message-ID: http://hg.python.org/cpython/rev/e303c55be470 changeset: 75878:e303c55be470 branch: 2.7 parent: 75874:c2d0bf94615d user: Benjamin Peterson date: Thu Mar 22 10:39:16 2012 -0400 summary: this should technicaly be identifier files: Python/future.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -85,7 +85,7 @@ */ if (s->kind == ImportFrom_kind) { - PyObject *modname = s->v.ImportFrom.module; + identifier modname = s->v.ImportFrom.module; if (modname && PyString_GET_SIZE(modname) == 10 && !strcmp(PyString_AS_STRING(modname), "__future__")) { if (done) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 15:40:31 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 15:40:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/61aa76adca20 changeset: 75879:61aa76adca20 parent: 75876:5fe7d19ec49a parent: 75877:79422b3684f1 user: Benjamin Peterson date: Thu Mar 22 10:40:20 2012 -0400 summary: merge 3.2 files: Python/future.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -86,7 +86,7 @@ */ if (s->kind == ImportFrom_kind) { - PyObject *modname = s->v.ImportFrom.module; + identifier *modname = s->v.ImportFrom.module; if (modname && !PyUnicode_CompareWithASCIIString(modname, "__future__")) { if (done) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 16:06:52 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Thu, 22 Mar 2012 16:06:52 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogZml4ICMxMDM0MDog?= =?utf8?q?properly_handle_EINVAL_on_OSX_and_also_avoid_to_call?= Message-ID: http://hg.python.org/cpython/rev/8c19c9914c22 changeset: 75880:8c19c9914c22 branch: 2.7 parent: 75878:e303c55be470 user: Giampaolo Rodola' date: Thu Mar 22 16:06:43 2012 +0100 summary: fix #10340: properly handle EINVAL on OSX and also avoid to call handle_connect() in case of a disconnetected socket which is not meant to connect. files: Lib/asyncore.py | 17 +++++++++-------- Lib/test/test_asyncore.py | 16 ++++++++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -225,6 +225,7 @@ debug = False connected = False accepting = False + connecting = False closing = False addr = None ignore_log_types = frozenset(['warning']) @@ -248,7 +249,7 @@ try: self.addr = sock.getpeername() except socket.error, err: - if err.args[0] == ENOTCONN: + if err.args[0] in (ENOTCONN, EINVAL): # To handle the case where we got an unconnected # socket. self.connected = False @@ -342,6 +343,7 @@ def connect(self, address): self.connected = False + self.connecting = True err = self.socket.connect_ex(address) if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ or err == EINVAL and os.name in ('nt', 'ce'): @@ -401,6 +403,7 @@ def close(self): self.connected = False self.accepting = False + self.connecting = False self.del_channel() try: self.socket.close() @@ -439,7 +442,8 @@ # sockets that are connected self.handle_accept() elif not self.connected: - self.handle_connect_event() + if self.connecting: + self.handle_connect_event() self.handle_read() else: self.handle_read() @@ -450,6 +454,7 @@ raise socket.error(err, _strerror(err)) self.handle_connect() self.connected = True + self.connecting = False def handle_write_event(self): if self.accepting: @@ -458,12 +463,8 @@ return if not self.connected: - #check for errors - err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - if err != 0: - raise socket.error(err, _strerror(err)) - - self.handle_connect_event() + if self.connecting: + self.handle_connect_event() self.handle_write() def handle_expt_event(self): diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -7,6 +7,7 @@ import time import warnings import errno +import struct from test import test_support from test.test_support import TESTFN, run_unittest, unlink @@ -703,6 +704,21 @@ finally: sock.close() + @unittest.skipUnless(threading, 'Threading required for this test.') + @test_support.reap_threads + def test_quick_connect(self): + # see: http://bugs.python.org/issue10340 + server = TCPServer() + t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, count=500)) + t.start() + + for x in xrange(20): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 1, 0)) + s.connect(server.address) + s.close() + class TestAPI_UseSelect(BaseTestAPI): use_poll = False diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,10 @@ Library ------- +- Issue #10340: asyncore - properly handle EINVAL in dispatcher constructor on + OSX; avoid to call handle_connect in case of a disconnected socket which + was not meant to connect. + - Issue #12757: Fix the skipping of doctests when python is run with -OO so that it works in unittest's verbose mode as well as non-verbose mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 16:19:53 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Thu, 22 Mar 2012 16:19:53 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogZml4ICMxMDM0MDog?= =?utf8?q?properly_handle_EINVAL_on_OSX_and_also_avoid_to_call?= Message-ID: http://hg.python.org/cpython/rev/e2cddb3f4526 changeset: 75881:e2cddb3f4526 branch: 3.2 parent: 75877:79422b3684f1 user: Giampaolo Rodola' date: Thu Mar 22 16:17:43 2012 +0100 summary: fix #10340: properly handle EINVAL on OSX and also avoid to call handle_connect() in case of a disconnetected socket which is not meant to connect. files: Lib/asyncore.py | 17 +++++++++-------- Lib/test/test_asyncore.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -225,6 +225,7 @@ debug = False connected = False accepting = False + connecting = False closing = False addr = None ignore_log_types = frozenset(['warning']) @@ -248,7 +249,7 @@ try: self.addr = sock.getpeername() except socket.error as err: - if err.args[0] == ENOTCONN: + if err.args[0] in (ENOTCONN, EINVAL): # To handle the case where we got an unconnected # socket. self.connected = False @@ -342,6 +343,7 @@ def connect(self, address): self.connected = False + self.connecting = True err = self.socket.connect_ex(address) if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ or err == EINVAL and os.name in ('nt', 'ce'): @@ -401,6 +403,7 @@ def close(self): self.connected = False self.accepting = False + self.connecting = False self.del_channel() try: self.socket.close() @@ -439,7 +442,8 @@ # sockets that are connected self.handle_accept() elif not self.connected: - self.handle_connect_event() + if self.connecting: + self.handle_connect_event() self.handle_read() else: self.handle_read() @@ -450,6 +454,7 @@ raise socket.error(err, _strerror(err)) self.handle_connect() self.connected = True + self.connecting = False def handle_write_event(self): if self.accepting: @@ -458,12 +463,8 @@ return if not self.connected: - #check for errors - err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - if err != 0: - raise socket.error(err, _strerror(err)) - - self.handle_connect_event() + if self.connecting: + self.handle_connect_event() self.handle_write() def handle_expt_event(self): diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -7,6 +7,7 @@ import time import warnings import errno +import struct from test import support from test.support import TESTFN, run_unittest, unlink @@ -730,6 +731,21 @@ finally: sock.close() + @unittest.skipUnless(threading, 'Threading required for this test.') + @support.reap_threads + def test_quick_connect(self): + # see: http://bugs.python.org/issue10340 + server = TCPServer() + t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, count=500)) + t.start() + + for x in range(20): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 1, 0)) + s.connect(server.address) + s.close() + class TestAPI_UseSelect(BaseTestAPI): use_poll = False -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 16:19:54 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Thu, 22 Mar 2012 16:19:54 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_79422b3684f1_in_3=2E3_branch_=28issue_10340=29?= Message-ID: http://hg.python.org/cpython/rev/6ffdca50a5ef changeset: 75882:6ffdca50a5ef parent: 75879:61aa76adca20 parent: 75881:e2cddb3f4526 user: Giampaolo Rodola' date: Thu Mar 22 16:19:45 2012 +0100 summary: merge 79422b3684f1 in 3.3 branch (issue 10340) files: Lib/asyncore.py | 17 +++++++++-------- Lib/test/test_asyncore.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -217,6 +217,7 @@ debug = False connected = False accepting = False + connecting = False closing = False addr = None ignore_log_types = frozenset(['warning']) @@ -240,7 +241,7 @@ try: self.addr = sock.getpeername() except socket.error as err: - if err.args[0] == ENOTCONN: + if err.args[0] in (ENOTCONN, EINVAL): # To handle the case where we got an unconnected # socket. self.connected = False @@ -334,6 +335,7 @@ def connect(self, address): self.connected = False + self.connecting = True err = self.socket.connect_ex(address) if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ or err == EINVAL and os.name in ('nt', 'ce'): @@ -393,6 +395,7 @@ def close(self): self.connected = False self.accepting = False + self.connecting = False self.del_channel() try: self.socket.close() @@ -431,7 +434,8 @@ # sockets that are connected self.handle_accept() elif not self.connected: - self.handle_connect_event() + if self.connecting: + self.handle_connect_event() self.handle_read() else: self.handle_read() @@ -442,6 +446,7 @@ raise socket.error(err, _strerror(err)) self.handle_connect() self.connected = True + self.connecting = False def handle_write_event(self): if self.accepting: @@ -450,12 +455,8 @@ return if not self.connected: - #check for errors - err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - if err != 0: - raise socket.error(err, _strerror(err)) - - self.handle_connect_event() + if self.connecting: + self.handle_connect_event() self.handle_write() def handle_expt_event(self): diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -7,6 +7,7 @@ import time import warnings import errno +import struct from test import support from test.support import TESTFN, run_unittest, unlink @@ -778,6 +779,21 @@ finally: sock.close() + @unittest.skipUnless(threading, 'Threading required for this test.') + @support.reap_threads + def test_quick_connect(self): + # see: http://bugs.python.org/issue10340 + server = TCPServer() + t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, count=500)) + t.start() + + for x in range(20): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 1, 0)) + s.connect(server.address) + s.close() + class TestAPI_UseIPv4Sockets(BaseTestAPI): family = socket.AF_INET -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 16:23:39 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Thu, 22 Mar 2012 16:23:39 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_issue_10340_-_f?= =?utf8?q?orgot_to_update_Misc/NEWS?= Message-ID: http://hg.python.org/cpython/rev/8c1fd9276b25 changeset: 75883:8c1fd9276b25 branch: 3.2 parent: 75881:e2cddb3f4526 user: Giampaolo Rodola' date: Thu Mar 22 16:22:06 2012 +0100 summary: issue 10340 - forgot to update Misc/NEWS files: Misc/NEWS | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,10 @@ Library ------- +- Issue #10340: asyncore - properly handle EINVAL in dispatcher constructor on + OSX; avoid to call handle_connect in case of a disconnected socket which + was not meant to connect. + - Issue #12757: Fix the skipping of doctests when python is run with -OO so that it works in unittest's verbose mode as well as non-verbose mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 16:24:40 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Thu, 22 Mar 2012 16:24:40 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_=2310340=3A_properly_ha?= =?utf8?q?ndle_EINVAL_on_OSX_and_also_avoid_to_call?= Message-ID: http://hg.python.org/cpython/rev/13cefcbcc7da changeset: 75884:13cefcbcc7da parent: 75882:6ffdca50a5ef user: Giampaolo Rodola' date: Thu Mar 22 16:24:33 2012 +0100 summary: fix #10340: properly handle EINVAL on OSX and also avoid to call handle_connect() in case of a disconnetected socket which is not meant to connect. files: Misc/NEWS | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,10 @@ Library ------- +- Issue #10340: asyncore - properly handle EINVAL in dispatcher constructor on + OSX; avoid to call handle_connect in case of a disconnected socket which + was not meant to connect. + - Issue #14204: The ssl module now has support for the Next Protocol Negotiation extension, if available in the underlying OpenSSL library. Patch by Colin Marc. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 17:37:32 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Thu, 22 Mar 2012 17:37:32 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEwNTM4?= =?utf8?q?=2E_Put_a_reference_to_the_source_object_in_the_Py=5Fbuffer_when?= Message-ID: http://hg.python.org/cpython/rev/17c671529f7e changeset: 75885:17c671529f7e branch: 2.7 parent: 75880:8c19c9914c22 user: Kristj?n Valur J?nsson date: Thu Mar 22 16:35:37 2012 +0000 summary: Issue #10538. Put a reference to the source object in the Py_buffer when converting the old buffer for PyArgs_ParseTuple with *s files: Python/getargs.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1410,7 +1410,7 @@ *errmsg = "convertible to a buffer"; return count; } - PyBuffer_FillInfo(view, NULL, buf, count, 1, 0); + PyBuffer_FillInfo(view, arg, buf, count, 1, 0); return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 20:30:15 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 22 Mar 2012 20:30:15 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/5f0ec33b3b1b changeset: 75886:5f0ec33b3b1b parent: 75884:13cefcbcc7da parent: 75883:8c1fd9276b25 user: Benjamin Peterson date: Thu Mar 22 15:30:03 2012 -0400 summary: merge 3.2 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 21:20:20 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Thu, 22 Mar 2012 21:20:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Issue_=2310538_?= =?utf8?q?-_Update_Misc/NEWS?= Message-ID: http://hg.python.org/cpython/rev/8efe88c0f14e changeset: 75887:8efe88c0f14e branch: 2.7 parent: 75885:17c671529f7e user: krisvale date: Thu Mar 22 20:17:42 2012 +0000 summary: Issue #10538 - Update Misc/NEWS files: Misc/NEWS | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,11 @@ - Issue #13521: dict.setdefault() now does only one lookup for the given key, making it "atomic" for many purposes. Patch by Filip Gruszczy?ski. +- Issue #10538: When using the "s*" code with PyArg_ParseTuple() to fill a + Py_buffer structure with data from an object supporting only the old + PyBuffer interface, a reference to the source objects is now properly added + to the Py_buffer.obj member. + Library ------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 21:35:22 2012 From: python-checkins at python.org (ned.deily) Date: Thu, 22 Mar 2012 21:35:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314382=3A_Ensure_ne?= =?utf8?q?w_unittest=2Etest=2Etestmock_is_installed=2E?= Message-ID: http://hg.python.org/cpython/rev/1ec74eeda4e8 changeset: 75888:1ec74eeda4e8 parent: 75886:5f0ec33b3b1b user: Ned Deily date: Thu Mar 22 13:34:11 2012 -0700 summary: Issue #14382: Ensure new unittest.test.testmock is installed. (Original patch by Vinay Sajip) files: Makefile.pre.in | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1019,7 +1019,7 @@ packaging/tests/pypiserver/with_real_externals/simple/foobar \ turtledemo \ multiprocessing multiprocessing/dummy \ - unittest unittest/test \ + unittest unittest/test unittest/test/testmock \ curses pydoc_data $(MACHDEPS) libinstall: build_all $(srcdir)/Lib/$(PLATDIR) $(srcdir)/Modules/xxmodule.c @for i in $(SCRIPTDIR) $(LIBDEST); \ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 22 22:20:53 2012 From: python-checkins at python.org (georg.brandl) Date: Thu, 22 Mar 2012 22:20:53 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_indentation=2E?= Message-ID: http://hg.python.org/cpython/rev/449a0eae0415 changeset: 75889:449a0eae0415 user: Georg Brandl date: Thu Mar 22 22:20:21 2012 +0100 summary: Fix indentation. files: Doc/library/stdtypes.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1663,14 +1663,15 @@ Return the number of *i*'s for which ``s[i] == x``. - .. versionadded:: 3.2 + .. versionadded:: 3.2 .. method:: range.index(x) Return the smallest *i* such that ``s[i] == x``. Raises :exc:`ValueError` when *x* is not in the range. - .. versionadded:: 3.2 + .. versionadded:: 3.2 + .. _typesseq-mutable: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 00:16:42 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Fri, 23 Mar 2012 00:16:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Issue_=2314387_?= =?utf8?q?=3A_undefine_=27small=27_so_that_it_doesn=27t_clash_with_Windows?= =?utf8?q?_headers=2E?= Message-ID: http://hg.python.org/cpython/rev/aff7ff2aae8c changeset: 75890:aff7ff2aae8c branch: 3.2 parent: 75883:8c1fd9276b25 user: Kristj?n Valur J?nsson date: Thu Mar 22 23:10:37 2012 +0000 summary: Issue #14387 : undefine 'small' so that it doesn't clash with Windows headers. files: Include/accu.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Include/accu.h b/Include/accu.h --- a/Include/accu.h +++ b/Include/accu.h @@ -16,6 +16,8 @@ extern "C" { #endif +#undef small /* defined by some Windows headers */ + typedef struct { PyObject *large; /* A list of previously accumulated large strings */ PyObject *small; /* Pending small strings */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 00:16:42 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Fri, 23 Mar 2012 00:16:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_with_3=2E2_=28Issue_=2314387=29?= Message-ID: http://hg.python.org/cpython/rev/780aaa7b4b62 changeset: 75891:780aaa7b4b62 parent: 75889:449a0eae0415 parent: 75890:aff7ff2aae8c user: Kristj?n Valur J?nsson date: Thu Mar 22 23:13:48 2012 +0000 summary: Merge with 3.2 (Issue #14387) files: Include/accu.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Include/accu.h b/Include/accu.h --- a/Include/accu.h +++ b/Include/accu.h @@ -16,6 +16,8 @@ extern "C" { #endif +#undef small /* defined by some Windows headers */ + typedef struct { PyObject *large; /* A list of previously accumulated large strings */ PyObject *small; /* Pending small strings */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 03:18:02 2012 From: python-checkins at python.org (r.david.murray) Date: Fri, 23 Mar 2012 03:18:02 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=2314380=3A_Have_MIMEText_d?= =?utf8?q?efaults_to_utf-8_when_passed_non-ASCII_unicode?= Message-ID: http://hg.python.org/cpython/rev/bfd1ba2bbaf8 changeset: 75892:bfd1ba2bbaf8 user: R David Murray date: Thu Mar 22 22:17:51 2012 -0400 summary: #14380: Have MIMEText defaults to utf-8 when passed non-ASCII unicode Previously it would just accept the unicode, which would wind up as unicode in the transfer-encoded message object, which is just wrong. Patch by Jeff Knupp. files: Doc/library/email.mime.rst | 6 +++--- Lib/email/mime/text.py | 10 ++++++++++ Lib/test/test_email/test_email.py | 15 ++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Doc/library/email.mime.rst b/Doc/library/email.mime.rst --- a/Doc/library/email.mime.rst +++ b/Doc/library/email.mime.rst @@ -175,7 +175,7 @@ .. currentmodule:: email.mime.text -.. class:: MIMEText(_text, _subtype='plain', _charset='us-ascii') +.. class:: MIMEText(_text, _subtype='plain', _charset=None) Module: :mod:`email.mime.text` @@ -185,5 +185,5 @@ minor type and defaults to :mimetype:`plain`. *_charset* is the character set of the text and is passed as a parameter to the :class:`~email.mime.nonmultipart.MIMENonMultipart` constructor; it defaults - to ``us-ascii``. No guessing or encoding is performed on the text data. - + to ``us-ascii`` if the string contains only ``ascii`` codepoints, and + ``utf-8`` otherwise. diff --git a/Lib/email/mime/text.py b/Lib/email/mime/text.py --- a/Lib/email/mime/text.py +++ b/Lib/email/mime/text.py @@ -27,4 +27,14 @@ """ MIMENonMultipart.__init__(self, 'text', _subtype, **{'charset': _charset}) + + # If _charset was defualted, check to see see if there are non-ascii + # characters present. Default to utf-8 if there are. + # XXX: This can be removed once #7304 is fixed. + if _charset =='us-ascii': + try: + _text.encode(_charset) + except UnicodeEncodeError: + _charset = 'utf-8' + self.set_payload(_text, _charset) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -617,6 +617,19 @@ abc """)) + def test_unicode_body_defaults_to_utf8_encoding(self): + # Issue 14291 + m = MIMEText('? testabc\n') + self.assertEqual(str(m),textwrap.dedent("""\ + MIME-Version: 1.0 + Content-Type: text/plain; charset="utf-8" + Content-Transfer-Encoding: base64 + + w4kgdGVzdGFiYwo= + """)) + + + # Test the email.encoders module class TestEncoders(unittest.TestCase): @@ -642,7 +655,7 @@ eq(msg['content-transfer-encoding'], '7bit') # Similar, but with 8bit data msg = MIMEText('hello \xf8 world') - eq(msg['content-transfer-encoding'], '8bit') + eq(msg['content-transfer-encoding'], 'base64') # And now with a different charset msg = MIMEText('hello \xf8 world', _charset='iso-8859-1') eq(msg['content-transfer-encoding'], 'quoted-printable') diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -548,6 +548,7 @@ Kim Knapp Lenny Kneler Pat Knight +Jeff Knupp Greg Kochanski Damon Kohler Marko Kohtala diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ Library ------- +- Issue #14380: MIMEText now defaults to utf-8 when passed non-ASCII unicode + with no charset specified. + - Issue #10340: asyncore - properly handle EINVAL in dispatcher constructor on OSX; avoid to call handle_connect in case of a disconnected socket which was not meant to connect. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 03:41:20 2012 From: python-checkins at python.org (r.david.murray) Date: Fri, 23 Mar 2012 03:41:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_=2314380=3A_Make_actual_def?= =?utf8?q?ault_match_docs=2C_fix_=5F=5Finit=5F=5F_order=2E?= Message-ID: http://hg.python.org/cpython/rev/9ceac471bd8c changeset: 75893:9ceac471bd8c user: R David Murray date: Thu Mar 22 22:40:44 2012 -0400 summary: #14380: Make actual default match docs, fix __init__ order. ?ric pointed out that given that the default was documented as None, someone would reasonably pass that to get the default behavior. In fixing the code to use None, I noticed that the change to _charset was being done after it had already been passed to MIMENonMultipart. The change to the test verifies that the order is now correct. files: Lib/email/mime/text.py | 22 ++++++++++-------- Lib/test/test_email/test_email.py | 3 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Lib/email/mime/text.py b/Lib/email/mime/text.py --- a/Lib/email/mime/text.py +++ b/Lib/email/mime/text.py @@ -14,7 +14,7 @@ class MIMEText(MIMENonMultipart): """Class for generating text/* type MIME documents.""" - def __init__(self, _text, _subtype='plain', _charset='us-ascii'): + def __init__(self, _text, _subtype='plain', _charset=None): """Create a text/* type MIME document. _text is the string for this message object. @@ -25,16 +25,18 @@ header. This defaults to "us-ascii". Note that as a side-effect, the Content-Transfer-Encoding header will also be set. """ + + # If no _charset was specified, check to see see if there are non-ascii + # characters present. If not, use 'us-ascii', otherwise use utf-8. + # XXX: This can be removed once #7304 is fixed. + if _charset is None: + try: + _text.encode('us-ascii') + _charset = 'us-ascii' + except UnicodeEncodeError: + _charset = 'utf-8' + MIMENonMultipart.__init__(self, 'text', _subtype, **{'charset': _charset}) - # If _charset was defualted, check to see see if there are non-ascii - # characters present. Default to utf-8 if there are. - # XXX: This can be removed once #7304 is fixed. - if _charset =='us-ascii': - try: - _text.encode(_charset) - except UnicodeEncodeError: - _charset = 'utf-8' - self.set_payload(_text, _charset) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -621,15 +621,14 @@ # Issue 14291 m = MIMEText('? testabc\n') self.assertEqual(str(m),textwrap.dedent("""\ + Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 - Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 w4kgdGVzdGFiYwo= """)) - # Test the email.encoders module class TestEncoders(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Mar 23 05:46:00 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 23 Mar 2012 05:46:00 +0100 Subject: [Python-checkins] Daily reference leaks (bfd1ba2bbaf8): sum=0 Message-ID: results for bfd1ba2bbaf8 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogEo1E3e', '-x'] From python-checkins at python.org Fri Mar 23 13:24:52 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 23 Mar 2012 13:24:52 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2313782=3A_streamlin?= =?utf8?q?e_argument_type-checking_in_ET=2EElement?= Message-ID: http://hg.python.org/cpython/rev/75268a773455 changeset: 75894:75268a773455 user: Eli Bendersky date: Fri Mar 23 14:24:20 2012 +0200 summary: Issue #13782: streamline argument type-checking in ET.Element append, extend and insert now consistently type-check their argument in both the C and Python implementations, and raise TypeError for non-Element argument. Added tests files: Doc/library/xml.etree.elementtree.rst | 12 +++++++----- Lib/test/test_xml_etree.py | 12 +++++++++--- Lib/xml/etree/ElementTree.py | 12 ++++++++---- Modules/_elementtree.c | 9 +++++++++ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -281,14 +281,15 @@ .. method:: append(subelement) - Adds the element *subelement* to the end of this elements internal list - of subelements. + Adds the element *subelement* to the end of this element's internal list + of subelements. Raises :exc:`TypeError` if *subelement* is not an + :class:`Element`. .. method:: extend(subelements) Appends *subelements* from a sequence object with zero or more elements. - Raises :exc:`AssertionError` if a subelement is not a valid object. + Raises :exc:`TypeError` if a subelement is not an :class:`Element`. .. versionadded:: 3.2 @@ -325,9 +326,10 @@ Use method :meth:`Element.iter` instead. - .. method:: insert(index, element) + .. method:: insert(index, subelement) - Inserts a subelement at the given position in this element. + Inserts *subelement* at the given position in this element. Raises + :exc:`TypeError` if *subelement* is not an :class:`Element`. .. method:: iter(tag=None) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1839,8 +1839,15 @@ # -------------------------------------------------------------------- +class BasicElementTest(unittest.TestCase): + def test_augmentation_type_errors(self): + e = ET.Element('joe') + self.assertRaises(TypeError, e.append, 'b') + self.assertRaises(TypeError, e.extend, [ET.Element('bar'), 'foo']) + self.assertRaises(TypeError, e.insert, 0, 'foo') + + class ElementTreeTest(unittest.TestCase): - def test_istype(self): self.assertIsInstance(ET.ParseError, type) self.assertIsInstance(ET.QName, type) @@ -1879,7 +1886,6 @@ class TreeBuilderTest(unittest.TestCase): - sample1 = ('' @@ -1931,7 +1937,6 @@ class NoAcceleratorTest(unittest.TestCase): - # Test that the C accelerator was not imported for pyET def test_correct_import_pyET(self): self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') @@ -2096,6 +2101,7 @@ test_classes = [ ElementSlicingTest, + BasicElementTest, StringIOTest, ParseErrorTest, ElementTreeTest, diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -298,7 +298,7 @@ # @param element The element to add. def append(self, element): - # assert iselement(element) + self._assert_is_element(element) self._children.append(element) ## @@ -308,8 +308,8 @@ # @since 1.3 def extend(self, elements): - # for element in elements: - # assert iselement(element) + for element in elements: + self._assert_is_element(element) self._children.extend(elements) ## @@ -318,9 +318,13 @@ # @param index Where to insert the new subelement. def insert(self, index, element): - # assert iselement(element) + self._assert_is_element(element) self._children.insert(index, element) + def _assert_is_element(self, e): + if not isinstance(e, Element): + raise TypeError('expected an Element, not %s' % type(e).__name__) + ## # Removes a matching subelement. Unlike the find methods, # this method compares elements based on identity, not on tag diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -803,6 +803,15 @@ seqlen = PySequence_Size(seq); for (i = 0; i < seqlen; i++) { PyObject* element = PySequence_Fast_GET_ITEM(seq, i); + if (!PyObject_IsInstance(element, (PyObject *)&Element_Type)) { + Py_DECREF(seq); + PyErr_Format( + PyExc_TypeError, + "expected an Element, not \"%.200s\"", + Py_TYPE(element)->tp_name); + return NULL; + } + if (element_add_subelement(self, element) < 0) { Py_DECREF(seq); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 13:30:02 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Fri, 23 Mar 2012 13:30:02 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_failing_asyncore_test_a?= =?utf8?q?s_per_http=3A//bugs=2Epython=2Eorg/issue10340=23msg156586?= Message-ID: http://hg.python.org/cpython/rev/e35a5bbb0b91 changeset: 75895:e35a5bbb0b91 parent: 75893:9ceac471bd8c user: Giampaolo Rodola' date: Fri Mar 23 13:29:01 2012 +0100 summary: fix failing asyncore test as per http://bugs.python.org/issue10340#msg156586 files: Lib/test/test_asyncore.py | 20 +++++++++++--------- 1 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -783,16 +783,18 @@ @support.reap_threads def test_quick_connect(self): # see: http://bugs.python.org/issue10340 - server = TCPServer() - t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, count=500)) - t.start() + if self.family in (socket.AF_INET, getattr(socket, "AF_INET6", object())): + server = BaseServer(self.family, self.addr) + t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, + count=500)) + t.start() - for x in range(20): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, - struct.pack('ii', 1, 0)) - s.connect(server.address) - s.close() + for x in range(20): + s = socket.socket(self.family, socket.SOCK_STREAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 1, 0)) + s.connect(server.address) + s.close() class TestAPI_UseIPv4Sockets(BaseTestAPI): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 13:30:03 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Fri, 23 Mar 2012 13:30:03 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge?= Message-ID: http://hg.python.org/cpython/rev/669893133f9f changeset: 75896:669893133f9f parent: 75895:e35a5bbb0b91 parent: 75894:75268a773455 user: Giampaolo Rodola' date: Fri Mar 23 13:29:49 2012 +0100 summary: merge files: Doc/library/xml.etree.elementtree.rst | 12 +++++++----- Lib/test/test_xml_etree.py | 12 +++++++++--- Lib/xml/etree/ElementTree.py | 12 ++++++++---- Modules/_elementtree.c | 9 +++++++++ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -281,14 +281,15 @@ .. method:: append(subelement) - Adds the element *subelement* to the end of this elements internal list - of subelements. + Adds the element *subelement* to the end of this element's internal list + of subelements. Raises :exc:`TypeError` if *subelement* is not an + :class:`Element`. .. method:: extend(subelements) Appends *subelements* from a sequence object with zero or more elements. - Raises :exc:`AssertionError` if a subelement is not a valid object. + Raises :exc:`TypeError` if a subelement is not an :class:`Element`. .. versionadded:: 3.2 @@ -325,9 +326,10 @@ Use method :meth:`Element.iter` instead. - .. method:: insert(index, element) + .. method:: insert(index, subelement) - Inserts a subelement at the given position in this element. + Inserts *subelement* at the given position in this element. Raises + :exc:`TypeError` if *subelement* is not an :class:`Element`. .. method:: iter(tag=None) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1839,8 +1839,15 @@ # -------------------------------------------------------------------- +class BasicElementTest(unittest.TestCase): + def test_augmentation_type_errors(self): + e = ET.Element('joe') + self.assertRaises(TypeError, e.append, 'b') + self.assertRaises(TypeError, e.extend, [ET.Element('bar'), 'foo']) + self.assertRaises(TypeError, e.insert, 0, 'foo') + + class ElementTreeTest(unittest.TestCase): - def test_istype(self): self.assertIsInstance(ET.ParseError, type) self.assertIsInstance(ET.QName, type) @@ -1879,7 +1886,6 @@ class TreeBuilderTest(unittest.TestCase): - sample1 = ('' @@ -1931,7 +1937,6 @@ class NoAcceleratorTest(unittest.TestCase): - # Test that the C accelerator was not imported for pyET def test_correct_import_pyET(self): self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') @@ -2096,6 +2101,7 @@ test_classes = [ ElementSlicingTest, + BasicElementTest, StringIOTest, ParseErrorTest, ElementTreeTest, diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -298,7 +298,7 @@ # @param element The element to add. def append(self, element): - # assert iselement(element) + self._assert_is_element(element) self._children.append(element) ## @@ -308,8 +308,8 @@ # @since 1.3 def extend(self, elements): - # for element in elements: - # assert iselement(element) + for element in elements: + self._assert_is_element(element) self._children.extend(elements) ## @@ -318,9 +318,13 @@ # @param index Where to insert the new subelement. def insert(self, index, element): - # assert iselement(element) + self._assert_is_element(element) self._children.insert(index, element) + def _assert_is_element(self, e): + if not isinstance(e, Element): + raise TypeError('expected an Element, not %s' % type(e).__name__) + ## # Removes a matching subelement. Unlike the find methods, # this method compares elements based on identity, not on tag diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -803,6 +803,15 @@ seqlen = PySequence_Size(seq); for (i = 0; i < seqlen; i++) { PyObject* element = PySequence_Fast_GET_ITEM(seq, i); + if (!PyObject_IsInstance(element, (PyObject *)&Element_Type)) { + Py_DECREF(seq); + PyErr_Format( + PyExc_TypeError, + "expected an Element, not \"%.200s\"", + Py_TYPE(element)->tp_name); + return NULL; + } + if (element_add_subelement(self, element) < 0) { Py_DECREF(seq); return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 14:01:20 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Fri, 23 Mar 2012 14:01:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_typo_when_?= =?utf8?q?=22PyObject*=22_was_changed_to_=22identifier=22?= Message-ID: http://hg.python.org/cpython/rev/b97964af7299 changeset: 75897:b97964af7299 branch: 3.2 parent: 75890:aff7ff2aae8c user: Kristj?n Valur J?nsson date: Fri Mar 23 12:50:53 2012 +0000 summary: Fix typo when "PyObject*" was changed to "identifier" files: Python/future.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -86,7 +86,7 @@ */ if (s->kind == ImportFrom_kind) { - identifier *modname = s->v.ImportFrom.module; + identifier modname = s->v.ImportFrom.module; if (modname && !PyUnicode_CompareWithASCIIString(modname, "__future__")) { if (done) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 14:01:23 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Fri, 23 Mar 2012 14:01:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/2a60096b3019 changeset: 75898:2a60096b3019 parent: 75896:669893133f9f parent: 75897:b97964af7299 user: Kristj?n Valur J?nsson date: Fri Mar 23 12:52:11 2012 +0000 summary: Merge with 3.2 files: Python/future.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/future.c b/Python/future.c --- a/Python/future.c +++ b/Python/future.c @@ -86,7 +86,7 @@ */ if (s->kind == ImportFrom_kind) { - identifier *modname = s->v.ImportFrom.module; + identifier modname = s->v.ImportFrom.module; if (modname && !PyUnicode_CompareWithASCIIString(modname, "__future__")) { if (done) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 14:49:04 2012 From: python-checkins at python.org (stefan.krah) Date: Fri, 23 Mar 2012 14:49:04 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Use_the_same_exception_hier?= =?utf8?q?archy_as_decimal=2Epy=2E_FloatOperation_now_also?= Message-ID: http://hg.python.org/cpython/rev/94009b75a09d changeset: 75899:94009b75a09d user: Stefan Krah date: Fri Mar 23 14:46:48 2012 +0100 summary: Use the same exception hierarchy as decimal.py. FloatOperation now also inherits from TypeError. Cleanup in module initialization to make repeated import failures robust. files: Doc/library/decimal.rst | 2 +- Lib/decimal.py | 2 +- Lib/test/test_decimal.py | 40 +++++++++++ Modules/_decimal/_decimal.c | 85 +++++++++++++++++++----- 4 files changed, 107 insertions(+), 22 deletions(-) diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -1577,7 +1577,7 @@ InvalidOperation Rounded Subnormal - FloatOperation + FloatOperation(DecimalException, exceptions.TypeError) .. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -391,7 +391,7 @@ In all cases, Inexact, Rounded, and Subnormal will also be raised. """ -class FloatOperation(DecimalException): +class FloatOperation(DecimalException, TypeError): """Enable stricter semantics for mixing floats and Decimals. If the signal is not trapped (default), mixing floats and Decimals is diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -2378,6 +2378,46 @@ self.assertRaises(TypeError, D("-1").copy_abs, context=xc) self.assertRaises(TypeError, D("-1").copy_negate, context=xc) + def test_exception_hierarchy(self): + + decimal = self.decimal + DecimalException = decimal.DecimalException + InvalidOperation = decimal.InvalidOperation + FloatOperation = decimal.FloatOperation + DivisionByZero = decimal.DivisionByZero + Overflow = decimal.Overflow + Underflow = decimal.Underflow + Subnormal = decimal.Subnormal + Inexact = decimal.Inexact + Rounded = decimal.Rounded + Clamped = decimal.Clamped + + self.assertTrue(issubclass(DecimalException, ArithmeticError)) + + self.assertTrue(issubclass(InvalidOperation, DecimalException)) + self.assertTrue(issubclass(FloatOperation, DecimalException)) + self.assertTrue(issubclass(FloatOperation, TypeError)) + self.assertTrue(issubclass(DivisionByZero, DecimalException)) + self.assertTrue(issubclass(DivisionByZero, ZeroDivisionError)) + self.assertTrue(issubclass(Overflow, Rounded)) + self.assertTrue(issubclass(Overflow, Inexact)) + self.assertTrue(issubclass(Overflow, DecimalException)) + self.assertTrue(issubclass(Underflow, Inexact)) + self.assertTrue(issubclass(Underflow, Rounded)) + self.assertTrue(issubclass(Underflow, Subnormal)) + self.assertTrue(issubclass(Underflow, DecimalException)) + + self.assertTrue(issubclass(Subnormal, DecimalException)) + self.assertTrue(issubclass(Inexact, DecimalException)) + self.assertTrue(issubclass(Rounded, DecimalException)) + self.assertTrue(issubclass(Clamped, DecimalException)) + + self.assertTrue(issubclass(decimal.ConversionSyntax, InvalidOperation)) + self.assertTrue(issubclass(decimal.DivisionImpossible, InvalidOperation)) + self.assertTrue(issubclass(decimal.DivisionUndefined, InvalidOperation)) + self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError)) + self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation)) + class CPythonAPItests(PythonAPItests): decimal = C class PyPythonAPItests(PythonAPItests): diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -143,7 +143,10 @@ /* Top level Exception; inherits from ArithmeticError */ static PyObject *DecimalException = NULL; -/* Exceptions that correspond to IEEE signals; inherit from DecimalException */ +/* Exceptions that correspond to IEEE signals */ +#define SUBNORMAL 5 +#define INEXACT 6 +#define ROUNDED 7 #define SIGNAL_MAP_LEN 9 static DecCondMap signal_map[] = { {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, @@ -5403,9 +5406,38 @@ ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); /* Add exceptions that correspond to IEEE signals */ - for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { - ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, - DecimalException, NULL)); + for (i = SIGNAL_MAP_LEN-1; i >= 0; i--) { + PyObject *base; + + cm = signal_map + i; + + switch (cm->flag) { + case MPD_Float_operation: + base = PyTuple_Pack(2, DecimalException, PyExc_TypeError); + break; + case MPD_Division_by_zero: + base = PyTuple_Pack(2, DecimalException, PyExc_ZeroDivisionError); + break; + case MPD_Overflow: + base = PyTuple_Pack(2, signal_map[INEXACT].ex, + signal_map[ROUNDED].ex); + break; + case MPD_Underflow: + base = PyTuple_Pack(3, signal_map[INEXACT].ex, + signal_map[ROUNDED].ex, + signal_map[SUBNORMAL].ex); + break; + default: + base = PyTuple_Pack(1, DecimalException); + break; + } + + if (base == NULL) { + goto error; + } + + ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL)); + Py_DECREF(base); /* add to module */ Py_INCREF(cm->ex); @@ -5425,8 +5457,20 @@ /* Add remaining exceptions, inherit from InvalidOperation */ for (cm = cond_map+1; cm->name != NULL; cm++) { - ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, - signal_map[0].ex, NULL)); + PyObject *base; + if (cm->flag == MPD_Division_undefined) { + base = PyTuple_Pack(2, signal_map[0].ex, PyExc_ZeroDivisionError); + } + else { + base = PyTuple_Pack(1, signal_map[0].ex); + } + if (base == NULL) { + goto error; + } + + ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL)); + Py_DECREF(base); + Py_INCREF(cm->ex); CHECK_INT(PyModule_AddObject(m, cm->name, cm->ex)); } @@ -5472,6 +5516,7 @@ for (ssize_cm = ssize_constants; ssize_cm->name != NULL; ssize_cm++) { ASSIGN_PTR(obj, PyLong_FromSsize_t(ssize_cm->val)); CHECK_INT(PyModule_AddObject(m, ssize_cm->name, obj)); + obj = NULL; } /* Init int constants */ @@ -5488,23 +5533,23 @@ error: - Py_XDECREF(obj); /* GCOV_NOT_REACHED */ - Py_XDECREF(numbers); /* GCOV_NOT_REACHED */ - Py_XDECREF(Number); /* GCOV_NOT_REACHED */ - Py_XDECREF(Rational); /* GCOV_NOT_REACHED */ - Py_XDECREF(collections); /* GCOV_NOT_REACHED */ - Py_XDECREF(MutableMapping); /* GCOV_NOT_REACHED */ - Py_XDECREF(SignalTuple); /* GCOV_NOT_REACHED */ - Py_XDECREF(DecimalTuple); /* GCOV_NOT_REACHED */ + Py_CLEAR(obj); /* GCOV_NOT_REACHED */ + Py_CLEAR(numbers); /* GCOV_NOT_REACHED */ + Py_CLEAR(Number); /* GCOV_NOT_REACHED */ + Py_CLEAR(Rational); /* GCOV_NOT_REACHED */ + Py_CLEAR(collections); /* GCOV_NOT_REACHED */ + Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ + Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */ + Py_CLEAR(DecimalTuple); /* GCOV_NOT_REACHED */ #ifdef WITHOUT_THREADS - Py_XDECREF(module_context); /* GCOV_NOT_REACHED */ + Py_CLEAR(module_context); /* GCOV_NOT_REACHED */ #else - Py_XDECREF(default_context_template); /* GCOV_NOT_REACHED */ - Py_XDECREF(tls_context_key); /* GCOV_NOT_REACHED */ + Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */ + Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */ #endif - Py_XDECREF(basic_context_template); /* GCOV_NOT_REACHED */ - Py_XDECREF(extended_context_template); /* GCOV_NOT_REACHED */ - Py_XDECREF(m); /* GCOV_NOT_REACHED */ + Py_CLEAR(basic_context_template); /* GCOV_NOT_REACHED */ + Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */ + Py_CLEAR(m); /* GCOV_NOT_REACHED */ return NULL; /* GCOV_NOT_REACHED */ } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 15:05:42 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Fri, 23 Mar 2012 15:05:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_attempt_to_fix_?= =?utf8?q?asyncore_buildbot_failure?= Message-ID: http://hg.python.org/cpython/rev/0b960e41e533 changeset: 75900:0b960e41e533 branch: 2.7 parent: 75887:8efe88c0f14e user: Giampaolo Rodola' date: Fri Mar 23 15:04:27 2012 +0100 summary: attempt to fix asyncore buildbot failure files: Lib/test/test_asyncore.py | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -714,10 +714,15 @@ for x in xrange(20): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(.2) s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) - s.connect(server.address) - s.close() + try: + s.connect(server.address) + except socket.error: + pass + finally: + s.close() class TestAPI_UseSelect(BaseTestAPI): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 15:10:05 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Fri, 23 Mar 2012 15:10:05 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_attempt_to_fix_?= =?utf8?q?asyncore_buildbot_failure?= Message-ID: http://hg.python.org/cpython/rev/2db4e916245a changeset: 75901:2db4e916245a branch: 3.2 parent: 75897:b97964af7299 user: Giampaolo Rodola' date: Fri Mar 23 15:07:07 2012 +0100 summary: attempt to fix asyncore buildbot failure files: Lib/test/test_asyncore.py | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -741,11 +741,15 @@ for x in range(20): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(.2) s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) - s.connect(server.address) - s.close() - + try: + s.connect(server.address) + except socket.error: + pass + finally: + s.close() class TestAPI_UseSelect(BaseTestAPI): use_poll = False -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 15:10:06 2012 From: python-checkins at python.org (giampaolo.rodola) Date: Fri, 23 Mar 2012 15:10:06 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_attempt_to_fix_asyncore_buildbot_failure?= Message-ID: http://hg.python.org/cpython/rev/71b66ba4d9c0 changeset: 75902:71b66ba4d9c0 parent: 75899:94009b75a09d parent: 75901:2db4e916245a user: Giampaolo Rodola' date: Fri Mar 23 15:09:58 2012 +0100 summary: attempt to fix asyncore buildbot failure files: Lib/test/test_asyncore.py | 14 +++++++++----- 1 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -789,14 +789,18 @@ count=500)) t.start() - for x in range(20): - s = socket.socket(self.family, socket.SOCK_STREAM) - s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, - struct.pack('ii', 1, 0)) + + s = socket.socket(self.family, socket.SOCK_STREAM) + s.settimeout(.2) + s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 1, 0)) + try: s.connect(server.address) + except socket.error: + pass + finally: s.close() - class TestAPI_UseIPv4Sockets(BaseTestAPI): family = socket.AF_INET addr = (HOST, 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 15:38:30 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 23 Mar 2012 15:38:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314314?= =?utf8?q?=3A_backported_fix=2E?= Message-ID: http://hg.python.org/cpython/rev/113b8e3cbba4 changeset: 75903:113b8e3cbba4 branch: 2.7 parent: 75900:0b960e41e533 user: Vinay Sajip date: Fri Mar 23 14:33:00 2012 +0000 summary: Closes #14314: backported fix. files: Lib/logging/handlers.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -868,6 +868,7 @@ self.toaddrs = toaddrs self.subject = subject self.secure = secure + self._timeout = 5.0 def getSubject(self, record): """ @@ -890,7 +891,7 @@ port = self.mailport if not port: port = smtplib.SMTP_PORT - smtp = smtplib.SMTP(self.mailhost, port) + smtp = smtplib.SMTP(self.mailhost, port, timeout=self._timeout) msg = self.format(record) msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % ( self.fromaddr, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 15:38:30 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 23 Mar 2012 15:38:30 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314314?= =?utf8?q?=3A_backported_fix=2E?= Message-ID: http://hg.python.org/cpython/rev/54055646fd1f changeset: 75904:54055646fd1f branch: 3.2 parent: 75901:2db4e916245a user: Vinay Sajip date: Fri Mar 23 14:36:22 2012 +0000 summary: Closes #14314: backported fix. files: Lib/logging/handlers.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -857,6 +857,7 @@ self.toaddrs = toaddrs self.subject = subject self.secure = secure + self._timeout = 5.0 def getSubject(self, record): """ @@ -879,7 +880,7 @@ port = self.mailport if not port: port = smtplib.SMTP_PORT - smtp = smtplib.SMTP(self.mailhost, port) + smtp = smtplib.SMTP(self.mailhost, port, timeout=self._timeout) msg = self.format(record) msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % ( self.fromaddr, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 15:38:31 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 23 Mar 2012 15:38:31 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Null_merge_for_backported_fix=2E?= Message-ID: http://hg.python.org/cpython/rev/dc0379b90364 changeset: 75905:dc0379b90364 parent: 75902:71b66ba4d9c0 parent: 75904:54055646fd1f user: Vinay Sajip date: Fri Mar 23 14:38:12 2012 +0000 summary: Null merge for backported fix. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 16:38:20 2012 From: python-checkins at python.org (stefan.krah) Date: Fri, 23 Mar 2012 16:38:20 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Whitespace=2E?= Message-ID: http://hg.python.org/cpython/rev/87bb80538fa8 changeset: 75906:87bb80538fa8 parent: 75899:94009b75a09d user: Stefan Krah date: Fri Mar 23 16:22:05 2012 +0100 summary: Whitespace. files: Modules/_decimal/libmpdec/mpdecimal.c | 14 +- Modules/_decimal/libmpdec/umodarith.h | 190 +++++++------- 2 files changed, 102 insertions(+), 102 deletions(-) diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c --- a/Modules/_decimal/libmpdec/mpdecimal.c +++ b/Modules/_decimal/libmpdec/mpdecimal.c @@ -5849,7 +5849,7 @@ t = mpd_adjexp(x); if (t > 0) { - /* x >= 10 -> floor(log10(floor(abs(log10(x))))) */ + /* x >= 10 -> floor(log10(floor(abs(log10(x))))) */ return mpd_exp_digits(t) - 1; } else if (t < -1) { @@ -5907,7 +5907,7 @@ } } else { - /* (0 < |x| < 1 and y > 0) or (|x| > 1 and y < 0). */ + /* (0 < |x| < 1 and y > 0) or (|x| > 1 and y < 0). */ ub_omega = mpd_exp_digits(mpd_etiny(ctx)); if (ub_omega < lb_zeta + lb_theta) { _settriple(result, resultsign, 1, mpd_etiny(ctx)-1); @@ -6637,7 +6637,7 @@ { if (mpd_isspecial(a) || mpd_isspecial(b)) { return ((mpd_isnan(a) && mpd_isnan(b)) || - (mpd_isinfinite(a) && mpd_isinfinite(b))); + (mpd_isinfinite(a) && mpd_isinfinite(b))); } return a->exp == b->exp; @@ -7055,10 +7055,10 @@ u.exp = u.digits - ctx->prec + result->exp - 1; _mpd_qsub(tmp, result, &u, &maxctx, status); - if (*status&MPD_Errors) goto nanresult; + if (*status&MPD_Errors) goto nanresult; _mpd_qmul(tmp, tmp, tmp, &maxctx, status); - if (*status&MPD_Errors) goto nanresult; + if (*status&MPD_Errors) goto nanresult; if (_mpd_cmp(tmp, a) == 1) { u.exp += 1; @@ -7067,10 +7067,10 @@ } else { _mpd_qadd(tmp, result, &u, &maxctx, status); - if (*status&MPD_Errors) goto nanresult; + if (*status&MPD_Errors) goto nanresult; _mpd_qmul(tmp, tmp, tmp, &maxctx, status); - if (*status&MPD_Errors) goto nanresult; + if (*status&MPD_Errors) goto nanresult; if (_mpd_cmp(tmp, a) == -1) { u.exp += 1; diff --git a/Modules/_decimal/libmpdec/umodarith.h b/Modules/_decimal/libmpdec/umodarith.h --- a/Modules/_decimal/libmpdec/umodarith.h +++ b/Modules/_decimal/libmpdec/umodarith.h @@ -403,18 +403,18 @@ mpd_uint_t retval; asm ( - "fildl %2\n\t" - "fildl %1\n\t" - "fmulp %%st, %%st(1)\n\t" - "fldt (%4)\n\t" - "fmul %%st(1), %%st\n\t" - "flds %5\n\t" - "fadd %%st, %%st(1)\n\t" - "fsubrp %%st, %%st(1)\n\t" - "fldl (%3)\n\t" - "fmulp %%st, %%st(1)\n\t" - "fsubrp %%st, %%st(1)\n\t" - "fistpl %0\n\t" + "fildl %2\n\t" + "fildl %1\n\t" + "fmulp %%st, %%st(1)\n\t" + "fldt (%4)\n\t" + "fmul %%st(1), %%st\n\t" + "flds %5\n\t" + "fadd %%st, %%st(1)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fldl (%3)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fistpl %0\n\t" : "=m" (retval) : "m" (a), "m" (b), "r" (dmod), "r" (dinvmod), "m" (MPD_TWO63) : "st", "memory" @@ -433,24 +433,24 @@ double *dmod, uint32_t *dinvmod) { asm ( - "fildl %2\n\t" - "fildl (%1)\n\t" - "fmul %%st(1), %%st\n\t" - "fxch %%st(1)\n\t" - "fildl (%0)\n\t" - "fmulp %%st, %%st(1) \n\t" - "fldt (%4)\n\t" - "flds %5\n\t" + "fildl %2\n\t" + "fildl (%1)\n\t" + "fmul %%st(1), %%st\n\t" + "fxch %%st(1)\n\t" + "fildl (%0)\n\t" + "fmulp %%st, %%st(1) \n\t" + "fldt (%4)\n\t" + "flds %5\n\t" "fld %%st(2)\n\t" - "fmul %%st(2)\n\t" - "fadd %%st(1)\n\t" - "fsub %%st(1)\n\t" - "fmull (%3)\n\t" + "fmul %%st(2)\n\t" + "fadd %%st(1)\n\t" + "fsub %%st(1)\n\t" + "fmull (%3)\n\t" "fsubrp %%st, %%st(3)\n\t" "fxch %%st(2)\n\t" - "fistpl (%0)\n\t" - "fmul %%st(2)\n\t" - "fadd %%st(1)\n\t" + "fistpl (%0)\n\t" + "fmul %%st(2)\n\t" + "fadd %%st(1)\n\t" "fsubp %%st, %%st(1)\n\t" "fmull (%3)\n\t" "fsubrp %%st, %%st(1)\n\t" @@ -472,36 +472,36 @@ double *dmod, uint32_t *dinvmod) { asm ( - "fildl %3\n\t" - "fildl (%2)\n\t" - "fmulp %%st, %%st(1)\n\t" - "fildl %1\n\t" - "fildl (%0)\n\t" - "fmulp %%st, %%st(1)\n\t" - "fldt (%5)\n\t" + "fildl %3\n\t" + "fildl (%2)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fildl %1\n\t" + "fildl (%0)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fldt (%5)\n\t" "fld %%st(2)\n\t" - "fmul %%st(1), %%st\n\t" - "fxch %%st(1)\n\t" - "fmul %%st(2), %%st\n\t" - "flds %6\n\t" - "fldl (%4)\n\t" - "fxch %%st(3)\n\t" - "fadd %%st(1), %%st\n\t" - "fxch %%st(2)\n\t" - "fadd %%st(1), %%st\n\t" - "fxch %%st(2)\n\t" - "fsub %%st(1), %%st\n\t" - "fxch %%st(2)\n\t" - "fsubp %%st, %%st(1)\n\t" - "fxch %%st(1)\n\t" - "fmul %%st(2), %%st\n\t" - "fxch %%st(1)\n\t" - "fmulp %%st, %%st(2)\n\t" - "fsubrp %%st, %%st(3)\n\t" - "fsubrp %%st, %%st(1)\n\t" - "fxch %%st(1)\n\t" - "fistpl (%2)\n\t" - "fistpl (%0)\n\t" + "fmul %%st(1), %%st\n\t" + "fxch %%st(1)\n\t" + "fmul %%st(2), %%st\n\t" + "flds %6\n\t" + "fldl (%4)\n\t" + "fxch %%st(3)\n\t" + "fadd %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fadd %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fsub %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fsubp %%st, %%st(1)\n\t" + "fxch %%st(1)\n\t" + "fmul %%st(2), %%st\n\t" + "fxch %%st(1)\n\t" + "fmulp %%st, %%st(2)\n\t" + "fsubrp %%st, %%st(3)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fxch %%st(1)\n\t" + "fistpl (%2)\n\t" + "fistpl (%0)\n\t" : : "r" (a0), "m" (b0), "r" (a1), "m" (b1), "r" (dmod), "r" (dinvmod), "m" (MPD_TWO63) @@ -518,20 +518,20 @@ mpd_uint_t retval; __asm { - mov eax, dinvmod - mov edx, dmod + mov eax, dinvmod + mov edx, dmod fild b fild a - fmulp st(1), st - fld TBYTE PTR [eax] + fmulp st(1), st + fld TBYTE PTR [eax] fmul st, st(1) - fld MPD_TWO63 + fld MPD_TWO63 fadd st(1), st - fsubp st(1), st - fld QWORD PTR [edx] - fmulp st(1), st - fsubp st(1), st - fistp retval + fsubp st(1), st + fld QWORD PTR [edx] + fmulp st(1), st + fsubp st(1), st + fistp retval } return retval; @@ -547,32 +547,32 @@ double *dmod, uint32_t *dinvmod) { __asm { - mov ecx, dmod - mov edx, a1 - mov ebx, dinvmod - mov eax, a0 + mov ecx, dmod + mov edx, a1 + mov ebx, dinvmod + mov eax, a0 fild w fild DWORD PTR [edx] fmul st, st(1) fxch st(1) fild DWORD PTR [eax] - fmulp st(1), st - fld TBYTE PTR [ebx] - fld MPD_TWO63 - fld st(2) + fmulp st(1), st + fld TBYTE PTR [ebx] + fld MPD_TWO63 + fld st(2) fmul st, st(2) fadd st, st(1) fsub st, st(1) fmul QWORD PTR [ecx] - fsubp st(3), st + fsubp st(3), st fxch st(2) - fistp DWORD PTR [eax] + fistp DWORD PTR [eax] fmul st, st(2) fadd st, st(1) - fsubrp st(1), st + fsubrp st(1), st fmul QWORD PTR [ecx] - fsubp st(1), st - fistp DWORD PTR [edx] + fsubp st(1), st + fistp DWORD PTR [edx] } } @@ -586,23 +586,23 @@ double *dmod, uint32_t *dinvmod) { __asm { - mov ecx, dmod - mov edx, a1 - mov ebx, dinvmod - mov eax, a0 + mov ecx, dmod + mov edx, a1 + mov ebx, dinvmod + mov eax, a0 fild b1 fild DWORD PTR [edx] - fmulp st(1), st + fmulp st(1), st fild b0 fild DWORD PTR [eax] - fmulp st(1), st - fld TBYTE PTR [ebx] - fld st(2) + fmulp st(1), st + fld TBYTE PTR [ebx] + fld st(2) fmul st, st(1) fxch st(1) fmul st, st(2) - fld DWORD PTR MPD_TWO63 - fld QWORD PTR [ecx] + fld DWORD PTR MPD_TWO63 + fld QWORD PTR [ecx] fxch st(3) fadd st, st(1) fxch st(2) @@ -610,16 +610,16 @@ fxch st(2) fsub st, st(1) fxch st(2) - fsubrp st(1), st + fsubrp st(1), st fxch st(1) fmul st, st(2) fxch st(1) - fmulp st(2), st - fsubp st(3), st - fsubp st(1), st + fmulp st(2), st + fsubp st(3), st + fsubp st(1), st fxch st(1) - fistp DWORD PTR [edx] - fistp DWORD PTR [eax] + fistp DWORD PTR [edx] + fistp DWORD PTR [eax] } } #endif /* PPRO MASM (_MSC_VER) */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 16:38:23 2012 From: python-checkins at python.org (stefan.krah) Date: Fri, 23 Mar 2012 16:38:23 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_formatting_after_removi?= =?utf8?q?ng_tabs=2E?= Message-ID: http://hg.python.org/cpython/rev/b81a1ef8949c changeset: 75907:b81a1ef8949c user: Stefan Krah date: Fri Mar 23 16:34:41 2012 +0100 summary: Fix formatting after removing tabs. files: Modules/_decimal/libmpdec/fourstep.c | 6 ++++-- Modules/_decimal/libmpdec/sixstep.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Modules/_decimal/libmpdec/fourstep.c b/Modules/_decimal/libmpdec/fourstep.c --- a/Modules/_decimal/libmpdec/fourstep.c +++ b/Modules/_decimal/libmpdec/fourstep.c @@ -184,7 +184,8 @@ } } -#if 0 /* An unordered transform is sufficient for convolution. */ +#if 0 + /* An unordered transform is sufficient for convolution. */ /* Transpose the matrix. */ transpose_3xpow2(a, R, C); #endif @@ -213,7 +214,8 @@ assert(n <= 3*MPD_MAXTRANSFORM_2N); -#if 0 /* An unordered transform is sufficient for convolution. */ +#if 0 + /* An unordered transform is sufficient for convolution. */ /* Transpose the matrix, producing an R*C matrix. */ transpose_3xpow2(a, C, R); #endif diff --git a/Modules/_decimal/libmpdec/sixstep.c b/Modules/_decimal/libmpdec/sixstep.c --- a/Modules/_decimal/libmpdec/sixstep.c +++ b/Modules/_decimal/libmpdec/sixstep.c @@ -115,7 +115,8 @@ } mpd_free(tparams); -#if 0 /* An unordered transform is sufficient for convolution. */ +#if 0 + /* An unordered transform is sufficient for convolution. */ /* Transpose the matrix. */ if (!transpose_pow2(a, R, C)) { return 0; @@ -151,7 +152,8 @@ R = ((mpd_size_t)1) << (log2n - (log2n / 2)); /* number of rows */ -#if 0 /* An unordered transform is sufficient for convolution. */ +#if 0 + /* An unordered transform is sufficient for convolution. */ /* Transpose the matrix, producing an R*C matrix. */ if (!transpose_pow2(a, C, R)) { return 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 23 16:38:24 2012 From: python-checkins at python.org (stefan.krah) Date: Fri, 23 Mar 2012 16:38:24 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?b?KTogTWVyZ2Uu?= Message-ID: http://hg.python.org/cpython/rev/60a84d86f1fa changeset: 75908:60a84d86f1fa parent: 75907:b81a1ef8949c parent: 75905:dc0379b90364 user: Stefan Krah date: Fri Mar 23 16:37:41 2012 +0100 summary: Merge. files: Lib/test/test_asyncore.py | 14 +++++++++----- 1 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -789,14 +789,18 @@ count=500)) t.start() - for x in range(20): - s = socket.socket(self.family, socket.SOCK_STREAM) - s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, - struct.pack('ii', 1, 0)) + + s = socket.socket(self.family, socket.SOCK_STREAM) + s.settimeout(.2) + s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, + struct.pack('ii', 1, 0)) + try: s.connect(server.address) + except socket.error: + pass + finally: s.close() - class TestAPI_UseIPv4Sockets(BaseTestAPI): family = socket.AF_INET addr = (HOST, 0) -- Repository URL: http://hg.python.org/cpython From jimjjewett at gmail.com Fri Mar 23 19:03:20 2012 From: jimjjewett at gmail.com (Jim Jewett) Date: Fri, 23 Mar 2012 14:03:20 -0400 Subject: [Python-checkins] cpython (3.2): attempt to fix asyncore buildbot failure In-Reply-To: References: Message-ID: What does this verify? My assumption from the name (test_quick_connect) and the context (an asynchronous server) is that it is verifying the server can handle a certain level of load. Refusing the sockets should then be a failure, or at least a skipped test. Would the below fail even if asyncore.loop were taken out of the threading.Thread target altogether? On Fri, Mar 23, 2012 at 10:10 AM, giampaolo.rodola wrote: > http://hg.python.org/cpython/rev/2db4e916245a > changeset: ? 75901:2db4e916245a > branch: ? ? ?3.2 > parent: ? ? ?75897:b97964af7299 > user: ? ? ? ?Giampaolo Rodola' > date: ? ? ? ?Fri Mar 23 15:07:07 2012 +0100 > summary: > ?attempt to fix asyncore buildbot failure > > files: > ?Lib/test/test_asyncore.py | ?10 +++++++--- > ?1 files changed, 7 insertions(+), 3 deletions(-) > > > diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py > --- a/Lib/test/test_asyncore.py > +++ b/Lib/test/test_asyncore.py > @@ -741,11 +741,15 @@ > > ? ? ? ? for x in range(20): > ? ? ? ? ? ? s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) > + ? ? ? ? ? ?s.settimeout(.2) > ? ? ? ? ? ? s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, > ? ? ? ? ? ? ? ? ? ? ? ? ?struct.pack('ii', 1, 0)) > - ? ? ? ? ? ?s.connect(server.address) > - ? ? ? ? ? ?s.close() > - > + ? ? ? ? ? ?try: > + ? ? ? ? ? ? ? ?s.connect(server.address) > + ? ? ? ? ? ?except socket.error: > + ? ? ? ? ? ? ? ?pass > + ? ? ? ? ? ?finally: > + ? ? ? ? ? ? ? ?s.close() > > ?class TestAPI_UseSelect(BaseTestAPI): > ? ? use_poll = False > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > From python-checkins at python.org Fri Mar 23 19:07:28 2012 From: python-checkins at python.org (stefan.krah) Date: Fri, 23 Mar 2012 19:07:28 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=237652=3A_Enable_lin?= =?utf8?q?king_of_=5Fdecimal=2Eso_against_an_installed_libmpdec=2E?= Message-ID: http://hg.python.org/cpython/rev/f6d646e30028 changeset: 75909:f6d646e30028 user: Stefan Krah date: Fri Mar 23 19:06:27 2012 +0100 summary: Issue #7652: Enable linking of _decimal.so against an installed libmpdec. files: Misc/NEWS | 3 + configure | 18 ++++++++ configure.ac | 9 ++++ setup.py | 88 +++++++++++++++++++++------------------ 4 files changed, 78 insertions(+), 40 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ Library ------- +- Issue #7652: Add --with-system-libmpdec option to configure for linking + the _decimal module against an installed libmpdec. + - Issue #14380: MIMEText now defaults to utf-8 when passed non-ASCII unicode with no charset specified. diff --git a/configure b/configure --- a/configure +++ b/configure @@ -762,6 +762,7 @@ with_libs with_system_expat with_system_ffi +with_system_libmpdec enable_loadable_sqlite_extensions with_dbmliborder with_signal_module @@ -1434,6 +1435,8 @@ --with-system-expat build pyexpat module using an installed expat library --with-system-ffi build _ctypes module using an installed ffi library + --with-system-libmpdec build _decimal module using an installed libmpdec + library --with-dbmliborder=db1:db2:... order to check db backends for dbm. Valid value is a colon separated string with the backend names @@ -8501,6 +8504,21 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_system_ffi" >&5 $as_echo "$with_system_ffi" >&6; } +# Check for use of the system libmpdec library +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-system-libmpdec" >&5 +$as_echo_n "checking for --with-system-libmpdec... " >&6; } + +# Check whether --with-system_libmpdec was given. +if test "${with_system_libmpdec+set}" = set; then : + withval=$with_system_libmpdec; +else + with_system_libmpdec="no" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_system_libmpdec" >&5 +$as_echo "$with_system_libmpdec" >&6; } + # Check for support for loadable sqlite extensions { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-loadable-sqlite-extensions" >&5 $as_echo_n "checking for --enable-loadable-sqlite-extensions... " >&6; } diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -2048,6 +2048,15 @@ AC_MSG_RESULT($with_system_ffi) +# Check for use of the system libmpdec library +AC_MSG_CHECKING(for --with-system-libmpdec) +AC_ARG_WITH(system_libmpdec, + AS_HELP_STRING([--with-system-libmpdec], [build _decimal module using an installed libmpdec library]), + [], + [with_system_libmpdec="no"]) + +AC_MSG_RESULT($with_system_libmpdec) + # Check for support for loadable sqlite extensions AC_MSG_CHECKING(for --enable-loadable-sqlite-extensions) AC_ARG_ENABLE(loadable-sqlite-extensions, diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -1796,42 +1796,53 @@ self.use_system_libffi = True def _decimal_ext(self): - sources = [ - '_decimal/_decimal.c', - '_decimal/libmpdec/basearith.c', - '_decimal/libmpdec/constants.c', - '_decimal/libmpdec/context.c', - '_decimal/libmpdec/convolute.c', - '_decimal/libmpdec/crt.c', - '_decimal/libmpdec/difradix2.c', - '_decimal/libmpdec/fnt.c', - '_decimal/libmpdec/fourstep.c', - '_decimal/libmpdec/io.c', - '_decimal/libmpdec/memory.c', - '_decimal/libmpdec/mpdecimal.c', - '_decimal/libmpdec/numbertheory.c', - '_decimal/libmpdec/sixstep.c', - '_decimal/libmpdec/transpose.c', - ] - depends = [ - '_decimal/docstrings.h', - '_decimal/libmpdec/basearith.h', - '_decimal/libmpdec/bits.h', - '_decimal/libmpdec/constants.h', - '_decimal/libmpdec/convolute.h', - '_decimal/libmpdec/crt.h', - '_decimal/libmpdec/difradix2.h', - '_decimal/libmpdec/fnt.h', - '_decimal/libmpdec/fourstep.h', - '_decimal/libmpdec/io.h', - '_decimal/libmpdec/memory.h', - '_decimal/libmpdec/mpdecimal.h', - '_decimal/libmpdec/numbertheory.h', - '_decimal/libmpdec/sixstep.h', - '_decimal/libmpdec/transpose.h', - '_decimal/libmpdec/typearith.h', - '_decimal/libmpdec/umodarith.h', - ] + extra_compile_args = [] + undef_macros=['NDEBUG'] + if '--with-system-libmpdec' in sysconfig.get_config_var("CONFIG_ARGS"): + include_dirs = [] + libraries = ['mpdec'] + sources = ['_decimal/_decimal.c'] + depends = ['_decimal/docstrings.h'] + else: + include_dirs = ['./Modules/_decimal/libmpdec'] + libraries = [] + sources = [ + '_decimal/_decimal.c', + '_decimal/libmpdec/basearith.c', + '_decimal/libmpdec/constants.c', + '_decimal/libmpdec/context.c', + '_decimal/libmpdec/convolute.c', + '_decimal/libmpdec/crt.c', + '_decimal/libmpdec/difradix2.c', + '_decimal/libmpdec/fnt.c', + '_decimal/libmpdec/fourstep.c', + '_decimal/libmpdec/io.c', + '_decimal/libmpdec/memory.c', + '_decimal/libmpdec/mpdecimal.c', + '_decimal/libmpdec/numbertheory.c', + '_decimal/libmpdec/sixstep.c', + '_decimal/libmpdec/transpose.c', + ] + depends = [ + '_decimal/docstrings.h', + '_decimal/libmpdec/basearith.h', + '_decimal/libmpdec/bits.h', + '_decimal/libmpdec/constants.h', + '_decimal/libmpdec/convolute.h', + '_decimal/libmpdec/crt.h', + '_decimal/libmpdec/difradix2.h', + '_decimal/libmpdec/fnt.h', + '_decimal/libmpdec/fourstep.h', + '_decimal/libmpdec/io.h', + '_decimal/libmpdec/memory.h', + '_decimal/libmpdec/mpdecimal.h', + '_decimal/libmpdec/numbertheory.h', + '_decimal/libmpdec/sixstep.h', + '_decimal/libmpdec/transpose.h', + '_decimal/libmpdec/typearith.h', + '_decimal/libmpdec/umodarith.h', + ] + config = { 'x64': [('CONFIG_64','1'), ('ASM','1')], 'uint128': [('CONFIG_64','1'), ('ANSI','1'), ('HAVE_UINT128_T','1')], @@ -1843,10 +1854,6 @@ 'universal': [('UNIVERSAL','1')] } - include_dirs = ['./Modules/_decimal/libmpdec'] - extra_compile_args = [] - undef_macros=['NDEBUG'] - platform = self.get_platform() cc = sysconfig.get_config_var('CC') sizeof_size_t = sysconfig.get_config_var('SIZEOF_SIZE_T') @@ -1898,6 +1905,7 @@ ext = Extension ( '_decimal', include_dirs=include_dirs, + libraries=libraries, define_macros=define_macros, undef_macros=undef_macros, extra_compile_args=extra_compile_args, -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Mar 24 05:45:52 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 24 Mar 2012 05:45:52 +0100 Subject: [Python-checkins] Daily reference leaks (f6d646e30028): sum=0 Message-ID: results for f6d646e30028 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogpPrdyb', '-x'] From python-checkins at python.org Sat Mar 24 08:12:42 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 24 Mar 2012 08:12:42 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_indentation=2E?= Message-ID: http://hg.python.org/cpython/rev/1b4f18b68a6f changeset: 75910:1b4f18b68a6f user: Georg Brandl date: Sat Mar 24 08:12:41 2012 +0100 summary: Fix indentation. files: Doc/library/stdtypes.rst | 48 ++++++++++++++-------------- 1 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -645,30 +645,30 @@ Here are the rules in detail: - - If ``x = m / n`` is a nonnegative rational number and ``n`` is not divisible - by ``P``, define ``hash(x)`` as ``m * invmod(n, P) % P``, where ``invmod(n, - P)`` gives the inverse of ``n`` modulo ``P``. - - - If ``x = m / n`` is a nonnegative rational number and ``n`` is - divisible by ``P`` (but ``m`` is not) then ``n`` has no inverse - modulo ``P`` and the rule above doesn't apply; in this case define - ``hash(x)`` to be the constant value ``sys.hash_info.inf``. - - - If ``x = m / n`` is a negative rational number define ``hash(x)`` - as ``-hash(-x)``. If the resulting hash is ``-1``, replace it with - ``-2``. - - - The particular values ``sys.hash_info.inf``, ``-sys.hash_info.inf`` - and ``sys.hash_info.nan`` are used as hash values for positive - infinity, negative infinity, or nans (respectively). (All hashable - nans have the same hash value.) - - - For a :class:`complex` number ``z``, the hash values of the real - and imaginary parts are combined by computing ``hash(z.real) + - sys.hash_info.imag * hash(z.imag)``, reduced modulo - ``2**sys.hash_info.width`` so that it lies in - ``range(-2**(sys.hash_info.width - 1), 2**(sys.hash_info.width - - 1))``. Again, if the result is ``-1``, it's replaced with ``-2``. +- If ``x = m / n`` is a nonnegative rational number and ``n`` is not divisible + by ``P``, define ``hash(x)`` as ``m * invmod(n, P) % P``, where ``invmod(n, + P)`` gives the inverse of ``n`` modulo ``P``. + +- If ``x = m / n`` is a nonnegative rational number and ``n`` is + divisible by ``P`` (but ``m`` is not) then ``n`` has no inverse + modulo ``P`` and the rule above doesn't apply; in this case define + ``hash(x)`` to be the constant value ``sys.hash_info.inf``. + +- If ``x = m / n`` is a negative rational number define ``hash(x)`` + as ``-hash(-x)``. If the resulting hash is ``-1``, replace it with + ``-2``. + +- The particular values ``sys.hash_info.inf``, ``-sys.hash_info.inf`` + and ``sys.hash_info.nan`` are used as hash values for positive + infinity, negative infinity, or nans (respectively). (All hashable + nans have the same hash value.) + +- For a :class:`complex` number ``z``, the hash values of the real + and imaginary parts are combined by computing ``hash(z.real) + + sys.hash_info.imag * hash(z.imag)``, reduced modulo + ``2**sys.hash_info.width`` so that it lies in + ``range(-2**(sys.hash_info.width - 1), 2**(sys.hash_info.width - + 1))``. Again, if the result is ``-1``, it's replaced with ``-2``. To clarify the above rules, here's some example Python code, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 24 10:06:48 2012 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 24 Mar 2012 10:06:48 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314154=3A_Reimpleme?= =?utf8?q?nt_the_bigmem_test_memory_watchdog_as_a_subprocess=2E?= Message-ID: http://hg.python.org/cpython/rev/53a2488605e3 changeset: 75911:53a2488605e3 user: Charles-Fran?ois Natali date: Sat Mar 24 10:06:23 2012 +0100 summary: Issue #14154: Reimplement the bigmem test memory watchdog as a subprocess. files: Lib/test/memory_watchdog.py | 28 +++ Lib/test/support.py | 66 +------- Modules/faulthandler.c | 184 ------------------------ 3 files changed, 38 insertions(+), 240 deletions(-) diff --git a/Lib/test/memory_watchdog.py b/Lib/test/memory_watchdog.py new file mode 100644 --- /dev/null +++ b/Lib/test/memory_watchdog.py @@ -0,0 +1,28 @@ +"""Memory watchdog: periodically read the memory usage of the main test process +and print it out, until terminated.""" +# stdin should refer to the process' /proc//statm: we don't pass the +# process' PID to avoid a race condition in case of - unlikely - PID recycling. +# If the process crashes, reading from the /proc entry will fail with ESRCH. + + +import os +import sys +import time + + +try: + page_size = os.sysconf('SC_PAGESIZE') +except (ValueError, AttributeError): + try: + page_size = os.sysconf('SC_PAGE_SIZE') + except (ValueError, AttributeError): + page_size = 4096 + +while True: + sys.stdin.seek(0) + statm = sys.stdin.read() + data = int(statm.split()[5]) + sys.stdout.write(" ... process data size: {data:.1f}G\n" + .format(data=data * page_size / (1024 ** 3))) + sys.stdout.flush() + time.sleep(1) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -36,20 +36,10 @@ multiprocessing = None try: - import faulthandler -except ImportError: - faulthandler = None - -try: import zlib except ImportError: zlib = None -try: - import fcntl -except ImportError: - fcntl = None - __all__ = [ "Error", "TestFailed", "ResourceDenied", "import_module", "verbose", "use_resources", "max_memuse", "record_original_stdout", @@ -1151,62 +1141,26 @@ def __init__(self): self.procfile = '/proc/{pid}/statm'.format(pid=os.getpid()) self.started = False - self.thread = None - try: - self.page_size = os.sysconf('SC_PAGESIZE') - except (ValueError, AttributeError): - try: - self.page_size = os.sysconf('SC_PAGE_SIZE') - except (ValueError, AttributeError): - self.page_size = 4096 - - def consumer(self, fd): - HEADER = "l" - header_size = struct.calcsize(HEADER) - try: - while True: - header = os.read(fd, header_size) - if len(header) < header_size: - # Pipe closed on other end - break - data_len, = struct.unpack(HEADER, header) - data = os.read(fd, data_len) - statm = data.decode('ascii') - data = int(statm.split()[5]) - print(" ... process data size: {data:.1f}G" - .format(data=data * self.page_size / (1024 ** 3))) - finally: - os.close(fd) def start(self): - if not faulthandler or not hasattr(faulthandler, '_file_watchdog'): - return try: - rfd = os.open(self.procfile, os.O_RDONLY) + f = open(self.procfile, 'r') except OSError as e: warnings.warn('/proc not available for stats: {}'.format(e), RuntimeWarning) sys.stderr.flush() return - pipe_fd, wfd = os.pipe() - # set the write end of the pipe non-blocking to avoid blocking the - # watchdog thread when the consumer doesn't drain the pipe fast enough - if fcntl: - flags = fcntl.fcntl(wfd, fcntl.F_GETFL) - fcntl.fcntl(wfd, fcntl.F_SETFL, flags|os.O_NONBLOCK) - # _file_watchdog() doesn't take the GIL in its child thread, and - # therefore collects statistics timely - faulthandler._file_watchdog(rfd, wfd, 1.0) + + watchdog_script = findfile("memory_watchdog.py") + self.mem_watchdog = subprocess.Popen([sys.executable, watchdog_script], + stdin=f, stderr=subprocess.DEVNULL) + f.close() self.started = True - self.thread = threading.Thread(target=self.consumer, args=(pipe_fd,)) - self.thread.daemon = True - self.thread.start() def stop(self): - if not self.started: - return - faulthandler._cancel_file_watchdog() - self.thread.join() + if self.started: + self.mem_watchdog.terminate() + self.mem_watchdog.wait() def bigmemtest(size, memuse, dry_run=True): @@ -1234,7 +1188,7 @@ "not enough memory: %.1fG minimum needed" % (size * memuse / (1024 ** 3))) - if real_max_memuse and verbose and faulthandler and threading: + if real_max_memuse and verbose: print() print(" ... expected peak memory use: {peak:.1f}G" .format(peak=size * memuse / (1024 ** 3))) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -13,7 +13,6 @@ #ifdef WITH_THREAD # define FAULTHANDLER_LATER -# define FAULTHANDLER_WATCHDOG #endif #ifndef MS_WINDOWS @@ -66,20 +65,6 @@ } thread; #endif -#ifdef FAULTHANDLER_WATCHDOG -static struct { - int rfd; - int wfd; - PY_TIMEOUT_T period_us; /* period in microseconds */ - /* The main thread always holds this lock. It is only released when - faulthandler_watchdog() is interrupted before this thread exits, or at - Python exit. */ - PyThread_type_lock cancel_event; - /* released by child thread when joined */ - PyThread_type_lock running; -} watchdog; -#endif - #ifdef FAULTHANDLER_USER typedef struct { int enabled; @@ -604,139 +589,6 @@ } #endif /* FAULTHANDLER_LATER */ -#ifdef FAULTHANDLER_WATCHDOG - -static void -file_watchdog(void *unused) -{ - PyLockStatus st; - PY_TIMEOUT_T timeout; - -#define MAXDATA 1024 - char buf1[MAXDATA], buf2[MAXDATA]; - char *data = buf1, *old_data = buf2; - Py_ssize_t data_len, old_data_len = -1; - -#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) - sigset_t set; - - /* we don't want to receive any signal */ - sigfillset(&set); - pthread_sigmask(SIG_SETMASK, &set, NULL); -#endif - - /* On first pass, feed file contents immediately */ - timeout = 0; - do { - st = PyThread_acquire_lock_timed(watchdog.cancel_event, - timeout, 0); - timeout = watchdog.period_us; - if (st == PY_LOCK_ACQUIRED) { - PyThread_release_lock(watchdog.cancel_event); - break; - } - /* Timeout => read and write data */ - assert(st == PY_LOCK_FAILURE); - - if (lseek(watchdog.rfd, 0, SEEK_SET) < 0) { - break; - } - data_len = read(watchdog.rfd, data, MAXDATA); - if (data_len < 0) { - break; - } - if (data_len != old_data_len || memcmp(data, old_data, data_len)) { - char *tdata; - Py_ssize_t tlen; - /* Contents changed, feed them to wfd */ - long x = (long) data_len; - /* We can't do anything if the consumer is too slow, just bail out */ - if (write(watchdog.wfd, (void *) &x, sizeof(x)) < sizeof(x)) - break; - if (write(watchdog.wfd, data, data_len) < data_len) - break; - tdata = data; - data = old_data; - old_data = tdata; - tlen = data_len; - data_len = old_data_len; - old_data_len = tlen; - } - } while (1); - - close(watchdog.rfd); - close(watchdog.wfd); - - /* The only way out */ - PyThread_release_lock(watchdog.running); -#undef MAXDATA -} - -static void -cancel_file_watchdog(void) -{ - /* Notify cancellation */ - PyThread_release_lock(watchdog.cancel_event); - - /* Wait for thread to join */ - PyThread_acquire_lock(watchdog.running, 1); - PyThread_release_lock(watchdog.running); - - /* The main thread should always hold the cancel_event lock */ - PyThread_acquire_lock(watchdog.cancel_event, 1); -} - -static PyObject* -faulthandler_file_watchdog(PyObject *self, - PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = {"rfd", "wfd", "period", NULL}; - double period; - PY_TIMEOUT_T period_us; - int rfd, wfd; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "iid:_file_watchdog", kwlist, - &rfd, &wfd, &period)) - return NULL; - if ((period * 1e6) >= (double) PY_TIMEOUT_MAX) { - PyErr_SetString(PyExc_OverflowError, "period value is too large"); - return NULL; - } - period_us = (PY_TIMEOUT_T)(period * 1e6); - if (period_us <= 0) { - PyErr_SetString(PyExc_ValueError, "period must be greater than 0"); - return NULL; - } - - /* Cancel previous thread, if running */ - cancel_file_watchdog(); - - watchdog.rfd = rfd; - watchdog.wfd = wfd; - watchdog.period_us = period_us; - - /* Arm these locks to serve as events when released */ - PyThread_acquire_lock(watchdog.running, 1); - - if (PyThread_start_new_thread(file_watchdog, NULL) == -1) { - PyThread_release_lock(watchdog.running); - PyErr_SetString(PyExc_RuntimeError, - "unable to start file watchdog thread"); - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject* -faulthandler_cancel_file_watchdog(PyObject *self) -{ - cancel_file_watchdog(); - Py_RETURN_NONE; -} -#endif /* FAULTHANDLER_WATCHDOG */ - #ifdef FAULTHANDLER_USER static int faulthandler_register(int signum, int chain, _Py_sighandler_t *p_previous) @@ -1126,18 +978,6 @@ "to dump_tracebacks_later().")}, #endif -#ifdef FAULTHANDLER_WATCHDOG - {"_file_watchdog", - (PyCFunction)faulthandler_file_watchdog, METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("_file_watchdog(rfd, wfd, period):\n" - "feed the contents of 'rfd' to 'wfd', if changed,\n" - "every 'period seconds'.")}, - {"_cancel_file_watchdog", - (PyCFunction)faulthandler_cancel_file_watchdog, METH_NOARGS, - PyDoc_STR("_cancel_file_watchdog():\ncancel the previous call " - "to _file_watchdog().")}, -#endif - #ifdef FAULTHANDLER_USER {"register", (PyCFunction)faulthandler_register_py, METH_VARARGS|METH_KEYWORDS, @@ -1263,16 +1103,6 @@ } PyThread_acquire_lock(thread.cancel_event, 1); #endif -#ifdef FAULTHANDLER_WATCHDOG - watchdog.cancel_event = PyThread_allocate_lock(); - watchdog.running = PyThread_allocate_lock(); - if (!watchdog.cancel_event || !watchdog.running) { - PyErr_SetString(PyExc_RuntimeError, - "could not allocate locks for faulthandler"); - return -1; - } - PyThread_acquire_lock(watchdog.cancel_event, 1); -#endif return faulthandler_env_options(); } @@ -1297,20 +1127,6 @@ } #endif -#ifdef FAULTHANDLER_WATCHDOG - /* file watchdog */ - if (watchdog.cancel_event) { - cancel_file_watchdog(); - PyThread_release_lock(watchdog.cancel_event); - PyThread_free_lock(watchdog.cancel_event); - watchdog.cancel_event = NULL; - } - if (watchdog.running) { - PyThread_free_lock(watchdog.running); - watchdog.running = NULL; - } -#endif - #ifdef FAULTHANDLER_USER /* user */ if (user_signals != NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 24 17:38:35 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 24 Mar 2012 17:38:35 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0NDAw?= =?utf8?q?=3A_Fix_typo=2E?= Message-ID: http://hg.python.org/cpython/rev/e0e28695f11b changeset: 75912:e0e28695f11b branch: 2.7 parent: 75903:113b8e3cbba4 user: Martin v. L?wis date: Sat Mar 24 17:38:29 2012 +0100 summary: Issue #14400: Fix typo. files: Doc/howto/cporting.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst --- a/Doc/howto/cporting.rst +++ b/Doc/howto/cporting.rst @@ -257,7 +257,7 @@ returns failure. (Since there's no way to store a name in a CObject, noisy failure of :c:func:`PyCapsule_SetName` was deemed preferable to silent failure here. If this is - inconveient, feel free to modify your local + inconvenient, feel free to modify your local copy as you see fit.) You can find :file:`capsulethunk.h` in the Python source distribution -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 24 17:40:57 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 24 Mar 2012 17:40:57 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0NDAw?= =?utf8?q?=3A_Fix_typo=2E?= Message-ID: http://hg.python.org/cpython/rev/ff679f22682b changeset: 75913:ff679f22682b branch: 3.2 parent: 75904:54055646fd1f user: Martin v. L?wis date: Sat Mar 24 17:39:57 2012 +0100 summary: Issue #14400: Fix typo. files: Doc/howto/cporting.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst --- a/Doc/howto/cporting.rst +++ b/Doc/howto/cporting.rst @@ -257,7 +257,7 @@ returns failure. (Since there's no way to store a name in a CObject, noisy failure of :c:func:`PyCapsule_SetName` was deemed preferable to silent failure here. If this is - inconveient, feel free to modify your local + inconvenient, feel free to modify your local copy as you see fit.) You can find :file:`capsulethunk.h` in the Python source distribution -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 24 17:40:59 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 24 Mar 2012 17:40:59 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/79deef49082d changeset: 75914:79deef49082d parent: 75911:53a2488605e3 parent: 75913:ff679f22682b user: Martin v. L?wis date: Sat Mar 24 17:40:50 2012 +0100 summary: merge 3.2 files: Doc/howto/cporting.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst --- a/Doc/howto/cporting.rst +++ b/Doc/howto/cporting.rst @@ -257,7 +257,7 @@ returns failure. (Since there's no way to store a name in a CObject, noisy failure of :c:func:`PyCapsule_SetName` was deemed preferable to silent failure here. If this is - inconveient, feel free to modify your local + inconvenient, feel free to modify your local copy as you see fit.) You can find :file:`capsulethunk.h` in the Python source distribution -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 24 17:53:22 2012 From: python-checkins at python.org (eli.bendersky) Date: Sat, 24 Mar 2012 17:53:22 +0100 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314349=3A_Fix_the_d?= =?utf8?q?oc_of_the_MAKE=5FFUNCTION_opcode_in_Doc/library/dis=2Erst_to?= Message-ID: http://hg.python.org/cpython/rev/242d3f8e8c50 changeset: 75915:242d3f8e8c50 user: Eli Bendersky date: Sat Mar 24 18:52:45 2012 +0200 summary: Issue #14349: Fix the doc of the MAKE_FUNCTION opcode in Doc/library/dis.rst to correctly list the stack params it expects. files: Doc/library/dis.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -754,9 +754,10 @@ .. opcode:: MAKE_FUNCTION (argc) - Pushes a new function object on the stack. TOS is the code associated with the - function. The function object is defined to have *argc* default parameters, - which are found below TOS. + Pushes a new function object on the stack. TOS is the + :term:`qualified name` of the function; TOS1 is the code associated with + the function. The function object is defined to have *argc* default parameters, + which are found below TOS1. .. opcode:: MAKE_CLOSURE (argc) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 24 20:37:43 2012 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 24 Mar 2012 20:37:43 +0100 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEzOTAy?= =?utf8?q?=3A_Fix_a_random_test=5Fthreading_failure_on_FreeBSD_6_buildbots?= =?utf8?q?_=28due?= Message-ID: http://hg.python.org/cpython/rev/2456e4e69cd0 changeset: 75916:2456e4e69cd0 branch: 3.2 parent: 75913:ff679f22682b user: Charles-Fran?ois Natali date: Sat Mar 24 20:36:09 2012 +0100 summary: Issue #13902: Fix a random test_threading failure on FreeBSD 6 buildbots (due to a known bug in pthread implementation on FreeBSD < 7). files: Lib/test/test_threading.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -624,6 +624,7 @@ output = "end of worker thread\nend of main thread\n" self.assertScriptHasOutput(script, output) + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_6_daemon_threads(self): # Check that a daemon thread cannot crash the interpreter on shutdown # by manipulating internal structures that are being disposed of in -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 24 20:37:45 2012 From: python-checkins at python.org (charles-francois.natali) Date: Sat, 24 Mar 2012 20:37:45 +0100 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2313902=3A_Fix_a_random_test=5Fthreading_failure_on_F?= =?utf8?q?reeBSD_6_buildbots_=28due?= Message-ID: http://hg.python.org/cpython/rev/c1191cbc7b37 changeset: 75917:c1191cbc7b37 parent: 75915:242d3f8e8c50 parent: 75916:2456e4e69cd0 user: Charles-Fran?ois Natali date: Sat Mar 24 20:37:01 2012 +0100 summary: Issue #13902: Fix a random test_threading failure on FreeBSD 6 buildbots (due to a known bug in pthread implementation on FreeBSD < 7). files: Lib/test/test_threading.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -632,6 +632,7 @@ output = "end of worker thread\nend of main thread\n" self.assertScriptHasOutput(script, output) + @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_6_daemon_threads(self): # Check that a daemon thread cannot crash the interpreter on shutdown # by manipulating internal structures that are being disposed of in -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Mar 25 05:45:23 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 25 Mar 2012 05:45:23 +0200 Subject: [Python-checkins] Daily reference leaks (c1191cbc7b37): sum=0 Message-ID: results for c1191cbc7b37 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog3GOPXJ', '-x'] From python-checkins at python.org Sun Mar 25 08:43:47 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 25 Mar 2012 08:43:47 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314401?= =?utf8?q?=3A_fix_typos_in_curses_howto=2E?= Message-ID: http://hg.python.org/cpython/rev/87539f66156b changeset: 75918:87539f66156b branch: 2.7 parent: 75912:e0e28695f11b user: Georg Brandl date: Sun Mar 25 08:43:22 2012 +0200 summary: Closes #14401: fix typos in curses howto. files: Doc/howto/curses.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -118,7 +118,7 @@ A common problem when debugging a curses application is to get your terminal messed up when the application dies without restoring the terminal to its previous state. In Python this commonly happens when your code is buggy and -raises an uncaught exception. Keys are no longer be echoed to the screen when +raises an uncaught exception. Keys are no longer echoed to the screen when you type them, for example, which makes using the shell difficult. In Python you can avoid these complications and make debugging much easier by @@ -271,7 +271,7 @@ highlight certain words. curses supports this by allowing you to specify an attribute for each cell on the screen. -An attribute is a integer, each bit representing a different attribute. You can +An attribute is an integer, each bit representing a different attribute. You can try to display text with multiple attribute bits set, but curses doesn't guarantee that all the possible combinations are available, or that they're all visually distinct. That depends on the ability of the terminal being used, so @@ -300,7 +300,7 @@ curses.A_REVERSE) stdscr.refresh() -The curses library also supports color on those terminals that provide it, The +The curses library also supports color on those terminals that provide it. The most common such terminal is probably the Linux console, followed by color xterms. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 08:43:57 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 25 Mar 2012 08:43:57 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314401?= =?utf8?q?=3A_fix_typos_in_curses_howto=2E?= Message-ID: http://hg.python.org/cpython/rev/a9129cf78cf0 changeset: 75919:a9129cf78cf0 branch: 3.2 parent: 75916:2456e4e69cd0 user: Georg Brandl date: Sun Mar 25 08:43:22 2012 +0200 summary: Closes #14401: fix typos in curses howto. files: Doc/howto/curses.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -118,7 +118,7 @@ A common problem when debugging a curses application is to get your terminal messed up when the application dies without restoring the terminal to its previous state. In Python this commonly happens when your code is buggy and -raises an uncaught exception. Keys are no longer be echoed to the screen when +raises an uncaught exception. Keys are no longer echoed to the screen when you type them, for example, which makes using the shell difficult. In Python you can avoid these complications and make debugging much easier by @@ -271,7 +271,7 @@ highlight certain words. curses supports this by allowing you to specify an attribute for each cell on the screen. -An attribute is a integer, each bit representing a different attribute. You can +An attribute is an integer, each bit representing a different attribute. You can try to display text with multiple attribute bits set, but curses doesn't guarantee that all the possible combinations are available, or that they're all visually distinct. That depends on the ability of the terminal being used, so @@ -300,7 +300,7 @@ curses.A_REVERSE) stdscr.refresh() -The curses library also supports color on those terminals that provide it, The +The curses library also supports color on those terminals that provide it. The most common such terminal is probably the Linux console, followed by color xterms. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 08:43:59 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 25 Mar 2012 08:43:59 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/43f6a1078d67 changeset: 75920:43f6a1078d67 parent: 75917:c1191cbc7b37 parent: 75919:a9129cf78cf0 user: Georg Brandl date: Sun Mar 25 08:43:32 2012 +0200 summary: merge with 3.2 files: Doc/howto/curses.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -118,7 +118,7 @@ A common problem when debugging a curses application is to get your terminal messed up when the application dies without restoring the terminal to its previous state. In Python this commonly happens when your code is buggy and -raises an uncaught exception. Keys are no longer be echoed to the screen when +raises an uncaught exception. Keys are no longer echoed to the screen when you type them, for example, which makes using the shell difficult. In Python you can avoid these complications and make debugging much easier by @@ -271,7 +271,7 @@ highlight certain words. curses supports this by allowing you to specify an attribute for each cell on the screen. -An attribute is a integer, each bit representing a different attribute. You can +An attribute is an integer, each bit representing a different attribute. You can try to display text with multiple attribute bits set, but curses doesn't guarantee that all the possible combinations are available, or that they're all visually distinct. That depends on the ability of the terminal being used, so @@ -300,7 +300,7 @@ curses.A_REVERSE) stdscr.refresh() -The curses library also supports color on those terminals that provide it, The +The curses library also supports color on those terminals that provide it. The most common such terminal is probably the Linux console, followed by color xterms. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 10:44:40 2012 From: python-checkins at python.org (andrew.svetlov) Date: Sun, 25 Mar 2012 10:44:40 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314200_=E2=80=94_no?= =?utf8?q?w_displayhook_for_IDLE_works_in_non-subprocess_mode_as_well?= Message-ID: http://hg.python.org/cpython/rev/89878808f4ce changeset: 75921:89878808f4ce user: Andrew Svetlov date: Sun Mar 25 11:43:02 2012 +0300 summary: Issue #14200 ? now displayhook for IDLE works in non-subprocess mode as well as subprecess. files: Lib/idlelib/PyShell.py | 2 ++ Lib/idlelib/rpc.py | 19 +++++++++++++++++++ Lib/idlelib/run.py | 22 +--------------------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -999,6 +999,8 @@ return False else: nosub = "==== No Subprocess ====" + sys.displayhook = rpc.displayhook + self.write("Python %s on %s\n%s\n%s" % (sys.version, sys.platform, self.COPYRIGHT, nosub)) self.showprompt() diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py --- a/Lib/idlelib/rpc.py +++ b/Lib/idlelib/rpc.py @@ -40,6 +40,7 @@ import copyreg import types import marshal +import builtins def unpickle_code(ms): @@ -603,3 +604,21 @@ # XXX KBK 09Sep03 We need a proper unit test for this module. Previously # existing test code was removed at Rev 1.27 (r34098). + +def displayhook(value): + """Override standard display hook to use non-locale encoding""" + if value is None: + return + # Set '_' to None to avoid recursion + builtins._ = None + text = repr(value) + try: + sys.stdout.write(text) + except UnicodeEncodeError: + # let's use ascii while utf8-bmp codec doesn't present + encoding = 'ascii' + bytes = text.encode(encoding, 'backslashreplace') + text = bytes.decode(encoding, 'strict') + sys.stdout.write(text) + sys.stdout.write("\n") + builtins._ = value diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -6,7 +6,6 @@ import _thread as thread import threading import queue -import builtins from idlelib import CallTips from idlelib import AutoComplete @@ -262,25 +261,6 @@ thread.interrupt_main() -def displayhook(value): - """Override standard display hook to use non-locale encoding""" - if value is None: - return - # Set '_' to None to avoid recursion - builtins._ = None - text = repr(value) - try: - sys.stdout.write(text) - except UnicodeEncodeError: - # let's use ascii while utf8-bmp codec doesn't present - encoding = 'ascii' - bytes = text.encode(encoding, 'backslashreplace') - text = bytes.decode(encoding, 'strict') - sys.stdout.write(text) - sys.stdout.write("\n") - builtins._ = value - - class MyHandler(rpc.RPCHandler): def handle(self): @@ -290,7 +270,7 @@ sys.stdin = self.console = self.get_remote_proxy("stdin") sys.stdout = self.get_remote_proxy("stdout") sys.stderr = self.get_remote_proxy("stderr") - sys.displayhook = displayhook + sys.displayhook = rpc.displayhook # page help() text to shell. import pydoc # import must be done here to capture i/o binding pydoc.pager = pydoc.plainpager -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 10:45:32 2012 From: python-checkins at python.org (andrew.svetlov) Date: Sun, 25 Mar 2012 10:45:32 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_extra_spaces_in_doc_?= =?utf8?q?example=2E?= Message-ID: http://hg.python.org/cpython/rev/7d8339083cb3 changeset: 75922:7d8339083cb3 user: Andrew Svetlov date: Sun Mar 25 11:44:59 2012 +0300 summary: Remove extra spaces in doc example. files: Doc/library/tkinter.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -193,9 +193,9 @@ self.hi_there["command"] = self.say_hi self.hi_there.pack(side="top") - self.QUIT = tk.Button(self, text = "QUIT", fg = "red", - command = root.destroy) - self.QUIT.pack(side = "bottom") + self.QUIT = tk.Button(self, text="QUIT", fg="red", + command=root.destroy) + self.QUIT.pack(side="bottom") def say_hi(self): print("hi there, everyone!") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 19:00:54 2012 From: python-checkins at python.org (stefan.krah) Date: Sun, 25 Mar 2012 19:00:54 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Raise_MemoryError_instead_o?= =?utf8?q?f_InvalidOperation/MallocError_for_compatibility?= Message-ID: http://hg.python.org/cpython/rev/0ed7da703a33 changeset: 75923:0ed7da703a33 user: Stefan Krah date: Sun Mar 25 18:59:21 2012 +0200 summary: Raise MemoryError instead of InvalidOperation/MallocError for compatibility with decimal.py. The standard specifies InsufficientStorage (MallocError) as a sub-condition of InvalidOperation. This allows a calculation to continue with NaN results when allocation fails. files: Lib/test/test_decimal.py | 2 +- Modules/_decimal/_decimal.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -3837,7 +3837,7 @@ x = dir(C) y = [s for s in dir(P) if '__' in s or not s.startswith('_')] - self.assertEqual(set(x) - set(y), {'MallocError'}) + self.assertEqual(set(x) - set(y), set()) def test_context_attributes(self): diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -168,7 +168,9 @@ {"DivisionImpossible", "decimal.DivisionImpossible", MPD_Division_impossible, NULL}, {"DivisionUndefined", "decimal.DivisionUndefined", MPD_Division_undefined, NULL}, {"InvalidContext", "decimal.InvalidContext", MPD_Invalid_context, NULL}, +#ifdef EXTRA_FUNCTIONALITY {"MallocError", "decimal.MallocError", MPD_Malloc_error, NULL}, +#endif {NULL} }; @@ -466,9 +468,14 @@ mpd_context_t *ctx = CTX(context); ctx->status |= status; - if (ctx->traps&status) { + if (status & (ctx->traps|MPD_Malloc_error)) { PyObject *ex, *siglist; + if (status & MPD_Malloc_error) { + PyErr_NoMemory(); + return 1; + } + ex = flags_as_exception(ctx->traps&status); if (ex == NULL) { return 1; /* GCOV_NOT_REACHED */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 19:16:23 2012 From: python-checkins at python.org (michael.foord) Date: Sun, 25 Mar 2012 19:16:23 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_unittest=2Emock=2EMagicMock?= =?utf8?q?_objects_are_now_unorderable_by_default?= Message-ID: http://hg.python.org/cpython/rev/bd52c8331dac changeset: 75924:bd52c8331dac parent: 75922:7d8339083cb3 user: Michael Foord date: Sun Mar 25 18:16:07 2012 +0100 summary: unittest.mock.MagicMock objects are now unorderable by default files: Lib/unittest/mock.py | 22 +++++---- Lib/unittest/test/testmock/testmagicmethods.py | 13 +++++ Misc/NEWS | 2 + 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -167,16 +167,15 @@ signature, func = result src = "lambda %s: None" % signature - context = {'_mock_': mock} - checksig = eval(src, context) + checksig = eval(src, {}) _copy_func_details(func, checksig) name = original.__name__ if not name.isidentifier(): name = 'funcopy' - context = {'checksig': checksig, 'mock': mock} + context = {'_checksig_': checksig, 'mock': mock} src = """def %s(*args, **kwargs): - checksig(*args, **kwargs) + _checksig_(*args, **kwargs) return mock(*args, **kwargs)""" % name exec (src, context) funcopy = context[name] @@ -620,14 +619,16 @@ def __dir__(self): """Filter the output of `dir(mock)` to only useful members.""" + if not FILTER_DIR: + return object.__dir__(self) + extras = self._mock_methods or [] from_type = dir(type(self)) from_dict = list(self.__dict__) - if FILTER_DIR: - from_type = [e for e in from_type if not e.startswith('_')] - from_dict = [e for e in from_dict if not e.startswith('_') or - _is_magic(e)] + from_type = [e for e in from_type if not e.startswith('_')] + from_dict = [e for e in from_dict if not e.startswith('_') or + _is_magic(e)] return sorted(set(extras + from_type + from_dict + list(self._mock_children))) @@ -1582,6 +1583,10 @@ } _return_values = { + '__lt__': NotImplemented, + '__gt__': NotImplemented, + '__le__': NotImplemented, + '__ge__': NotImplemented, '__int__': 1, '__contains__': False, '__len__': 0, @@ -2000,7 +2005,6 @@ _parent._mock_children[_name] = mock if is_type and not instance and 'return_value' not in kwargs: - # XXXX could give a name to the return_value mock? mock.return_value = create_autospec(spec, spec_set, instance=True, _name='()', _parent=mock) diff --git a/Lib/unittest/test/testmock/testmagicmethods.py b/Lib/unittest/test/testmock/testmagicmethods.py --- a/Lib/unittest/test/testmock/testmagicmethods.py +++ b/Lib/unittest/test/testmock/testmagicmethods.py @@ -156,6 +156,19 @@ self. assertTrue(mock <= 3) self. assertTrue(mock >= 3) + self.assertRaises(TypeError, lambda: MagicMock() < object()) + self.assertRaises(TypeError, lambda: object() < MagicMock()) + self.assertRaises(TypeError, lambda: MagicMock() < MagicMock()) + self.assertRaises(TypeError, lambda: MagicMock() > object()) + self.assertRaises(TypeError, lambda: object() > MagicMock()) + self.assertRaises(TypeError, lambda: MagicMock() > MagicMock()) + self.assertRaises(TypeError, lambda: MagicMock() <= object()) + self.assertRaises(TypeError, lambda: object() <= MagicMock()) + self.assertRaises(TypeError, lambda: MagicMock() <= MagicMock()) + self.assertRaises(TypeError, lambda: MagicMock() >= object()) + self.assertRaises(TypeError, lambda: object() >= MagicMock()) + self.assertRaises(TypeError, lambda: MagicMock() >= MagicMock()) + def test_equality(self): for mock in Mock(), MagicMock(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,8 @@ Library ------- +- Issue #14295: Add unittest.mock + - Issue #7652: Add --with-system-libmpdec option to configure for linking the _decimal module against an installed libmpdec. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 19:16:24 2012 From: python-checkins at python.org (michael.foord) Date: Sun, 25 Mar 2012 19:16:24 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_Merge?= Message-ID: http://hg.python.org/cpython/rev/28183f010a05 changeset: 75925:28183f010a05 parent: 75924:bd52c8331dac parent: 75923:0ed7da703a33 user: Michael Foord date: Sun Mar 25 18:16:26 2012 +0100 summary: Merge files: Lib/test/test_decimal.py | 2 +- Modules/_decimal/_decimal.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -3837,7 +3837,7 @@ x = dir(C) y = [s for s in dir(P) if '__' in s or not s.startswith('_')] - self.assertEqual(set(x) - set(y), {'MallocError'}) + self.assertEqual(set(x) - set(y), set()) def test_context_attributes(self): diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -168,7 +168,9 @@ {"DivisionImpossible", "decimal.DivisionImpossible", MPD_Division_impossible, NULL}, {"DivisionUndefined", "decimal.DivisionUndefined", MPD_Division_undefined, NULL}, {"InvalidContext", "decimal.InvalidContext", MPD_Invalid_context, NULL}, +#ifdef EXTRA_FUNCTIONALITY {"MallocError", "decimal.MallocError", MPD_Malloc_error, NULL}, +#endif {NULL} }; @@ -466,9 +468,14 @@ mpd_context_t *ctx = CTX(context); ctx->status |= status; - if (ctx->traps&status) { + if (status & (ctx->traps|MPD_Malloc_error)) { PyObject *ex, *siglist; + if (status & MPD_Malloc_error) { + PyErr_NoMemory(); + return 1; + } + ex = flags_as_exception(ctx->traps&status); if (ex == NULL) { return 1; /* GCOV_NOT_REACHED */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 19:58:00 2012 From: python-checkins at python.org (michael.foord) Date: Sun, 25 Mar 2012 19:58:00 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Support_subclassing_unittes?= =?utf8?q?t=2Emock=2E=5Fpatch_and_fix_various_obscure_bugs_around?= Message-ID: http://hg.python.org/cpython/rev/93a1bd40dd49 changeset: 75926:93a1bd40dd49 user: Michael Foord date: Sun Mar 25 18:57:58 2012 +0100 summary: Support subclassing unittest.mock._patch and fix various obscure bugs around patcher spec arguments files: Lib/unittest/mock.py | 76 +++++-- Lib/unittest/test/testmock/testpatch.py | 109 +++++++++++- 2 files changed, 152 insertions(+), 33 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -998,7 +998,7 @@ raise ValueError( "Cannot use 'new' and 'new_callable' together" ) - if autospec is not False: + if autospec is not None: raise ValueError( "Cannot use 'autospec' and 'new_callable' together" ) @@ -1059,6 +1059,7 @@ extra_args = [] entered_patchers = [] + exc_info = tuple() try: for patching in patched.patchings: arg = patching.__enter__() @@ -1076,11 +1077,13 @@ # the patcher may have been started, but an exception # raised whilst entering one of its additional_patchers entered_patchers.append(patching) + # Pass the exception to __exit__ + exc_info = sys.exc_info() # re-raise the exception raise finally: for patching in reversed(entered_patchers): - patching.__exit__() + patching.__exit__(*exc_info) patched.patchings = [self] if hasattr(func, 'func_code'): @@ -1120,17 +1123,40 @@ new_callable = self.new_callable self.target = self.getter() + # normalise False to None + if spec is False: + spec = None + if spec_set is False: + spec_set = None + if autospec is False: + autospec = None + + if spec is not None and autospec is not None: + raise TypeError("Can't specify spec and autospec") + if ((spec is not None or autospec is not None) and + spec_set not in (True, None)): + raise TypeError("Can't provide explicit spec_set *and* spec or autospec") + original, local = self.get_original() - if new is DEFAULT and autospec is False: + if new is DEFAULT and autospec is None: inherit = False - if spec_set == True: - spec_set = original - elif spec == True: + if spec is True: # set spec to the object we are replacing spec = original - - if (spec or spec_set) is not None: + if spec_set is True: + spec_set = original + spec = None + elif spec is not None: + if spec_set is True: + spec_set = spec + spec = None + elif spec_set is True: + spec_set = original + + if spec is not None or spec_set is not None: + if original is DEFAULT: + raise TypeError("Can't use 'spec' with create=True") if isinstance(original, type): # If we're patching out a class and there is a spec inherit = True @@ -1139,7 +1165,7 @@ _kwargs = {} if new_callable is not None: Klass = new_callable - elif (spec or spec_set) is not None: + elif spec is not None or spec_set is not None: if not _callable(spec or spec_set): Klass = NonCallableMagicMock @@ -1159,14 +1185,17 @@ if inherit and _is_instance_mock(new): # we can only tell if the instance should be callable if the # spec is not a list - if (not _is_list(spec or spec_set) and not - _instance_callable(spec or spec_set)): + this_spec = spec + if spec_set is not None: + this_spec = spec_set + if (not _is_list(this_spec) and not + _instance_callable(this_spec)): Klass = NonCallableMagicMock _kwargs.pop('name') new.return_value = Klass(_new_parent=new, _new_name='()', **_kwargs) - elif autospec is not False: + elif autospec is not None: # spec is ignored, new *must* be default, spec_set is treated # as a boolean. Should we check spec is not None and that spec_set # is a bool? @@ -1175,6 +1204,8 @@ "autospec creates the mock for you. Can't specify " "autospec and new." ) + if original is DEFAULT: + raise TypeError("Can't use 'spec' with create=True") spec_set = bool(spec_set) if autospec is True: autospec = original @@ -1204,7 +1235,7 @@ return new - def __exit__(self, *_): + def __exit__(self, *exc_info): """Undo the patch.""" if not _is_started(self): raise RuntimeError('stop called on unstarted patcher') @@ -1222,7 +1253,7 @@ del self.target for patcher in reversed(self.additional_patchers): if _is_started(patcher): - patcher.__exit__() + patcher.__exit__(*exc_info) start = __enter__ stop = __exit__ @@ -1241,14 +1272,10 @@ def _patch_object( target, attribute, new=DEFAULT, spec=None, - create=False, spec_set=None, autospec=False, + create=False, spec_set=None, autospec=None, new_callable=None, **kwargs ): """ - patch.object(target, attribute, new=DEFAULT, spec=None, create=False, - spec_set=None, autospec=False, - new_callable=None, **kwargs) - patch the named member (`attribute`) on an object (`target`) with a mock object. @@ -1268,10 +1295,8 @@ ) -def _patch_multiple(target, spec=None, create=False, - spec_set=None, autospec=False, - new_callable=None, **kwargs - ): +def _patch_multiple(target, spec=None, create=False, spec_set=None, + autospec=None, new_callable=None, **kwargs): """Perform multiple patches in a single call. It takes the object to be patched (either as an object or a string to fetch the object by importing) and keyword arguments for the patches:: @@ -1321,8 +1346,7 @@ def patch( target, new=DEFAULT, spec=None, create=False, - spec_set=None, autospec=False, - new_callable=None, **kwargs + spec_set=None, autospec=None, new_callable=None, **kwargs ): """ `patch` acts as a function decorator, class decorator or a context @@ -2079,7 +2103,7 @@ try: return obj.__class__ except AttributeError: - # in Python 2, _sre.SRE_Pattern objects have no __class__ + # it is possible for objects to have no __class__ return type(obj) diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -11,14 +11,15 @@ from unittest.mock import ( NonCallableMock, CallableMixin, patch, sentinel, - MagicMock, Mock, NonCallableMagicMock, patch, - DEFAULT, call + MagicMock, Mock, NonCallableMagicMock, patch, _patch, + DEFAULT, call, _get_target ) builtin_string = 'builtins' PTModule = sys.modules[__name__] +MODNAME = '%s.PTModule' % __name__ def _get_proxy(obj, get_only=True): @@ -724,8 +725,8 @@ patcher = patch('%s.something' % __name__) self.assertIs(something, original) mock = patcher.start() - self.assertIsNot(mock, original) try: + self.assertIsNot(mock, original) self.assertIs(something, mock) finally: patcher.stop() @@ -744,8 +745,8 @@ patcher = patch.object(PTModule, 'something', 'foo') self.assertIs(something, original) replaced = patcher.start() - self.assertEqual(replaced, 'foo') try: + self.assertEqual(replaced, 'foo') self.assertIs(something, replaced) finally: patcher.stop() @@ -759,9 +760,10 @@ self.assertEqual(d, original) patcher.start() - self.assertEqual(d, {'spam': 'eggs'}) - - patcher.stop() + try: + self.assertEqual(d, {'spam': 'eggs'}) + finally: + patcher.stop() self.assertEqual(d, original) @@ -1647,6 +1649,99 @@ self.assertEqual(squizz.squozz, 3) + def test_patch_propogrates_exc_on_exit(self): + class holder: + exc_info = None, None, None + + class custom_patch(_patch): + def __exit__(self, etype=None, val=None, tb=None): + _patch.__exit__(self, etype, val, tb) + holder.exc_info = etype, val, tb + stop = __exit__ + + def with_custom_patch(target): + getter, attribute = _get_target(target) + return custom_patch( + getter, attribute, DEFAULT, None, False, None, + None, None, {} + ) + + @with_custom_patch('squizz.squozz') + def test(mock): + raise RuntimeError + + self.assertRaises(RuntimeError, test) + self.assertIs(holder.exc_info[0], RuntimeError) + self.assertIsNotNone(holder.exc_info[1], + 'exception value not propgated') + self.assertIsNotNone(holder.exc_info[2], + 'exception traceback not propgated') + + + def test_create_and_specs(self): + for kwarg in ('spec', 'spec_set', 'autospec'): + p = patch('%s.doesnotexist' % __name__, create=True, + **{kwarg: True}) + self.assertRaises(TypeError, p.start) + self.assertRaises(NameError, lambda: doesnotexist) + + # check that spec with create is innocuous if the original exists + p = patch(MODNAME, create=True, **{kwarg: True}) + p.start() + p.stop() + + + def test_multiple_specs(self): + original = PTModule + for kwarg in ('spec', 'spec_set'): + p = patch(MODNAME, autospec=0, **{kwarg: 0}) + self.assertRaises(TypeError, p.start) + self.assertIs(PTModule, original) + + for kwarg in ('spec', 'autospec'): + p = patch(MODNAME, spec_set=0, **{kwarg: 0}) + self.assertRaises(TypeError, p.start) + self.assertIs(PTModule, original) + + for kwarg in ('spec_set', 'autospec'): + p = patch(MODNAME, spec=0, **{kwarg: 0}) + self.assertRaises(TypeError, p.start) + self.assertIs(PTModule, original) + + + def test_specs_false_instead_of_none(self): + p = patch(MODNAME, spec=False, spec_set=False, autospec=False) + mock = p.start() + try: + # no spec should have been set, so attribute access should not fail + mock.does_not_exist + mock.does_not_exist = 3 + finally: + p.stop() + + + def test_falsey_spec(self): + for kwarg in ('spec', 'autospec', 'spec_set'): + p = patch(MODNAME, **{kwarg: 0}) + m = p.start() + try: + self.assertRaises(AttributeError, getattr, m, 'doesnotexit') + finally: + p.stop() + + + def test_spec_set_true(self): + for kwarg in ('spec', 'autospec'): + p = patch(MODNAME, spec_set=True, **{kwarg: True}) + m = p.start() + try: + self.assertRaises(AttributeError, setattr, m, + 'doesnotexist', 'something') + self.assertRaises(AttributeError, getattr, m, 'doesnotexist') + finally: + p.stop() + + if __name__ == '__main__': unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 20:11:59 2012 From: python-checkins at python.org (michael.foord) Date: Sun, 25 Mar 2012 20:11:59 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_unittest=2Emock=3A_set_file?= =?utf8?q?=5Fspec_on_first_use?= Message-ID: http://hg.python.org/cpython/rev/058396f89fea changeset: 75927:058396f89fea user: Michael Foord date: Sun Mar 25 19:03:13 2012 +0100 summary: unittest.mock: set file_spec on first use files: Lib/unittest/mock.py | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -2138,11 +2138,15 @@ 'func_name', ]) -import _io -file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) - + +file_spec = None def mock_open(mock=None, read_data=None): + global file_spec + if file_spec is None: + import _io + file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) + if mock is None: mock = MagicMock(spec=file_spec) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 20:11:59 2012 From: python-checkins at python.org (michael.foord) Date: Sun, 25 Mar 2012 20:11:59 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Addition_of_docstrings_to_u?= =?utf8?q?nittest=2Emock_helpers?= Message-ID: http://hg.python.org/cpython/rev/e8f9399a0554 changeset: 75928:e8f9399a0554 user: Michael Foord date: Sun Mar 25 19:07:33 2012 +0100 summary: Addition of docstrings to unittest.mock helpers files: Lib/unittest/mock.py | 22 ++++++++++++++++++++-- 1 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1205,7 +1205,7 @@ "autospec and new." ) if original is DEFAULT: - raise TypeError("Can't use 'spec' with create=True") + raise TypeError("Can't use 'autospec' with create=True") spec_set = bool(spec_set) if autospec is True: autospec = original @@ -2142,6 +2142,17 @@ file_spec = None def mock_open(mock=None, read_data=None): + """ + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` method of the file handle to return. + This is an empty string by default. + """ global file_spec if file_spec is None: import _io @@ -2162,7 +2173,14 @@ class PropertyMock(Mock): - """A Mock variant with __get__ and __set__ methods to act as a property""" + """ + A mock intended to be used as a property, or other descriptor, on a class. + `PropertyMock` provides `__get__` and `__set__` methods so you can specify + a return value when it is fetched. + + Fetching a `PropertyMock` instance from an object calls the mock, with + no args. Setting it calls the mock with the value being set. + """ def __get__(self, obj, obj_type): return self() def __set__(self, obj, val): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 20:12:00 2012 From: python-checkins at python.org (michael.foord) Date: Sun, 25 Mar 2012 20:12:00 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Minor_changes_to_the_unitte?= =?utf8?q?st=2Emock=2Emock=5Fopen_helper?= Message-ID: http://hg.python.org/cpython/rev/b0002db98a54 changeset: 75929:b0002db98a54 user: Michael Foord date: Sun Mar 25 19:11:50 2012 +0100 summary: Minor changes to the unittest.mock.mock_open helper files: Lib/unittest/mock.py | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -2141,7 +2141,8 @@ file_spec = None -def mock_open(mock=None, read_data=None): + +def mock_open(mock=None, read_data=''): """ A helper function to create a mock to replace the use of `open`. It works for `open` called directly or used as a context manager. @@ -2159,14 +2160,12 @@ file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) if mock is None: - mock = MagicMock(spec=file_spec) + mock = MagicMock(name='open', spec=open) handle = MagicMock(spec=file_spec) handle.write.return_value = None handle.__enter__.return_value = handle - - if read_data is not None: - handle.read.return_value = read_data + handle.read.return_value = read_data mock.return_value = handle return mock -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 20:16:09 2012 From: python-checkins at python.org (michael.foord) Date: Sun, 25 Mar 2012 20:16:09 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_more_Python_2_code_f?= =?utf8?q?rom_unittest=2Emock_=28obsolete_function_attributes=29?= Message-ID: http://hg.python.org/cpython/rev/91bd46503ede changeset: 75930:91bd46503ede user: Michael Foord date: Sun Mar 25 19:16:10 2012 +0100 summary: Remove more Python 2 code from unittest.mock (obsolete function attributes) files: Lib/unittest/mock.py | 14 -------------- 1 files changed, 0 insertions(+), 14 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -2037,10 +2037,6 @@ # MagicMock already does the useful magic methods for us continue - if isinstance(spec, FunctionTypes) and entry in FunctionAttributes: - # allow a mock to actually be a function - continue - # XXXX do we need a better way of getting attributes without # triggering code execution (?) Probably not - we need the actual # object to mock it so we would rather trigger a property than mock @@ -2128,16 +2124,6 @@ type(_ANY.__eq__), ) -FunctionAttributes = set([ - 'func_closure', - 'func_code', - 'func_defaults', - 'func_dict', - 'func_doc', - 'func_globals', - 'func_name', -]) - file_spec = None -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 20:35:21 2012 From: python-checkins at python.org (michael.foord) Date: Sun, 25 Mar 2012 20:35:21 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_unittest=2Emock=3A_remove_a?= =?utf8?q?nother_piece_of_Python_2_specific_code?= Message-ID: http://hg.python.org/cpython/rev/4d14fb0f12f5 changeset: 75931:4d14fb0f12f5 user: Michael Foord date: Sun Mar 25 19:35:22 2012 +0100 summary: unittest.mock: remove another piece of Python 2 specific code files: Lib/unittest/mock.py | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -2120,8 +2120,6 @@ type(create_autospec), # instance method type(ANY.__eq__), - # unbound method - type(_ANY.__eq__), ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 20:38:19 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 25 Mar 2012 20:38:19 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Switch_to_new_?= =?utf8?q?=22lighter=22_doc_design=2E?= Message-ID: http://hg.python.org/cpython/rev/ca0230c21c79 changeset: 75932:ca0230c21c79 branch: 3.2 parent: 75919:a9129cf78cf0 user: Georg Brandl date: Sun Mar 25 20:31:57 2012 +0200 summary: Switch to new "lighter" doc design. files: Doc/conf.py | 5 ++++- Doc/tools/sphinxext/layout.html | 1 + Doc/tools/sphinxext/pyspecific.py | 4 ++-- Doc/tools/sphinxext/static/copybutton.js | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py --- a/Doc/conf.py +++ b/Doc/conf.py @@ -65,9 +65,12 @@ # Options for HTML output # ----------------------- -html_theme = 'default' +html_theme = 'pydoctheme' +html_theme_path = ['tools/sphinxext'] html_theme_options = {'collapsiblesidebar': True} +html_short_title = '%s Documentation' % release + # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' diff --git a/Doc/tools/sphinxext/layout.html b/Doc/tools/sphinxext/layout.html --- a/Doc/tools/sphinxext/layout.html +++ b/Doc/tools/sphinxext/layout.html @@ -2,6 +2,7 @@ {% block rootrellink %}
  • +
  • Python{{ reldelim1 }}
  • {{ shorttitle }}{{ reldelim1 }}
  • {% endblock %} {% block extrahead %} diff --git a/Doc/tools/sphinxext/pyspecific.py b/Doc/tools/sphinxext/pyspecific.py --- a/Doc/tools/sphinxext/pyspecific.py +++ b/Doc/tools/sphinxext/pyspecific.py @@ -27,10 +27,10 @@ self.body.append(self.starttag(node, 'p', CLASS=node['type'])) text = versionlabels[node['type']] % node['version'] if len(node): - text += ': ' + text += ':' else: text += '.' - self.body.append('%s' % text) + self.body.append('%s ' % text) from sphinx.writers.html import HTMLTranslator from sphinx.locale import versionlabels diff --git a/Doc/tools/sphinxext/static/copybutton.js b/Doc/tools/sphinxext/static/copybutton.js --- a/Doc/tools/sphinxext/static/copybutton.js +++ b/Doc/tools/sphinxext/static/copybutton.js @@ -17,7 +17,8 @@ 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', 'border-color': border_color, 'border-style': border_style, 'border-width': border_width, 'color': border_color, 'text-size': '75%', - 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em' + 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', + 'border-radius': '0 3px 0 0' } // create and add the button to all the code blocks that contain >>> -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 20:38:19 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 25 Mar 2012 20:38:19 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/b5126bafed40 changeset: 75933:b5126bafed40 parent: 75930:91bd46503ede parent: 75932:ca0230c21c79 user: Georg Brandl date: Sun Mar 25 20:32:35 2012 +0200 summary: merge with 3.2 files: Doc/conf.py | 5 ++++- Doc/tools/sphinxext/layout.html | 1 + Doc/tools/sphinxext/pyspecific.py | 4 ++-- Doc/tools/sphinxext/static/copybutton.js | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py --- a/Doc/conf.py +++ b/Doc/conf.py @@ -65,9 +65,12 @@ # Options for HTML output # ----------------------- -html_theme = 'default' +html_theme = 'pydoctheme' +html_theme_path = ['tools/sphinxext'] html_theme_options = {'collapsiblesidebar': True} +html_short_title = '%s Documentation' % release + # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' diff --git a/Doc/tools/sphinxext/layout.html b/Doc/tools/sphinxext/layout.html --- a/Doc/tools/sphinxext/layout.html +++ b/Doc/tools/sphinxext/layout.html @@ -2,6 +2,7 @@ {% block rootrellink %}
  • +
  • Python{{ reldelim1 }}
  • {{ shorttitle }}{{ reldelim1 }}
  • {% endblock %} {% block extrahead %} diff --git a/Doc/tools/sphinxext/pyspecific.py b/Doc/tools/sphinxext/pyspecific.py --- a/Doc/tools/sphinxext/pyspecific.py +++ b/Doc/tools/sphinxext/pyspecific.py @@ -27,10 +27,10 @@ self.body.append(self.starttag(node, 'p', CLASS=node['type'])) text = versionlabels[node['type']] % node['version'] if len(node): - text += ': ' + text += ':' else: text += '.' - self.body.append('%s' % text) + self.body.append('%s ' % text) from sphinx.writers.html import HTMLTranslator from sphinx.locale import versionlabels diff --git a/Doc/tools/sphinxext/static/copybutton.js b/Doc/tools/sphinxext/static/copybutton.js --- a/Doc/tools/sphinxext/static/copybutton.js +++ b/Doc/tools/sphinxext/static/copybutton.js @@ -17,7 +17,8 @@ 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', 'border-color': border_color, 'border-style': border_style, 'border-width': border_width, 'color': border_color, 'text-size': '75%', - 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em' + 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', + 'border-radius': '0 3px 0 0' } // create and add the button to all the code blocks that contain >>> -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 20:38:20 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 25 Mar 2012 20:38:20 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/34462fbad1b4 changeset: 75934:34462fbad1b4 parent: 75933:b5126bafed40 parent: 75931:4d14fb0f12f5 user: Georg Brandl date: Sun Mar 25 20:38:15 2012 +0200 summary: merge heads files: Lib/unittest/mock.py | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -2120,8 +2120,6 @@ type(create_autospec), # instance method type(ANY.__eq__), - # unbound method - type(_ANY.__eq__), ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Mar 25 20:41:01 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 25 Mar 2012 20:41:01 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Add_missing_fil?= =?utf8?q?es_for_new_doc_theme=2E?= Message-ID: http://hg.python.org/cpython/rev/3ac66b3dfe82 changeset: 75935:3ac66b3dfe82 branch: 3.2 parent: 75932:ca0230c21c79 user: Georg Brandl date: Sun Mar 25 20:40:57 2012 +0200 summary: Add missing files for new doc theme. files: Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css | 170 ++++++++++ Doc/tools/sphinxext/pydoctheme/theme.conf | 23 + Doc/tools/sphinxext/static/sidebar.js | 155 +++++++++ 3 files changed, 348 insertions(+), 0 deletions(-) diff --git a/Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css b/Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css new file mode 100644 --- /dev/null +++ b/Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css @@ -0,0 +1,170 @@ + at import url("default.css"); + +body { + background-color: white; + margin-left: 1em; + margin-right: 1em; +} + +div.related { + margin-bottom: 1.2em; + padding: 0.5em 0; + border-top: 1px solid #ccc; + margin-top: 0.5em; +} + +div.related a:hover { + color: #0095C4; +} + +div.related:first-child { + border-top: 0; + border-bottom: 1px solid #ccc; +} + +div.sphinxsidebar { + background-color: #eeeeee; + border-radius: 5px; + line-height: 130%; + font-size: smaller; +} + +div.sphinxsidebar h3, div.sphinxsidebar h4 { + margin-top: 1.5em; +} + +div.sphinxsidebarwrapper > h3:first-child { + margin-top: 0.2em; +} + +div.sphinxsidebarwrapper > ul > li > ul > li { + margin-bottom: 0.4em; +} + +div.sphinxsidebar a:hover { + color: #0095C4; +} + +div.sphinxsidebar input { + font-family: 'Lucida Grande',Arial,sans-serif; + border: 1px solid #999999; + font-size: smaller; + border-radius: 3px; +} + +div.sphinxsidebar input[type=text] { + max-width: 150px; +} + +div.body { + padding: 0 0 0 1.2em; +} + +div.body p { + line-height: 140%; +} + +div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { + margin: 0; + border: 0; + padding: 0.3em 0; +} + +div.body hr { + border: 0; + background-color: #ccc; + height: 1px; +} + +div.body pre { + border-radius: 3px; + border: 1px solid #ac9; +} + +div.body div.admonition, div.body div.impl-detail { + border-radius: 3px; +} + +div.body div.impl-detail > p { + margin: 0; +} + +div.body div.seealso { + border: 1px solid #dddd66; +} + +div.body a { + color: #00608f; +} + +div.body a:visited { + color: #30306f; +} + +div.body a:hover { + color: #00B0E4; +} + +tt, pre { + font-family: monospace, sans-serif; + font-size: 96.5%; +} + +div.body tt { + border-radius: 3px; +} + +div.body tt.descname { + font-size: 120%; +} + +div.body tt.xref, div.body a tt { + font-weight: normal; +} + +p.deprecated { + border-radius: 3px; +} + +table.docutils { + border: 1px solid #ddd; + min-width: 20%; + border-radius: 3px; + margin-top: 10px; + margin-bottom: 10px; +} + +table.docutils td, table.docutils th { + border: 1px solid #ddd !important; + border-radius: 3px; +} + +table p, table li { + text-align: left !important; +} + +table.docutils th { + background-color: #eee; + padding: 0.3em 0.5em; +} + +table.docutils td { + background-color: white; + padding: 0.3em 0.5em; +} + +table.footnote, table.footnote td { + border: 0 !important; +} + +div.footer { + line-height: 150%; + margin-top: -2em; + text-align: right; + width: auto; + margin-right: 10px; +} + +div.footer a:hover { + color: #0095C4; +} diff --git a/Doc/tools/sphinxext/pydoctheme/theme.conf b/Doc/tools/sphinxext/pydoctheme/theme.conf new file mode 100644 --- /dev/null +++ b/Doc/tools/sphinxext/pydoctheme/theme.conf @@ -0,0 +1,23 @@ +[theme] +inherit = default +stylesheet = pydoctheme.css +pygments_style = sphinx + +[options] +bodyfont = 'Lucida Grande', Arial, sans-serif +headfont = 'Lucida Grande', Arial, sans-serif +footerbgcolor = white +footertextcolor = #555555 +relbarbgcolor = white +relbartextcolor = #666666 +relbarlinkcolor = #444444 +sidebarbgcolor = white +sidebartextcolor = #444444 +sidebarlinkcolor = #444444 +bgcolor = white +textcolor = #222222 +linkcolor = #0090c0 +visitedlinkcolor = #00608f +headtextcolor = #1a1a1a +headbgcolor = white +headlinkcolor = #aaaaaa diff --git a/Doc/tools/sphinxext/static/sidebar.js b/Doc/tools/sphinxext/static/sidebar.js new file mode 100644 --- /dev/null +++ b/Doc/tools/sphinxext/static/sidebar.js @@ -0,0 +1,155 @@ +/* + * sidebar.js + * ~~~~~~~~~~ + * + * This script makes the Sphinx sidebar collapsible. + * + * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds in + * .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton used to + * collapse and expand the sidebar. + * + * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden and the + * width of the sidebar and the margin-left of the document are decreased. + * When the sidebar is expanded the opposite happens. This script saves a + * per-browser/per-session cookie used to remember the position of the sidebar + * among the pages. Once the browser is closed the cookie is deleted and the + * position reset to the default (expanded). + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +$(function() { + // global elements used by the functions. + // the 'sidebarbutton' element is defined as global after its + // creation, in the add_sidebar_button function + var bodywrapper = $('.bodywrapper'); + var sidebar = $('.sphinxsidebar'); + var sidebarwrapper = $('.sphinxsidebarwrapper'); + + // original margin-left of the bodywrapper and width of the sidebar + // with the sidebar expanded + var bw_margin_expanded = bodywrapper.css('margin-left'); + var ssb_width_expanded = sidebar.width(); + + // margin-left of the bodywrapper and width of the sidebar + // with the sidebar collapsed + var bw_margin_collapsed = '.8em'; + var ssb_width_collapsed = '.8em'; + + // colors used by the current theme + var dark_color = '#AAAAAA'; + var light_color = '#CCCCCC'; + + function sidebar_is_collapsed() { + return sidebarwrapper.is(':not(:visible)'); + } + + function toggle_sidebar() { + if (sidebar_is_collapsed()) + expand_sidebar(); + else + collapse_sidebar(); + } + + function collapse_sidebar() { + sidebarwrapper.hide(); + sidebar.css('width', ssb_width_collapsed); + bodywrapper.css('margin-left', bw_margin_collapsed); + sidebarbutton.css({ + 'margin-left': '0', + 'height': bodywrapper.height(), + 'border-radius': '5px' + }); + sidebarbutton.find('span').text('?'); + sidebarbutton.attr('title', _('Expand sidebar')); + document.cookie = 'sidebar=collapsed'; + } + + function expand_sidebar() { + bodywrapper.css('margin-left', bw_margin_expanded); + sidebar.css('width', ssb_width_expanded); + sidebarwrapper.show(); + sidebarbutton.css({ + 'margin-left': ssb_width_expanded-12, + 'height': bodywrapper.height(), + 'border-radius': '0 5px 5px 0' + }); + sidebarbutton.find('span').text('?'); + sidebarbutton.attr('title', _('Collapse sidebar')); + //sidebarwrapper.css({'padding-top': + // Math.max(window.pageYOffset - sidebarwrapper.offset().top, 10)}); + document.cookie = 'sidebar=expanded'; + } + + function add_sidebar_button() { + sidebarwrapper.css({ + 'float': 'left', + 'margin-right': '0', + 'width': ssb_width_expanded - 28 + }); + // create the button + sidebar.append( + '
    «
    ' + ); + var sidebarbutton = $('#sidebarbutton'); + // find the height of the viewport to center the '<<' in the page + var viewport_height; + if (window.innerHeight) + viewport_height = window.innerHeight; + else + viewport_height = $(window).height(); + var sidebar_offset = sidebar.offset().top; + var sidebar_height = Math.max(bodywrapper.height(), sidebar.height()); + sidebarbutton.find('span').css({ + 'display': 'block', + 'position': 'fixed', + 'top': Math.min(viewport_height/2, sidebar_height/2 + sidebar_offset) - 10 + }); + + sidebarbutton.click(toggle_sidebar); + sidebarbutton.attr('title', _('Collapse sidebar')); + sidebarbutton.css({ + 'border-radius': '0 5px 5px 0', + 'color': '#444444', + 'background-color': '#CCCCCC', + 'font-size': '1.2em', + 'cursor': 'pointer', + 'height': sidebar_height, + 'padding-top': '1px', + 'padding-left': '1px', + 'margin-left': ssb_width_expanded - 12 + }); + + sidebarbutton.hover( + function () { + $(this).css('background-color', dark_color); + }, + function () { + $(this).css('background-color', light_color); + } + ); + } + + function set_position_from_cookie() { + if (!document.cookie) + return; + var items = document.cookie.split(';'); + for(var k=0; k http://hg.python.org/cpython/rev/20160bc8520e changeset: 75936:20160bc8520e parent: 75934:34462fbad1b4 parent: 75935:3ac66b3dfe82 user: Georg Brandl date: Sun Mar 25 20:41:06 2012 +0200 summary: merge with 3.2 files: Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css | 170 ++++++++++ Doc/tools/sphinxext/pydoctheme/theme.conf | 23 + Doc/tools/sphinxext/static/sidebar.js | 155 +++++++++ 3 files changed, 348 insertions(+), 0 deletions(-) diff --git a/Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css b/Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css new file mode 100644 --- /dev/null +++ b/Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css @@ -0,0 +1,170 @@ + at import url("default.css"); + +body { + background-color: white; + margin-left: 1em; + margin-right: 1em; +} + +div.related { + margin-bottom: 1.2em; + padding: 0.5em 0; + border-top: 1px solid #ccc; + margin-top: 0.5em; +} + +div.related a:hover { + color: #0095C4; +} + +div.related:first-child { + border-top: 0; + border-bottom: 1px solid #ccc; +} + +div.sphinxsidebar { + background-color: #eeeeee; + border-radius: 5px; + line-height: 130%; + font-size: smaller; +} + +div.sphinxsidebar h3, div.sphinxsidebar h4 { + margin-top: 1.5em; +} + +div.sphinxsidebarwrapper > h3:first-child { + margin-top: 0.2em; +} + +div.sphinxsidebarwrapper > ul > li > ul > li { + margin-bottom: 0.4em; +} + +div.sphinxsidebar a:hover { + color: #0095C4; +} + +div.sphinxsidebar input { + font-family: 'Lucida Grande',Arial,sans-serif; + border: 1px solid #999999; + font-size: smaller; + border-radius: 3px; +} + +div.sphinxsidebar input[type=text] { + max-width: 150px; +} + +div.body { + padding: 0 0 0 1.2em; +} + +div.body p { + line-height: 140%; +} + +div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { + margin: 0; + border: 0; + padding: 0.3em 0; +} + +div.body hr { + border: 0; + background-color: #ccc; + height: 1px; +} + +div.body pre { + border-radius: 3px; + border: 1px solid #ac9; +} + +div.body div.admonition, div.body div.impl-detail { + border-radius: 3px; +} + +div.body div.impl-detail > p { + margin: 0; +} + +div.body div.seealso { + border: 1px solid #dddd66; +} + +div.body a { + color: #00608f; +} + +div.body a:visited { + color: #30306f; +} + +div.body a:hover { + color: #00B0E4; +} + +tt, pre { + font-family: monospace, sans-serif; + font-size: 96.5%; +} + +div.body tt { + border-radius: 3px; +} + +div.body tt.descname { + font-size: 120%; +} + +div.body tt.xref, div.body a tt { + font-weight: normal; +} + +p.deprecated { + border-radius: 3px; +} + +table.docutils { + border: 1px solid #ddd; + min-width: 20%; + border-radius: 3px; + margin-top: 10px; + margin-bottom: 10px; +} + +table.docutils td, table.docutils th { + border: 1px solid #ddd !important; + border-radius: 3px; +} + +table p, table li { + text-align: left !important; +} + +table.docutils th { + background-color: #eee; + padding: 0.3em 0.5em; +} + +table.docutils td { + background-color: white; + padding: 0.3em 0.5em; +} + +table.footnote, table.footnote td { + border: 0 !important; +} + +div.footer { + line-height: 150%; + margin-top: -2em; + text-align: right; + width: auto; + margin-right: 10px; +} + +div.footer a:hover { + color: #0095C4; +} diff --git a/Doc/tools/sphinxext/pydoctheme/theme.conf b/Doc/tools/sphinxext/pydoctheme/theme.conf new file mode 100644 --- /dev/null +++ b/Doc/tools/sphinxext/pydoctheme/theme.conf @@ -0,0 +1,23 @@ +[theme] +inherit = default +stylesheet = pydoctheme.css +pygments_style = sphinx + +[options] +bodyfont = 'Lucida Grande', Arial, sans-serif +headfont = 'Lucida Grande', Arial, sans-serif +footerbgcolor = white +footertextcolor = #555555 +relbarbgcolor = white +relbartextcolor = #666666 +relbarlinkcolor = #444444 +sidebarbgcolor = white +sidebartextcolor = #444444 +sidebarlinkcolor = #444444 +bgcolor = white +textcolor = #222222 +linkcolor = #0090c0 +visitedlinkcolor = #00608f +headtextcolor = #1a1a1a +headbgcolor = white +headlinkcolor = #aaaaaa diff --git a/Doc/tools/sphinxext/static/sidebar.js b/Doc/tools/sphinxext/static/sidebar.js new file mode 100644 --- /dev/null +++ b/Doc/tools/sphinxext/static/sidebar.js @@ -0,0 +1,155 @@ +/* + * sidebar.js + * ~~~~~~~~~~ + * + * This script makes the Sphinx sidebar collapsible. + * + * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds in + * .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton used to + * collapse and expand the sidebar. + * + * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden and the + * width of the sidebar and the margin-left of the document are decreased. + * When the sidebar is expanded the opposite happens. This script saves a + * per-browser/per-session cookie used to remember the position of the sidebar + * among the pages. Once the browser is closed the cookie is deleted and the + * position reset to the default (expanded). + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +$(function() { + // global elements used by the functions. + // the 'sidebarbutton' element is defined as global after its + // creation, in the add_sidebar_button function + var bodywrapper = $('.bodywrapper'); + var sidebar = $('.sphinxsidebar'); + var sidebarwrapper = $('.sphinxsidebarwrapper'); + + // original margin-left of the bodywrapper and width of the sidebar + // with the sidebar expanded + var bw_margin_expanded = bodywrapper.css('margin-left'); + var ssb_width_expanded = sidebar.width(); + + // margin-left of the bodywrapper and width of the sidebar + // with the sidebar collapsed + var bw_margin_collapsed = '.8em'; + var ssb_width_collapsed = '.8em'; + + // colors used by the current theme + var dark_color = '#AAAAAA'; + var light_color = '#CCCCCC'; + + function sidebar_is_collapsed() { + return sidebarwrapper.is(':not(:visible)'); + } + + function toggle_sidebar() { + if (sidebar_is_collapsed()) + expand_sidebar(); + else + collapse_sidebar(); + } + + function collapse_sidebar() { + sidebarwrapper.hide(); + sidebar.css('width', ssb_width_collapsed); + bodywrapper.css('margin-left', bw_margin_collapsed); + sidebarbutton.css({ + 'margin-left': '0', + 'height': bodywrapper.height(), + 'border-radius': '5px' + }); + sidebarbutton.find('span').text('?'); + sidebarbutton.attr('title', _('Expand sidebar')); + document.cookie = 'sidebar=collapsed'; + } + + function expand_sidebar() { + bodywrapper.css('margin-left', bw_margin_expanded); + sidebar.css('width', ssb_width_expanded); + sidebarwrapper.show(); + sidebarbutton.css({ + 'margin-left': ssb_width_expanded-12, + 'height': bodywrapper.height(), + 'border-radius': '0 5px 5px 0' + }); + sidebarbutton.find('span').text('?'); + sidebarbutton.attr('title', _('Collapse sidebar')); + //sidebarwrapper.css({'padding-top': + // Math.max(window.pageYOffset - sidebarwrapper.offset().top, 10)}); + document.cookie = 'sidebar=expanded'; + } + + function add_sidebar_button() { + sidebarwrapper.css({ + 'float': 'left', + 'margin-right': '0', + 'width': ssb_width_expanded - 28 + }); + // create the button + sidebar.append( + '
    «
    ' + ); + var sidebarbutton = $('#sidebarbutton'); + // find the height of the viewport to center the '<<' in the page + var viewport_height; + if (window.innerHeight) + viewport_height = window.innerHeight; + else + viewport_height = $(window).height(); + var sidebar_offset = sidebar.offset().top; + var sidebar_height = Math.max(bodywrapper.height(), sidebar.height()); + sidebarbutton.find('span').css({ + 'display': 'block', + 'position': 'fixed', + 'top': Math.min(viewport_height/2, sidebar_height/2 + sidebar_offset) - 10 + }); + + sidebarbutton.click(toggle_sidebar); + sidebarbutton.attr('title', _('Collapse sidebar')); + sidebarbutton.css({ + 'border-radius': '0 5px 5px 0', + 'color': '#444444', + 'background-color': '#CCCCCC', + 'font-size': '1.2em', + 'cursor': 'pointer', + 'height': sidebar_height, + 'padding-top': '1px', + 'padding-left': '1px', + 'margin-left': ssb_width_expanded - 12 + }); + + sidebarbutton.hover( + function () { + $(this).css('background-color', dark_color); + }, + function () { + $(this).css('background-color', light_color); + } + ); + } + + function set_position_from_cookie() { + if (!document.cookie) + return; + var items = document.cookie.split(';'); + for(var k=0; k http://hg.python.org/cpython/rev/7a65fcdb85b6 changeset: 75937:7a65fcdb85b6 user: Michael Foord date: Sun Mar 25 19:53:18 2012 +0100 summary: unittest.mock: a mock created by patch with a spec as the list argument will be callable if __call__ is in the spec files: Lib/unittest/mock.py | 9 +++++- Lib/unittest/test/testmock/testpatch.py | 20 +++++++++++++ 2 files changed, 28 insertions(+), 1 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1166,7 +1166,14 @@ if new_callable is not None: Klass = new_callable elif spec is not None or spec_set is not None: - if not _callable(spec or spec_set): + this_spec = spec + if spec_set is not None: + this_spec = spec_set + if _is_list(this_spec): + not_callable = '__call__' not in this_spec + else: + not_callable = not callable(this_spec) + if not_callable: Klass = NonCallableMagicMock if spec is not None: diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/testmock/testpatch.py @@ -1742,6 +1742,26 @@ p.stop() + def test_callable_spec_as_list(self): + spec = ('__call__',) + p = patch(MODNAME, spec=spec) + m = p.start() + try: + self.assertTrue(callable(m)) + finally: + p.stop() + + + def test_not_callable_spec_as_list(self): + spec = ('foo', 'bar') + p = patch(MODNAME, spec=spec) + m = p.start() + try: + self.assertFalse(callable(m)) + finally: + p.stop() + + if __name__ == '__main__': unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 00:13:02 2012 From: python-checkins at python.org (michael.foord) Date: Mon, 26 Mar 2012 00:13:02 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Adding_unittest=2Emock_docu?= =?utf8?q?mentation?= Message-ID: http://hg.python.org/cpython/rev/adc1fc2dc872 changeset: 75938:adc1fc2dc872 user: Michael Foord date: Sun Mar 25 23:12:55 2012 +0100 summary: Adding unittest.mock documentation files: Doc/library/development.rst | 6 + Doc/library/unittest.mock-examples.rst | 887 +++++++++ Doc/library/unittest.mock-getting-started.rst | 419 ++++ Doc/library/unittest.mock-helpers.rst | 537 +++++ Doc/library/unittest.mock-magicmethods.rst | 226 ++ Doc/library/unittest.mock-patch.rst | 538 +++++ Doc/library/unittest.mock.rst | 900 ++++++++++ Lib/unittest/mock.py | 8 +- 8 files changed, 3516 insertions(+), 5 deletions(-) diff --git a/Doc/library/development.rst b/Doc/library/development.rst --- a/Doc/library/development.rst +++ b/Doc/library/development.rst @@ -19,5 +19,11 @@ pydoc.rst doctest.rst unittest.rst + unittest.mock.rst + unittest.mock-patch.rst + unittest.mock-magicmethods.rst + unittest.mock-helpers.rst + unittest.mock-getting-started.rst + unittest.mock-examples.rst 2to3.rst test.rst diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst new file mode 100644 --- /dev/null +++ b/Doc/library/unittest.mock-examples.rst @@ -0,0 +1,887 @@ +.. _further-examples: + +:mod:`unittest.mock` --- further examples +========================================= + +.. module:: unittest.mock + :synopsis: Mock object library. +.. moduleauthor:: Michael Foord +.. currentmodule:: unittest.mock + +.. versionadded:: 3.3 + + +Here are some more examples for some slightly more advanced scenarios than in +the :ref:`getting started ` guide. + + +Mocking chained calls +--------------------- + +Mocking chained calls is actually straightforward with mock once you +understand the :attr:`~Mock.return_value` attribute. When a mock is called for +the first time, or you fetch its `return_value` before it has been called, a +new `Mock` is created. + +This means that you can see how the object returned from a call to a mocked +object has been used by interrogating the `return_value` mock: + + >>> mock = Mock() + >>> mock().foo(a=2, b=3) + + >>> mock.return_value.foo.assert_called_with(a=2, b=3) + +From here it is a simple step to configure and then make assertions about +chained calls. Of course another alternative is writing your code in a more +testable way in the first place... + +So, suppose we have some code that looks a little bit like this: + + >>> class Something(object): + ... def __init__(self): + ... self.backend = BackendProvider() + ... def method(self): + ... response = self.backend.get_endpoint('foobar').create_call('spam', 'eggs').start_call() + ... # more code + +Assuming that `BackendProvider` is already well tested, how do we test +`method()`? Specifically, we want to test that the code section `# more +code` uses the response object in the correct way. + +As this chain of calls is made from an instance attribute we can monkey patch +the `backend` attribute on a `Something` instance. In this particular case +we are only interested in the return value from the final call to +`start_call` so we don't have much configuration to do. Let's assume the +object it returns is 'file-like', so we'll ensure that our response object +uses the builtin `file` as its `spec`. + +To do this we create a mock instance as our mock backend and create a mock +response object for it. To set the response as the return value for that final +`start_call` we could do this: + + `mock_backend.get_endpoint.return_value.create_call.return_value.start_call.return_value = mock_response`. + +We can do that in a slightly nicer way using the :meth:`~Mock.configure_mock` +method to directly set the return value for us: + + >>> something = Something() + >>> mock_response = Mock(spec=file) + >>> mock_backend = Mock() + >>> config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response} + >>> mock_backend.configure_mock(**config) + +With these we monkey patch the "mock backend" in place and can make the real +call: + + >>> something.backend = mock_backend + >>> something.method() + +Using :attr:`~Mock.mock_calls` we can check the chained call with a single +assert. A chained call is several calls in one line of code, so there will be +several entries in `mock_calls`. We can use :meth:`call.call_list` to create +this list of calls for us: + + >>> chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call() + >>> call_list = chained.call_list() + >>> assert mock_backend.mock_calls == call_list + + +Partial mocking +--------------- + +In some tests I wanted to mock out a call to `datetime.date.today() +`_ to return +a known date, but I didn't want to prevent the code under test from +creating new date objects. Unfortunately `datetime.date` is written in C, and +so I couldn't just monkey-patch out the static `date.today` method. + +I found a simple way of doing this that involved effectively wrapping the date +class with a mock, but passing through calls to the constructor to the real +class (and returning real instances). + +The :func:`patch decorator ` is used here to +mock out the `date` class in the module under test. The :attr:`side_effect` +attribute on the mock date class is then set to a lambda function that returns +a real date. When the mock date class is called a real date will be +constructed and returned by `side_effect`. + + >>> from datetime import date + >>> with patch('mymodule.date') as mock_date: + ... mock_date.today.return_value = date(2010, 10, 8) + ... mock_date.side_effect = lambda *args, **kw: date(*args, **kw) + ... + ... assert mymodule.date.today() == date(2010, 10, 8) + ... assert mymodule.date(2009, 6, 8) == date(2009, 6, 8) + ... + +Note that we don't patch `datetime.date` globally, we patch `date` in the +module that *uses* it. See :ref:`where to patch `. + +When `date.today()` is called a known date is returned, but calls to the +`date(...)` constructor still return normal dates. Without this you can find +yourself having to calculate an expected result using exactly the same +algorithm as the code under test, which is a classic testing anti-pattern. + +Calls to the date constructor are recorded in the `mock_date` attributes +(`call_count` and friends) which may also be useful for your tests. + +An alternative way of dealing with mocking dates, or other builtin classes, +is discussed in `this blog entry +`_. + + +Mocking a Generator Method +-------------------------- + +A Python generator is a function or method that uses the `yield statement +`_ to +return a series of values when iterated over [#]_. + +A generator method / function is called to return the generator object. It is +the generator object that is then iterated over. The protocol method for +iteration is `__iter__ +`_, so we can +mock this using a `MagicMock`. + +Here's an example class with an "iter" method implemented as a generator: + + >>> class Foo(object): + ... def iter(self): + ... for i in [1, 2, 3]: + ... yield i + ... + >>> foo = Foo() + >>> list(foo.iter()) + [1, 2, 3] + + +How would we mock this class, and in particular its "iter" method? + +To configure the values returned from the iteration (implicit in the call to +`list`), we need to configure the object returned by the call to `foo.iter()`. + + >>> mock_foo = MagicMock() + >>> mock_foo.iter.return_value = iter([1, 2, 3]) + >>> list(mock_foo.iter()) + [1, 2, 3] + +.. [#] There are also generator expressions and more `advanced uses + `_ of generators, but we aren't + concerned about them here. A very good introduction to generators and how + powerful they are is: `Generator Tricks for Systems Programmers + `_. + + +Applying the same patch to every test method +-------------------------------------------- + +If you want several patches in place for multiple test methods the obvious way +is to apply the patch decorators to every method. This can feel like unnecessary +repetition. For Python 2.6 or more recent you can use `patch` (in all its +various forms) as a class decorator. This applies the patches to all test +methods on the class. A test method is identified by methods whose names start +with `test`: + + >>> @patch('mymodule.SomeClass') + ... class MyTest(TestCase): + ... + ... def test_one(self, MockSomeClass): + ... self.assertTrue(mymodule.SomeClass is MockSomeClass) + ... + ... def test_two(self, MockSomeClass): + ... self.assertTrue(mymodule.SomeClass is MockSomeClass) + ... + ... def not_a_test(self): + ... return 'something' + ... + >>> MyTest('test_one').test_one() + >>> MyTest('test_two').test_two() + >>> MyTest('test_two').not_a_test() + 'something' + +An alternative way of managing patches is to use the :ref:`start-and-stop`. +These allow you to move the patching into your `setUp` and `tearDown` methods. + + >>> class MyTest(TestCase): + ... def setUp(self): + ... self.patcher = patch('mymodule.foo') + ... self.mock_foo = self.patcher.start() + ... + ... def test_foo(self): + ... self.assertTrue(mymodule.foo is self.mock_foo) + ... + ... def tearDown(self): + ... self.patcher.stop() + ... + >>> MyTest('test_foo').run() + +If you use this technique you must ensure that the patching is "undone" by +calling `stop`. This can be fiddlier than you might think, because if an +exception is raised in the setUp then tearDown is not called. +:meth:`unittest.TestCase.addCleanup` makes this easier: + + >>> class MyTest(TestCase): + ... def setUp(self): + ... patcher = patch('mymodule.foo') + ... self.addCleanup(patcher.stop) + ... self.mock_foo = patcher.start() + ... + ... def test_foo(self): + ... self.assertTrue(mymodule.foo is self.mock_foo) + ... + >>> MyTest('test_foo').run() + + +Mocking Unbound Methods +----------------------- + +Whilst writing tests today I needed to patch an *unbound method* (patching the +method on the class rather than on the instance). I needed self to be passed +in as the first argument because I want to make asserts about which objects +were calling this particular method. The issue is that you can't patch with a +mock for this, because if you replace an unbound method with a mock it doesn't +become a bound method when fetched from the instance, and so it doesn't get +self passed in. The workaround is to patch the unbound method with a real +function instead. The :func:`patch` decorator makes it so simple to +patch out methods with a mock that having to create a real function becomes a +nuisance. + +If you pass `autospec=True` to patch then it does the patching with a +*real* function object. This function object has the same signature as the one +it is replacing, but delegates to a mock under the hood. You still get your +mock auto-created in exactly the same way as before. What it means though, is +that if you use it to patch out an unbound method on a class the mocked +function will be turned into a bound method if it is fetched from an instance. +It will have `self` passed in as the first argument, which is exactly what I +wanted: + + >>> class Foo(object): + ... def foo(self): + ... pass + ... + >>> with patch.object(Foo, 'foo', autospec=True) as mock_foo: + ... mock_foo.return_value = 'foo' + ... foo = Foo() + ... foo.foo() + ... + 'foo' + >>> mock_foo.assert_called_once_with(foo) + +If we don't use `autospec=True` then the unbound method is patched out +with a Mock instance instead, and isn't called with `self`. + + +Checking multiple calls with mock +--------------------------------- + +mock has a nice API for making assertions about how your mock objects are used. + + >>> mock = Mock() + >>> mock.foo_bar.return_value = None + >>> mock.foo_bar('baz', spam='eggs') + >>> mock.foo_bar.assert_called_with('baz', spam='eggs') + +If your mock is only being called once you can use the +:meth:`assert_called_once_with` method that also asserts that the +:attr:`call_count` is one. + + >>> mock.foo_bar.assert_called_once_with('baz', spam='eggs') + >>> mock.foo_bar() + >>> mock.foo_bar.assert_called_once_with('baz', spam='eggs') + Traceback (most recent call last): + ... + AssertionError: Expected to be called once. Called 2 times. + +Both `assert_called_with` and `assert_called_once_with` make assertions about +the *most recent* call. If your mock is going to be called several times, and +you want to make assertions about *all* those calls you can use +:attr:`~Mock.call_args_list`: + + >>> mock = Mock(return_value=None) + >>> mock(1, 2, 3) + >>> mock(4, 5, 6) + >>> mock() + >>> mock.call_args_list + [call(1, 2, 3), call(4, 5, 6), call()] + +The :data:`call` helper makes it easy to make assertions about these calls. You +can build up a list of expected calls and compare it to `call_args_list`. This +looks remarkably similar to the repr of the `call_args_list`: + + >>> expected = [call(1, 2, 3), call(4, 5, 6), call()] + >>> mock.call_args_list == expected + True + + +Coping with mutable arguments +----------------------------- + +Another situation is rare, but can bite you, is when your mock is called with +mutable arguments. `call_args` and `call_args_list` store *references* to the +arguments. If the arguments are mutated by the code under test then you can no +longer make assertions about what the values were when the mock was called. + +Here's some example code that shows the problem. Imagine the following functions +defined in 'mymodule':: + + def frob(val): + pass + + def grob(val): + "First frob and then clear val" + frob(val) + val.clear() + +When we try to test that `grob` calls `frob` with the correct argument look +what happens: + + >>> with patch('mymodule.frob') as mock_frob: + ... val = set([6]) + ... mymodule.grob(val) + ... + >>> val + set([]) + >>> mock_frob.assert_called_with(set([6])) + Traceback (most recent call last): + ... + AssertionError: Expected: ((set([6]),), {}) + Called with: ((set([]),), {}) + +One possibility would be for mock to copy the arguments you pass in. This +could then cause problems if you do assertions that rely on object identity +for equality. + +Here's one solution that uses the :attr:`side_effect` +functionality. If you provide a `side_effect` function for a mock then +`side_effect` will be called with the same args as the mock. This gives us an +opportunity to copy the arguments and store them for later assertions. In this +example I'm using *another* mock to store the arguments so that I can use the +mock methods for doing the assertion. Again a helper function sets this up for +me. + + >>> from copy import deepcopy + >>> from unittest.mock import Mock, patch, DEFAULT + >>> def copy_call_args(mock): + ... new_mock = Mock() + ... def side_effect(*args, **kwargs): + ... args = deepcopy(args) + ... kwargs = deepcopy(kwargs) + ... new_mock(*args, **kwargs) + ... return DEFAULT + ... mock.side_effect = side_effect + ... return new_mock + ... + >>> with patch('mymodule.frob') as mock_frob: + ... new_mock = copy_call_args(mock_frob) + ... val = set([6]) + ... mymodule.grob(val) + ... + >>> new_mock.assert_called_with(set([6])) + >>> new_mock.call_args + call(set([6])) + +`copy_call_args` is called with the mock that will be called. It returns a new +mock that we do the assertion on. The `side_effect` function makes a copy of +the args and calls our `new_mock` with the copy. + +.. note:: + + If your mock is only going to be used once there is an easier way of + checking arguments at the point they are called. You can simply do the + checking inside a `side_effect` function. + + >>> def side_effect(arg): + ... assert arg == set([6]) + ... + >>> mock = Mock(side_effect=side_effect) + >>> mock(set([6])) + >>> mock(set()) + Traceback (most recent call last): + ... + AssertionError + +An alternative approach is to create a subclass of `Mock` or `MagicMock` that +copies (using :func:`copy.deepcopy`) the arguments. +Here's an example implementation: + + >>> from copy import deepcopy + >>> class CopyingMock(MagicMock): + ... def __call__(self, *args, **kwargs): + ... args = deepcopy(args) + ... kwargs = deepcopy(kwargs) + ... return super(CopyingMock, self).__call__(*args, **kwargs) + ... + >>> c = CopyingMock(return_value=None) + >>> arg = set() + >>> c(arg) + >>> arg.add(1) + >>> c.assert_called_with(set()) + >>> c.assert_called_with(arg) + Traceback (most recent call last): + ... + AssertionError: Expected call: mock(set([1])) + Actual call: mock(set([])) + >>> c.foo + + +When you subclass `Mock` or `MagicMock` all dynamically created attributes, +and the `return_value` will use your subclass automatically. That means all +children of a `CopyingMock` will also have the type `CopyingMock`. + + +Multiple calls with different effects +------------------------------------- + +Handling code that needs to behave differently on subsequent calls during the +test can be tricky. For example you may have a function that needs to raise +an exception the first time it is called but returns a response on the second +call (testing retry behaviour). + +One approach is to use a :attr:`side_effect` function that replaces itself. The +first time it is called the `side_effect` sets a new `side_effect` that will +be used for the second call. It then raises an exception: + + >>> def side_effect(*args): + ... def second_call(*args): + ... return 'response' + ... mock.side_effect = second_call + ... raise Exception('boom') + ... + >>> mock = Mock(side_effect=side_effect) + >>> mock('first') + Traceback (most recent call last): + ... + Exception: boom + >>> mock('second') + 'response' + >>> mock.assert_called_with('second') + +Another perfectly valid way would be to pop return values from a list. If the +return value is an exception, raise it instead of returning it: + + >>> returns = [Exception('boom'), 'response'] + >>> def side_effect(*args): + ... result = returns.pop(0) + ... if isinstance(result, Exception): + ... raise result + ... return result + ... + >>> mock = Mock(side_effect=side_effect) + >>> mock('first') + Traceback (most recent call last): + ... + Exception: boom + >>> mock('second') + 'response' + >>> mock.assert_called_with('second') + +Which approach you prefer is a matter of taste. The first approach is actually +a line shorter but maybe the second approach is more readable. + + +Nesting Patches +--------------- + +Using patch as a context manager is nice, but if you do multiple patches you +can end up with nested with statements indenting further and further to the +right: + + >>> class MyTest(TestCase): + ... + ... def test_foo(self): + ... with patch('mymodule.Foo') as mock_foo: + ... with patch('mymodule.Bar') as mock_bar: + ... with patch('mymodule.Spam') as mock_spam: + ... assert mymodule.Foo is mock_foo + ... assert mymodule.Bar is mock_bar + ... assert mymodule.Spam is mock_spam + ... + >>> original = mymodule.Foo + >>> MyTest('test_foo').test_foo() + >>> assert mymodule.Foo is original + +With unittest `cleanup` functions and the :ref:`start-and-stop` we can +achieve the same effect without the nested indentation. A simple helper +method, `create_patch`, puts the patch in place and returns the created mock +for us: + + >>> class MyTest(TestCase): + ... + ... def create_patch(self, name): + ... patcher = patch(name) + ... thing = patcher.start() + ... self.addCleanup(patcher.stop) + ... return thing + ... + ... def test_foo(self): + ... mock_foo = self.create_patch('mymodule.Foo') + ... mock_bar = self.create_patch('mymodule.Bar') + ... mock_spam = self.create_patch('mymodule.Spam') + ... + ... assert mymodule.Foo is mock_foo + ... assert mymodule.Bar is mock_bar + ... assert mymodule.Spam is mock_spam + ... + >>> original = mymodule.Foo + >>> MyTest('test_foo').run() + >>> assert mymodule.Foo is original + + +Mocking a dictionary with MagicMock +----------------------------------- + +You may want to mock a dictionary, or other container object, recording all +access to it whilst having it still behave like a dictionary. + +We can do this with :class:`MagicMock`, which will behave like a dictionary, +and using :data:`~Mock.side_effect` to delegate dictionary access to a real +underlying dictionary that is under our control. + +When the `__getitem__` and `__setitem__` methods of our `MagicMock` are called +(normal dictionary access) then `side_effect` is called with the key (and in +the case of `__setitem__` the value too). We can also control what is returned. + +After the `MagicMock` has been used we can use attributes like +:data:`~Mock.call_args_list` to assert about how the dictionary was used: + + >>> my_dict = {'a': 1, 'b': 2, 'c': 3} + >>> def getitem(name): + ... return my_dict[name] + ... + >>> def setitem(name, val): + ... my_dict[name] = val + ... + >>> mock = MagicMock() + >>> mock.__getitem__.side_effect = getitem + >>> mock.__setitem__.side_effect = setitem + +.. note:: + + An alternative to using `MagicMock` is to use `Mock` and *only* provide + the magic methods you specifically want: + + >>> mock = Mock() + >>> mock.__setitem__ = Mock(side_effect=getitem) + >>> mock.__getitem__ = Mock(side_effect=setitem) + + A *third* option is to use `MagicMock` but passing in `dict` as the `spec` + (or `spec_set`) argument so that the `MagicMock` created only has + dictionary magic methods available: + + >>> mock = MagicMock(spec_set=dict) + >>> mock.__getitem__.side_effect = getitem + >>> mock.__setitem__.side_effect = setitem + +With these side effect functions in place, the `mock` will behave like a normal +dictionary but recording the access. It even raises a `KeyError` if you try +to access a key that doesn't exist. + + >>> mock['a'] + 1 + >>> mock['c'] + 3 + >>> mock['d'] + Traceback (most recent call last): + ... + KeyError: 'd' + >>> mock['b'] = 'fish' + >>> mock['d'] = 'eggs' + >>> mock['b'] + 'fish' + >>> mock['d'] + 'eggs' + +After it has been used you can make assertions about the access using the normal +mock methods and attributes: + + >>> mock.__getitem__.call_args_list + [call('a'), call('c'), call('d'), call('b'), call('d')] + >>> mock.__setitem__.call_args_list + [call('b', 'fish'), call('d', 'eggs')] + >>> my_dict + {'a': 1, 'c': 3, 'b': 'fish', 'd': 'eggs'} + + +Mock subclasses and their attributes +------------------------------------ + +There are various reasons why you might want to subclass `Mock`. One reason +might be to add helper methods. Here's a silly example: + + >>> class MyMock(MagicMock): + ... def has_been_called(self): + ... return self.called + ... + >>> mymock = MyMock(return_value=None) + >>> mymock + + >>> mymock.has_been_called() + False + >>> mymock() + >>> mymock.has_been_called() + True + +The standard behaviour for `Mock` instances is that attributes and the return +value mocks are of the same type as the mock they are accessed on. This ensures +that `Mock` attributes are `Mocks` and `MagicMock` attributes are `MagicMocks` +[#]_. So if you're subclassing to add helper methods then they'll also be +available on the attributes and return value mock of instances of your +subclass. + + >>> mymock.foo + + >>> mymock.foo.has_been_called() + False + >>> mymock.foo() + + >>> mymock.foo.has_been_called() + True + +Sometimes this is inconvenient. For example, `one user +`_ is subclassing mock to +created a `Twisted adaptor +`_. +Having this applied to attributes too actually causes errors. + +`Mock` (in all its flavours) uses a method called `_get_child_mock` to create +these "sub-mocks" for attributes and return values. You can prevent your +subclass being used for attributes by overriding this method. The signature is +that it takes arbitrary keyword arguments (`**kwargs`) which are then passed +onto the mock constructor: + + >>> class Subclass(MagicMock): + ... def _get_child_mock(self, **kwargs): + ... return MagicMock(**kwargs) + ... + >>> mymock = Subclass() + >>> mymock.foo + + >>> assert isinstance(mymock, Subclass) + >>> assert not isinstance(mymock.foo, Subclass) + >>> assert not isinstance(mymock(), Subclass) + +.. [#] An exception to this rule are the non-callable mocks. Attributes use the + callable variant because otherwise non-callable mocks couldn't have callable + methods. + + +Mocking imports with patch.dict +------------------------------- + +One situation where mocking can be hard is where you have a local import inside +a function. These are harder to mock because they aren't using an object from +the module namespace that we can patch out. + +Generally local imports are to be avoided. They are sometimes done to prevent +circular dependencies, for which there is *usually* a much better way to solve +the problem (refactor the code) or to prevent "up front costs" by delaying the +import. This can also be solved in better ways than an unconditional local +import (store the module as a class or module attribute and only do the import +on first use). + +That aside there is a way to use `mock` to affect the results of an import. +Importing fetches an *object* from the `sys.modules` dictionary. Note that it +fetches an *object*, which need not be a module. Importing a module for the +first time results in a module object being put in `sys.modules`, so usually +when you import something you get a module back. This need not be the case +however. + +This means you can use :func:`patch.dict` to *temporarily* put a mock in place +in `sys.modules`. Any imports whilst this patch is active will fetch the mock. +When the patch is complete (the decorated function exits, the with statement +body is complete or `patcher.stop()` is called) then whatever was there +previously will be restored safely. + +Here's an example that mocks out the 'fooble' module. + + >>> mock = Mock() + >>> with patch.dict('sys.modules', {'fooble': mock}): + ... import fooble + ... fooble.blob() + ... + + >>> assert 'fooble' not in sys.modules + >>> mock.blob.assert_called_once_with() + +As you can see the `import fooble` succeeds, but on exit there is no 'fooble' +left in `sys.modules`. + +This also works for the `from module import name` form: + + >>> mock = Mock() + >>> with patch.dict('sys.modules', {'fooble': mock}): + ... from fooble import blob + ... blob.blip() + ... + + >>> mock.blob.blip.assert_called_once_with() + +With slightly more work you can also mock package imports: + + >>> mock = Mock() + >>> modules = {'package': mock, 'package.module': mock.module} + >>> with patch.dict('sys.modules', modules): + ... from package.module import fooble + ... fooble() + ... + + >>> mock.module.fooble.assert_called_once_with() + + +Tracking order of calls and less verbose call assertions +-------------------------------------------------------- + +The :class:`Mock` class allows you to track the *order* of method calls on +your mock objects through the :attr:`~Mock.method_calls` attribute. This +doesn't allow you to track the order of calls between separate mock objects, +however we can use :attr:`~Mock.mock_calls` to achieve the same effect. + +Because mocks track calls to child mocks in `mock_calls`, and accessing an +arbitrary attribute of a mock creates a child mock, we can create our separate +mocks from a parent one. Calls to those child mock will then all be recorded, +in order, in the `mock_calls` of the parent: + + >>> manager = Mock() + >>> mock_foo = manager.foo + >>> mock_bar = manager.bar + + >>> mock_foo.something() + + >>> mock_bar.other.thing() + + + >>> manager.mock_calls + [call.foo.something(), call.bar.other.thing()] + +We can then assert about the calls, including the order, by comparing with +the `mock_calls` attribute on the manager mock: + + >>> expected_calls = [call.foo.something(), call.bar.other.thing()] + >>> manager.mock_calls == expected_calls + True + +If `patch` is creating, and putting in place, your mocks then you can attach +them to a manager mock using the :meth:`~Mock.attach_mock` method. After +attaching calls will be recorded in `mock_calls` of the manager. + + >>> manager = MagicMock() + >>> with patch('mymodule.Class1') as MockClass1: + ... with patch('mymodule.Class2') as MockClass2: + ... manager.attach_mock(MockClass1, 'MockClass1') + ... manager.attach_mock(MockClass2, 'MockClass2') + ... MockClass1().foo() + ... MockClass2().bar() + ... + + + >>> manager.mock_calls + [call.MockClass1(), + call.MockClass1().foo(), + call.MockClass2(), + call.MockClass2().bar()] + +If many calls have been made, but you're only interested in a particular +sequence of them then an alternative is to use the +:meth:`~Mock.assert_has_calls` method. This takes a list of calls (constructed +with the :data:`call` object). If that sequence of calls are in +:attr:`~Mock.mock_calls` then the assert succeeds. + + >>> m = MagicMock() + >>> m().foo().bar().baz() + + >>> m.one().two().three() + + >>> calls = call.one().two().three().call_list() + >>> m.assert_has_calls(calls) + +Even though the chained call `m.one().two().three()` aren't the only calls that +have been made to the mock, the assert still succeeds. + +Sometimes a mock may have several calls made to it, and you are only interested +in asserting about *some* of those calls. You may not even care about the +order. In this case you can pass `any_order=True` to `assert_has_calls`: + + >>> m = MagicMock() + >>> m(1), m.two(2, 3), m.seven(7), m.fifty('50') + (...) + >>> calls = [call.fifty('50'), call(1), call.seven(7)] + >>> m.assert_has_calls(calls, any_order=True) + + +More complex argument matching +------------------------------ + +Using the same basic concept as :data:`ANY` we can implement matchers to do more +complex assertions on objects used as arguments to mocks. + +Suppose we expect some object to be passed to a mock that by default +compares equal based on object identity (which is the Python default for user +defined classes). To use :meth:`~Mock.assert_called_with` we would need to pass +in the exact same object. If we are only interested in some of the attributes +of this object then we can create a matcher that will check these attributes +for us. + +You can see in this example how a 'standard' call to `assert_called_with` isn't +sufficient: + + >>> class Foo(object): + ... def __init__(self, a, b): + ... self.a, self.b = a, b + ... + >>> mock = Mock(return_value=None) + >>> mock(Foo(1, 2)) + >>> mock.assert_called_with(Foo(1, 2)) + Traceback (most recent call last): + ... + AssertionError: Expected: call(<__main__.Foo object at 0x...>) + Actual call: call(<__main__.Foo object at 0x...>) + +A comparison function for our `Foo` class might look something like this: + + >>> def compare(self, other): + ... if not type(self) == type(other): + ... return False + ... if self.a != other.a: + ... return False + ... if self.b != other.b: + ... return False + ... return True + ... + +And a matcher object that can use comparison functions like this for its +equality operation would look something like this: + + >>> class Matcher(object): + ... def __init__(self, compare, some_obj): + ... self.compare = compare + ... self.some_obj = some_obj + ... def __eq__(self, other): + ... return self.compare(self.some_obj, other) + ... + +Putting all this together: + + >>> match_foo = Matcher(compare, Foo(1, 2)) + >>> mock.assert_called_with(match_foo) + +The `Matcher` is instantiated with our compare function and the `Foo` object +we want to compare against. In `assert_called_with` the `Matcher` equality +method will be called, which compares the object the mock was called with +against the one we created our matcher with. If they match then +`assert_called_with` passes, and if they don't an `AssertionError` is raised: + + >>> match_wrong = Matcher(compare, Foo(3, 4)) + >>> mock.assert_called_with(match_wrong) + Traceback (most recent call last): + ... + AssertionError: Expected: ((,), {}) + Called with: ((,), {}) + +With a bit of tweaking you could have the comparison function raise the +`AssertionError` directly and provide a more useful failure message. + +As of version 1.5, the Python testing library `PyHamcrest +`_ provides similar functionality, +that may be useful here, in the form of its equality matcher +(`hamcrest.library.integration.match_equality +`_). diff --git a/Doc/library/unittest.mock-getting-started.rst b/Doc/library/unittest.mock-getting-started.rst new file mode 100644 --- /dev/null +++ b/Doc/library/unittest.mock-getting-started.rst @@ -0,0 +1,419 @@ +:mod:`unittest.mock` --- getting started +======================================== + +.. module:: unittest.mock + :synopsis: Mock object library. +.. moduleauthor:: Michael Foord +.. currentmodule:: unittest.mock + +.. versionadded:: 3.3 + + +.. _getting-started: + +Using Mock +---------- + +Mock Patching Methods +~~~~~~~~~~~~~~~~~~~~~ + +Common uses for :class:`Mock` objects include: + +* Patching methods +* Recording method calls on objects + +You might want to replace a method on an object to check that +it is called with the correct arguments by another part of the system: + + >>> real = SomeClass() + >>> real.method = MagicMock(name='method') + >>> real.method(3, 4, 5, key='value') + + +Once our mock has been used (`real.method` in this example) it has methods +and attributes that allow you to make assertions about how it has been used. + +.. note:: + + In most of these examples the :class:`Mock` and :class:`MagicMock` classes + are interchangeable. As the `MagicMock` is the more capable class it makes + a sensible one to use by default. + +Once the mock has been called its :attr:`~Mock.called` attribute is set to +`True`. More importantly we can use the :meth:`~Mock.assert_called_with` or +:meth`~Mock.assert_called_once_with` method to check that it was called with +the correct arguments. + +This example tests that calling `ProductionClass().method` results in a call to +the `something` method: + + >>> class ProductionClass(object): + ... def method(self): + ... self.something(1, 2, 3) + ... def something(self, a, b, c): + ... pass + ... + >>> real = ProductionClass() + >>> real.something = MagicMock() + >>> real.method() + >>> real.something.assert_called_once_with(1, 2, 3) + + + +Mock for Method Calls on an Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the last example we patched a method directly on an object to check that it +was called correctly. Another common use case is to pass an object into a +method (or some part of the system under test) and then check that it is used +in the correct way. + +The simple `ProductionClass` below has a `closer` method. If it is called with +an object then it calls `close` on it. + + >>> class ProductionClass(object): + ... def closer(self, something): + ... something.close() + ... + +So to test it we need to pass in an object with a `close` method and check +that it was called correctly. + + >>> real = ProductionClass() + >>> mock = Mock() + >>> real.closer(mock) + >>> mock.close.assert_called_with() + +We don't have to do any work to provide the 'close' method on our mock. +Accessing close creates it. So, if 'close' hasn't already been called then +accessing it in the test will create it, but :meth:`~Mock.assert_called_with` +will raise a failure exception. + + +Mocking Classes +~~~~~~~~~~~~~~~ + +A common use case is to mock out classes instantiated by your code under test. +When you patch a class, then that class is replaced with a mock. Instances +are created by *calling the class*. This means you access the "mock instance" +by looking at the return value of the mocked class. + +In the example below we have a function `some_function` that instantiates `Foo` +and calls a method on it. The call to `patch` replaces the class `Foo` with a +mock. The `Foo` instance is the result of calling the mock, so it is configured +by modify the mock :attr:`~Mock.return_value`. + + >>> def some_function(): + ... instance = module.Foo() + ... return instance.method() + ... + >>> with patch('module.Foo') as mock: + ... instance = mock.return_value + ... instance.method.return_value = 'the result' + ... result = some_function() + ... assert result == 'the result' + + +Naming your mocks +~~~~~~~~~~~~~~~~~ + +It can be useful to give your mocks a name. The name is shown in the repr of +the mock and can be helpful when the mock appears in test failure messages. The +name is also propagated to attributes or methods of the mock: + + >>> mock = MagicMock(name='foo') + >>> mock + + >>> mock.method + + + +Tracking all Calls +~~~~~~~~~~~~~~~~~~ + +Often you want to track more than a single call to a method. The +:attr:`~Mock.mock_calls` attribute records all calls +to child attributes of the mock - and also to their children. + + >>> mock = MagicMock() + >>> mock.method() + + >>> mock.attribute.method(10, x=53) + + >>> mock.mock_calls + [call.method(), call.attribute.method(10, x=53)] + +If you make an assertion about `mock_calls` and any unexpected methods +have been called, then the assertion will fail. This is useful because as well +as asserting that the calls you expected have been made, you are also checking +that they were made in the right order and with no additional calls: + +You use the :data:`call` object to construct lists for comparing with +`mock_calls`: + + >>> expected = [call.method(), call.attribute.method(10, x=53)] + >>> mock.mock_calls == expected + True + + +Setting Return Values and Attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting the return values on a mock object is trivially easy: + + >>> mock = Mock() + >>> mock.return_value = 3 + >>> mock() + 3 + +Of course you can do the same for methods on the mock: + + >>> mock = Mock() + >>> mock.method.return_value = 3 + >>> mock.method() + 3 + +The return value can also be set in the constructor: + + >>> mock = Mock(return_value=3) + >>> mock() + 3 + +If you need an attribute setting on your mock, just do it: + + >>> mock = Mock() + >>> mock.x = 3 + >>> mock.x + 3 + +Sometimes you want to mock up a more complex situation, like for example +`mock.connection.cursor().execute("SELECT 1")`. If we wanted this call to +return a list, then we have to configure the result of the nested call. + +We can use :data:`call` to construct the set of calls in a "chained call" like +this for easy assertion afterwards: + + >>> mock = Mock() + >>> cursor = mock.connection.cursor.return_value + >>> cursor.execute.return_value = ['foo'] + >>> mock.connection.cursor().execute("SELECT 1") + ['foo'] + >>> expected = call.connection.cursor().execute("SELECT 1").call_list() + >>> mock.mock_calls + [call.connection.cursor(), call.connection.cursor().execute('SELECT 1')] + >>> mock.mock_calls == expected + True + +It is the call to `.call_list()` that turns our call object into a list of +calls representing the chained calls. + + +Raising exceptions with mocks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A useful attribute is :attr:`~Mock.side_effect`. If you set this to an +exception class or instance then the exception will be raised when the mock +is called. + + >>> mock = Mock(side_effect=Exception('Boom!')) + >>> mock() + Traceback (most recent call last): + ... + Exception: Boom! + + +Side effect functions and iterables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`side_effect` can also be set to a function or an iterable. The use case for +`side_effect` as an iterable is where your mock is going to be called several +times, and you want each call to return a different value. When you set +`side_effect` to an iterable every call to the mock returns the next value +from the iterable: + + >>> mock = MagicMock(side_effect=[4, 5, 6]) + >>> mock() + 4 + >>> mock() + 5 + >>> mock() + 6 + + +For more advanced use cases, like dynamically varying the return values +depending on what the mock is called with, `side_effect` can be a function. +The function will be called with the same arguments as the mock. Whatever the +function returns is what the call returns: + + >>> vals = {(1, 2): 1, (2, 3): 2} + >>> def side_effect(*args): + ... return vals[args] + ... + >>> mock = MagicMock(side_effect=side_effect) + >>> mock(1, 2) + 1 + >>> mock(2, 3) + 2 + + +Creating a Mock from an Existing Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One problem with over use of mocking is that it couples your tests to the +implementation of your mocks rather than your real code. Suppose you have a +class that implements `some_method`. In a test for another class, you +provide a mock of this object that *also* provides `some_method`. If later +you refactor the first class, so that it no longer has `some_method` - then +your tests will continue to pass even though your code is now broken! + +`Mock` allows you to provide an object as a specification for the mock, +using the `spec` keyword argument. Accessing methods / attributes on the +mock that don't exist on your specification object will immediately raise an +attribute error. If you change the implementation of your specification, then +tests that use that class will start failing immediately without you having to +instantiate the class in those tests. + + >>> mock = Mock(spec=SomeClass) + >>> mock.old_method() + Traceback (most recent call last): + ... + AttributeError: object has no attribute 'old_method' + +If you want a stronger form of specification that prevents the setting +of arbitrary attributes as well as the getting of them then you can use +`spec_set` instead of `spec`. + + + +Patch Decorators +---------------- + +.. note:: + + With `patch` it matters that you patch objects in the namespace where they + are looked up. This is normally straightforward, but for a quick guide + read :ref:`where to patch `. + + +A common need in tests is to patch a class attribute or a module attribute, +for example patching a builtin or patching a class in a module to test that it +is instantiated. Modules and classes are effectively global, so patching on +them has to be undone after the test or the patch will persist into other +tests and cause hard to diagnose problems. + +mock provides three convenient decorators for this: `patch`, `patch.object` and +`patch.dict`. `patch` takes a single string, of the form +`package.module.Class.attribute` to specify the attribute you are patching. It +also optionally takes a value that you want the attribute (or class or +whatever) to be replaced with. 'patch.object' takes an object and the name of +the attribute you would like patched, plus optionally the value to patch it +with. + +`patch.object`: + + >>> original = SomeClass.attribute + >>> @patch.object(SomeClass, 'attribute', sentinel.attribute) + ... def test(): + ... assert SomeClass.attribute == sentinel.attribute + ... + >>> test() + >>> assert SomeClass.attribute == original + + >>> @patch('package.module.attribute', sentinel.attribute) + ... def test(): + ... from package.module import attribute + ... assert attribute is sentinel.attribute + ... + >>> test() + +If you are patching a module (including `__builtin__`) then use `patch` +instead of `patch.object`: + + >>> mock = MagicMock(return_value = sentinel.file_handle) + >>> with patch('__builtin__.open', mock): + ... handle = open('filename', 'r') + ... + >>> mock.assert_called_with('filename', 'r') + >>> assert handle == sentinel.file_handle, "incorrect file handle returned" + +The module name can be 'dotted', in the form `package.module` if needed: + + >>> @patch('package.module.ClassName.attribute', sentinel.attribute) + ... def test(): + ... from package.module import ClassName + ... assert ClassName.attribute == sentinel.attribute + ... + >>> test() + +A nice pattern is to actually decorate test methods themselves: + + >>> class MyTest(unittest2.TestCase): + ... @patch.object(SomeClass, 'attribute', sentinel.attribute) + ... def test_something(self): + ... self.assertEqual(SomeClass.attribute, sentinel.attribute) + ... + >>> original = SomeClass.attribute + >>> MyTest('test_something').test_something() + >>> assert SomeClass.attribute == original + +If you want to patch with a Mock, you can use `patch` with only one argument +(or `patch.object` with two arguments). The mock will be created for you and +passed into the test function / method: + + >>> class MyTest(unittest2.TestCase): + ... @patch.object(SomeClass, 'static_method') + ... def test_something(self, mock_method): + ... SomeClass.static_method() + ... mock_method.assert_called_with() + ... + >>> MyTest('test_something').test_something() + +You can stack up multiple patch decorators using this pattern: + + >>> class MyTest(unittest2.TestCase): + ... @patch('package.module.ClassName1') + ... @patch('package.module.ClassName2') + ... def test_something(self, MockClass2, MockClass1): + ... self.assertTrue(package.module.ClassName1 is MockClass1) + ... self.assertTrue(package.module.ClassName2 is MockClass2) + ... + >>> MyTest('test_something').test_something() + +When you nest patch decorators the mocks are passed in to the decorated +function in the same order they applied (the normal *python* order that +decorators are applied). This means from the bottom up, so in the example +above the mock for `test_module.ClassName2` is passed in first. + +There is also :func:`patch.dict` for setting values in a dictionary just +during a scope and restoring the dictionary to its original state when the test +ends: + + >>> foo = {'key': 'value'} + >>> original = foo.copy() + >>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True): + ... assert foo == {'newkey': 'newvalue'} + ... + >>> assert foo == original + +`patch`, `patch.object` and `patch.dict` can all be used as context managers. + +Where you use `patch` to create a mock for you, you can get a reference to the +mock using the "as" form of the with statement: + + >>> class ProductionClass(object): + ... def method(self): + ... pass + ... + >>> with patch.object(ProductionClass, 'method') as mock_method: + ... mock_method.return_value = None + ... real = ProductionClass() + ... real.method(1, 2, 3) + ... + >>> mock_method.assert_called_with(1, 2, 3) + + +As an alternative `patch`, `patch.object` and `patch.dict` can be used as +class decorators. When used in this way it is the same as applying the +decorator indvidually to every method whose name starts with "test". + +For some more advanced examples, see the :ref:`further-examples` page. diff --git a/Doc/library/unittest.mock-helpers.rst b/Doc/library/unittest.mock-helpers.rst new file mode 100644 --- /dev/null +++ b/Doc/library/unittest.mock-helpers.rst @@ -0,0 +1,537 @@ +:mod:`unittest.mock` --- helpers +================================ + +.. module:: unittest.mock + :synopsis: Mock object library. +.. moduleauthor:: Michael Foord +.. currentmodule:: unittest.mock + +.. versionadded:: 3.3 + + +sentinel +-------- + +.. data:: sentinel + + The ``sentinel`` object provides a convenient way of providing unique + objects for your tests. + + Attributes are created on demand when you access them by name. Accessing + the same attribute will always return the same object. The objects + returned have a sensible repr so that test failure messages are readable. + +Sometimes when testing you need to test that a specific object is passed as an +argument to another method, or returned. It can be common to create named +sentinel objects to test this. `sentinel` provides a convenient way of +creating and testing the identity of objects like this. + +In this example we monkey patch `method` to return `sentinel.some_object`: + + >>> real = ProductionClass() + >>> real.method = Mock(name="method") + >>> real.method.return_value = sentinel.some_object + >>> result = real.method() + >>> assert result is sentinel.some_object + >>> sentinel.some_object + sentinel.some_object + + +DEFAULT +------- + + +.. data:: DEFAULT + + The `DEFAULT` object is a pre-created sentinel (actually + `sentinel.DEFAULT`). It can be used by :attr:`~Mock.side_effect` + functions to indicate that the normal return value should be used. + + + +call +---- + +.. function:: call(*args, **kwargs) + + `call` is a helper object for making simpler assertions, for comparing + with :attr:`~Mock.call_args`, :attr:`~Mock.call_args_list`, + :attr:`~Mock.mock_calls` and:attr: `~Mock.method_calls`. `call` can also be + used with :meth:`~Mock.assert_has_calls`. + + >>> m = MagicMock(return_value=None) + >>> m(1, 2, a='foo', b='bar') + >>> m() + >>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()] + True + +.. method:: call.call_list() + + For a call object that represents multiple calls, `call_list` + returns a list of all the intermediate calls as well as the + final call. + +`call_list` is particularly useful for making assertions on "chained calls". A +chained call is multiple calls on a single line of code. This results in +multiple entries in :attr:`~Mock.mock_calls` on a mock. Manually constructing +the sequence of calls can be tedious. + +:meth:`~call.call_list` can construct the sequence of calls from the same +chained call: + + >>> m = MagicMock() + >>> m(1).method(arg='foo').other('bar')(2.0) + + >>> kall = call(1).method(arg='foo').other('bar')(2.0) + >>> kall.call_list() + [call(1), + call().method(arg='foo'), + call().method().other('bar'), + call().method().other()(2.0)] + >>> m.mock_calls == kall.call_list() + True + +.. _calls-as-tuples: + +A `call` object is either a tuple of (positional args, keyword args) or +(name, positional args, keyword args) depending on how it was constructed. When +you construct them yourself this isn't particularly interesting, but the `call` +objects that are in the :attr:`Mock.call_args`, :attr:`Mock.call_args_list` and +:attr:`Mock.mock_calls` attributes can be introspected to get at the individual +arguments they contain. + +The `call` objects in :attr:`Mock.call_args` and :attr:`Mock.call_args_list` +are two-tuples of (positional args, keyword args) whereas the `call` objects +in :attr:`Mock.mock_calls`, along with ones you construct yourself, are +three-tuples of (name, positional args, keyword args). + +You can use their "tupleness" to pull out the individual arguments for more +complex introspection and assertions. The positional arguments are a tuple +(an empty tuple if there are no positional arguments) and the keyword +arguments are a dictionary: + + >>> m = MagicMock(return_value=None) + >>> m(1, 2, 3, arg='one', arg2='two') + >>> kall = m.call_args + >>> args, kwargs = kall + >>> args + (1, 2, 3) + >>> kwargs + {'arg2': 'two', 'arg': 'one'} + >>> args is kall[0] + True + >>> kwargs is kall[1] + True + + >>> m = MagicMock() + >>> m.foo(4, 5, 6, arg='two', arg2='three') + + >>> kall = m.mock_calls[0] + >>> name, args, kwargs = kall + >>> name + 'foo' + >>> args + (4, 5, 6) + >>> kwargs + {'arg2': 'three', 'arg': 'two'} + >>> name is m.mock_calls[0][0] + True + + +create_autospec +--------------- + +.. function:: create_autospec(spec, spec_set=False, instance=False, **kwargs) + + Create a mock object using another object as a spec. Attributes on the + mock will use the corresponding attribute on the `spec` object as their + spec. + + Functions or methods being mocked will have their arguments checked to + ensure that they are called with the correct signature. + + If `spec_set` is `True` then attempting to set attributes that don't exist + on the spec object will raise an `AttributeError`. + + If a class is used as a spec then the return value of the mock (the + instance of the class) will have the same spec. You can use a class as the + spec for an instance object by passing `instance=True`. The returned mock + will only be callable if instances of the mock are callable. + + `create_autospec` also takes arbitrary keyword arguments that are passed to + the constructor of the created mock. + +See :ref:`auto-speccing` for examples of how to use auto-speccing with +`create_autospec` and the `autospec` argument to :func:`patch`. + + +ANY +--- + +.. data:: ANY + +Sometimes you may need to make assertions about *some* of the arguments in a +call to mock, but either not care about some of the arguments or want to pull +them individually out of :attr:`~Mock.call_args` and make more complex +assertions on them. + +To ignore certain arguments you can pass in objects that compare equal to +*everything*. Calls to :meth:`~Mock.assert_called_with` and +:meth:`~Mock.assert_called_once_with` will then succeed no matter what was +passed in. + + >>> mock = Mock(return_value=None) + >>> mock('foo', bar=object()) + >>> mock.assert_called_once_with('foo', bar=ANY) + +`ANY` can also be used in comparisons with call lists like +:attr:`~Mock.mock_calls`: + + >>> m = MagicMock(return_value=None) + >>> m(1) + >>> m(1, 2) + >>> m(object()) + >>> m.mock_calls == [call(1), call(1, 2), ANY] + True + + + +FILTER_DIR +---------- + +.. data:: FILTER_DIR + +`FILTER_DIR` is a module level variable that controls the way mock objects +respond to `dir` (only for Python 2.6 or more recent). The default is `True`, +which uses the filtering described below, to only show useful members. If you +dislike this filtering, or need to switch it off for diagnostic purposes, then +set `mock.FILTER_DIR = False`. + +With filtering on, `dir(some_mock)` shows only useful attributes and will +include any dynamically created attributes that wouldn't normally be shown. +If the mock was created with a `spec` (or `autospec` of course) then all the +attributes from the original are shown, even if they haven't been accessed +yet: + + >>> dir(Mock()) + ['assert_any_call', + 'assert_called_once_with', + 'assert_called_with', + 'assert_has_calls', + 'attach_mock', + ... + >>> from urllib import request + >>> dir(Mock(spec=request)) + ['AbstractBasicAuthHandler', + 'AbstractDigestAuthHandler', + 'AbstractHTTPHandler', + 'BaseHandler', + ... + +Many of the not-very-useful (private to `Mock` rather than the thing being +mocked) underscore and double underscore prefixed attributes have been +filtered from the result of calling `dir` on a `Mock`. If you dislike this +behaviour you can switch it off by setting the module level switch +`FILTER_DIR`: + + >>> from unittest import mock + >>> mock.FILTER_DIR = False + >>> dir(mock.Mock()) + ['_NonCallableMock__get_return_value', + '_NonCallableMock__get_side_effect', + '_NonCallableMock__return_value_doc', + '_NonCallableMock__set_return_value', + '_NonCallableMock__set_side_effect', + '__call__', + '__class__', + ... + +Alternatively you can just use `vars(my_mock)` (instance members) and +`dir(type(my_mock))` (type members) to bypass the filtering irrespective of +`mock.FILTER_DIR`. + + +mock_open +--------- + +.. function:: mock_open(mock=None, read_data=None) + + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` method of the file handle to return. + This is an empty string by default. + +Using `open` as a context manager is a great way to ensure your file handles +are closed properly and is becoming common:: + + with open('/some/path', 'w') as f: + f.write('something') + +The issue is that even if you mock out the call to `open` it is the +*returned object* that is used as a context manager (and has `__enter__` and +`__exit__` called). + +Mocking context managers with a :class:`MagicMock` is common enough and fiddly +enough that a helper function is useful. + + >>> m = mock_open() + >>> with patch('__main__.open', m, create=True): + ... with open('foo', 'w') as h: + ... h.write('some stuff') + ... + >>> m.mock_calls + [call('foo', 'w'), + call().__enter__(), + call().write('some stuff'), + call().__exit__(None, None, None)] + >>> m.assert_called_once_with('foo', 'w') + >>> handle = m() + >>> handle.write.assert_called_once_with('some stuff') + +And for reading files: + + >>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: + ... with open('foo') as h: + ... result = h.read() + ... + >>> m.assert_called_once_with('foo') + >>> assert result == 'bibble' + + +.. _auto-speccing: + +Autospeccing +------------ + +Autospeccing is based on the existing `spec` feature of mock. It limits the +api of mocks to the api of an original object (the spec), but it is recursive +(implemented lazily) so that attributes of mocks only have the same api as +the attributes of the spec. In addition mocked functions / methods have the +same call signature as the original so they raise a `TypeError` if they are +called incorrectly. + +Before I explain how auto-speccing works, here's why it is needed. + +`Mock` is a very powerful and flexible object, but it suffers from two flaws +when used to mock out objects from a system under test. One of these flaws is +specific to the `Mock` api and the other is a more general problem with using +mock objects. + +First the problem specific to `Mock`. `Mock` has two assert methods that are +extremely handy: :meth:`~Mock.assert_called_with` and +:meth:`~Mock.assert_called_once_with`. + + >>> mock = Mock(name='Thing', return_value=None) + >>> mock(1, 2, 3) + >>> mock.assert_called_once_with(1, 2, 3) + >>> mock(1, 2, 3) + >>> mock.assert_called_once_with(1, 2, 3) + Traceback (most recent call last): + ... + AssertionError: Expected to be called once. Called 2 times. + +Because mocks auto-create attributes on demand, and allow you to call them +with arbitrary arguments, if you misspell one of these assert methods then +your assertion is gone: + +.. code-block:: pycon + + >>> mock = Mock(name='Thing', return_value=None) + >>> mock(1, 2, 3) + >>> mock.assret_called_once_with(4, 5, 6) + +Your tests can pass silently and incorrectly because of the typo. + +The second issue is more general to mocking. If you refactor some of your +code, rename members and so on, any tests for code that is still using the +*old api* but uses mocks instead of the real objects will still pass. This +means your tests can all pass even though your code is broken. + +Note that this is another reason why you need integration tests as well as +unit tests. Testing everything in isolation is all fine and dandy, but if you +don't test how your units are "wired together" there is still lots of room +for bugs that tests might have caught. + +`mock` already provides a feature to help with this, called speccing. If you +use a class or instance as the `spec` for a mock then you can only access +attributes on the mock that exist on the real class: + + >>> from urllib import request + >>> mock = Mock(spec=request.Request) + >>> mock.assret_called_with + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'assret_called_with' + +The spec only applies to the mock itself, so we still have the same issue +with any methods on the mock: + +.. code-block:: pycon + + >>> mock.has_data() + + >>> mock.has_data.assret_called_with() + +Auto-speccing solves this problem. You can either pass `autospec=True` to +`patch` / `patch.object` or use the `create_autospec` function to create a +mock with a spec. If you use the `autospec=True` argument to `patch` then the +object that is being replaced will be used as the spec object. Because the +speccing is done "lazily" (the spec is created as attributes on the mock are +accessed) you can use it with very complex or deeply nested objects (like +modules that import modules that import modules) without a big performance +hit. + +Here's an example of it in use: + + >>> from urllib import request + >>> patcher = patch('__main__.request', autospec=True) + >>> mock_request = patcher.start() + >>> request is mock_request + True + >>> mock_request.Request + + +You can see that `request.Request` has a spec. `request.Request` takes two +arguments in the constructor (one of which is `self`). Here's what happens if +we try to call it incorrectly: + + >>> req = request.Request() + Traceback (most recent call last): + ... + TypeError: () takes at least 2 arguments (1 given) + +The spec also applies to instantiated classes (i.e. the return value of +specced mocks): + + >>> req = request.Request('foo') + >>> req + + +`Request` objects are not callable, so the return value of instantiating our +mocked out `request.Request` is a non-callable mock. With the spec in place +any typos in our asserts will raise the correct error: + + >>> req.add_header('spam', 'eggs') + + >>> req.add_header.assret_called_with + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'assret_called_with' + >>> req.add_header.assert_called_with('spam', 'eggs') + +In many cases you will just be able to add `autospec=True` to your existing +`patch` calls and then be protected against bugs due to typos and api +changes. + +As well as using `autospec` through `patch` there is a +:func:`create_autospec` for creating autospecced mocks directly: + + >>> from urllib import request + >>> mock_request = create_autospec(request) + >>> mock_request.Request('foo', 'bar') + + +This isn't without caveats and limitations however, which is why it is not +the default behaviour. In order to know what attributes are available on the +spec object, autospec has to introspect (access attributes) the spec. As you +traverse attributes on the mock a corresponding traversal of the original +object is happening under the hood. If any of your specced objects have +properties or descriptors that can trigger code execution then you may not be +able to use autospec. On the other hand it is much better to design your +objects so that introspection is safe [#]_. + +A more serious problem is that it is common for instance attributes to be +created in the `__init__` method and not to exist on the class at all. +`autospec` can't know about any dynamically created attributes and restricts +the api to visible attributes. + + >>> class Something(object): + ... def __init__(self): + ... self.a = 33 + ... + >>> with patch('__main__.Something', autospec=True): + ... thing = Something() + ... thing.a + ... + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'a' + +There are a few different ways of resolving this problem. The easiest, but +not necessarily the least annoying, way is to simply set the required +attributes on the mock after creation. Just because `autospec` doesn't allow +you to fetch attributes that don't exist on the spec it doesn't prevent you +setting them: + + >>> with patch('__main__.Something', autospec=True): + ... thing = Something() + ... thing.a = 33 + ... + +There is a more aggressive version of both `spec` and `autospec` that *does* +prevent you setting non-existent attributes. This is useful if you want to +ensure your code only *sets* valid attributes too, but obviously it prevents +this particular scenario: + + >>> with patch('__main__.Something', autospec=True, spec_set=True): + ... thing = Something() + ... thing.a = 33 + ... + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'a' + +Probably the best way of solving the problem is to add class attributes as +default values for instance members initialised in `__init__`. Note that if +you are only setting default attributes in `__init__` then providing them via +class attributes (shared between instances of course) is faster too. e.g. + +.. code-block:: python + + class Something(object): + a = 33 + +This brings up another issue. It is relatively common to provide a default +value of `None` for members that will later be an object of a different type. +`None` would be useless as a spec because it wouldn't let you access *any* +attributes or methods on it. As `None` is *never* going to be useful as a +spec, and probably indicates a member that will normally of some other type, +`autospec` doesn't use a spec for members that are set to `None`. These will +just be ordinary mocks (well - `MagicMocks`): + + >>> class Something(object): + ... member = None + ... + >>> mock = create_autospec(Something) + >>> mock.member.foo.bar.baz() + + +If modifying your production classes to add defaults isn't to your liking +then there are more options. One of these is simply to use an instance as the +spec rather than the class. The other is to create a subclass of the +production class and add the defaults to the subclass without affecting the +production class. Both of these require you to use an alternative object as +the spec. Thankfully `patch` supports this - you can simply pass the +alternative object as the `autospec` argument: + + >>> class Something(object): + ... def __init__(self): + ... self.a = 33 + ... + >>> class SomethingForTest(Something): + ... a = 33 + ... + >>> p = patch('__main__.Something', autospec=SomethingForTest) + >>> mock = p.start() + >>> mock.a + + + +.. [#] This only applies to classes or already instantiated objects. Calling + a mocked class to create a mock instance *does not* create a real instance. + It is only attribute lookups - along with calls to `dir` - that are done. diff --git a/Doc/library/unittest.mock-magicmethods.rst b/Doc/library/unittest.mock-magicmethods.rst new file mode 100644 --- /dev/null +++ b/Doc/library/unittest.mock-magicmethods.rst @@ -0,0 +1,226 @@ +:mod:`unittest.mock` --- MagicMock and magic method support +=========================================================== + +.. module:: unittest.mock + :synopsis: Mock object library. +.. moduleauthor:: Michael Foord +.. currentmodule:: unittest.mock + +.. versionadded:: 3.3 + + +.. _magic-methods: + +Mocking Magic Methods +--------------------- + +:class:`Mock` supports mocking the Python protocol methods, also known as +"magic methods". This allows mock objects to replace containers or other +objects that implement Python protocols. + +Because magic methods are looked up differently from normal methods [#]_, this +support has been specially implemented. This means that only specific magic +methods are supported. The supported list includes *almost* all of them. If +there are any missing that you need please let us know. + +You mock magic methods by setting the method you are interested in to a function +or a mock instance. If you are using a function then it *must* take ``self`` as +the first argument [#]_. + + >>> def __str__(self): + ... return 'fooble' + ... + >>> mock = Mock() + >>> mock.__str__ = __str__ + >>> str(mock) + 'fooble' + + >>> mock = Mock() + >>> mock.__str__ = Mock() + >>> mock.__str__.return_value = 'fooble' + >>> str(mock) + 'fooble' + + >>> mock = Mock() + >>> mock.__iter__ = Mock(return_value=iter([])) + >>> list(mock) + [] + +One use case for this is for mocking objects used as context managers in a +`with` statement: + + >>> mock = Mock() + >>> mock.__enter__ = Mock(return_value='foo') + >>> mock.__exit__ = Mock(return_value=False) + >>> with mock as m: + ... assert m == 'foo' + ... + >>> mock.__enter__.assert_called_with() + >>> mock.__exit__.assert_called_with(None, None, None) + +Calls to magic methods do not appear in :attr:`~Mock.method_calls`, but they +are recorded in :attr:`~Mock.mock_calls`. + +.. note:: + + If you use the `spec` keyword argument to create a mock then attempting to + set a magic method that isn't in the spec will raise an `AttributeError`. + +The full list of supported magic methods is: + +* ``__hash__``, ``__sizeof__``, ``__repr__`` and ``__str__`` +* ``__dir__``, ``__format__`` and ``__subclasses__`` +* ``__floor__``, ``__trunc__`` and ``__ceil__`` +* Comparisons: ``__cmp__``, ``__lt__``, ``__gt__``, ``__le__``, ``__ge__``, + ``__eq__`` and ``__ne__`` +* Container methods: ``__getitem__``, ``__setitem__``, ``__delitem__``, + ``__contains__``, ``__len__``, ``__iter__``, ``__getslice__``, + ``__setslice__``, ``__reversed__`` and ``__missing__`` +* Context manager: ``__enter__`` and ``__exit__`` +* Unary numeric methods: ``__neg__``, ``__pos__`` and ``__invert__`` +* The numeric methods (including right hand and in-place variants): + ``__add__``, ``__sub__``, ``__mul__``, ``__div__``, + ``__floordiv__``, ``__mod__``, ``__divmod__``, ``__lshift__``, + ``__rshift__``, ``__and__``, ``__xor__``, ``__or__``, and ``__pow__`` +* Numeric conversion methods: ``__complex__``, ``__int__``, ``__float__``, + ``__index__`` and ``__coerce__`` +* Descriptor methods: ``__get__``, ``__set__`` and ``__delete__`` +* Pickling: ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, + ``__getnewargs__``, ``__getstate__`` and ``__setstate__`` + + +The following methods exist but are *not* supported as they are either in use +by mock, can't be set dynamically, or can cause problems: + +* ``__getattr__``, ``__setattr__``, ``__init__`` and ``__new__`` +* ``__prepare__``, ``__instancecheck__``, ``__subclasscheck__``, ``__del__`` + + + +Magic Mock +---------- + +There are two `MagicMock` variants: `MagicMock` and `NonCallableMagicMock`. + + +.. class:: MagicMock(*args, **kw) + + ``MagicMock`` is a subclass of :class:`Mock` with default implementations + of most of the magic methods. You can use ``MagicMock`` without having to + configure the magic methods yourself. + + The constructor parameters have the same meaning as for :class:`Mock`. + + If you use the `spec` or `spec_set` arguments then *only* magic methods + that exist in the spec will be created. + + +.. class:: NonCallableMagicMock(*args, **kw) + + A non-callable version of `MagicMock`. + + The constructor parameters have the same meaning as for + :class:`MagicMock`, with the exception of `return_value` and + `side_effect` which have no meaning on a non-callable mock. + +The magic methods are setup with `MagicMock` objects, so you can configure them +and use them in the usual way: + + >>> mock = MagicMock() + >>> mock[3] = 'fish' + >>> mock.__setitem__.assert_called_with(3, 'fish') + >>> mock.__getitem__.return_value = 'result' + >>> mock[2] + 'result' + +By default many of the protocol methods are required to return objects of a +specific type. These methods are preconfigured with a default return value, so +that they can be used without you having to do anything if you aren't interested +in the return value. You can still *set* the return value manually if you want +to change the default. + +Methods and their defaults: + +* ``__lt__``: NotImplemented +* ``__gt__``: NotImplemented +* ``__le__``: NotImplemented +* ``__ge__``: NotImplemented +* ``__int__`` : 1 +* ``__contains__`` : False +* ``__len__`` : 1 +* ``__iter__`` : iter([]) +* ``__exit__`` : False +* ``__complex__`` : 1j +* ``__float__`` : 1.0 +* ``__bool__`` : True +* ``__index__`` : 1 +* ``__hash__`` : default hash for the mock +* ``__str__`` : default str for the mock +* ``__sizeof__``: default sizeof for the mock + +For example: + + >>> mock = MagicMock() + >>> int(mock) + 1 + >>> len(mock) + 0 + >>> list(mock) + [] + >>> object() in mock + False + +The two equality method, `__eq__` and `__ne__`, are special. +They do the default equality comparison on identity, using a side +effect, unless you change their return value to return something else: + + >>> MagicMock() == 3 + False + >>> MagicMock() != 3 + True + >>> mock = MagicMock() + >>> mock.__eq__.return_value = True + >>> mock == 3 + True + +The return value of `MagicMock.__iter__` can be any iterable object and isn't +required to be an iterator: + + >>> mock = MagicMock() + >>> mock.__iter__.return_value = ['a', 'b', 'c'] + >>> list(mock) + ['a', 'b', 'c'] + >>> list(mock) + ['a', 'b', 'c'] + +If the return value *is* an iterator, then iterating over it once will consume +it and subsequent iterations will result in an empty list: + + >>> mock.__iter__.return_value = iter(['a', 'b', 'c']) + >>> list(mock) + ['a', 'b', 'c'] + >>> list(mock) + [] + +``MagicMock`` has all of the supported magic methods configured except for some +of the obscure and obsolete ones. You can still set these up if you want. + +Magic methods that are supported but not setup by default in ``MagicMock`` are: + +* ``__subclasses__`` +* ``__dir__`` +* ``__format__`` +* ``__get__``, ``__set__`` and ``__delete__`` +* ``__reversed__`` and ``__missing__`` +* ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, ``__getnewargs__``, + ``__getstate__`` and ``__setstate__`` +* ``__getformat__`` and ``__setformat__`` + + + +.. [#] Magic methods *should* be looked up on the class rather than the + instance. Different versions of Python are inconsistent about applying this + rule. The supported protocol methods should work with all supported versions + of Python. +.. [#] The function is basically hooked up to the class, but each ``Mock`` + instance is kept isolated from the others. diff --git a/Doc/library/unittest.mock-patch.rst b/Doc/library/unittest.mock-patch.rst new file mode 100644 --- /dev/null +++ b/Doc/library/unittest.mock-patch.rst @@ -0,0 +1,538 @@ +:mod:`unittest.mock` --- the patchers +===================================== + +.. module:: unittest.mock + :synopsis: Mock object library. +.. moduleauthor:: Michael Foord +.. currentmodule:: unittest.mock + +.. versionadded:: 3.3 + +The patch decorators are used for patching objects only within the scope of +the function they decorate. They automatically handle the unpatching for you, +even if exceptions are raised. All of these functions can also be used in with +statements or as class decorators. + + +patch +----- + +.. note:: + + `patch` is straightforward to use. The key is to do the patching in the + right namespace. See the section `where to patch`_. + +.. function:: patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) + + `patch` acts as a function decorator, class decorator or a context + manager. Inside the body of the function or with statement, the `target` + (specified in the form `'package.module.ClassName'`) is patched + with a `new` object. When the function/with statement exits the patch is + undone. + + The `target` is imported and the specified attribute patched with the new + object, so it must be importable from the environment you are calling the + decorator from. The target is imported when the decorated function is + executed, not at decoration time. + + If `new` is omitted, then a new `MagicMock` is created and passed in as an + extra argument to the decorated function. + + The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` + if patch is creating one for you. + + In addition you can pass `spec=True` or `spec_set=True`, which causes + patch to pass in the object being mocked as the spec/spec_set object. + + `new_callable` allows you to specify a different class, or callable object, + that will be called to create the `new` object. By default `MagicMock` is + used. + + A more powerful form of `spec` is `autospec`. If you set `autospec=True` + then the mock with be created with a spec from the object being replaced. + All attributes of the mock will also have the spec of the corresponding + attribute of the object being replaced. Methods and functions being mocked + will have their arguments checked and will raise a `TypeError` if they are + called with the wrong signature. For mocks + replacing a class, their return value (the 'instance') will have the same + spec as the class. See the :func:`create_autospec` function and + :ref:`auto-speccing`. + + Instead of `autospec=True` you can pass `autospec=some_object` to use an + arbitrary object as the spec instead of the one being replaced. + + By default `patch` will fail to replace attributes that don't exist. If + you pass in `create=True`, and the attribute doesn't exist, patch will + create the attribute for you when the patched function is called, and + delete it again afterwards. This is useful for writing tests against + attributes that your production code creates at runtime. It is off by by + default because it can be dangerous. With it switched on you can write + passing tests against APIs that don't actually exist! + + Patch can be used as a `TestCase` class decorator. It works by + decorating each test method in the class. This reduces the boilerplate + code when your test methods share a common patchings set. `patch` finds + tests by looking for method names that start with `patch.TEST_PREFIX`. + By default this is `test`, which matches the way `unittest` finds tests. + You can specify an alternative prefix by setting `patch.TEST_PREFIX`. + + Patch can be used as a context manager, with the with statement. Here the + patching applies to the indented block after the with statement. If you + use "as" then the patched object will be bound to the name after the + "as"; very useful if `patch` is creating a mock object for you. + + `patch` takes arbitrary keyword arguments. These will be passed to + the `Mock` (or `new_callable`) on construction. + + `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are + available for alternate use-cases. + + +Patching a class replaces the class with a `MagicMock` *instance*. If the +class is instantiated in the code under test then it will be the +:attr:`~Mock.return_value` of the mock that will be used. + +If the class is instantiated multiple times you could use +:attr:`~Mock.side_effect` to return a new mock each time. Alternatively you +can set the `return_value` to be anything you want. + +To configure return values on methods of *instances* on the patched class +you must do this on the `return_value`. For example: + + >>> class Class(object): + ... def method(self): + ... pass + ... + >>> with patch('__main__.Class') as MockClass: + ... instance = MockClass.return_value + ... instance.method.return_value = 'foo' + ... assert Class() is instance + ... assert Class().method() == 'foo' + ... + +If you use `spec` or `spec_set` and `patch` is replacing a *class*, then the +return value of the created mock will have the same spec. + + >>> Original = Class + >>> patcher = patch('__main__.Class', spec=True) + >>> MockClass = patcher.start() + >>> instance = MockClass() + >>> assert isinstance(instance, Original) + >>> patcher.stop() + +The `new_callable` argument is useful where you want to use an alternative +class to the default :class:`MagicMock` for the created mock. For example, if +you wanted a :class:`NonCallableMock` to be used: + + >>> thing = object() + >>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing: + ... assert thing is mock_thing + ... thing() + ... + Traceback (most recent call last): + ... + TypeError: 'NonCallableMock' object is not callable + +Another use case might be to replace an object with a `StringIO` instance: + + >>> from StringIO import StringIO + >>> def foo(): + ... print 'Something' + ... + >>> @patch('sys.stdout', new_callable=StringIO) + ... def test(mock_stdout): + ... foo() + ... assert mock_stdout.getvalue() == 'Something\n' + ... + >>> test() + +When `patch` is creating a mock for you, it is common that the first thing +you need to do is to configure the mock. Some of that configuration can be done +in the call to patch. Any arbitrary keywords you pass into the call will be +used to set attributes on the created mock: + + >>> patcher = patch('__main__.thing', first='one', second='two') + >>> mock_thing = patcher.start() + >>> mock_thing.first + 'one' + >>> mock_thing.second + 'two' + +As well as attributes on the created mock attributes, like the +:attr:`~Mock.return_value` and :attr:`~Mock.side_effect`, of child mocks can +also be configured. These aren't syntactically valid to pass in directly as +keyword arguments, but a dictionary with these as keys can still be expanded +into a `patch` call using `**`: + + >>> config = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> patcher = patch('__main__.thing', **config) + >>> mock_thing = patcher.start() + >>> mock_thing.method() + 3 + >>> mock_thing.other() + Traceback (most recent call last): + ... + KeyError + + +patch.object +------------ + +.. function:: patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) + + patch the named member (`attribute`) on an object (`target`) with a mock + object. + + `patch.object` can be used as a decorator, class decorator or a context + manager. Arguments `new`, `spec`, `create`, `spec_set`, `autospec` and + `new_callable` have the same meaning as for `patch`. Like `patch`, + `patch.object` takes arbitrary keyword arguments for configuring the mock + object it creates. + + When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + +You can either call `patch.object` with three arguments or two arguments. The +three argument form takes the object to be patched, the attribute name and the +object to replace the attribute with. + +When calling with the two argument form you omit the replacement object, and a +mock is created for you and passed in as an extra argument to the decorated +function: + + >>> @patch.object(SomeClass, 'class_method') + ... def test(mock_method): + ... SomeClass.class_method(3) + ... mock_method.assert_called_with(3) + ... + >>> test() + +`spec`, `create` and the other arguments to `patch.object` have the same +meaning as they do for `patch`. + + +patch.dict +---------- + +.. function:: patch.dict(in_dict, values=(), clear=False, **kwargs) + + Patch a dictionary, or dictionary like object, and restore the dictionary + to its original state after the test. + + `in_dict` can be a dictionary or a mapping like container. If it is a + mapping then it must at least support getting, setting and deleting items + plus iterating over keys. + + `in_dict` can also be a string specifying the name of the dictionary, which + will then be fetched by importing it. + + `values` can be a dictionary of values to set in the dictionary. `values` + can also be an iterable of `(key, value)` pairs. + + If `clear` is True then the dictionary will be cleared before the new + values are set. + + `patch.dict` can also be called with arbitrary keyword arguments to set + values in the dictionary. + + `patch.dict` can be used as a context manager, decorator or class + decorator. When used as a class decorator `patch.dict` honours + `patch.TEST_PREFIX` for choosing which methods to wrap. + +`patch.dict` can be used to add members to a dictionary, or simply let a test +change a dictionary, and ensure the dictionary is restored when the test +ends. + + >>> foo = {} + >>> with patch.dict(foo, {'newkey': 'newvalue'}): + ... assert foo == {'newkey': 'newvalue'} + ... + >>> assert foo == {} + + >>> import os + >>> with patch.dict('os.environ', {'newkey': 'newvalue'}): + ... print os.environ['newkey'] + ... + newvalue + >>> assert 'newkey' not in os.environ + +Keywords can be used in the `patch.dict` call to set values in the dictionary: + + >>> mymodule = MagicMock() + >>> mymodule.function.return_value = 'fish' + >>> with patch.dict('sys.modules', mymodule=mymodule): + ... import mymodule + ... mymodule.function('some', 'args') + ... + 'fish' + +`patch.dict` can be used with dictionary like objects that aren't actually +dictionaries. At the very minimum they must support item getting, setting, +deleting and either iteration or membership test. This corresponds to the +magic methods `__getitem__`, `__setitem__`, `__delitem__` and either +`__iter__` or `__contains__`. + + >>> class Container(object): + ... def __init__(self): + ... self.values = {} + ... def __getitem__(self, name): + ... return self.values[name] + ... def __setitem__(self, name, value): + ... self.values[name] = value + ... def __delitem__(self, name): + ... del self.values[name] + ... def __iter__(self): + ... return iter(self.values) + ... + >>> thing = Container() + >>> thing['one'] = 1 + >>> with patch.dict(thing, one=2, two=3): + ... assert thing['one'] == 2 + ... assert thing['two'] == 3 + ... + >>> assert thing['one'] == 1 + >>> assert list(thing) == ['one'] + + +patch.multiple +-------------- + +.. function:: patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) + + Perform multiple patches in a single call. It takes the object to be + patched (either as an object or a string to fetch the object by importing) + and keyword arguments for the patches:: + + with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): + ... + + Use :data:`DEFAULT` as the value if you want `patch.multiple` to create + mocks for you. In this case the created mocks are passed into a decorated + function by keyword, and a dictionary is returned when `patch.multiple` is + used as a context manager. + + `patch.multiple` can be used as a decorator, class decorator or a context + manager. The arguments `spec`, `spec_set`, `create`, `autospec` and + `new_callable` have the same meaning as for `patch`. These arguments will + be applied to *all* patches done by `patch.multiple`. + + When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + +If you want `patch.multiple` to create mocks for you, then you can use +:data:`DEFAULT` as the value. If you use `patch.multiple` as a decorator +then the created mocks are passed into the decorated function by keyword. + + >>> thing = object() + >>> other = object() + + >>> @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) + ... def test_function(thing, other): + ... assert isinstance(thing, MagicMock) + ... assert isinstance(other, MagicMock) + ... + >>> test_function() + +`patch.multiple` can be nested with other `patch` decorators, but put arguments +passed by keyword *after* any of the standard arguments created by `patch`: + + >>> @patch('sys.exit') + ... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) + ... def test_function(mock_exit, other, thing): + ... assert 'other' in repr(other) + ... assert 'thing' in repr(thing) + ... assert 'exit' in repr(mock_exit) + ... + >>> test_function() + +If `patch.multiple` is used as a context manager, the value returned by the +context manger is a dictionary where created mocks are keyed by name: + + >>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values: + ... assert 'other' in repr(values['other']) + ... assert 'thing' in repr(values['thing']) + ... assert values['thing'] is thing + ... assert values['other'] is other + ... + + +.. _start-and-stop: + +patch methods: start and stop +----------------------------- + +All the patchers have `start` and `stop` methods. These make it simpler to do +patching in `setUp` methods or where you want to do multiple patches without +nesting decorators or with statements. + +To use them call `patch`, `patch.object` or `patch.dict` as normal and keep a +reference to the returned `patcher` object. You can then call `start` to put +the patch in place and `stop` to undo it. + +If you are using `patch` to create a mock for you then it will be returned by +the call to `patcher.start`. + + >>> patcher = patch('package.module.ClassName') + >>> from package import module + >>> original = module.ClassName + >>> new_mock = patcher.start() + >>> assert module.ClassName is not original + >>> assert module.ClassName is new_mock + >>> patcher.stop() + >>> assert module.ClassName is original + >>> assert module.ClassName is not new_mock + + +A typical use case for this might be for doing multiple patches in the `setUp` +method of a `TestCase`: + + >>> class MyTest(TestCase): + ... def setUp(self): + ... self.patcher1 = patch('package.module.Class1') + ... self.patcher2 = patch('package.module.Class2') + ... self.MockClass1 = self.patcher1.start() + ... self.MockClass2 = self.patcher2.start() + ... + ... def tearDown(self): + ... self.patcher1.stop() + ... self.patcher2.stop() + ... + ... def test_something(self): + ... assert package.module.Class1 is self.MockClass1 + ... assert package.module.Class2 is self.MockClass2 + ... + >>> MyTest('test_something').run() + +.. caution:: + + If you use this technique you must ensure that the patching is "undone" by + calling `stop`. This can be fiddlier than you might think, because if an + exception is raised in the ``setUp`` then ``tearDown`` is not called. + :meth:`unittest.TestCase.addCleanup` makes this easier: + + >>> class MyTest(TestCase): + ... def setUp(self): + ... patcher = patch('package.module.Class') + ... self.MockClass = patcher.start() + ... self.addCleanup(patcher.stop) + ... + ... def test_something(self): + ... assert package.module.Class is self.MockClass + ... + + As an added bonus you no longer need to keep a reference to the `patcher` + object. + +In fact `start` and `stop` are just aliases for the context manager +`__enter__` and `__exit__` methods. + + +TEST_PREFIX +----------- + +All of the patchers can be used as class decorators. When used in this way +they wrap every test method on the class. The patchers recognise methods that +start with `test` as being test methods. This is the same way that the +:class:`unittest.TestLoader` finds test methods by default. + +It is possible that you want to use a different prefix for your tests. You can +inform the patchers of the different prefix by setting `patch.TEST_PREFIX`: + + >>> patch.TEST_PREFIX = 'foo' + >>> value = 3 + >>> + >>> @patch('__main__.value', 'not three') + ... class Thing(object): + ... def foo_one(self): + ... print value + ... def foo_two(self): + ... print value + ... + >>> + >>> Thing().foo_one() + not three + >>> Thing().foo_two() + not three + >>> value + 3 + + +Nesting Patch Decorators +------------------------ + +If you want to perform multiple patches then you can simply stack up the +decorators. + +You can stack up multiple patch decorators using this pattern: + + >>> @patch.object(SomeClass, 'class_method') + ... @patch.object(SomeClass, 'static_method') + ... def test(mock1, mock2): + ... assert SomeClass.static_method is mock1 + ... assert SomeClass.class_method is mock2 + ... SomeClass.static_method('foo') + ... SomeClass.class_method('bar') + ... return mock1, mock2 + ... + >>> mock1, mock2 = test() + >>> mock1.assert_called_once_with('foo') + >>> mock2.assert_called_once_with('bar') + + +Note that the decorators are applied from the bottom upwards. This is the +standard way that Python applies decorators. The order of the created mocks +passed into your test function matches this order. + + +.. _where-to-patch: + +Where to patch +-------------- + +`patch` works by (temporarily) changing the object that a *name* points to with +another one. There can be many names pointing to any individual object, so +for patching to work you must ensure that you patch the name used by the system +under test. + +The basic principle is that you patch where an object is *looked up*, which +is not necessarily the same place as where it is defined. A couple of +examples will help to clarify this. + +Imagine we have a project that we want to test with the following structure:: + + a.py + -> Defines SomeClass + + b.py + -> from a import SomeClass + -> some_function instantiates SomeClass + +Now we want to test `some_function` but we want to mock out `SomeClass` using +`patch`. The problem is that when we import module b, which we will have to +do then it imports `SomeClass` from module a. If we use `patch` to mock out +`a.SomeClass` then it will have no effect on our test; module b already has a +reference to the *real* `SomeClass` and it looks like our patching had no +effect. + +The key is to patch out `SomeClass` where it is used (or where it is looked up +). In this case `some_function` will actually look up `SomeClass` in module b, +where we have imported it. The patching should look like:: + + @patch('b.SomeClass') + +However, consider the alternative scenario where instead of `from a import +SomeClass` module b does `import a` and `some_function` uses `a.SomeClass`. Both +of these import forms are common. In this case the class we want to patch is +being looked up on the a module and so we have to patch `a.SomeClass` instead:: + + @patch('a.SomeClass') + + +Patching Descriptors and Proxy Objects +-------------------------------------- + +Both patch_ and patch.object_ correctly patch and restore descriptors: class +methods, static methods and properties. You should patch these on the *class* +rather than an instance. They also work with *some* objects +that proxy attribute access, like the `django setttings object +`_. diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst new file mode 100644 --- /dev/null +++ b/Doc/library/unittest.mock.rst @@ -0,0 +1,900 @@ +:mod:`unittest.mock` --- mock object library +============================================ + +.. module:: unittest.mock + :synopsis: Mock object library. +.. moduleauthor:: Michael Foord +.. currentmodule:: unittest.mock + +.. versionadded:: 3.3 + +:mod:`unittest.mock` is a library for testing in Python. It allows you to +replace parts of your system under test with mock objects and make assertions +about how they have been used. + +`unittest.mock` provides a core :class:`Mock` class removing the need to +create a host of stubs throughout your test suite. After performing an +action, you can make assertions about which methods / attributes were used +and arguments they were called with. You can also specify return values and +set needed attributes in the normal way. + +Additionally, mock provides a :func:`patch` decorator that handles patching +module and class level attributes within the scope of a test, along with +:const:`sentinel` for creating unique objects. See the `quick guide`_ for +some examples of how to use :class:`Mock`, :class:`MagicMock` and +:func:`patch`. + +Mock is very easy to use and is designed for use with :mod:`unittest`. Mock +is based on the 'action -> assertion' pattern instead of `'record -> replay'` +used by many mocking frameworks. + +There is a backport of `unittest.mock` for earlier versions of Python, +available as `mock on PyPI `_. + +**Source code:** :source:`Lib/unittest/mock.py` + + +Quick Guide +----------- + +:class:`Mock` and :class:`MagicMock` objects create all attributes and +methods as you access them and store details of how they have been used. You +can configure them, to specify return values or limit what attributes are +available, and then make assertions about how they have been used: + + >>> from unittest.mock import MagicMock + >>> thing = ProductionClass() + >>> thing.method = MagicMock(return_value=3) + >>> thing.method(3, 4, 5, key='value') + 3 + >>> thing.method.assert_called_with(3, 4, 5, key='value') + +:attr:`side_effect` allows you to perform side effects, including raising an +exception when a mock is called: + + >>> mock = Mock(side_effect=KeyError('foo')) + >>> mock() + Traceback (most recent call last): + ... + KeyError: 'foo' + + >>> values = {'a': 1, 'b': 2, 'c': 3} + >>> def side_effect(arg): + ... return values[arg] + ... + >>> mock.side_effect = side_effect + >>> mock('a'), mock('b'), mock('c') + (1, 2, 3) + >>> mock.side_effect = [5, 4, 3, 2, 1] + >>> mock(), mock(), mock() + (5, 4, 3) + +Mock has many other ways you can configure it and control its behaviour. For +example the `spec` argument configures the mock to take its specification +from another object. Attempting to access attributes or methods on the mock +that don't exist on the spec will fail with an `AttributeError`. + +The :func:`patch` decorator / context manager makes it easy to mock classes or +objects in a module under test. The object you specify will be replaced with a +mock (or other object) during the test and restored when the test ends: + + >>> from unittest.mock import patch + >>> @patch('module.ClassName2') + ... @patch('module.ClassName1') + ... def test(MockClass1, MockClass2): + ... module.ClassName1() + ... module.ClassName2() + + ... assert MockClass1 is module.ClassName1 + ... assert MockClass2 is module.ClassName2 + ... assert MockClass1.called + ... assert MockClass2.called + ... + >>> test() + +.. note:: + + When you nest patch decorators the mocks are passed in to the decorated + function in the same order they applied (the normal *python* order that + decorators are applied). This means from the bottom up, so in the example + above the mock for `module.ClassName1` is passed in first. + + With `patch` it matters that you patch objects in the namespace where they + are looked up. This is normally straightforward, but for a quick guide + read :ref:`where to patch `. + +As well as a decorator `patch` can be used as a context manager in a with +statement: + + >>> with patch.object(ProductionClass, 'method', return_value=None) as mock_method: + ... thing = ProductionClass() + ... thing.method(1, 2, 3) + ... + >>> mock_method.assert_called_once_with(1, 2, 3) + + +There is also :func:`patch.dict` for setting values in a dictionary just +during a scope and restoring the dictionary to its original state when the test +ends: + + >>> foo = {'key': 'value'} + >>> original = foo.copy() + >>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True): + ... assert foo == {'newkey': 'newvalue'} + ... + >>> assert foo == original + +Mock supports the mocking of Python :ref:`magic methods `. The +easiest way of using magic methods is with the :class:`MagicMock` class. It +allows you to do things like: + + >>> mock = MagicMock() + >>> mock.__str__.return_value = 'foobarbaz' + >>> str(mock) + 'foobarbaz' + >>> mock.__str__.assert_called_with() + +Mock allows you to assign functions (or other Mock instances) to magic methods +and they will be called appropriately. The `MagicMock` class is just a Mock +variant that has all of the magic methods pre-created for you (well, all the +useful ones anyway). + +The following is an example of using magic methods with the ordinary Mock +class: + + >>> mock = Mock() + >>> mock.__str__ = Mock(return_value='wheeeeee') + >>> str(mock) + 'wheeeeee' + +For ensuring that the mock objects in your tests have the same api as the +objects they are replacing, you can use :ref:`auto-speccing `. +Auto-speccing can be done through the `autospec` argument to patch, or the +:func:`create_autospec` function. Auto-speccing creates mock objects that +have the same attributes and methods as the objects they are replacing, and +any functions and methods (including constructors) have the same call +signature as the real object. + +This ensures that your mocks will fail in the same way as your production +code if they are used incorrectly: + + >>> from unittest.mock import create_autospec + >>> def function(a, b, c): + ... pass + ... + >>> mock_function = create_autospec(function, return_value='fishy') + >>> mock_function(1, 2, 3) + 'fishy' + >>> mock_function.assert_called_once_with(1, 2, 3) + >>> mock_function('wrong arguments') + Traceback (most recent call last): + ... + TypeError: () takes exactly 3 arguments (1 given) + +`create_autospec` can also be used on classes, where it copies the signature of +the `__init__` method, and on callable objects where it copies the signature of +the `__call__` method. + + + +The Mock Class +-------------- + + +`Mock` is a flexible mock object intended to replace the use of stubs and +test doubles throughout your code. Mocks are callable and create attributes as +new mocks when you access them [#]_. Accessing the same attribute will always +return the same mock. Mocks record how you use them, allowing you to make +assertions about what your code has done to them. + +:class:`MagicMock` is a subclass of `Mock` with all the magic methods +pre-created and ready to use. There are also non-callable variants, useful +when you are mocking out objects that aren't callable: +:class:`NonCallableMock` and :class:`NonCallableMagicMock` + +The :func:`patch` decorators makes it easy to temporarily replace classes +in a particular module with a `Mock` object. By default `patch` will create +a `MagicMock` for you. You can specify an alternative class of `Mock` using +the `new_callable` argument to `patch`. + + +.. class:: Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, **kwargs) + + Create a new `Mock` object. `Mock` takes several optional arguments + that specify the behaviour of the Mock object: + + * `spec`: This can be either a list of strings or an existing object (a + class or instance) that acts as the specification for the mock object. If + you pass in an object then a list of strings is formed by calling dir on + the object (excluding unsupported magic attributes and methods). + Accessing any attribute not in this list will raise an `AttributeError`. + + If `spec` is an object (rather than a list of strings) then + :attr:`__class__` returns the class of the spec object. This allows mocks + to pass `isinstance` tests. + + * `spec_set`: A stricter variant of `spec`. If used, attempting to *set* + or get an attribute on the mock that isn't on the object passed as + `spec_set` will raise an `AttributeError`. + + * `side_effect`: A function to be called whenever the Mock is called. See + the :attr:`~Mock.side_effect` attribute. Useful for raising exceptions or + dynamically changing return values. The function is called with the same + arguments as the mock, and unless it returns :data:`DEFAULT`, the return + value of this function is used as the return value. + + Alternatively `side_effect` can be an exception class or instance. In + this case the exception will be raised when the mock is called. + + If `side_effect` is an iterable then each call to the mock will return + the next value from the iterable. + + A `side_effect` can be cleared by setting it to `None`. + + * `return_value`: The value returned when the mock is called. By default + this is a new Mock (created on first access). See the + :attr:`return_value` attribute. + + * `wraps`: Item for the mock object to wrap. If `wraps` is not None then + calling the Mock will pass the call through to the wrapped object + (returning the real result and ignoring `return_value`). Attribute access + on the mock will return a Mock object that wraps the corresponding + attribute of the wrapped object (so attempting to access an attribute + that doesn't exist will raise an `AttributeError`). + + If the mock has an explicit `return_value` set then calls are not passed + to the wrapped object and the `return_value` is returned instead. + + * `name`: If the mock has a name then it will be used in the repr of the + mock. This can be useful for debugging. The name is propagated to child + mocks. + + Mocks can also be called with arbitrary keyword arguments. These will be + used to set attributes on the mock after it is created. See the + :meth:`configure_mock` method for details. + + + .. method:: assert_called_with(*args, **kwargs) + + This method is a convenient way of asserting that calls are made in a + particular way: + + >>> mock = Mock() + >>> mock.method(1, 2, 3, test='wow') + + >>> mock.method.assert_called_with(1, 2, 3, test='wow') + + + .. method:: assert_called_once_with(*args, **kwargs) + + Assert that the mock was called exactly once and with the specified + arguments. + + >>> mock = Mock(return_value=None) + >>> mock('foo', bar='baz') + >>> mock.assert_called_once_with('foo', bar='baz') + >>> mock('foo', bar='baz') + >>> mock.assert_called_once_with('foo', bar='baz') + Traceback (most recent call last): + ... + AssertionError: Expected to be called once. Called 2 times. + + + .. method:: assert_any_call(*args, **kwargs) + + assert the mock has been called with the specified arguments. + + The assert passes if the mock has *ever* been called, unlike + :meth:`assert_called_with` and :meth:`assert_called_once_with` that + only pass if the call is the most recent one. + + >>> mock = Mock(return_value=None) + >>> mock(1, 2, arg='thing') + >>> mock('some', 'thing', 'else') + >>> mock.assert_any_call(1, 2, arg='thing') + + + .. method:: assert_has_calls(calls, any_order=False) + + assert the mock has been called with the specified calls. + The `mock_calls` list is checked for the calls. + + If `any_order` is False (the default) then the calls must be + sequential. There can be extra calls before or after the + specified calls. + + If `any_order` is True then the calls can be in any order, but + they must all appear in :attr:`mock_calls`. + + >>> mock = Mock(return_value=None) + >>> mock(1) + >>> mock(2) + >>> mock(3) + >>> mock(4) + >>> calls = [call(2), call(3)] + >>> mock.assert_has_calls(calls) + >>> calls = [call(4), call(2), call(3)] + >>> mock.assert_has_calls(calls, any_order=True) + + + .. method:: reset_mock() + + The reset_mock method resets all the call attributes on a mock object: + + >>> mock = Mock(return_value=None) + >>> mock('hello') + >>> mock.called + True + >>> mock.reset_mock() + >>> mock.called + False + + This can be useful where you want to make a series of assertions that + reuse the same object. Note that `reset_mock` *doesn't* clear the + return value, :attr:`side_effect` or any child attributes you have + set using normal assignment. Child mocks and the return value mock + (if any) are reset as well. + + + .. method:: mock_add_spec(spec, spec_set=False) + + Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is `True` then only attributes on the spec can be set. + + + .. method:: attach_mock(mock, attribute) + + Attach a mock as an attribute of this one, replacing its name and + parent. Calls to the attached mock will be recorded in the + :attr:`method_calls` and :attr:`mock_calls` attributes of this one. + + + .. method:: configure_mock(**kwargs) + + Set attributes on the mock through keyword arguments. + + Attributes plus return values and side effects can be set on child + mocks using standard dot notation and unpacking a dictionary in the + method call: + + >>> mock = Mock() + >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> mock.configure_mock(**attrs) + >>> mock.method() + 3 + >>> mock.other() + Traceback (most recent call last): + ... + KeyError + + The same thing can be achieved in the constructor call to mocks: + + >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> mock = Mock(some_attribute='eggs', **attrs) + >>> mock.some_attribute + 'eggs' + >>> mock.method() + 3 + >>> mock.other() + Traceback (most recent call last): + ... + KeyError + + `configure_mock` exists to make it easier to do configuration + after the mock has been created. + + + .. method:: __dir__() + + `Mock` objects limit the results of `dir(some_mock)` to useful results. + For mocks with a `spec` this includes all the permitted attributes + for the mock. + + See :data:`FILTER_DIR` for what this filtering does, and how to + switch it off. + + + .. method:: _get_child_mock(**kw) + + Create the child mocks for attributes and return value. + By default child mocks will be the same type as the parent. + Subclasses of Mock may want to override this to customize the way + child mocks are made. + + For non-callable mocks the callable variant will be used (rather than + any custom subclass). + + + .. attribute:: called + + A boolean representing whether or not the mock object has been called: + + >>> mock = Mock(return_value=None) + >>> mock.called + False + >>> mock() + >>> mock.called + True + + .. attribute:: call_count + + An integer telling you how many times the mock object has been called: + + >>> mock = Mock(return_value=None) + >>> mock.call_count + 0 + >>> mock() + >>> mock() + >>> mock.call_count + 2 + + + .. attribute:: return_value + + Set this to configure the value returned by calling the mock: + + >>> mock = Mock() + >>> mock.return_value = 'fish' + >>> mock() + 'fish' + + The default return value is a mock object and you can configure it in + the normal way: + + >>> mock = Mock() + >>> mock.return_value.attribute = sentinel.Attribute + >>> mock.return_value() + + >>> mock.return_value.assert_called_with() + + `return_value` can also be set in the constructor: + + >>> mock = Mock(return_value=3) + >>> mock.return_value + 3 + >>> mock() + 3 + + + .. attribute:: side_effect + + This can either be a function to be called when the mock is called, + or an exception (class or instance) to be raised. + + If you pass in a function it will be called with same arguments as the + mock and unless the function returns the :data:`DEFAULT` singleton the + call to the mock will then return whatever the function returns. If the + function returns :data:`DEFAULT` then the mock will return its normal + value (from the :attr:`return_value`. + + An example of a mock that raises an exception (to test exception + handling of an API): + + >>> mock = Mock() + >>> mock.side_effect = Exception('Boom!') + >>> mock() + Traceback (most recent call last): + ... + Exception: Boom! + + Using `side_effect` to return a sequence of values: + + >>> mock = Mock() + >>> mock.side_effect = [3, 2, 1] + >>> mock(), mock(), mock() + (3, 2, 1) + + The `side_effect` function is called with the same arguments as the + mock (so it is wise for it to take arbitrary args and keyword + arguments) and whatever it returns is used as the return value for + the call. The exception is if `side_effect` returns :data:`DEFAULT`, + in which case the normal :attr:`return_value` is used. + + >>> mock = Mock(return_value=3) + >>> def side_effect(*args, **kwargs): + ... return DEFAULT + ... + >>> mock.side_effect = side_effect + >>> mock() + 3 + + `side_effect` can be set in the constructor. Here's an example that + adds one to the value the mock is called with and returns it: + + >>> side_effect = lambda value: value + 1 + >>> mock = Mock(side_effect=side_effect) + >>> mock(3) + 4 + >>> mock(-8) + -7 + + Setting `side_effect` to `None` clears it: + + >>> m = Mock(side_effect=KeyError, return_value=3) + >>> m() + Traceback (most recent call last): + ... + KeyError + >>> m.side_effect = None + >>> m() + 3 + + + .. attribute:: call_args + + This is either `None` (if the mock hasn't been called), or the + arguments that the mock was last called with. This will be in the + form of a tuple: the first member is any ordered arguments the mock + was called with (or an empty tuple) and the second member is any + keyword arguments (or an empty dictionary). + + >>> mock = Mock(return_value=None) + >>> print mock.call_args + None + >>> mock() + >>> mock.call_args + call() + >>> mock.call_args == () + True + >>> mock(3, 4) + >>> mock.call_args + call(3, 4) + >>> mock.call_args == ((3, 4),) + True + >>> mock(3, 4, 5, key='fish', next='w00t!') + >>> mock.call_args + call(3, 4, 5, key='fish', next='w00t!') + + `call_args`, along with members of the lists :attr:`call_args_list`, + :attr:`method_calls` and :attr:`mock_calls` are :data:`call` objects. + These are tuples, so they can be unpacked to get at the individual + arguments and make more complex assertions. See + :ref:`calls as tuples `. + + + .. attribute:: call_args_list + + This is a list of all the calls made to the mock object in sequence + (so the length of the list is the number of times it has been + called). Before any calls have been made it is an empty list. The + :data:`call` object can be used for conveniently constructing lists of + calls to compare with `call_args_list`. + + >>> mock = Mock(return_value=None) + >>> mock() + >>> mock(3, 4) + >>> mock(key='fish', next='w00t!') + >>> mock.call_args_list + [call(), call(3, 4), call(key='fish', next='w00t!')] + >>> expected = [(), ((3, 4),), ({'key': 'fish', 'next': 'w00t!'},)] + >>> mock.call_args_list == expected + True + + Members of `call_args_list` are :data:`call` objects. These can be + unpacked as tuples to get at the individual arguments. See + :ref:`calls as tuples `. + + + .. attribute:: method_calls + + As well as tracking calls to themselves, mocks also track calls to + methods and attributes, and *their* methods and attributes: + + >>> mock = Mock() + >>> mock.method() + + >>> mock.property.method.attribute() + + >>> mock.method_calls + [call.method(), call.property.method.attribute()] + + Members of `method_calls` are :data:`call` objects. These can be + unpacked as tuples to get at the individual arguments. See + :ref:`calls as tuples `. + + + .. attribute:: mock_calls + + `mock_calls` records *all* calls to the mock object, its methods, magic + methods *and* return value mocks. + + >>> mock = MagicMock() + >>> result = mock(1, 2, 3) + >>> mock.first(a=3) + + >>> mock.second() + + >>> int(mock) + 1 + >>> result(1) + + >>> expected = [call(1, 2, 3), call.first(a=3), call.second(), + ... call.__int__(), call()(1)] + >>> mock.mock_calls == expected + True + + Members of `mock_calls` are :data:`call` objects. These can be + unpacked as tuples to get at the individual arguments. See + :ref:`calls as tuples `. + + + .. attribute:: __class__ + + Normally the `__class__` attribute of an object will return its type. + For a mock object with a `spec` `__class__` returns the spec class + instead. This allows mock objects to pass `isinstance` tests for the + object they are replacing / masquerading as: + + >>> mock = Mock(spec=3) + >>> isinstance(mock, int) + True + + `__class__` is assignable to, this allows a mock to pass an + `isinstance` check without forcing you to use a spec: + + >>> mock = Mock() + >>> mock.__class__ = dict + >>> isinstance(mock, dict) + True + +.. class:: NonCallableMock(spec=None, wraps=None, name=None, spec_set=None, **kwargs) + + A non-callable version of `Mock`. The constructor parameters have the same + meaning of `Mock`, with the exception of `return_value` and `side_effect` + which have no meaning on a non-callable mock. + +Mock objects that use a class or an instance as a `spec` or `spec_set` are able +to pass `isintance` tests: + + >>> mock = Mock(spec=SomeClass) + >>> isinstance(mock, SomeClass) + True + >>> mock = Mock(spec_set=SomeClass()) + >>> isinstance(mock, SomeClass) + True + +The `Mock` classes have support for mocking magic methods. See :ref:`magic +methods ` for the full details. + +The mock classes and the :func:`patch` decorators all take arbitrary keyword +arguments for configuration. For the `patch` decorators the keywords are +passed to the constructor of the mock being created. The keyword arguments +are for configuring attributes of the mock: + + >>> m = MagicMock(attribute=3, other='fish') + >>> m.attribute + 3 + >>> m.other + 'fish' + +The return value and side effect of child mocks can be set in the same way, +using dotted notation. As you can't use dotted names directly in a call you +have to create a dictionary and unpack it using `**`: + + >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> mock = Mock(some_attribute='eggs', **attrs) + >>> mock.some_attribute + 'eggs' + >>> mock.method() + 3 + >>> mock.other() + Traceback (most recent call last): + ... + KeyError + + +.. class:: PropertyMock(*args, **kwargs) + + A mock intended to be used as a property, or other descriptor, on a class. + `PropertyMock` provides `__get__` and `__set__` methods so you can specify + a return value when it is fetched. + + Fetching a `PropertyMock` instance from an object calls the mock, with + no args. Setting it calls the mock with the value being set. + + >>> class Foo(object): + ... @property + ... def foo(self): + ... return 'something' + ... @foo.setter + ... def foo(self, value): + ... pass + ... + >>> with patch('__main__.Foo.foo', new_callable=PropertyMock) as mock_foo: + ... mock_foo.return_value = 'mockity-mock' + ... this_foo = Foo() + ... print this_foo.foo + ... this_foo.foo = 6 + ... + mockity-mock + >>> mock_foo.mock_calls + [call(), call(6)] + + +Calling +~~~~~~~ + +Mock objects are callable. The call will return the value set as the +:attr:`~Mock.return_value` attribute. The default return value is a new Mock +object; it is created the first time the return value is accessed (either +explicitly or by calling the Mock) - but it is stored and the same one +returned each time. + +Calls made to the object will be recorded in the attributes +like :attr:`~Mock.call_args` and :attr:`~Mock.call_args_list`. + +If :attr:`~Mock.side_effect` is set then it will be called after the call has +been recorded, so if `side_effect` raises an exception the call is still +recorded. + +The simplest way to make a mock raise an exception when called is to make +:attr:`~Mock.side_effect` an exception class or instance: + + >>> m = MagicMock(side_effect=IndexError) + >>> m(1, 2, 3) + Traceback (most recent call last): + ... + IndexError + >>> m.mock_calls + [call(1, 2, 3)] + >>> m.side_effect = KeyError('Bang!') + >>> m('two', 'three', 'four') + Traceback (most recent call last): + ... + KeyError: 'Bang!' + >>> m.mock_calls + [call(1, 2, 3), call('two', 'three', 'four')] + +If `side_effect` is a function then whatever that function returns is what +calls to the mock return. The `side_effect` function is called with the +same arguments as the mock. This allows you to vary the return value of the +call dynamically, based on the input: + + >>> def side_effect(value): + ... return value + 1 + ... + >>> m = MagicMock(side_effect=side_effect) + >>> m(1) + 2 + >>> m(2) + 3 + >>> m.mock_calls + [call(1), call(2)] + +If you want the mock to still return the default return value (a new mock), or +any set return value, then there are two ways of doing this. Either return +`mock.return_value` from inside `side_effect`, or return :data:`DEFAULT`: + + >>> m = MagicMock() + >>> def side_effect(*args, **kwargs): + ... return m.return_value + ... + >>> m.side_effect = side_effect + >>> m.return_value = 3 + >>> m() + 3 + >>> def side_effect(*args, **kwargs): + ... return DEFAULT + ... + >>> m.side_effect = side_effect + >>> m() + 3 + +To remove a `side_effect`, and return to the default behaviour, set the +`side_effect` to `None`: + + >>> m = MagicMock(return_value=6) + >>> def side_effect(*args, **kwargs): + ... return 3 + ... + >>> m.side_effect = side_effect + >>> m() + 3 + >>> m.side_effect = None + >>> m() + 6 + +The `side_effect` can also be any iterable object. Repeated calls to the mock +will return values from the iterable (until the iterable is exhausted and +a `StopIteration` is raised): + + >>> m = MagicMock(side_effect=[1, 2, 3]) + >>> m() + 1 + >>> m() + 2 + >>> m() + 3 + >>> m() + Traceback (most recent call last): + ... + StopIteration + + +.. _deleting-attributes: + +Deleting Attributes +~~~~~~~~~~~~~~~~~~~ + +Mock objects create attributes on demand. This allows them to pretend to be +objects of any type. + +You may want a mock object to return `False` to a `hasattr` call, or raise an +`AttributeError` when an attribute is fetched. You can do this by providing +an object as a `spec` for a mock, but that isn't always convenient. + +You "block" attributes by deleting them. Once deleted, accessing an attribute +will raise an `AttributeError`. + + >>> mock = MagicMock() + >>> hasattr(mock, 'm') + True + >>> del mock.m + >>> hasattr(mock, 'm') + False + >>> del mock.f + >>> mock.f + Traceback (most recent call last): + ... + AttributeError: f + + +Attaching Mocks as Attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When you attach a mock as an attribute of another mock (or as the return +value) it becomes a "child" of that mock. Calls to the child are recorded in +the :attr:`~Mock.method_calls` and :attr:`~Mock.mock_calls` attributes of the +parent. This is useful for configuring child mocks and then attaching them to +the parent, or for attaching mocks to a parent that records all calls to the +children and allows you to make assertions about the order of calls between +mocks: + + >>> parent = MagicMock() + >>> child1 = MagicMock(return_value=None) + >>> child2 = MagicMock(return_value=None) + >>> parent.child1 = child1 + >>> parent.child2 = child2 + >>> child1(1) + >>> child2(2) + >>> parent.mock_calls + [call.child1(1), call.child2(2)] + +The exception to this is if the mock has a name. This allows you to prevent +the "parenting" if for some reason you don't want it to happen. + + >>> mock = MagicMock() + >>> not_a_child = MagicMock(name='not-a-child') + >>> mock.attribute = not_a_child + >>> mock.attribute() + + >>> mock.mock_calls + [] + +Mocks created for you by :func:`patch` are automatically given names. To +attach mocks that have names to a parent you use the :meth:`~Mock.attach_mock` +method: + + >>> thing1 = object() + >>> thing2 = object() + >>> parent = MagicMock() + >>> with patch('__main__.thing1', return_value=None) as child1: + ... with patch('__main__.thing2', return_value=None) as child2: + ... parent.attach_mock(child1, 'child1') + ... parent.attach_mock(child2, 'child2') + ... child1('one') + ... child2('two') + ... + >>> parent.mock_calls + [call.child1('one'), call.child2('two')] + + +.. [#] The only exceptions are magic methods and attributes (those that have + leading and trailing double underscores). Mock doesn't create these but + instead of raises an ``AttributeError``. This is because the interpreter + will often implicitly request these methods, and gets *very* confused to + get a new Mock object when it expects a magic method. If you need magic + method support see :ref:`magic methods `. diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1577,11 +1577,9 @@ # __del__ is not supported at all as it causes problems if it exists _non_defaults = set('__%s__' % method for method in [ - 'cmp', 'getslice', 'setslice', 'coerce', 'subclasses', - 'format', 'get', 'set', 'delete', 'reversed', - 'missing', 'reduce', 'reduce_ex', 'getinitargs', - 'getnewargs', 'getstate', 'setstate', 'getformat', - 'setformat', 'repr', 'dir' + 'get', 'set', 'delete', 'reversed', 'missing', 'reduce', 'reduce_ex', + 'getinitargs', 'getnewargs', 'getstate', 'setstate', 'getformat', + 'setformat', 'repr', 'dir', 'subclasses', 'format', ]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 00:27:08 2012 From: python-checkins at python.org (michael.foord) Date: Mon, 26 Mar 2012 00:27:08 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_unittest=2Emock=3A_removed_?= =?utf8?q?another_bit_of_Python_2_only_code?= Message-ID: http://hg.python.org/cpython/rev/f8d01c8baf6a changeset: 75939:f8d01c8baf6a user: Michael Foord date: Sun Mar 25 23:27:12 2012 +0100 summary: unittest.mock: removed another bit of Python 2 only code files: Lib/unittest/mock.py | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1086,12 +1086,6 @@ patching.__exit__(*exc_info) patched.patchings = [self] - if hasattr(func, 'func_code'): - # not in Python 3 - patched.compat_co_firstlineno = getattr( - func, "compat_co_firstlineno", - func.func_code.co_firstlineno - ) return patched -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 04:42:02 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 26 Mar 2012 04:42:02 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_kill_this_terri?= =?utf8?q?bly_outdated_comment?= Message-ID: http://hg.python.org/cpython/rev/59f0cb9b8fd7 changeset: 75940:59f0cb9b8fd7 branch: 3.2 parent: 75904:54055646fd1f user: Benjamin Peterson date: Sun Mar 25 22:40:54 2012 -0400 summary: kill this terribly outdated comment files: Objects/unicodeobject.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9208,10 +9208,6 @@ } static PyMethodDef unicode_methods[] = { - - /* Order is according to common usage: often used methods should - appear first, since lookup is done sequentially. */ - {"encode", (PyCFunction) unicode_encode, METH_VARARGS | METH_KEYWORDS, encode__doc__}, {"replace", (PyCFunction) unicode_replace, METH_VARARGS, replace__doc__}, {"split", (PyCFunction) unicode_split, METH_VARARGS, split__doc__}, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 04:42:03 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 26 Mar 2012 04:42:03 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf8?q?_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/66117d4bb586 changeset: 75941:66117d4bb586 branch: 3.2 parent: 75940:59f0cb9b8fd7 parent: 75935:3ac66b3dfe82 user: Benjamin Peterson date: Sun Mar 25 22:41:06 2012 -0400 summary: merge heads files: Doc/conf.py | 5 +- Doc/howto/cporting.rst | 2 +- Doc/howto/curses.rst | 6 +- Doc/tools/sphinxext/layout.html | 1 + Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css | 170 ++++++++++ Doc/tools/sphinxext/pydoctheme/theme.conf | 23 + Doc/tools/sphinxext/pyspecific.py | 4 +- Doc/tools/sphinxext/static/copybutton.js | 3 +- Doc/tools/sphinxext/static/sidebar.js | 155 +++++++++ Lib/test/test_threading.py | 1 + 10 files changed, 362 insertions(+), 8 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py --- a/Doc/conf.py +++ b/Doc/conf.py @@ -65,9 +65,12 @@ # Options for HTML output # ----------------------- -html_theme = 'default' +html_theme = 'pydoctheme' +html_theme_path = ['tools/sphinxext'] html_theme_options = {'collapsiblesidebar': True} +html_short_title = '%s Documentation' % release + # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' diff --git a/Doc/howto/cporting.rst b/Doc/howto/cporting.rst --- a/Doc/howto/cporting.rst +++ b/Doc/howto/cporting.rst @@ -257,7 +257,7 @@ returns failure. (Since there's no way to store a name in a CObject, noisy failure of :c:func:`PyCapsule_SetName` was deemed preferable to silent failure here. If this is - inconveient, feel free to modify your local + inconvenient, feel free to modify your local copy as you see fit.) You can find :file:`capsulethunk.h` in the Python source distribution diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -118,7 +118,7 @@ A common problem when debugging a curses application is to get your terminal messed up when the application dies without restoring the terminal to its previous state. In Python this commonly happens when your code is buggy and -raises an uncaught exception. Keys are no longer be echoed to the screen when +raises an uncaught exception. Keys are no longer echoed to the screen when you type them, for example, which makes using the shell difficult. In Python you can avoid these complications and make debugging much easier by @@ -271,7 +271,7 @@ highlight certain words. curses supports this by allowing you to specify an attribute for each cell on the screen. -An attribute is a integer, each bit representing a different attribute. You can +An attribute is an integer, each bit representing a different attribute. You can try to display text with multiple attribute bits set, but curses doesn't guarantee that all the possible combinations are available, or that they're all visually distinct. That depends on the ability of the terminal being used, so @@ -300,7 +300,7 @@ curses.A_REVERSE) stdscr.refresh() -The curses library also supports color on those terminals that provide it, The +The curses library also supports color on those terminals that provide it. The most common such terminal is probably the Linux console, followed by color xterms. diff --git a/Doc/tools/sphinxext/layout.html b/Doc/tools/sphinxext/layout.html --- a/Doc/tools/sphinxext/layout.html +++ b/Doc/tools/sphinxext/layout.html @@ -2,6 +2,7 @@ {% block rootrellink %}
  • +
  • Python{{ reldelim1 }}
  • {{ shorttitle }}{{ reldelim1 }}
  • {% endblock %} {% block extrahead %} diff --git a/Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css b/Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css new file mode 100644 --- /dev/null +++ b/Doc/tools/sphinxext/pydoctheme/static/pydoctheme.css @@ -0,0 +1,170 @@ + at import url("default.css"); + +body { + background-color: white; + margin-left: 1em; + margin-right: 1em; +} + +div.related { + margin-bottom: 1.2em; + padding: 0.5em 0; + border-top: 1px solid #ccc; + margin-top: 0.5em; +} + +div.related a:hover { + color: #0095C4; +} + +div.related:first-child { + border-top: 0; + border-bottom: 1px solid #ccc; +} + +div.sphinxsidebar { + background-color: #eeeeee; + border-radius: 5px; + line-height: 130%; + font-size: smaller; +} + +div.sphinxsidebar h3, div.sphinxsidebar h4 { + margin-top: 1.5em; +} + +div.sphinxsidebarwrapper > h3:first-child { + margin-top: 0.2em; +} + +div.sphinxsidebarwrapper > ul > li > ul > li { + margin-bottom: 0.4em; +} + +div.sphinxsidebar a:hover { + color: #0095C4; +} + +div.sphinxsidebar input { + font-family: 'Lucida Grande',Arial,sans-serif; + border: 1px solid #999999; + font-size: smaller; + border-radius: 3px; +} + +div.sphinxsidebar input[type=text] { + max-width: 150px; +} + +div.body { + padding: 0 0 0 1.2em; +} + +div.body p { + line-height: 140%; +} + +div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { + margin: 0; + border: 0; + padding: 0.3em 0; +} + +div.body hr { + border: 0; + background-color: #ccc; + height: 1px; +} + +div.body pre { + border-radius: 3px; + border: 1px solid #ac9; +} + +div.body div.admonition, div.body div.impl-detail { + border-radius: 3px; +} + +div.body div.impl-detail > p { + margin: 0; +} + +div.body div.seealso { + border: 1px solid #dddd66; +} + +div.body a { + color: #00608f; +} + +div.body a:visited { + color: #30306f; +} + +div.body a:hover { + color: #00B0E4; +} + +tt, pre { + font-family: monospace, sans-serif; + font-size: 96.5%; +} + +div.body tt { + border-radius: 3px; +} + +div.body tt.descname { + font-size: 120%; +} + +div.body tt.xref, div.body a tt { + font-weight: normal; +} + +p.deprecated { + border-radius: 3px; +} + +table.docutils { + border: 1px solid #ddd; + min-width: 20%; + border-radius: 3px; + margin-top: 10px; + margin-bottom: 10px; +} + +table.docutils td, table.docutils th { + border: 1px solid #ddd !important; + border-radius: 3px; +} + +table p, table li { + text-align: left !important; +} + +table.docutils th { + background-color: #eee; + padding: 0.3em 0.5em; +} + +table.docutils td { + background-color: white; + padding: 0.3em 0.5em; +} + +table.footnote, table.footnote td { + border: 0 !important; +} + +div.footer { + line-height: 150%; + margin-top: -2em; + text-align: right; + width: auto; + margin-right: 10px; +} + +div.footer a:hover { + color: #0095C4; +} diff --git a/Doc/tools/sphinxext/pydoctheme/theme.conf b/Doc/tools/sphinxext/pydoctheme/theme.conf new file mode 100644 --- /dev/null +++ b/Doc/tools/sphinxext/pydoctheme/theme.conf @@ -0,0 +1,23 @@ +[theme] +inherit = default +stylesheet = pydoctheme.css +pygments_style = sphinx + +[options] +bodyfont = 'Lucida Grande', Arial, sans-serif +headfont = 'Lucida Grande', Arial, sans-serif +footerbgcolor = white +footertextcolor = #555555 +relbarbgcolor = white +relbartextcolor = #666666 +relbarlinkcolor = #444444 +sidebarbgcolor = white +sidebartextcolor = #444444 +sidebarlinkcolor = #444444 +bgcolor = white +textcolor = #222222 +linkcolor = #0090c0 +visitedlinkcolor = #00608f +headtextcolor = #1a1a1a +headbgcolor = white +headlinkcolor = #aaaaaa diff --git a/Doc/tools/sphinxext/pyspecific.py b/Doc/tools/sphinxext/pyspecific.py --- a/Doc/tools/sphinxext/pyspecific.py +++ b/Doc/tools/sphinxext/pyspecific.py @@ -27,10 +27,10 @@ self.body.append(self.starttag(node, 'p', CLASS=node['type'])) text = versionlabels[node['type']] % node['version'] if len(node): - text += ': ' + text += ':' else: text += '.' - self.body.append('%s' % text) + self.body.append('%s ' % text) from sphinx.writers.html import HTMLTranslator from sphinx.locale import versionlabels diff --git a/Doc/tools/sphinxext/static/copybutton.js b/Doc/tools/sphinxext/static/copybutton.js --- a/Doc/tools/sphinxext/static/copybutton.js +++ b/Doc/tools/sphinxext/static/copybutton.js @@ -17,7 +17,8 @@ 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', 'border-color': border_color, 'border-style': border_style, 'border-width': border_width, 'color': border_color, 'text-size': '75%', - 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em' + 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', + 'border-radius': '0 3px 0 0' } // create and add the button to all the code blocks that contain >>> diff --git a/Doc/tools/sphinxext/static/sidebar.js b/Doc/tools/sphinxext/static/sidebar.js new file mode 100644 --- /dev/null +++ b/Doc/tools/sphinxext/static/sidebar.js @@ -0,0 +1,155 @@ +/* + * sidebar.js + * ~~~~~~~~~~ + * + * This script makes the Sphinx sidebar collapsible. + * + * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds in + * .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton used to + * collapse and expand the sidebar. + * + * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden and the + * width of the sidebar and the margin-left of the document are decreased. + * When the sidebar is expanded the opposite happens. This script saves a + * per-browser/per-session cookie used to remember the position of the sidebar + * among the pages. Once the browser is closed the cookie is deleted and the + * position reset to the default (expanded). + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +$(function() { + // global elements used by the functions. + // the 'sidebarbutton' element is defined as global after its + // creation, in the add_sidebar_button function + var bodywrapper = $('.bodywrapper'); + var sidebar = $('.sphinxsidebar'); + var sidebarwrapper = $('.sphinxsidebarwrapper'); + + // original margin-left of the bodywrapper and width of the sidebar + // with the sidebar expanded + var bw_margin_expanded = bodywrapper.css('margin-left'); + var ssb_width_expanded = sidebar.width(); + + // margin-left of the bodywrapper and width of the sidebar + // with the sidebar collapsed + var bw_margin_collapsed = '.8em'; + var ssb_width_collapsed = '.8em'; + + // colors used by the current theme + var dark_color = '#AAAAAA'; + var light_color = '#CCCCCC'; + + function sidebar_is_collapsed() { + return sidebarwrapper.is(':not(:visible)'); + } + + function toggle_sidebar() { + if (sidebar_is_collapsed()) + expand_sidebar(); + else + collapse_sidebar(); + } + + function collapse_sidebar() { + sidebarwrapper.hide(); + sidebar.css('width', ssb_width_collapsed); + bodywrapper.css('margin-left', bw_margin_collapsed); + sidebarbutton.css({ + 'margin-left': '0', + 'height': bodywrapper.height(), + 'border-radius': '5px' + }); + sidebarbutton.find('span').text('?'); + sidebarbutton.attr('title', _('Expand sidebar')); + document.cookie = 'sidebar=collapsed'; + } + + function expand_sidebar() { + bodywrapper.css('margin-left', bw_margin_expanded); + sidebar.css('width', ssb_width_expanded); + sidebarwrapper.show(); + sidebarbutton.css({ + 'margin-left': ssb_width_expanded-12, + 'height': bodywrapper.height(), + 'border-radius': '0 5px 5px 0' + }); + sidebarbutton.find('span').text('?'); + sidebarbutton.attr('title', _('Collapse sidebar')); + //sidebarwrapper.css({'padding-top': + // Math.max(window.pageYOffset - sidebarwrapper.offset().top, 10)}); + document.cookie = 'sidebar=expanded'; + } + + function add_sidebar_button() { + sidebarwrapper.css({ + 'float': 'left', + 'margin-right': '0', + 'width': ssb_width_expanded - 28 + }); + // create the button + sidebar.append( + '
    «
    ' + ); + var sidebarbutton = $('#sidebarbutton'); + // find the height of the viewport to center the '<<' in the page + var viewport_height; + if (window.innerHeight) + viewport_height = window.innerHeight; + else + viewport_height = $(window).height(); + var sidebar_offset = sidebar.offset().top; + var sidebar_height = Math.max(bodywrapper.height(), sidebar.height()); + sidebarbutton.find('span').css({ + 'display': 'block', + 'position': 'fixed', + 'top': Math.min(viewport_height/2, sidebar_height/2 + sidebar_offset) - 10 + }); + + sidebarbutton.click(toggle_sidebar); + sidebarbutton.attr('title', _('Collapse sidebar')); + sidebarbutton.css({ + 'border-radius': '0 5px 5px 0', + 'color': '#444444', + 'background-color': '#CCCCCC', + 'font-size': '1.2em', + 'cursor': 'pointer', + 'height': sidebar_height, + 'padding-top': '1px', + 'padding-left': '1px', + 'margin-left': ssb_width_expanded - 12 + }); + + sidebarbutton.hover( + function () { + $(this).css('background-color', dark_color); + }, + function () { + $(this).css('background-color', light_color); + } + ); + } + + function set_position_from_cookie() { + if (!document.cookie) + return; + var items = document.cookie.split(';'); + for(var k=0; k http://hg.python.org/cpython/rev/51016ff7f8c9 changeset: 75942:51016ff7f8c9 parent: 75939:f8d01c8baf6a parent: 75941:66117d4bb586 user: Benjamin Peterson date: Sun Mar 25 22:41:16 2012 -0400 summary: merge 3.2 files: Objects/unicodeobject.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13173,10 +13173,6 @@ } static PyMethodDef unicode_methods[] = { - - /* Order is according to common usage: often used methods should - appear first, since lookup is done sequentially. */ - {"encode", (PyCFunction) unicode_encode, METH_VARARGS | METH_KEYWORDS, encode__doc__}, {"replace", (PyCFunction) unicode_replace, METH_VARARGS, replace__doc__}, {"split", (PyCFunction) unicode_split, METH_VARARGS | METH_KEYWORDS, split__doc__}, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 04:42:04 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 26 Mar 2012 04:42:04 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_kill_this_terri?= =?utf8?q?bly_outdated_comment?= Message-ID: http://hg.python.org/cpython/rev/e5e53f30b2ed changeset: 75943:e5e53f30b2ed branch: 2.7 parent: 75918:87539f66156b user: Benjamin Peterson date: Sun Mar 25 22:40:54 2012 -0400 summary: kill this terribly outdated comment files: Objects/unicodeobject.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7795,10 +7795,6 @@ static PyMethodDef unicode_methods[] = { - - /* Order is according to common usage: often used methods should - appear first, since lookup is done sequentially. */ - {"encode", (PyCFunction) unicode_encode, METH_VARARGS | METH_KEYWORDS, encode__doc__}, {"replace", (PyCFunction) unicode_replace, METH_VARARGS, replace__doc__}, {"split", (PyCFunction) unicode_split, METH_VARARGS, split__doc__}, -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Mar 26 05:46:57 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 26 Mar 2012 05:46:57 +0200 Subject: [Python-checkins] Daily reference leaks (f8d01c8baf6a): sum=0 Message-ID: results for f8d01c8baf6a on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogTwsFdG', '-x'] From python-checkins at python.org Mon Mar 26 15:15:14 2012 From: python-checkins at python.org (stefan.krah) Date: Mon, 26 Mar 2012 15:15:14 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzMzNjc6?= =?utf8?q?_NULL-terminate_argv=5B=5D_copies_to_prevent_an_invalid_access?= Message-ID: http://hg.python.org/cpython/rev/c0900fd6e4b3 changeset: 75944:c0900fd6e4b3 branch: 3.2 parent: 75941:66117d4bb586 user: Stefan Krah date: Mon Mar 26 15:05:22 2012 +0200 summary: Issue #3367: NULL-terminate argv[] copies to prevent an invalid access in sys_update_path(). files: Modules/python.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/python.c b/Modules/python.c --- a/Modules/python.c +++ b/Modules/python.c @@ -22,9 +22,9 @@ int main(int argc, char **argv) { - wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*argc); + wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); /* We need a second copies, as Python might modify the first one. */ - wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*argc); + wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); int i, res; char *oldloc; /* 754 requires that FP exceptions run in "no stop" mode by default, @@ -58,6 +58,8 @@ } argv_copy2[i] = argv_copy[i]; } + argv_copy2[argc] = argv_copy[argc] = NULL; + setlocale(LC_ALL, oldloc); free(oldloc); res = Py_Main(argc, argv_copy); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 15:15:15 2012 From: python-checkins at python.org (stefan.krah) Date: Mon, 26 Mar 2012 15:15:15 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=233367=3A_Merge_fix_from_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/1ab8fa2277d9 changeset: 75945:1ab8fa2277d9 parent: 75942:51016ff7f8c9 parent: 75944:c0900fd6e4b3 user: Stefan Krah date: Mon Mar 26 15:11:22 2012 +0200 summary: Issue #3367: Merge fix from 3.2. files: Modules/python.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Modules/python.c b/Modules/python.c --- a/Modules/python.c +++ b/Modules/python.c @@ -22,9 +22,9 @@ int main(int argc, char **argv) { - wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*argc); + wchar_t **argv_copy = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); /* We need a second copies, as Python might modify the first one. */ - wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*argc); + wchar_t **argv_copy2 = (wchar_t **)PyMem_Malloc(sizeof(wchar_t*)*(argc+1)); int i, res; char *oldloc; /* 754 requires that FP exceptions run in "no stop" mode by default, @@ -58,6 +58,8 @@ } argv_copy2[i] = argv_copy[i]; } + argv_copy2[argc] = argv_copy[argc] = NULL; + setlocale(LC_ALL, oldloc); free(oldloc); res = Py_Main(argc, argv_copy); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 18:17:57 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 26 Mar 2012 18:17:57 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Minor_documenta?= =?utf8?q?tion_tweak=2E?= Message-ID: http://hg.python.org/cpython/rev/a39396d6cc4b changeset: 75946:a39396d6cc4b branch: 2.7 parent: 75943:e5e53f30b2ed user: Vinay Sajip date: Mon Mar 26 17:06:44 2012 +0100 summary: Minor documentation tweak. files: Doc/library/logging.handlers.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -650,7 +650,7 @@ :class:`BufferingHandler`, which is an abstract class. This buffers logging records in memory. Whenever each record is added to the buffer, a check is made by calling :meth:`shouldFlush` to see if the buffer should be flushed. If it -should, then :meth:`flush` is expected to do the needful. +should, then :meth:`flush` is expected to do the flushing. .. class:: BufferingHandler(capacity) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 18:17:58 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 26 Mar 2012 18:17:58 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Minor_documenta?= =?utf8?q?tion_tweak=2E?= Message-ID: http://hg.python.org/cpython/rev/9c234943efc2 changeset: 75947:9c234943efc2 branch: 3.2 parent: 75944:c0900fd6e4b3 user: Vinay Sajip date: Mon Mar 26 17:09:58 2012 +0100 summary: Minor documentation tweak. files: Doc/library/logging.handlers.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -654,7 +654,7 @@ :class:`BufferingHandler`, which is an abstract class. This buffers logging records in memory. Whenever each record is added to the buffer, a check is made by calling :meth:`shouldFlush` to see if the buffer should be flushed. If it -should, then :meth:`flush` is expected to do the needful. +should, then :meth:`flush` is expected to do the flushing. .. class:: BufferingHandler(capacity) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 18:17:59 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 26 Mar 2012 18:17:59 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Updated_handler_documentation=2E?= Message-ID: http://hg.python.org/cpython/rev/3bb51f26f3bf changeset: 75948:3bb51f26f3bf parent: 75945:1ab8fa2277d9 parent: 75947:9c234943efc2 user: Vinay Sajip date: Mon Mar 26 17:17:39 2012 +0100 summary: Updated handler documentation. files: Doc/library/logging.handlers.rst | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -704,7 +704,7 @@ supports sending logging messages to an email address via SMTP. -.. class:: SMTPHandler(mailhost, fromaddr, toaddrs, subject, credentials=None, secure=None) +.. class:: SMTPHandler(mailhost, fromaddr, toaddrs, subject, credentials=None, secure=None, timeout=1.0) Returns a new instance of the :class:`SMTPHandler` class. The instance is initialized with the from and to addresses and subject line of the email. The @@ -720,6 +720,12 @@ and certificate file. (This tuple is passed to the :meth:`smtplib.SMTP.starttls` method.) + A timeout can be specified for communication with the SMTP server using the + *timeout* argument. + + .. versionadded:: 3.3 + The *timeout* argument was added. + .. method:: emit(record) Formats the record and sends it to the specified addressees. @@ -744,7 +750,7 @@ :class:`BufferingHandler`, which is an abstract class. This buffers logging records in memory. Whenever each record is added to the buffer, a check is made by calling :meth:`shouldFlush` to see if the buffer should be flushed. If it -should, then :meth:`flush` is expected to do the needful. +should, then :meth:`flush` is expected to do the flushing. .. class:: BufferingHandler(capacity) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 19:34:55 2012 From: python-checkins at python.org (r.david.murray) Date: Mon, 26 Mar 2012 19:34:55 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_=2314413=3A_tweak_word_orde?= =?utf8?q?r_in_deprecation_section?= Message-ID: http://hg.python.org/cpython/rev/c407db9120e9 changeset: 75949:c407db9120e9 user: R David Murray date: Mon Mar 26 13:34:46 2012 -0400 summary: #14413: tweak word order in deprecation section files: Doc/whatsnew/3.3.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1118,7 +1118,8 @@ Deprecated Python modules, functions and methods ------------------------------------------------ -* The :mod:`packaging` module replaces the :mod:`distutils` module +* The :mod:`distutils` modules has been deprecated. Use the new + :mod:`packaging` module instead. * The ``unicode_internal`` codec has been deprecated because of the :pep:`393`, use UTF-8, UTF-16 (``utf-16-le`` or ``utf-16-be``), or UTF-32 (``utf-32-le`` or ``utf-32-be``) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 19:46:12 2012 From: python-checkins at python.org (sandro.tosi) Date: Mon, 26 Mar 2012 19:46:12 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0NDEw?= =?utf8?q?=3A_fix_typo_in_argparse_doc=3B_patch_by_Tshepang_Lekhonkhobe?= Message-ID: http://hg.python.org/cpython/rev/03771ea22ead changeset: 75950:03771ea22ead branch: 2.7 parent: 75946:a39396d6cc4b user: Sandro Tosi date: Mon Mar 26 19:35:52 2012 +0200 summary: Issue #14410: fix typo in argparse doc; patch by Tshepang Lekhonkhobe files: Doc/library/argparse.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1634,8 +1634,8 @@ --bar BAR bar help - Note that any arguments not your user defined groups will end up back in the - usual "positional arguments" and "optional arguments" sections. + Note that any arguments not in your user-defined groups will end up back + in the usual "positional arguments" and "optional arguments" sections. Mutual exclusion -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 19:46:13 2012 From: python-checkins at python.org (sandro.tosi) Date: Mon, 26 Mar 2012 19:46:13 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0NDEw?= =?utf8?q?=3A_fix_typo_in_argparse_doc=3B_patch_by_Tshepang_Lekhonkhobe?= Message-ID: http://hg.python.org/cpython/rev/3e18af617266 changeset: 75951:3e18af617266 branch: 3.2 parent: 75947:9c234943efc2 user: Sandro Tosi date: Mon Mar 26 19:36:23 2012 +0200 summary: Issue #14410: fix typo in argparse doc; patch by Tshepang Lekhonkhobe files: Doc/library/argparse.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1642,8 +1642,8 @@ --bar BAR bar help - Note that any arguments not your user defined groups will end up back in the - usual "positional arguments" and "optional arguments" sections. + Note that any arguments not in your user-defined groups will end up back + in the usual "positional arguments" and "optional arguments" sections. Mutual exclusion -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 19:46:14 2012 From: python-checkins at python.org (sandro.tosi) Date: Mon, 26 Mar 2012 19:46:14 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314410=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/4691f8a57db0 changeset: 75952:4691f8a57db0 parent: 75949:c407db9120e9 parent: 75951:3e18af617266 user: Sandro Tosi date: Mon Mar 26 19:36:44 2012 +0200 summary: Issue #14410: merge with 3.2 files: Doc/library/argparse.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1661,8 +1661,8 @@ --bar BAR bar help - Note that any arguments not your user defined groups will end up back in the - usual "positional arguments" and "optional arguments" sections. + Note that any arguments not in your user-defined groups will end up back + in the usual "positional arguments" and "optional arguments" sections. Mutual exclusion -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 20:44:25 2012 From: python-checkins at python.org (eli.bendersky) Date: Mon, 26 Mar 2012 20:44:25 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=236488=3A_Explain_th?= =?utf8?q?e_XPath_support_of_xml=2Eetree=2EElementTree=2C_with_code?= Message-ID: http://hg.python.org/cpython/rev/e38f4cf482c7 changeset: 75953:e38f4cf482c7 user: Eli Bendersky date: Mon Mar 26 20:43:32 2012 +0200 summary: Issue #6488: Explain the XPath support of xml.etree.ElementTree, with code samples and a reference. Also fix the other nits mentioned in the issue. This also partially addresses issue #14006. files: Doc/library/xml.etree.elementtree.rst | 155 +++++++++++-- 1 files changed, 132 insertions(+), 23 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -45,10 +45,119 @@ The :mod:`xml.etree.cElementTree` module is deprecated. +.. _elementtree-xpath: + +XPath support +------------- + +This module provides limited support for +`XPath expressions `_ for locating elements in a +tree. The goal is to support a small subset of the abbreviated syntax; a full +XPath engine is outside the scope of the module. + +Example +^^^^^^^ + +Here's an example that demonstrates some of the XPath capabilities of the +module:: + + import xml.etree.ElementTree as ET + + xml = r''' + + + 1 + 2008 + 141100 + + + + + 4 + 2011 + 59900 + + + + 68 + 2011 + 13600 + + + + + ''' + + tree = ET.fromstring(xml) + + # Top-level elements + tree.findall(".") + + # All 'neighbor' grand-children of 'country' children of the top-level + # elements + tree.findall("./country/neighbor") + + # Nodes with name='Singapore' that have a 'year' child + tree.findall(".//year/..[@name='Singapore']") + + # 'year' nodes that are children of nodes with name='Singapore' + tree.findall(".//*[@name='Singapore']/year") + + # All 'neighbor' nodes that are the second child of their parent + tree.findall(".//neighbor[2]") + +Supported XPath syntax +^^^^^^^^^^^^^^^^^^^^^^ + ++-----------------------+------------------------------------------------------+ +| Syntax | Meaning | ++=======================+======================================================+ +| ``tag`` | Selects all child elements with the given tag. | +| | For example, ``spam`` selects all child elements | +| | named ``spam``, ``spam/egg`` selects all | +| | grandchildren named ``egg`` in all children named | +| | ``spam``. | ++-----------------------+------------------------------------------------------+ +| ``*`` | Selects all child elements. For example, ``*/egg`` | +| | selects all grandchildren named ``egg``. | ++-----------------------+------------------------------------------------------+ +| ``.`` | Selects the current node. This is mostly useful | +| | at the beginning of the path, to indicate that it's | +| | a relative path. | ++-----------------------+------------------------------------------------------+ +| ``//`` | Selects all subelements, on all levels beneath the | +| | current element. For example, ``./egg`` selects | +| | all ``egg`` elements in the entire tree. | ++-----------------------+------------------------------------------------------+ +| ``..`` | Selects the parent element. | ++-----------------------+------------------------------------------------------+ +| ``[@attrib]`` | Selects all elements that have the given attribute. | ++-----------------------+------------------------------------------------------+ +| ``[@attrib='value']`` | Selects all elements for which the given attribute | +| | has the given value. The value cannot contain | +| | quotes. | ++-----------------------+------------------------------------------------------+ +| ``[tag]`` | Selects all elements that have a child named | +| | ``tag``. Only immediate children are supported. | ++-----------------------+------------------------------------------------------+ +| ``[position]`` | Selects all elements that are located at the given | +| | position. The position can be either an integer | +| | (1 is the first position), the expression ``last()`` | +| | (for the last position), or a position relative to | +| | the last position (e.g. ``last()-1``). | ++-----------------------+------------------------------------------------------+ + +Predicates (expressions within square brackets) must be preceded by a tag +name, an asterisk, or another predicate. ``position`` predicates must be +preceded by a tag name. + +Reference +--------- + .. _elementtree-functions: Functions ---------- +^^^^^^^^^ .. function:: Comment(text=None) @@ -199,7 +308,7 @@ .. _elementtree-element-objects: Element Objects ---------------- +^^^^^^^^^^^^^^^ .. class:: Element(tag, attrib={}, **extra) @@ -297,21 +406,24 @@ .. method:: find(match) Finds the first subelement matching *match*. *match* may be a tag name - or path. Returns an element instance or ``None``. + or a :ref:`path `. Returns an element instance + or ``None``. .. method:: findall(match) - Finds all matching subelements, by tag name or path. Returns a list - containing all matching elements in document order. + Finds all matching subelements, by tag name or + :ref:`path `. Returns a list containing all matching + elements in document order. .. method:: findtext(match, default=None) Finds text for the first subelement matching *match*. *match* may be - a tag name or path. Returns the text content of the first matching - element, or *default* if no element was found. Note that if the matching - element has no text content an empty string is returned. + a tag name or a :ref:`path `. Returns the text content + of the first matching element, or *default* if no element was found. + Note that if the matching element has no text content an empty string + is returned. .. method:: getchildren() @@ -345,8 +457,9 @@ .. method:: iterfind(match) - Finds all matching subelements, by tag name or path. Returns an iterable - yielding all matching elements in document order. + Finds all matching subelements, by tag name or + :ref:`path `. Returns an iterable yielding all + matching elements in document order. .. versionadded:: 3.2 @@ -391,7 +504,7 @@ .. _elementtree-elementtree-objects: ElementTree Objects -------------------- +^^^^^^^^^^^^^^^^^^^ .. class:: ElementTree(element=None, file=None) @@ -413,26 +526,17 @@ .. method:: find(match) - Finds the first toplevel element matching *match*. *match* may be a tag - name or path. Same as getroot().find(match). Returns the first matching - element, or ``None`` if no element was found. + Same as :meth:`Element.find`, starting at the root of the tree. .. method:: findall(match) - Finds all matching subelements, by tag name or path. Same as - getroot().findall(match). *match* may be a tag name or path. Returns a - list containing all matching elements, in document order. + Same as :meth:`Element.findall`, starting at the root of the tree. .. method:: findtext(match, default=None) - Finds the element text for the first toplevel element with given tag. - Same as getroot().findtext(match). *match* may be a tag name or path. - *default* is the value to return if the element was not found. Returns - the text content of the first matching element, or the default value no - element was found. Note that if the element is found, but has no text - content, this method returns an empty string. + Same as :meth:`Element.findtext`, starting at the root of the tree. .. method:: getiterator(tag=None) @@ -455,9 +559,7 @@ .. method:: iterfind(match) - Finds all matching subelements, by tag name or path. Same as - getroot().iterfind(match). Returns an iterable yielding all matching - elements in document order. + Same as :meth:`Element.iterfind`, starting at the root of the tree. .. versionadded:: 3.2 @@ -512,7 +614,7 @@ .. _elementtree-qname-objects: QName Objects -------------- +^^^^^^^^^^^^^ .. class:: QName(text_or_uri, tag=None) @@ -528,7 +630,7 @@ .. _elementtree-treebuilder-objects: TreeBuilder Objects -------------------- +^^^^^^^^^^^^^^^^^^^ .. class:: TreeBuilder(element_factory=None) @@ -579,7 +681,7 @@ .. _elementtree-xmlparser-objects: XMLParser Objects ------------------ +^^^^^^^^^^^^^^^^^ .. class:: XMLParser(html=0, target=None, encoding=None) @@ -648,7 +750,7 @@ 4 Exceptions ----------- +^^^^^^^^^^ .. class:: ParseError -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 20:50:36 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 26 Mar 2012 20:50:36 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_grammar?= Message-ID: http://hg.python.org/cpython/rev/64336c441320 changeset: 75954:64336c441320 user: Benjamin Peterson date: Mon Mar 26 14:50:32 2012 -0400 summary: grammar files: Objects/unicodeobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1820,7 +1820,7 @@ } } -/* Internal function, don't check maximum character */ +/* Internal function, doesn't check maximum character */ static PyObject* unicode_fromascii(const unsigned char* s, Py_ssize_t size) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 21:00:11 2012 From: python-checkins at python.org (andrew.svetlov) Date: Mon, 26 Mar 2012 21:00:11 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=23989712=3A_update_t?= =?utf8?q?he_code_to_process_tkinter_messages_in_IDLE?= Message-ID: http://hg.python.org/cpython/rev/837ac3abf0c5 changeset: 75955:837ac3abf0c5 user: Andrew Svetlov date: Mon Mar 26 21:56:44 2012 +0300 summary: Issue #989712: update the code to process tkinter messages in IDLE without mainloop. Thanks to Roger Serwy for patch. files: Lib/idlelib/run.py | 15 ++++++--------- 1 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -6,6 +6,7 @@ import _thread as thread import threading import queue +import tkinter from idlelib import CallTips from idlelib import AutoComplete @@ -39,18 +40,14 @@ warnings.formatwarning = idle_formatwarning_subproc -def handle_tk_events(): +tcl = tkinter.Tcl() + + +def handle_tk_events(tcl=tcl): """Process any tk events that are ready to be dispatched if tkinter has been imported, a tcl interpreter has been created and tk has been loaded.""" - tkinter = sys.modules.get('tkinter') - if tkinter and tkinter._default_root: - # tkinter has been imported, an Tcl interpreter was created and - # tk has been loaded. - root = tkinter._default_root - while root.tk.dooneevent(tkinter._tkinter.DONT_WAIT): - # Process pending events. - pass + tcl.eval("update") # Thread shared globals: Establish a queue between a subthread (which handles -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 21:11:53 2012 From: python-checkins at python.org (andrew.svetlov) Date: Mon, 26 Mar 2012 21:11:53 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_IDLE_can_be_launched_as_pyt?= =?utf8?q?hon_-m_ildelib?= Message-ID: http://hg.python.org/cpython/rev/06d613acf16c changeset: 75956:06d613acf16c user: Andrew Svetlov date: Mon Mar 26 22:11:46 2012 +0300 summary: IDLE can be launched as python -m ildelib files: Lib/idlelib/__main__.py | 9 +++++++++ Misc/NEWS | 2 ++ 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/__main__.py b/Lib/idlelib/__main__.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/__main__.py @@ -0,0 +1,9 @@ +""" +IDLE main entry point + +Run IDLE as python -m idlelib +""" + + +import idlelib.PyShell +idlelib.PyShell.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,8 @@ Library ------- +- IDLE can be launched as python -m ildelib + - Issue #14295: Add unittest.mock - Issue #7652: Add --with-system-libmpdec option to configure for linking -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 21:14:26 2012 From: python-checkins at python.org (andrew.svetlov) Date: Mon, 26 Mar 2012 21:14:26 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Update_missed_idlelib/NEWS?= =?utf8?q?=2Etxt?= Message-ID: http://hg.python.org/cpython/rev/03af0d16c328 changeset: 75957:03af0d16c328 user: Andrew Svetlov date: Mon Mar 26 22:14:13 2012 +0300 summary: Update missed idlelib/NEWS.txt files: Lib/idlelib/NEWS.txt | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ -What's New in IDLE 3.2.3? +What's New in IDLE 3.3? ========================= +- IDLE can be launched as `python -m ildelib` + - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 22:08:41 2012 From: python-checkins at python.org (victor.stinner) Date: Mon, 26 Mar 2012 22:08:41 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314368=3A_=5FPyTime?= =?utf8?q?=5Fgettimeofday=28=29_cannot_fail?= Message-ID: http://hg.python.org/cpython/rev/206c45f45236 changeset: 75958:206c45f45236 user: Victor Stinner date: Mon Mar 26 22:08:02 2012 +0200 summary: Issue #14368: _PyTime_gettimeofday() cannot fail floattime() must not raise an error if the current time is 1970.1.1 at 00:00. files: Modules/timemodule.c | 8 +------- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1063,14 +1063,8 @@ floattime(void) { _PyTime_timeval t; - double secs; _PyTime_gettimeofday(&t); - secs = (double)t.tv_sec + t.tv_usec*0.000001; - if (secs == 0.0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - return PyFloat_FromDouble(secs); + return PyFloat_FromDouble((double)t.tv_sec + t.tv_usec * 1e-6); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 22:15:40 2012 From: python-checkins at python.org (victor.stinner) Date: Mon, 26 Mar 2012 22:15:40 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314383=3A_Add_=5FPy?= =?utf8?q?Dict=5FGetItemId=28=29_and_=5FPyDict=5FSetItemId=28=29_functions?= Message-ID: http://hg.python.org/cpython/rev/c67f3681e032 changeset: 75959:c67f3681e032 user: Victor Stinner date: Mon Mar 26 22:10:51 2012 +0200 summary: Issue #14383: Add _PyDict_GetItemId() and _PyDict_SetItemId() functions These functions simplify the usage of static constant Unicode strings. Generalize the usage of _Py_Identifier in ceval.c and typeobject.c. files: Include/dictobject.h | 2 + Objects/dictobject.c | 20 ++ Objects/typeobject.c | 211 +++++++++++++----------------- Python/ceval.c | 15 +- 4 files changed, 122 insertions(+), 126 deletions(-) diff --git a/Include/dictobject.h b/Include/dictobject.h --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -155,7 +155,9 @@ int override); PyAPI_FUNC(PyObject *) PyDict_GetItemString(PyObject *dp, const char *key); +PyAPI_FUNC(PyObject *) _PyDict_GetItemId(PyObject *dp, struct _Py_Identifier *key); PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item); +PyAPI_FUNC(int) _PyDict_SetItemId(PyObject *dp, struct _Py_Identifier *key, PyObject *item); PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key); #ifdef __cplusplus diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2198,6 +2198,16 @@ PyObject_GC_Del, /* tp_free */ }; +PyObject * +_PyDict_GetItemId(PyObject *dp, struct _Py_Identifier *key) +{ + PyObject *kv; + kv = _PyUnicode_FromId(key); /* borrowed */ + if (kv == NULL) + return NULL; + return PyDict_GetItem(dp, kv); +} + /* For backward compatibility with old dictionary interface */ PyObject * @@ -2213,6 +2223,16 @@ } int +_PyDict_SetItemId(PyObject *v, struct _Py_Identifier *key, PyObject *item) +{ + PyObject *kv; + kv = _PyUnicode_FromId(key); /* borrowed */ + if (kv == NULL) + return -1; + return PyDict_SetItem(v, kv, item); +} + +int PyDict_SetItemString(PyObject *v, const char *key, PyObject *item) { PyObject *kv; diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -35,8 +35,18 @@ static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP]; static unsigned int next_version_tag = 0; +_Py_IDENTIFIER(__class__); _Py_IDENTIFIER(__dict__); -_Py_IDENTIFIER(__class__); +_Py_IDENTIFIER(__doc__); +_Py_IDENTIFIER(__getitem__); +_Py_IDENTIFIER(__getattribute__); +_Py_IDENTIFIER(__hash__); +_Py_IDENTIFIER(__module__); +_Py_IDENTIFIER(__name__); +_Py_IDENTIFIER(__new__); + +static PyObject * +_PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name); unsigned int PyType_ClearCache(void) @@ -319,7 +329,7 @@ char *s; if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { - mod = PyDict_GetItemString(type->tp_dict, "__module__"); + mod = _PyDict_GetItemId(type->tp_dict, &PyId___module__); if (!mod) { PyErr_Format(PyExc_AttributeError, "__module__"); return 0; @@ -344,7 +354,7 @@ PyType_Modified(type); - return PyDict_SetItemString(type->tp_dict, "__module__", value); + return _PyDict_SetItemId(type->tp_dict, &PyId___module__, value); } static PyObject * @@ -603,7 +613,7 @@ PyObject *result; if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) return PyUnicode_FromString(type->tp_doc); - result = PyDict_GetItemString(type->tp_dict, "__doc__"); + result = _PyDict_GetItemId(type->tp_dict, &PyId___doc__); if (result == NULL) { result = Py_None; Py_INCREF(result); @@ -624,7 +634,7 @@ if (!check_set_special_type_attr(type, value, "__doc__")) return -1; PyType_Modified(type); - return PyDict_SetItemString(type->tp_dict, "__doc__", value); + return _PyDict_SetItemId(type->tp_dict, &PyId___doc__, value); } static PyObject * @@ -1164,12 +1174,9 @@ static PyObject * lookup_maybe(PyObject *self, _Py_Identifier *attrid) { - PyObject *attr, *res; - - attr = _PyUnicode_FromId(attrid); - if (attr == NULL) - return NULL; - res = _PyType_Lookup(Py_TYPE(self), attr); + PyObject *res; + + res = _PyType_LookupId(Py_TYPE(self), attrid); if (res != NULL) { descrgetfunc f; if ((f = Py_TYPE(res)->tp_descr_get) == NULL) @@ -1312,7 +1319,6 @@ static PyObject * class_name(PyObject *cls) { - _Py_IDENTIFIER(__name__); PyObject *name = _PyObject_GetAttrId(cls, &PyId___name__); if (name == NULL) { PyErr_Clear(); @@ -1740,13 +1746,9 @@ static PyObject * get_dict_descriptor(PyTypeObject *type) { - PyObject *dict_str; PyObject *descr; - dict_str = _PyUnicode_FromId(&PyId___dict__); /* borrowed */ - if (dict_str == NULL) - return NULL; - descr = _PyType_Lookup(type, dict_str); + descr = _PyType_LookupId(type, &PyId___dict__); if (descr == NULL || !PyDescr_IsData(descr)) return NULL; @@ -1974,6 +1976,8 @@ PyMemberDef *mp; Py_ssize_t i, nbases, nslots, slotoffset, add_dict, add_weak; int j, may_add_dict, may_add_weak; + _Py_IDENTIFIER(__qualname__); + _Py_IDENTIFIER(__slots__); assert(args != NULL && PyTuple_Check(args)); assert(kwds == NULL || PyDict_Check(kwds)); @@ -2046,7 +2050,7 @@ goto error; /* Check for a __slots__ sequence variable in dict, and count it */ - slots = PyDict_GetItemString(dict, "__slots__"); + slots = _PyDict_GetItemId(dict, &PyId___slots__); nslots = 0; add_dict = 0; add_weak = 0; @@ -2214,13 +2218,13 @@ type->tp_dict = dict; /* Set __module__ in the dict */ - if (PyDict_GetItemString(dict, "__module__") == NULL) { + if (_PyDict_GetItemId(dict, &PyId___module__) == NULL) { tmp = PyEval_GetGlobals(); if (tmp != NULL) { - tmp = PyDict_GetItemString(tmp, "__name__"); + tmp = _PyDict_GetItemId(tmp, &PyId___name__); if (tmp != NULL) { - if (PyDict_SetItemString(dict, "__module__", - tmp) < 0) + if (_PyDict_SetItemId(dict, &PyId___module__, + tmp) < 0) goto error; } } @@ -2229,7 +2233,7 @@ /* Set ht_qualname to dict['__qualname__'] if available, else to __name__. The __qualname__ accessor will look for ht_qualname. */ - qualname = PyDict_GetItemString(dict, "__qualname__"); + qualname = _PyDict_GetItemId(dict, &PyId___qualname__); if (qualname != NULL) { if (!PyUnicode_Check(qualname)) { PyErr_Format(PyExc_TypeError, @@ -2249,7 +2253,7 @@ if that fails, it will still look into __dict__. */ { - PyObject *doc = PyDict_GetItemString(dict, "__doc__"); + PyObject *doc = _PyDict_GetItemId(dict, &PyId___doc__); if (doc != NULL && PyUnicode_Check(doc)) { Py_ssize_t len; char *doc_str; @@ -2270,12 +2274,13 @@ /* Special-case __new__: if it's a plain function, make it a static function */ - tmp = PyDict_GetItemString(dict, "__new__"); + tmp = _PyDict_GetItemId(dict, &PyId___new__); if (tmp != NULL && PyFunction_Check(tmp)) { tmp = PyStaticMethod_New(tmp); if (tmp == NULL) goto error; - PyDict_SetItemString(dict, "__new__", tmp); + if (_PyDict_SetItemId(dict, &PyId___new__, tmp) < 0) + goto error; Py_DECREF(tmp); } @@ -2477,6 +2482,16 @@ return res; } +static PyObject * +_PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name) +{ + PyObject *oname; + oname = _PyUnicode_FromId(name); /* borrowed */ + if (oname == NULL) + return NULL; + return _PyType_Lookup(type, oname); +} + /* This is similar to PyObject_GenericGetAttr(), but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ static PyObject * @@ -2922,7 +2937,7 @@ PyErr_SetString(PyExc_TypeError, "object.__new__() takes no parameters"); return NULL; } - + if (type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) { PyObject *abstract_methods = NULL; PyObject *builtins; @@ -2931,6 +2946,7 @@ PyObject *joined = NULL; PyObject *comma; _Py_static_string(comma_id, ", "); + _Py_IDENTIFIER(sorted); /* Compute ", ".join(sorted(type.__abstractmethods__)) into joined. */ @@ -2940,7 +2956,7 @@ builtins = PyEval_GetBuiltins(); if (builtins == NULL) goto error; - sorted = PyDict_GetItemString(builtins, "sorted"); + sorted = _PyDict_GetItemId(builtins, &PyId_sorted); if (sorted == NULL) goto error; sorted_methods = PyObject_CallFunctionObjArgs(sorted, @@ -3214,17 +3230,11 @@ PyObject *clsdict; PyObject *copyreg; PyObject *slotnames; - static PyObject *str_slotnames; + _Py_IDENTIFIER(__slotnames__); _Py_IDENTIFIER(_slotnames); - if (str_slotnames == NULL) { - str_slotnames = PyUnicode_InternFromString("__slotnames__"); - if (str_slotnames == NULL) - return NULL; - } - clsdict = ((PyTypeObject *)cls)->tp_dict; - slotnames = PyDict_GetItem(clsdict, str_slotnames); + slotnames = _PyDict_GetItemId(clsdict, &PyId___slotnames__); if (slotnames != NULL && PyList_Check(slotnames)) { Py_INCREF(slotnames); return slotnames; @@ -3258,20 +3268,13 @@ PyObject *slots = NULL, *listitems = NULL, *dictitems = NULL; PyObject *copyreg = NULL, *newobj = NULL, *res = NULL; Py_ssize_t i, n; - static PyObject *str_getnewargs = NULL, *str_getstate = NULL, - *str_newobj = NULL; - - if (str_getnewargs == NULL) { - str_getnewargs = PyUnicode_InternFromString("__getnewargs__"); - str_getstate = PyUnicode_InternFromString("__getstate__"); - str_newobj = PyUnicode_InternFromString("__newobj__"); - if (!str_getnewargs || !str_getstate || !str_newobj) - return NULL; - } + _Py_IDENTIFIER(__getnewargs__); + _Py_IDENTIFIER(__getstate__); + _Py_IDENTIFIER(__newobj__); cls = (PyObject *) Py_TYPE(obj); - getnewargs = PyObject_GetAttr(obj, str_getnewargs); + getnewargs = _PyObject_GetAttrId(obj, &PyId___getnewargs__); if (getnewargs != NULL) { args = PyObject_CallObject(getnewargs, NULL); Py_DECREF(getnewargs); @@ -3289,7 +3292,7 @@ if (args == NULL) goto end; - getstate = PyObject_GetAttr(obj, str_getstate); + getstate = _PyObject_GetAttrId(obj, &PyId___getstate__); if (getstate != NULL) { state = PyObject_CallObject(getstate, NULL); Py_DECREF(getstate); @@ -3368,7 +3371,7 @@ copyreg = import_copyreg(); if (copyreg == NULL) goto end; - newobj = PyObject_GetAttr(copyreg, str_newobj); + newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj__); if (newobj == NULL) goto end; @@ -3446,22 +3449,22 @@ static PyObject * object_reduce_ex(PyObject *self, PyObject *args) { - static PyObject *str_reduce = NULL, *objreduce; + static PyObject *objreduce; PyObject *reduce, *res; int proto = 0; + _Py_IDENTIFIER(__reduce__); if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto)) return NULL; - if (str_reduce == NULL) { - str_reduce = PyUnicode_InternFromString("__reduce__"); - objreduce = PyDict_GetItemString(PyBaseObject_Type.tp_dict, - "__reduce__"); - if (str_reduce == NULL || objreduce == NULL) + if (objreduce == NULL) { + objreduce = _PyDict_GetItemId(PyBaseObject_Type.tp_dict, + &PyId___reduce__); + if (objreduce == NULL) return NULL; } - reduce = PyObject_GetAttr(self, str_reduce); + reduce = _PyObject_GetAttrId(self, &PyId___reduce__); if (reduce == NULL) PyErr_Clear(); else { @@ -3469,7 +3472,7 @@ int override; cls = (PyObject *) Py_TYPE(self); - clsreduce = PyObject_GetAttr(cls, str_reduce); + clsreduce = _PyObject_GetAttrId(cls, &PyId___reduce__); if (clsreduce == NULL) { Py_DECREF(reduce); return NULL; @@ -3807,23 +3810,17 @@ type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS; } -static char *hash_name_op[] = { - "__eq__", - "__hash__", - NULL -}; - static int overrides_hash(PyTypeObject *type) { - char **p; PyObject *dict = type->tp_dict; + _Py_IDENTIFIER(__eq__); assert(dict != NULL); - for (p = hash_name_op; *p; p++) { - if (PyDict_GetItemString(dict, *p) != NULL) - return 1; - } + if (_PyDict_GetItemId(dict, &PyId___eq__) != NULL) + return 1; + if (_PyDict_GetItemId(dict, &PyId___hash__) != NULL) + return 1; return 0; } @@ -4109,16 +4106,16 @@ /* if the type dictionary doesn't contain a __doc__, set it from the tp_doc slot. */ - if (PyDict_GetItemString(type->tp_dict, "__doc__") == NULL) { + if (_PyDict_GetItemId(type->tp_dict, &PyId___doc__) == NULL) { if (type->tp_doc != NULL) { PyObject *doc = PyUnicode_FromString(type->tp_doc); if (doc == NULL) goto error; - PyDict_SetItemString(type->tp_dict, "__doc__", doc); + _PyDict_SetItemId(type->tp_dict, &PyId___doc__, doc); Py_DECREF(doc); } else { - PyDict_SetItemString(type->tp_dict, - "__doc__", Py_None); + _PyDict_SetItemId(type->tp_dict, + &PyId___doc__, Py_None); } } @@ -4129,8 +4126,8 @@ This signals that __hash__ is not inherited. */ if (type->tp_hash == NULL) { - if (PyDict_GetItemString(type->tp_dict, "__hash__") == NULL) { - if (PyDict_SetItemString(type->tp_dict, "__hash__", Py_None) < 0) + if (_PyDict_GetItemId(type->tp_dict, &PyId___hash__) == NULL) { + if (_PyDict_SetItemId(type->tp_dict, &PyId___hash__, Py_None) < 0) goto error; type->tp_hash = PyObject_HashNotImplemented; } @@ -4760,12 +4757,12 @@ { PyObject *func; - if (PyDict_GetItemString(type->tp_dict, "__new__") != NULL) + if (_PyDict_GetItemId(type->tp_dict, &PyId___new__) != NULL) return 0; func = PyCFunction_New(tp_new_methoddef, (PyObject *)type); if (func == NULL) return -1; - if (PyDict_SetItemString(type->tp_dict, "__new__", func)) { + if (_PyDict_SetItemId(type->tp_dict, &PyId___new__, func)) { Py_DECREF(func); return -1; } @@ -4795,19 +4792,19 @@ /* Boolean helper for SLOT1BINFULL(). right.__class__ is a nontrivial subclass of left.__class__. */ static int -method_is_overloaded(PyObject *left, PyObject *right, char *name) +method_is_overloaded(PyObject *left, PyObject *right, struct _Py_Identifier *name) { PyObject *a, *b; int ok; - b = PyObject_GetAttrString((PyObject *)(Py_TYPE(right)), name); + b = _PyObject_GetAttrId((PyObject *)(Py_TYPE(right)), name); if (b == NULL) { PyErr_Clear(); /* If right doesn't have it, it's not overloaded */ return 0; } - a = PyObject_GetAttrString((PyObject *)(Py_TYPE(left)), name); + a = _PyObject_GetAttrId((PyObject *)(Py_TYPE(left)), name); if (a == NULL) { PyErr_Clear(); Py_DECREF(b); @@ -4841,7 +4838,7 @@ PyObject *r; \ if (do_other && \ PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self)) && \ - method_is_overloaded(self, other, ROPSTR)) { \ + method_is_overloaded(self, other, &rop_id)) { \ r = call_maybe(other, &rop_id, "(O)", self); \ if (r != Py_NotImplemented) \ return r; \ @@ -4896,16 +4893,10 @@ static PyObject * slot_sq_item(PyObject *self, Py_ssize_t i) { - static PyObject *getitem_str; PyObject *func, *args = NULL, *ival = NULL, *retval = NULL; descrgetfunc f; - if (getitem_str == NULL) { - getitem_str = PyUnicode_InternFromString("__getitem__"); - if (getitem_str == NULL) - return NULL; - } - func = _PyType_Lookup(Py_TYPE(self), getitem_str); + func = _PyType_LookupId(Py_TYPE(self), &PyId___getitem__); if (func != NULL) { if ((f = Py_TYPE(func)->tp_descr_get) == NULL) Py_INCREF(func); @@ -4928,6 +4919,7 @@ } } else { + PyObject *getitem_str = _PyUnicode_FromId(&PyId___getitem__); PyErr_SetObject(PyExc_AttributeError, getitem_str); } Py_XDECREF(args); @@ -5174,7 +5166,6 @@ { PyObject *func, *res; Py_ssize_t h; - _Py_IDENTIFIER(__hash__); func = lookup_method(self, &PyId___hash__); @@ -5247,7 +5238,6 @@ static PyObject * slot_tp_getattro(PyObject *self, PyObject *name) { - _Py_IDENTIFIER(__getattribute__); return call_method(self, &PyId___getattribute__, "(O)", name); } @@ -5274,26 +5264,14 @@ { PyTypeObject *tp = Py_TYPE(self); PyObject *getattr, *getattribute, *res; - static PyObject *getattribute_str = NULL; - static PyObject *getattr_str = NULL; - - if (getattr_str == NULL) { - getattr_str = PyUnicode_InternFromString("__getattr__"); - if (getattr_str == NULL) - return NULL; - } - if (getattribute_str == NULL) { - getattribute_str = - PyUnicode_InternFromString("__getattribute__"); - if (getattribute_str == NULL) - return NULL; - } + _Py_IDENTIFIER(__getattr__); + /* speed hack: we could use lookup_maybe, but that would resolve the method fully for each attribute lookup for classes with __getattr__, even when the attribute is present. So we use _PyType_Lookup and create the method only when needed, with call_attribute. */ - getattr = _PyType_Lookup(tp, getattr_str); + getattr = _PyType_LookupId(tp, &PyId___getattr__); if (getattr == NULL) { /* No __getattr__ hook: use a simpler dispatcher */ tp->tp_getattro = slot_tp_getattro; @@ -5305,7 +5283,7 @@ __getattr__, even when self has the default __getattribute__ method. So we use _PyType_Lookup and create the method only when needed, with call_attribute. */ - getattribute = _PyType_Lookup(tp, getattribute_str); + getattribute = _PyType_LookupId(tp, &PyId___getattribute__); if (getattribute == NULL || (Py_TYPE(getattribute) == &PyWrapperDescr_Type && ((PyWrapperDescrObject *)getattribute)->d_wrapped == @@ -5376,7 +5354,6 @@ { PyObject *func, *res; _Py_IDENTIFIER(__iter__); - _Py_IDENTIFIER(__getitem__); func = lookup_method(self, &PyId___iter__); if (func != NULL) { @@ -5413,14 +5390,9 @@ { PyTypeObject *tp = Py_TYPE(self); PyObject *get; - static PyObject *get_str = NULL; - - if (get_str == NULL) { - get_str = PyUnicode_InternFromString("__get__"); - if (get_str == NULL) - return NULL; - } - get = _PyType_Lookup(tp, get_str); + _Py_IDENTIFIER(__get__); + + get = _PyType_LookupId(tp, &PyId___get__); if (get == NULL) { /* Avoid further slowdowns */ if (tp->tp_descr_get == slot_tp_descr_get) @@ -5479,17 +5451,12 @@ static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - static PyObject *new_str; PyObject *func; PyObject *newargs, *x; Py_ssize_t i, n; - - if (new_str == NULL) { - new_str = PyUnicode_InternFromString("__new__"); - if (new_str == NULL) - return NULL; - } - func = PyObject_GetAttr((PyObject *)type, new_str); + _Py_IDENTIFIER(__new__); + + func = _PyObject_GetAttrId((PyObject *)type, &PyId___new__); if (func == NULL) return NULL; assert(PyTuple_Check(args)); diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -822,6 +822,8 @@ PyObject *names; PyObject *consts; + _Py_IDENTIFIER(__ltrace__); + /* Computed GOTOs, or the-optimization-commonly-but-improperly-known-as-"threaded code" using gcc's labels-as-values extension @@ -1198,7 +1200,7 @@ } #ifdef LLTRACE - lltrace = PyDict_GetItemString(f->f_globals, "__lltrace__") != NULL; + lltrace = _PyDict_GetItemId(f->f_globals, &PyId___ltrace__) != NULL; #endif why = WHY_NOT; @@ -1926,8 +1928,9 @@ break; TARGET(LOAD_BUILD_CLASS) - x = PyDict_GetItemString(f->f_builtins, - "__build_class__"); + { + _Py_IDENTIFIER(__build_class__); + x = _PyDict_GetItemId(f->f_builtins, &PyId___build_class__); if (x == NULL) { PyErr_SetString(PyExc_ImportError, "__build_class__ not found"); @@ -1936,6 +1939,7 @@ Py_INCREF(x); PUSH(x); break; + } TARGET(STORE_NAME) w = GETITEM(names, oparg); @@ -2283,8 +2287,10 @@ DISPATCH(); TARGET(IMPORT_NAME) + { + _Py_IDENTIFIER(__import__); w = GETITEM(names, oparg); - x = PyDict_GetItemString(f->f_builtins, "__import__"); + x = _PyDict_GetItemId(f->f_builtins, &PyId___import__); if (x == NULL) { PyErr_SetString(PyExc_ImportError, "__import__ not found"); @@ -2325,6 +2331,7 @@ SET_TOP(x); if (x != NULL) DISPATCH(); break; + } TARGET(IMPORT_STAR) v = POP(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 22:53:37 2012 From: python-checkins at python.org (victor.stinner) Date: Mon, 26 Mar 2012 22:53:37 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_time=2Esteady=28strict?= =?utf8?q?=3DTrue=29=3A_don=27t_use_CLOCK=5FREALTIME?= Message-ID: http://hg.python.org/cpython/rev/566527ace50b changeset: 75960:566527ace50b user: Victor Stinner date: Mon Mar 26 22:53:14 2012 +0200 summary: Fix time.steady(strict=True): don't use CLOCK_REALTIME files: Modules/timemodule.c | 35 +++++++++++++++++++++++++------ 1 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -779,26 +779,47 @@ return PyFloat_FromDouble(secs); #elif defined(HAVE_CLOCK_GETTIME) - static int clk_index = 0; - clockid_t clk_ids[] = { + static int steady_clk_index = 0; + static int monotonic_clk_index = 0; + int *clk_index; + clockid_t steady_clk_ids[] = { #ifdef CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC_RAW, #endif CLOCK_MONOTONIC, CLOCK_REALTIME }; + clockid_t monotonic_clk_ids[] = { +#ifdef CLOCK_MONOTONIC_RAW + CLOCK_MONOTONIC_RAW, +#endif + CLOCK_MONOTONIC + }; + clockid_t *clk_ids; + int clk_ids_len; int ret; struct timespec tp; - while (0 <= clk_index) { - clockid_t clk_id = clk_ids[clk_index]; + if (strict) { + clk_index = &monotonic_clk_index; + clk_ids = monotonic_clk_ids; + clk_ids_len = Py_ARRAY_LENGTH(monotonic_clk_ids); + } + else { + clk_index = &steady_clk_index; + clk_ids = steady_clk_ids; + clk_ids_len = Py_ARRAY_LENGTH(steady_clk_ids); + } + + while (0 <= *clk_index) { + clockid_t clk_id = clk_ids[*clk_index]; ret = clock_gettime(clk_id, &tp); if (ret == 0) return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); - clk_index++; - if (Py_ARRAY_LENGTH(clk_ids) <= clk_index) - clk_index = -1; + (*clk_index)++; + if (clk_ids_len <= *clk_index) + (*clk_index) = -1; } if (strict) { PyErr_SetFromErrno(PyExc_OSError); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Mar 26 23:36:44 2012 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 26 Mar 2012 23:36:44 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_Fix_trailing_whitespace_in_PEP?= =?utf8?q?_411=2E?= Message-ID: http://hg.python.org/peps/rev/88b85dcf5a81 changeset: 4145:88b85dcf5a81 user: Guido van Rossum date: Mon Mar 26 14:36:36 2012 -0700 summary: Fix trailing whitespace in PEP 411. files: pep-0411.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0411.txt b/pep-0411.txt --- a/pep-0411.txt +++ b/pep-0411.txt @@ -41,7 +41,7 @@ In the next minor release, the package may either be "graduated" into a normal "stable" state in the standard library, remain in provisional state, or be rejected and removed entirely from the Python source tree. If the package ends -up graduating into the stable state after being provisional, its API may +up graduating into the stable state after being provisional, its API may be changed according to accumulated feedback. The core development team explicitly makes no guarantees about API stability and backward compatibility of provisional packages. @@ -64,7 +64,7 @@ A provisional package is one which has been deliberately excluded from the standard library's normal backwards compatibility guarantees. While major - changes to such packages are not expected, as long as they are marked + changes to such packages are not expected, as long as they are marked provisional, backwards incompatible changes (up to and including removal of the package) may occur if deemed necessary by core developers. Such changes will not be made gratuitously - they will occur only if serious flaws are -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Mar 26 23:50:05 2012 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 26 Mar 2012 23:50:05 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_Add_recent_post_date_to_PEP_41?= =?utf8?q?1=2E?= Message-ID: http://hg.python.org/peps/rev/3d1252bcd0e7 changeset: 4146:3d1252bcd0e7 user: Guido van Rossum date: Mon Mar 26 14:49:58 2012 -0700 summary: Add recent post date to PEP 411. files: pep-0411.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0411.txt b/pep-0411.txt --- a/pep-0411.txt +++ b/pep-0411.txt @@ -9,7 +9,7 @@ Content-Type: text/x-rst Created: 2012-02-10 Python-Version: 3.3 -Post-History: 2012-02-10 +Post-History: 2012-02-10, 2012-03-24 Abstract -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 01:12:23 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 27 Mar 2012 01:12:23 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_Add_PEP_418=3A_Add_monotonic_c?= =?utf8?q?lock?= Message-ID: http://hg.python.org/peps/rev/6f23b457c6f7 changeset: 4147:6f23b457c6f7 user: Victor Stinner date: Tue Mar 27 01:12:03 2012 +0200 summary: Add PEP 418: Add monotonic clock files: pep-0418.txt | 261 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 261 insertions(+), 0 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt new file mode 100644 --- /dev/null +++ b/pep-0418.txt @@ -0,0 +1,261 @@ +PEP: 418 +Title: Add monotonic clock +Version: $Revision$ +Last-Modified: $Date$ +Author: Victor Stinner +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 26-March-2012 +Python-Version: 3.3 + + +Abstract +======== + +Add time.monotonic() and time.steady() functions to Python 3.3. + + +Rationale +========= + +Use cases: + + * Display the current time to a human: use system clock. time.time() or + datetime.datetime.now() + * Implement a timeout: use monotonic clock, or fallback to the clock with + the highest resolution. time.steady() + * Benchmark and profiling: time.steady() + * Truly monotonic clock: ? + +time.steady() tries to use a monotonic clock, but it falls back to a +non-monotonic clock if no monotonic clock is available or if reading a +monotonic clock failed. + +The pybench benchmark tool supports the following clocks: time.clock(), +time.time() and systimes.processtime(). By default, it uses time.clock() on +Windows, and time.time() otherwise. It is possible to choose the clock using +the --timer command line option. + +Which clock? + + * System time: pthread_mutex_timedlock(), pthread_cond_wait() (CLOCK_REALTIME) + * Monotonic: clock_nanosleep() (CLOCK_MONOTONIC) + +Timeouts: + + * threading.Lock.wait() + * select.select() + * time.sleep() + * subprocess.Popen.communicate() + * etc. + + +Clocks +====== + +Monotonic +--------- + + * mach_absolute_time(): Mac OS X provides a monotonic clock: + mach_absolute_time(). mach_timebase_info() provides a fraction to convert it + to a number of nanoseconds. According to the documentation, + mach_timebase_info() is always equals to one and does never fail, even if + the function may fail according to its prototype. + * clock_gettime(CLOCK_MONOTONIC): Clock that cannot be set and represents + monotonic time since some unspecified starting point. + * clock_gettime(CLOCK_MONOTONIC_RAW), since Linux 2.6.28; Linux-specific: + Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time + that is not subject to NTP adjustments. + * Windows: GetTickCount(), GetTickCount64(). + +CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW clocks cannot be set. + +On Linux, NTP may adjust CLOCK_MONOTONIC rate, but not jump backward. If +available, CLOCK_MONOTONIC_RAW should be used instead of CLOCK_MONOTONIC to +avoid the NTP adjustement. CLOCK_MONOTONIC stops while the machine is +suspended. + +Resolution: + + * mach_absolute_time(): 1 nanosecond + * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW: be read using clock_getres(). + 1 nanosecond on Linux for example. + * GetTickCount(), GetTickCount64(): 1 millisecond + +May fail? + + * mach_absolute_time() cannot fail. According to the documentation, + mach_timebase_info() does never fail, even if the function has a return + value. + * clock_gettime() can fail if the system does not support the specified clock, + whereas the standard C library supports it. For example, CLOCK_MONOTONIC_RAW + requires a kernel version 2.6.28 or later. + * GetTickCount() and GetTickCount64() cannot fail + +Note: clock_gettime() requires to link the program with the realtime ("rt") library. + +Note: GetTickCount64() was added to Windows Vista and Windows Server 2008. + + +System time +----------- + +The system time can be set manually by the system administrator or +automatically by a NTP daemon. It can jump backward and forward, and is not +monotonic. + +System time on Windows +^^^^^^^^^^^^^^^^^^^^^^ + +The system time can be read using GetSystemTimeAsFileTime(), ftime() and +time(). + +The system time resolution can be read using GetSystemTimeAdjustment(). The +accurary is usually between 0.5 millisecond and 15 milliseconds. Resolution: + + * GetSystemTimeAsFileTime(): 100 nanoseconds + * ftime(): 1 millisecond + * time(): 1 second + +The system time can be set using SetSystemTime(). + +System time on UNIX +^^^^^^^^^^^^^^^^^^^ + +gettimeofday(), ftime(), time() and clock_settime(CLOCK_REALTIME) return the +system clock. + +Resolution: + + * clock_settime(): clock_getres(CLOCK_REALTIME), 1 nanosecond on Linux + * gettimeofday(): 1 microsecond + * ftime(): 1 millisecond + * time(): 1 second + +The system time can be set using settimeofday() or clock_settime(CLOCK_REALTIME). + + +Process and thread time +----------------------- + +The process and thread time cannot be set. They are not monotonic: the clocks +stop while the process/thread is idle. + +Process +^^^^^^^ + + * Windows: GetProcessTimes() + * clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process timer from the CPU. + * clock(): + + * Windows: The elapsed wall-clock time since the start of the process + (elapsed time in seconds times CLOCKS_PER_SEC). It can fail. + * UNIX: returns an approximation of processor time used by the program. + + * times() + * getrusage(): ru_utime and ru_stime fields + +Resolution: + + * clock() rate is CLOCKS_PER_SEC. It was called CLK_TCK in Microsoft C before + 6.0. On Linux 3, clock() has a resolution of 1 microsecond + * The clock resolution can be read using clock_getres(). + clock_getres(CLOCK_REALTIME) is 1 nanosecond on Linux + * GetProcessTimes(): call GetSystemTimeAdjustment() + +Thread +^^^^^^ + + * Windows: GetThreadTimes() + * clock_gettime(CLOCK_THREAD_CPUTIME_ID): Thread-specific CPU-time clock. + +Resolution: + + * CLOCK_THREAD_CPUTIME_ID: call clock_getres(). 1 nanosecond on Linux. + * GetThreadTimes(): call GetSystemTimeAdjustment() + +See also pthread_getcpuclockid(). + + +QueryPerformanceCounter +----------------------- + +Windows provides a high-resolution performance counter: +QueryPerformanceCounter(). Its frequency can be retrieved using +QueryPerformanceFrequency(). + +On Windows XP, QueryPerformanceFrequency() is the processor frequency and +QueryPerformanceCounter() is the TSC of the current processor. Windows XP +had a bug (see `KB896256 `_): on a +multiprocessor computer, QueryPerformanceCounter() returned a different value +for each processor. + +QueryPerformanceCounter() is not monotonic. + +QueryPerformanceFrequency() fails if the installed hardware does not support a +high-resolution performance counter. + +QueryPerformanceFrequency() should only be called once: the frequency will not +change while the system is running. + + +QueryUnbiasedInterruptTime +-------------------------- + +Gets the current unbiased interrupt time from the biased interrupt time and the +current sleep bias amount. This time is not affected by power management sleep +transitions. + +Is it monotonic? + +QueryUnbiasedInterruptTime() was introduced in Windows 7. + + + +API design +========== + +Two functions: time.monotonic(), time.steady() +---------------------------------------------- + + * time.steady() falls back to another clock if no monotonic clock is not + available or does not work, but it does never fail. + * time.monotonic() is not always available and may raise OSError. + +One function with a flag: time.steady(strict=False) +--------------------------------------------------- + + * time.steady(strict=False) falls back to another clock if no monotonic clock + is not available or does not work, but it does never fail. + * time.steady(strict=True) raises OSError if monotonic clock fails or + NotImplementedError if the system does not provide a monotonic clock + +"A keyword argument that gets passed as a constant in the caller is usually +poor API." + +One function, no flag +--------------------- + +time.steady() returns (time: float, is_monotonic: bool). + +An alternative is to use a function attribute: time.steady.monotonic. The +attribute value would be None before the first call to time.steady(). + + +Workaround operating system bugs? +================================= + +Should Python ensure manually that a monotonic clock is truly monotonic by +computing the maximum with the clock value and the previous value? + + * Virtual machines provide less reliable clocks. + * QueryPerformanceCounter() had a bug in 2006 on multiprocessor computers + + +Links +===== + + * `Windows: Game Timing and Multicore Processors + `_ + -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 01:30:58 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 27 Mar 2012 01:30:58 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Mention_an_use_case?= =?utf8?q?_for_truly_monotonic_clock?= Message-ID: http://hg.python.org/peps/rev/62a575761ca0 changeset: 4148:62a575761ca0 user: Victor Stinner date: Tue Mar 27 01:22:04 2012 +0200 summary: PEP 418: Mention an use case for truly monotonic clock files: pep-0418.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -26,7 +26,7 @@ * Implement a timeout: use monotonic clock, or fallback to the clock with the highest resolution. time.steady() * Benchmark and profiling: time.steady() - * Truly monotonic clock: ? + * Event scheduler: time.monotonic() time.steady() tries to use a monotonic clock, but it falls back to a non-monotonic clock if no monotonic clock is available or if reading a -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 01:30:59 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 27 Mar 2012 01:30:59 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Define_time=2Emonot?= =?utf8?q?onic_and_time=2Esteady?= Message-ID: http://hg.python.org/peps/rev/37be6f757fe5 changeset: 4149:37be6f757fe5 user: Victor Stinner date: Tue Mar 27 01:30:38 2012 +0200 summary: PEP 418: Define time.monotonic and time.steady files: pep-0418.txt | 33 +++++++++++++++++++++++++++++++-- 1 files changed, 31 insertions(+), 2 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -51,6 +51,32 @@ * etc. +Functions +========= + +time.monotonic +-------------- + +Monotonic clock advancing at a steady rate relative to real time. It cannot go +backward. It may be adjusted. The reference point of the returned value is +undefined so only the difference of consecutive calls is valid. + +May raise an OSError on error. + + +time.steady +----------- + +This clock advances at a steady rate relative to real time. It may be adjusted. +The reference point of the returned value is undefined so only the difference +of consecutive calls is valid. + +If available, a monotonic clock is used. The function falls back to another +clock if the monotonic clock failed or is not available. + +This function cannot fail. + + Clocks ====== @@ -234,6 +260,9 @@ "A keyword argument that gets passed as a constant in the caller is usually poor API." +Raising NotImplementedError for a function is something uncommon in Python and +should be avoided. + One function, no flag --------------------- @@ -243,8 +272,8 @@ attribute value would be None before the first call to time.steady(). -Workaround operating system bugs? -================================= +Working around operating system bugs? +===================================== Should Python ensure manually that a monotonic clock is truly monotonic by computing the maximum with the clock value and the previous value? -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 02:19:19 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 27 Mar 2012 02:19:19 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Add_more_links?= Message-ID: http://hg.python.org/peps/rev/e0ff02bd9be9 changeset: 4150:e0ff02bd9be9 user: Victor Stinner date: Tue Mar 27 02:19:00 2012 +0200 summary: PEP 418: Add more links files: pep-0418.txt | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -285,6 +285,17 @@ Links ===== + * `Issue #12822: NewGIL should use CLOCK_MONOTONIC if possible. + `_ + * `Issue #14222: Use time.steady() to implement timeout + `_ + * `Issue #14397: Use GetTickCount/GetTickCount64 instead of QueryPerformanceCounter for monotonic clock + `_ + * `python-monotonic-time + `_ + (`github `_) + * `Qt library: QElapsedTimer + `_ * `Windows: Game Timing and Multicore Processors `_ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 03:07:52 2012 From: python-checkins at python.org (r.david.murray) Date: Tue, 27 Mar 2012 03:07:52 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzUzMDE6IHJlLWFk?= =?utf8?q?d_image/vnd=2Emicrosoft=2Eicon_per_discussion?= Message-ID: http://hg.python.org/cpython/rev/3e7f6f931e09 changeset: 75961:3e7f6f931e09 branch: 2.7 parent: 75950:03771ea22ead user: R David Murray date: Mon Mar 26 21:06:04 2012 -0400 summary: #5301: re-add image/vnd.microsoft.icon per discussion We concluded that adding registered mimetypes present in most systems' mime databases can be considered a bug fix. files: Lib/mimetypes.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -432,6 +432,7 @@ '.hdf' : 'application/x-hdf', '.htm' : 'text/html', '.html' : 'text/html', + '.ico' : 'image/vnd.microsoft.icon', '.ief' : 'image/ief', '.jpe' : 'image/jpeg', '.jpeg' : 'image/jpeg', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 27 04:58:16 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 27 Mar 2012 04:58:16 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_doc_typo_noticed_by_Ama?= =?utf8?q?ury_Forgeot_d=27Arc?= Message-ID: http://hg.python.org/cpython/rev/7253ea3e8360 changeset: 75962:7253ea3e8360 parent: 75960:566527ace50b user: Eli Bendersky date: Tue Mar 27 04:57:23 2012 +0200 summary: Fix doc typo noticed by Amaury Forgeot d'Arc files: Doc/library/xml.etree.elementtree.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -126,7 +126,7 @@ | | a relative path. | +-----------------------+------------------------------------------------------+ | ``//`` | Selects all subelements, on all levels beneath the | -| | current element. For example, ``./egg`` selects | +| | current element. For example, ``.//egg`` selects | | | all ``egg`` elements in the entire tree. | +-----------------------+------------------------------------------------------+ | ``..`` | Selects the parent element. | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 27 05:21:41 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 27 Mar 2012 05:21:41 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_Address_Guido=27s_comments_fro?= =?utf8?q?m_the_pronouncement_request_on_python-dev?= Message-ID: http://hg.python.org/peps/rev/a1bb0a9af63f changeset: 4151:a1bb0a9af63f user: Eli Bendersky date: Tue Mar 27 05:20:49 2012 +0200 summary: Address Guido's comments from the pronouncement request on python-dev files: pep-0411.txt | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pep-0411.txt b/pep-0411.txt --- a/pep-0411.txt +++ b/pep-0411.txt @@ -19,7 +19,7 @@ hindered by the API lock-in and promise of backward compatibility implied by a package being formally part of Python. This PEP describes a methodology for marking a standard library package "provisional" for the period of a single -minor release. A provisional package may have its API modified prior to +feature release. A provisional package may have its API modified prior to "graduating" into a "stable" state. On one hand, this state provides the package with the benefits of being formally part of the Python distribution. On the other hand, the core development team explicitly states that no promises @@ -38,7 +38,7 @@ package's API is optimal, the package can be included and marked as "provisional". -In the next minor release, the package may either be "graduated" into a normal +In the next feature release, the package may either be "graduated" into a normal "stable" state in the standard library, remain in provisional state, or be rejected and removed entirely from the Python source tree. If the package ends up graduating into the stable state after being provisional, its API may @@ -87,7 +87,7 @@ ------------------------------------------------------ We expect most packages proposed for addition into the Python standard library -to go through a minor release in the provisional state. There may, however, +to go through a feature release in the provisional state. There may, however, be some exceptions, such as packages that use a pre-defined API (for example ``lzma``, which generally follows the API of the existing ``bz2`` package), or packages with an API that has wide acceptance in the Python development @@ -110,7 +110,10 @@ Essentially, the decision will be made by the core developers on a per-case basis. The point to emphasize here is that a package's inclusion in the standard library as "provisional" in some release does not guarantee it will -continue being part of Python in the next release. +continue being part of Python in the next release. At the same time, the bar +for making changes in a provisional package is quite high. We expect that +most of the API of most provisional packages will be unchanged at graduation. +Withdrawals are expected to be rare. Rationale -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 05:35:20 2012 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 27 Mar 2012 05:35:20 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_Approve_PEP_411=2E?= Message-ID: http://hg.python.org/peps/rev/b9f43fe69691 changeset: 4152:b9f43fe69691 user: Guido van Rossum date: Mon Mar 26 20:35:14 2012 -0700 summary: Approve PEP 411. files: pep-0411.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0411.txt b/pep-0411.txt --- a/pep-0411.txt +++ b/pep-0411.txt @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Nick Coghlan , Eli Bendersky -Status: Draft +Status: Approved Type: Informational Content-Type: text/x-rst Created: 2012-02-10 -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 05:35:37 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 27 Mar 2012 05:35:37 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_typo?= Message-ID: http://hg.python.org/cpython/rev/6982f460fa6d changeset: 75963:6982f460fa6d user: ?ric Araujo date: Mon Mar 26 23:35:31 2012 -0400 summary: Fix typo files: Lib/idlelib/NEWS.txt | 2 +- Misc/NEWS | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,7 +1,7 @@ What's New in IDLE 3.3? ========================= -- IDLE can be launched as `python -m ildelib` +- IDLE can be launched as `python -m idlelib` - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,7 +34,7 @@ Library ------- -- IDLE can be launched as python -m ildelib +- IDLE can be launched as python -m idlelib - Issue #14295: Add unittest.mock -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Mar 27 05:38:19 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 27 Mar 2012 05:38:19 +0200 Subject: [Python-checkins] Daily reference leaks (566527ace50b): sum=0 Message-ID: results for 566527ace50b on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogyLE4FY', '-x'] From python-checkins at python.org Tue Mar 27 07:43:47 2012 From: python-checkins at python.org (georg.brandl) Date: Tue, 27 Mar 2012 07:43:47 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Closes_=2314421=3A_use_with?= =?utf8?q?_statement_to_properly_close_socket_in_bandwidth_test=2E?= Message-ID: http://hg.python.org/cpython/rev/505aea930985 changeset: 75964:505aea930985 user: Georg Brandl date: Tue Mar 27 07:43:53 2012 +0200 summary: Closes #14421: use with statement to properly close socket in bandwidth test. files: Tools/ccbench/ccbench.py | 112 +++++++++++++------------- 1 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Tools/ccbench/ccbench.py b/Tools/ccbench/ccbench.py --- a/Tools/ccbench/ccbench.py +++ b/Tools/ccbench/ccbench.py @@ -435,70 +435,70 @@ def run_bandwidth_test(func, args, nthreads): # Create a listening socket to receive the packets. We use UDP which should # be painlessly cross-platform. - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.bind(("127.0.0.1", 0)) - addr = sock.getsockname() + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock: + sock.bind(("127.0.0.1", 0)) + addr = sock.getsockname() - duration = BANDWIDTH_DURATION - packet_size = BANDWIDTH_PACKET_SIZE - - results = [] - threads = [] - end_event = [] - start_cond = threading.Condition() - started = False - if nthreads > 0: - # Warm up - func(*args) + duration = BANDWIDTH_DURATION + packet_size = BANDWIDTH_PACKET_SIZE results = [] - loop = TimedLoop(func, args) - ready = [] - ready_cond = threading.Condition() + threads = [] + end_event = [] + start_cond = threading.Condition() + started = False + if nthreads > 0: + # Warm up + func(*args) - def run(): + results = [] + loop = TimedLoop(func, args) + ready = [] + ready_cond = threading.Condition() + + def run(): + with ready_cond: + ready.append(None) + ready_cond.notify() + with start_cond: + while not started: + start_cond.wait() + loop(start_time, duration * 1.5, end_event, do_yield=False) + + for i in range(nthreads): + threads.append(threading.Thread(target=run)) + for t in threads: + t.setDaemon(True) + t.start() + # Wait for threads to be ready with ready_cond: - ready.append(None) - ready_cond.notify() - with start_cond: - while not started: - start_cond.wait() - loop(start_time, duration * 1.5, end_event, do_yield=False) + while len(ready) < nthreads: + ready_cond.wait() - for i in range(nthreads): - threads.append(threading.Thread(target=run)) - for t in threads: - t.setDaemon(True) - t.start() - # Wait for threads to be ready - with ready_cond: - while len(ready) < nthreads: - ready_cond.wait() + # Run the client and wait for the first packet to arrive before + # unblocking the background threads. + process = run_bandwidth_client(addr=addr, + packet_size=packet_size, + duration=duration) + _time = time.time + # This will also wait for the parent to be ready + s = _recv(sock, packet_size) + remote_addr = eval(s.partition('#')[0]) - # Run the client and wait for the first packet to arrive before - # unblocking the background threads. - process = run_bandwidth_client(addr=addr, - packet_size=packet_size, - duration=duration) - _time = time.time - # This will also wait for the parent to be ready - s = _recv(sock, packet_size) - remote_addr = eval(s.partition('#')[0]) + with start_cond: + start_time = _time() + started = True + start_cond.notify(nthreads) - with start_cond: - start_time = _time() - started = True - start_cond.notify(nthreads) - - n = 0 - first_time = None - while not end_event and BW_END not in s: - _sendto(sock, s, remote_addr) - s = _recv(sock, packet_size) - if first_time is None: - first_time = _time() - n += 1 - end_time = _time() + n = 0 + first_time = None + while not end_event and BW_END not in s: + _sendto(sock, s, remote_addr) + s = _recv(sock, packet_size) + if first_time is None: + first_time = _time() + n += 1 + end_time = _time() end_event.append(None) for t in threads: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 27 07:47:17 2012 From: python-checkins at python.org (georg.brandl) Date: Tue, 27 Mar 2012 07:47:17 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314411?= =?utf8?q?=3A_remove_outdated_comment_in_rlcompleter_docstring=2E?= Message-ID: http://hg.python.org/cpython/rev/37751d1cb4a8 changeset: 75965:37751d1cb4a8 branch: 3.2 parent: 75951:3e18af617266 user: Georg Brandl date: Tue Mar 27 07:46:46 2012 +0200 summary: Closes #14411: remove outdated comment in rlcompleter docstring. files: Lib/rlcompleter.py | 36 +++++++++++++++------------------ 1 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -1,13 +1,11 @@ -"""Word completion for GNU readline 2.0. +"""Word completion for GNU readline. -This requires the latest extension to the readline module. The completer -completes keywords, built-ins and globals in a selectable namespace (which -defaults to __main__); when completing NAME.NAME..., it evaluates (!) the -expression up to the last dot and completes its attributes. +The completer completes keywords, built-ins and globals in a selectable +namespace (which defaults to __main__); when completing NAME.NAME..., it +evaluates (!) the expression up to the last dot and completes its attributes. -It's very cool to do "import sys" type "sys.", hit the -completion key (twice), and see the list of names defined by the -sys module! +It's very cool to do "import sys" type "sys.", hit the completion key (twice), +and see the list of names defined by the sys module! Tip: to use the tab key as the completion key, call @@ -15,21 +13,19 @@ Notes: -- Exceptions raised by the completer function are *ignored* (and -generally cause the completion to fail). This is a feature -- since -readline sets the tty device in raw (or cbreak) mode, printing a -traceback wouldn't work well without some complicated hoopla to save, -reset and restore the tty state. +- Exceptions raised by the completer function are *ignored* (and generally cause + the completion to fail). This is a feature -- since readline sets the tty + device in raw (or cbreak) mode, printing a traceback wouldn't work well + without some complicated hoopla to save, reset and restore the tty state. -- The evaluation of the NAME.NAME... form may cause arbitrary -application defined code to be executed if an object with a -__getattr__ hook is found. Since it is the responsibility of the -application (or the user) to enable this feature, I consider this an -acceptable risk. More complicated expressions (e.g. function calls or -indexing operations) are *not* evaluated. +- The evaluation of the NAME.NAME... form may cause arbitrary application + defined code to be executed if an object with a __getattr__ hook is found. + Since it is the responsibility of the application (or the user) to enable this + feature, I consider this an acceptable risk. More complicated expressions + (e.g. function calls or indexing operations) are *not* evaluated. - When the original stdin is not a tty device, GNU readline is never -used, and this module (and the readline module) are silently inactive. + used, and this module (and the readline module) are silently inactive. """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 27 07:47:20 2012 From: python-checkins at python.org (georg.brandl) Date: Tue, 27 Mar 2012 07:47:20 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/b69c6e092696 changeset: 75966:b69c6e092696 parent: 75964:505aea930985 parent: 75965:37751d1cb4a8 user: Georg Brandl date: Tue Mar 27 07:46:54 2012 +0200 summary: merge with 3.2 files: Lib/rlcompleter.py | 36 +++++++++++++++------------------ 1 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -1,13 +1,11 @@ -"""Word completion for GNU readline 2.0. +"""Word completion for GNU readline. -This requires the latest extension to the readline module. The completer -completes keywords, built-ins and globals in a selectable namespace (which -defaults to __main__); when completing NAME.NAME..., it evaluates (!) the -expression up to the last dot and completes its attributes. +The completer completes keywords, built-ins and globals in a selectable +namespace (which defaults to __main__); when completing NAME.NAME..., it +evaluates (!) the expression up to the last dot and completes its attributes. -It's very cool to do "import sys" type "sys.", hit the -completion key (twice), and see the list of names defined by the -sys module! +It's very cool to do "import sys" type "sys.", hit the completion key (twice), +and see the list of names defined by the sys module! Tip: to use the tab key as the completion key, call @@ -15,21 +13,19 @@ Notes: -- Exceptions raised by the completer function are *ignored* (and -generally cause the completion to fail). This is a feature -- since -readline sets the tty device in raw (or cbreak) mode, printing a -traceback wouldn't work well without some complicated hoopla to save, -reset and restore the tty state. +- Exceptions raised by the completer function are *ignored* (and generally cause + the completion to fail). This is a feature -- since readline sets the tty + device in raw (or cbreak) mode, printing a traceback wouldn't work well + without some complicated hoopla to save, reset and restore the tty state. -- The evaluation of the NAME.NAME... form may cause arbitrary -application defined code to be executed if an object with a -__getattr__ hook is found. Since it is the responsibility of the -application (or the user) to enable this feature, I consider this an -acceptable risk. More complicated expressions (e.g. function calls or -indexing operations) are *not* evaluated. +- The evaluation of the NAME.NAME... form may cause arbitrary application + defined code to be executed if an object with a __getattr__ hook is found. + Since it is the responsibility of the application (or the user) to enable this + feature, I consider this an acceptable risk. More complicated expressions + (e.g. function calls or indexing operations) are *not* evaluated. - When the original stdin is not a tty device, GNU readline is never -used, and this module (and the readline module) are silently inactive. + used, and this module (and the readline module) are silently inactive. """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 27 07:47:21 2012 From: python-checkins at python.org (georg.brandl) Date: Tue, 27 Mar 2012 07:47:21 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314411?= =?utf8?q?=3A_remove_outdated_comment_in_rlcompleter_docstring=2E?= Message-ID: http://hg.python.org/cpython/rev/39d1c2c7bcf7 changeset: 75967:39d1c2c7bcf7 branch: 2.7 parent: 75961:3e7f6f931e09 user: Georg Brandl date: Tue Mar 27 07:46:46 2012 +0200 summary: Closes #14411: remove outdated comment in rlcompleter docstring. files: Lib/rlcompleter.py | 36 +++++++++++++++------------------ 1 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -1,13 +1,11 @@ -"""Word completion for GNU readline 2.0. +"""Word completion for GNU readline. -This requires the latest extension to the readline module. The completer -completes keywords, built-ins and globals in a selectable namespace (which -defaults to __main__); when completing NAME.NAME..., it evaluates (!) the -expression up to the last dot and completes its attributes. +The completer completes keywords, built-ins and globals in a selectable +namespace (which defaults to __main__); when completing NAME.NAME..., it +evaluates (!) the expression up to the last dot and completes its attributes. -It's very cool to do "import sys" type "sys.", hit the -completion key (twice), and see the list of names defined by the -sys module! +It's very cool to do "import sys" type "sys.", hit the completion key (twice), +and see the list of names defined by the sys module! Tip: to use the tab key as the completion key, call @@ -15,18 +13,16 @@ Notes: -- Exceptions raised by the completer function are *ignored* (and -generally cause the completion to fail). This is a feature -- since -readline sets the tty device in raw (or cbreak) mode, printing a -traceback wouldn't work well without some complicated hoopla to save, -reset and restore the tty state. +- Exceptions raised by the completer function are *ignored* (and generally cause + the completion to fail). This is a feature -- since readline sets the tty + device in raw (or cbreak) mode, printing a traceback wouldn't work well + without some complicated hoopla to save, reset and restore the tty state. -- The evaluation of the NAME.NAME... form may cause arbitrary -application defined code to be executed if an object with a -__getattr__ hook is found. Since it is the responsibility of the -application (or the user) to enable this feature, I consider this an -acceptable risk. More complicated expressions (e.g. function calls or -indexing operations) are *not* evaluated. +- The evaluation of the NAME.NAME... form may cause arbitrary application + defined code to be executed if an object with a __getattr__ hook is found. + Since it is the responsibility of the application (or the user) to enable this + feature, I consider this an acceptable risk. More complicated expressions + (e.g. function calls or indexing operations) are *not* evaluated. - GNU readline is also used by the built-in functions input() and raw_input(), and thus these also benefit/suffer from the completer @@ -35,7 +31,7 @@ its input. - When the original stdin is not a tty device, GNU readline is never -used, and this module (and the readline module) are silently inactive. + used, and this module (and the readline module) are silently inactive. """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 27 11:50:29 2012 From: python-checkins at python.org (stefan.krah) Date: Tue, 27 Mar 2012 11:50:29 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2311826=3A_Fix_memor?= =?utf8?q?y_leak_in_atexitmodule=2E?= Message-ID: http://hg.python.org/cpython/rev/7c48bb929e6e changeset: 75968:7c48bb929e6e parent: 75966:b69c6e092696 user: Stefan Krah date: Tue Mar 27 11:49:21 2012 +0200 summary: Issue #11826: Fix memory leak in atexitmodule. files: Modules/atexitmodule.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c --- a/Modules/atexitmodule.c +++ b/Modules/atexitmodule.c @@ -211,6 +211,14 @@ Py_RETURN_NONE; } +static void +atexit_free(PyObject *m) +{ + atexitmodule_state *modstate; + modstate = GET_ATEXIT_STATE(m); + PyMem_Free(modstate->atexit_callbacks); +} + PyDoc_STRVAR(atexit_unregister__doc__, "unregister(func) -> None\n\ \n\ @@ -275,7 +283,7 @@ NULL, NULL, NULL, - NULL + (freefunc)atexit_free }; PyMODINIT_FUNC -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Mar 27 19:27:07 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 27 Mar 2012 19:27:07 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_rename_time=2Estead?= =?utf8?b?eSgpIHRvIHRpbWUudHJ5X21vbm90b25pYygpOyBhZGQgdGltZS5oaXJlcygp?= Message-ID: http://hg.python.org/peps/rev/d97faf471fe1 changeset: 4153:d97faf471fe1 user: Victor Stinner date: Tue Mar 27 19:27:28 2012 +0200 summary: PEP 418: rename time.steady() to time.try_monotonic(); add time.hires() files: pep-0418.txt | 134 +++++++++++++++++++++++++++++++------- 1 files changed, 109 insertions(+), 25 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -1,5 +1,5 @@ PEP: 418 -Title: Add monotonic clock +Title: Add monotonic and high-resolution time functions Version: $Revision$ Last-Modified: $Date$ Author: Victor Stinner @@ -13,7 +13,8 @@ Abstract ======== -Add time.monotonic() and time.steady() functions to Python 3.3. +Add time.monotonic(), time.hires() and time.try_monotonic() functions to Python +3.3. Rationale @@ -21,14 +22,14 @@ Use cases: - * Display the current time to a human: use system clock. time.time() or - datetime.datetime.now() + * Display the current time to a human (e.g. display a calendar or draw a wall + clock): use system clock. time.time() or datetime.datetime.now() * Implement a timeout: use monotonic clock, or fallback to the clock with - the highest resolution. time.steady() - * Benchmark and profiling: time.steady() + the highest resolution. time.try_monotonic() + * Benchmark and profiling: time.hires(), with a manual fallback to time.time() * Event scheduler: time.monotonic() -time.steady() tries to use a monotonic clock, but it falls back to a +time.try_monotonic() tries to use a monotonic clock, but it falls back to a non-monotonic clock if no monotonic clock is available or if reading a monotonic clock failed. @@ -54,23 +55,106 @@ Functions ========= -time.monotonic --------------- +time.time() +----------- -Monotonic clock advancing at a steady rate relative to real time. It cannot go -backward. It may be adjusted. The reference point of the returned value is -undefined so only the difference of consecutive calls is valid. +The system time is the "wall clock". It can be set manually by the system +administrator or automatically by a NTP daemon. It can jump backward and +forward, and is not monotonic. -May raise an OSError on error. + * Windows: GetSystemTimeAsFileTime() + * clock_gettime(CLOCK_REALTIME), gettimeofday(), ftime() or time() +It is avaialble on all platforms and cannot fail. -time.steady ------------ + +time.monotonic() +---------------- + +Monotonic clock advancing at a monotonic rate relative to real time. It +cannot go backward. Its rate may be adjusted by NTP. The reference point of the +returned value is undefined so only the difference of consecutive calls is +valid. + +It is not avaialble on all platforms and raise an OSError on error. +The monotonic clock may stop while the system is suspended. + +Pseudo-code:: + + if os.name == 'nt': + if hasattr(time, '_GetTickCount64'): + monotonic = _time.GetTickCount64 + else: + def monotonic(): + ticks = _time.GetTickCount() + if ticks < monotonic.last: + # Integer overflow detected + monotonic.delta += 2**32 + monotonic.last = ticks + return ticks + monotonic.delta + monotonic.last = 0 + monotonic.delta = 0 + if os.name == 'mac': + def monotonic(): + if monotonic.factor is None: + factor = _time.mach_timebase_info() + monotonic.factor = timebase[0] / timebase[1] + return _time.mach_absolute_time() * monotonic.factor + monotonic.factor = None + elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_MONOTONIC"): + def monotonic(): + if monotonic.use_monotonic_raw: + try: + return time.clock_gettime(time.CLOCK_MONOTONIC_RAW) + except OSError: + monotonic.use_monotonic_raw = False + return time.clock_gettime(time.CLOCK_MONOTONIC) + monotonic.use_monotonic_raw = hasattr(time, "CLOCK_MONOTONIC_RAW") + +time.hires() +------------ + +High-resolution clock. It has an unspecified starting point and may be +adjusted. The clock starting point changes when the system is resumed after +being suspended. + +Pseudo-code:: + + if os.name == 'nt': + def hires(): + return _time.QueryPerformanceCounter() + elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_REALTIME"): + def hires(): + return time.clock_gettime(time.CLOCK_REALTIME) + +It is not available on all platforms and may raise an OSError. + + +time.try_monotonic() +-------------------- This clock advances at a steady rate relative to real time. It may be adjusted. The reference point of the returned value is undefined so only the difference of consecutive calls is valid. +Pseudo-code:: + + def try_monotonic(): + if try_monotonic.use_monotonic: + try: + return time.monotonic() + except (AttributeError, OSError): + try_monotonic.use_monotonic = False + if try_monotonic.use_hires: + try: + return time.hires() + except (AttributeError, OSError): + try_monotonic.use_hires = False + return time.time() + try_monotonic.use_monotonic = True + try_monotonic.use_hires = True + + If available, a monotonic clock is used. The function falls back to another clock if the monotonic clock failed or is not available. @@ -127,10 +211,6 @@ System time ----------- -The system time can be set manually by the system administrator or -automatically by a NTP daemon. It can jump backward and forward, and is not -monotonic. - System time on Windows ^^^^^^^^^^^^^^^^^^^^^^ @@ -242,19 +322,19 @@ API design ========== -Two functions: time.monotonic(), time.steady() ----------------------------------------------- +Two functions: time.monotonic(), time.try_monotonic() +----------------------------------------------------- - * time.steady() falls back to another clock if no monotonic clock is not + * time.try_monotonic() falls back to another clock if no monotonic clock is not available or does not work, but it does never fail. * time.monotonic() is not always available and may raise OSError. -One function with a flag: time.steady(strict=False) ---------------------------------------------------- +One function with a flag: time.try_monotonic(strict=False) +---------------------------------------------------------- - * time.steady(strict=False) falls back to another clock if no monotonic clock + * time.try_monotonic(strict=False) falls back to another clock if no monotonic clock is not available or does not work, but it does never fail. - * time.steady(strict=True) raises OSError if monotonic clock fails or + * time.try_monotonic(strict=True) raises OSError if monotonic clock fails or NotImplementedError if the system does not provide a monotonic clock "A keyword argument that gets passed as a constant in the caller is usually @@ -266,10 +346,10 @@ One function, no flag --------------------- -time.steady() returns (time: float, is_monotonic: bool). +time.try_monotonic() returns (time: float, is_monotonic: bool). -An alternative is to use a function attribute: time.steady.monotonic. The -attribute value would be None before the first call to time.steady(). +An alternative is to use a function attribute: time.try_monotonic.monotonic. The +attribute value would be None before the first call to time.try_monotonic(). Working around operating system bugs? -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 19:34:08 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 27 Mar 2012 19:34:08 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Write_the_pseudo-co?= =?utf8?q?de_of_time=2Etime=28=29?= Message-ID: http://hg.python.org/peps/rev/2580540e4d62 changeset: 4154:2580540e4d62 user: Victor Stinner date: Tue Mar 27 19:34:04 2012 +0200 summary: PEP 418: Write the pseudo-code of time.time() files: pep-0418.txt | 27 ++++++++++++++++++++++++--- 1 files changed, 24 insertions(+), 3 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -62,10 +62,31 @@ administrator or automatically by a NTP daemon. It can jump backward and forward, and is not monotonic. - * Windows: GetSystemTimeAsFileTime() - * clock_gettime(CLOCK_REALTIME), gettimeofday(), ftime() or time() +It is avaialble on all platforms and cannot fail. -It is avaialble on all platforms and cannot fail. +Pseudo-code:: + + if os.name == "nt": + def time(): + return _time.GetSystemTimeAsFileTime() + elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_REALTIME"): + def time(): + # resolution = 1 nanosecond + return time.clock_gettime(time.CLOCK_REALTIME) + else: + def time(): + if hasattr(_time, "gettimeofday"): + try: + # resolution = 1 microsecond + return _time.gettimeofday() + except OSError: + pass + if hasattr(_time, "ftime"): + # resolution = 1 millisecond + return _time.ftime() + else: + # resolution = 1 second + return _time.time() time.monotonic() -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 19:40:09 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 27 Mar 2012 19:40:09 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Replace_=22API_desi?= =?utf8?q?gn=22_title_with_=22Alternatives=3A_API_design=22?= Message-ID: http://hg.python.org/peps/rev/55f86fc224d5 changeset: 4155:55f86fc224d5 user: Victor Stinner date: Tue Mar 27 19:40:24 2012 +0200 summary: PEP 418: Replace "API design" title with "Alternatives: API design" files: pep-0418.txt | 11 +++-------- 1 files changed, 3 insertions(+), 8 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -340,15 +340,8 @@ -API design -========== - -Two functions: time.monotonic(), time.try_monotonic() ------------------------------------------------------ - - * time.try_monotonic() falls back to another clock if no monotonic clock is not - available or does not work, but it does never fail. - * time.monotonic() is not always available and may raise OSError. +Alternatives: API design +======================== One function with a flag: time.try_monotonic(strict=False) ---------------------------------------------------------- @@ -364,6 +357,7 @@ Raising NotImplementedError for a function is something uncommon in Python and should be avoided. + One function, no flag --------------------- -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 19:49:55 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 27 Mar 2012 19:49:55 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_time=2Ehires=28=29_?= =?utf8?q?uses_time=2Emonotonic=28=29_if_available?= Message-ID: http://hg.python.org/peps/rev/b9e7d7ec8da4 changeset: 4156:b9e7d7ec8da4 user: Victor Stinner date: Tue Mar 27 19:50:13 2012 +0200 summary: PEP 418: time.hires() uses time.monotonic() if available hires() preference for clock_gettime() clocks: CLOCK_MONOTONIC_RAW > CLOCK_MONOTONIC > CLOCK_REALTIME files: pep-0418.txt | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -144,6 +144,8 @@ if os.name == 'nt': def hires(): return _time.QueryPerformanceCounter() + elif hasattr(time, "monotonic"): + hires = time.monotonic elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_REALTIME"): def hires(): return time.clock_gettime(time.CLOCK_REALTIME) -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Mar 27 23:36:43 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 27 Mar 2012 23:36:43 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_411=3A_I_suppose_that_Guid?= =?utf8?q?o_means_=22Accepted=22_instead_of_=22Approved=22?= Message-ID: http://hg.python.org/peps/rev/4d4952717917 changeset: 4157:4d4952717917 user: Victor Stinner date: Tue Mar 27 23:36:26 2012 +0200 summary: PEP 411: I suppose that Guido means "Accepted" instead of "Approved" If not, pep0/pep.py should be updated to add this new status value. files: pep-0411.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0411.txt b/pep-0411.txt --- a/pep-0411.txt +++ b/pep-0411.txt @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Nick Coghlan , Eli Bendersky -Status: Approved +Status: Accepted Type: Informational Content-Type: text/x-rst Created: 2012-02-10 -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Mar 28 02:18:28 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 28 Mar 2012 02:18:28 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_I=27m_not_quite_sur?= =?utf8?q?e=2C_but_it_looks_like_QueryPerformanceCounter=28=29_*is*?= Message-ID: http://hg.python.org/peps/rev/269df936b0a4 changeset: 4158:269df936b0a4 user: Victor Stinner date: Wed Mar 28 01:45:51 2012 +0200 summary: PEP 418: I'm not quite sure, but it looks like QueryPerformanceCounter() *is* monotonic files: pep-0418.txt | 43 +++++++++++++++++++++++++++++---------- 1 files changed, 32 insertions(+), 11 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -62,7 +62,7 @@ administrator or automatically by a NTP daemon. It can jump backward and forward, and is not monotonic. -It is avaialble on all platforms and cannot fail. +It is available on all platforms and cannot fail. Pseudo-code:: @@ -104,30 +104,47 @@ if os.name == 'nt': if hasattr(time, '_GetTickCount64'): - monotonic = _time.GetTickCount64 + _get_tick_count = _time.GetTickCount64 else: - def monotonic(): + def _get_tick_count(): ticks = _time.GetTickCount() - if ticks < monotonic.last: + if ticks < _get_tick_count.last: # Integer overflow detected - monotonic.delta += 2**32 - monotonic.last = ticks - return ticks + monotonic.delta - monotonic.last = 0 - monotonic.delta = 0 - if os.name == 'mac': + _get_tick_count.delta += 2**32 + _get_tick_count.last = ticks + return ticks + _get_tick_count.delta + _get_tick_count.last = 0 + _get_tick_count.delta = 0 + + def monotonic(): + if monotonic.use_performance_counter: + try: + return _time.QueryPerformanceCounter() + except OSError: + # QueryPerformanceFrequency() may fail, if the installed + # hardware does not support a high-resolution performance + # counter for example + monotonic.use_performance_counter = False + # Fallback to GetTickCount/GetTickCount64 which has + # a lower resolution + return _get_tick_count() + monotonic.use_performance_counter = True + + elif os.name == 'mac': def monotonic(): if monotonic.factor is None: factor = _time.mach_timebase_info() monotonic.factor = timebase[0] / timebase[1] return _time.mach_absolute_time() * monotonic.factor monotonic.factor = None + elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_MONOTONIC"): def monotonic(): if monotonic.use_monotonic_raw: try: return time.clock_gettime(time.CLOCK_MONOTONIC_RAW) except OSError: + # CLOCK_MONOTONIC_RAW requires a Linux kernel >= 2.6.28 monotonic.use_monotonic_raw = False return time.clock_gettime(time.CLOCK_MONOTONIC) monotonic.use_monotonic_raw = hasattr(time, "CLOCK_MONOTONIC_RAW") @@ -320,7 +337,7 @@ multiprocessor computer, QueryPerformanceCounter() returned a different value for each processor. -QueryPerformanceCounter() is not monotonic. +QueryPerformanceCounter() is monotonic. QueryPerformanceFrequency() fails if the installed hardware does not support a high-resolution performance counter. @@ -395,4 +412,8 @@ `_ * `Windows: Game Timing and Multicore Processors `_ + * `Implement a Continuously Updating, High-Resolution Time Provider for Windows + `_ + * `Perl: Time::HiRes + `_ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Mar 28 02:18:29 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 28 Mar 2012 02:18:29 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Fix_time=2Etime=28?= =?utf8?q?=29_pseudo-code=2C_clock=5Fgettime=28CLOCK=5FREALTIME=29_falls_b?= =?utf8?q?ack?= Message-ID: http://hg.python.org/peps/rev/cc16cf031db3 changeset: 4159:cc16cf031db3 user: Victor Stinner date: Wed Mar 28 01:57:37 2012 +0200 summary: PEP 418: Fix time.time() pseudo-code, clock_gettime(CLOCK_REALTIME) falls back to get _time.gettimeofday() on OSError Add also a note about the _time module. files: pep-0418.txt | 34 ++++++++++++++++++++++++---------- 1 files changed, 24 insertions(+), 10 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -64,22 +64,26 @@ It is available on all platforms and cannot fail. -Pseudo-code:: +Pseudo-code [#pseudo]_: :: if os.name == "nt": def time(): return _time.GetSystemTimeAsFileTime() - elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_REALTIME"): - def time(): - # resolution = 1 nanosecond - return time.clock_gettime(time.CLOCK_REALTIME) else: def time(): + if hasattr(time, "clock_gettime"): + try: + # resolution = 1 nanosecond + return time.clock_gettime(time.CLOCK_REALTIME) + except OSError: + # CLOCK_REALTIME is not supported (unlikely) + pass if hasattr(_time, "gettimeofday"): try: # resolution = 1 microsecond return _time.gettimeofday() except OSError: + # gettimeofday() should not fail pass if hasattr(_time, "ftime"): # resolution = 1 millisecond @@ -100,9 +104,10 @@ It is not avaialble on all platforms and raise an OSError on error. The monotonic clock may stop while the system is suspended. -Pseudo-code:: +Pseudo-code [#pseudo]_: :: if os.name == 'nt': + # GetTickCount64() requires Windows Vista, Server 2008 or later if hasattr(time, '_GetTickCount64'): _get_tick_count = _time.GetTickCount64 else: @@ -138,7 +143,7 @@ return _time.mach_absolute_time() * monotonic.factor monotonic.factor = None - elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_MONOTONIC"): + elif hasattr(time, "clock_gettime"): def monotonic(): if monotonic.use_monotonic_raw: try: @@ -156,7 +161,7 @@ adjusted. The clock starting point changes when the system is resumed after being suspended. -Pseudo-code:: +Pseudo-code [#pseudo]_: :: if os.name == 'nt': def hires(): @@ -243,9 +248,11 @@ requires a kernel version 2.6.28 or later. * GetTickCount() and GetTickCount64() cannot fail -Note: clock_gettime() requires to link the program with the realtime ("rt") library. +.. note:: + clock_gettime() requires to link the program with the realtime ("rt") library. -Note: GetTickCount64() was added to Windows Vista and Windows Server 2008. +.. note:: + GetTickCount64() was added to Windows Vista and Windows Server 2008. System time @@ -396,6 +403,13 @@ * QueryPerformanceCounter() had a bug in 2006 on multiprocessor computers +Footnotes +========= + +.. [#pseudo] _time is an hypothetical module used for the example. In practice, + functions will be implemented in C and so don't need a module. + + Links ===== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Mar 28 02:18:30 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 28 Mar 2012 02:18:30 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_merge_time=2Etry=5F?= =?utf8?q?monotonic=28=29_and_time=2Ehires=28=29_into_time=2Ehires=28=29?= Message-ID: http://hg.python.org/peps/rev/1c13f415a695 changeset: 4160:1c13f415a695 user: Victor Stinner date: Wed Mar 28 02:18:11 2012 +0200 summary: PEP 418: merge time.try_monotonic() and time.hires() into time.hires() Cleanup the PEP. files: pep-0418.txt | 215 ++++++++++++++------------------------ 1 files changed, 80 insertions(+), 135 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -13,8 +13,7 @@ Abstract ======== -Add time.monotonic(), time.hires() and time.try_monotonic() functions to Python -3.3. +Add time.monotonic() and time.hires() functions to Python 3.3. Rationale @@ -24,33 +23,9 @@ * Display the current time to a human (e.g. display a calendar or draw a wall clock): use system clock. time.time() or datetime.datetime.now() - * Implement a timeout: use monotonic clock, or fallback to the clock with - the highest resolution. time.try_monotonic() - * Benchmark and profiling: time.hires(), with a manual fallback to time.time() + * Benchmark, profiling, timeout: time.hires() * Event scheduler: time.monotonic() -time.try_monotonic() tries to use a monotonic clock, but it falls back to a -non-monotonic clock if no monotonic clock is available or if reading a -monotonic clock failed. - -The pybench benchmark tool supports the following clocks: time.clock(), -time.time() and systimes.processtime(). By default, it uses time.clock() on -Windows, and time.time() otherwise. It is possible to choose the clock using -the --timer command line option. - -Which clock? - - * System time: pthread_mutex_timedlock(), pthread_cond_wait() (CLOCK_REALTIME) - * Monotonic: clock_nanosleep() (CLOCK_MONOTONIC) - -Timeouts: - - * threading.Lock.wait() - * select.select() - * time.sleep() - * subprocess.Popen.communicate() - * etc. - Functions ========= @@ -60,7 +35,7 @@ The system time is the "wall clock". It can be set manually by the system administrator or automatically by a NTP daemon. It can jump backward and -forward, and is not monotonic. +forward. It is not monotonic. It is available on all platforms and cannot fail. @@ -96,12 +71,12 @@ time.monotonic() ---------------- -Monotonic clock advancing at a monotonic rate relative to real time. It -cannot go backward. Its rate may be adjusted by NTP. The reference point of the -returned value is undefined so only the difference of consecutive calls is -valid. +Clock advancing at a monotonic rate relative to real time. It cannot go +backward. Its rate may be adjusted by NTP. The reference point of the returned +value is undefined so only the difference of consecutive calls is valid. -It is not avaialble on all platforms and raise an OSError on error. +It is not available on all platforms and may raise an OSError. + The monotonic clock may stop while the system is suspended. Pseudo-code [#pseudo]_: :: @@ -157,53 +132,21 @@ time.hires() ------------ -High-resolution clock. It has an unspecified starting point and may be -adjusted. The clock starting point changes when the system is resumed after -being suspended. +High-resolution clock: use a monotonic clock if available, or fallback to the +system time. + +It is available on all platforms and cannot fail. Pseudo-code [#pseudo]_: :: - if os.name == 'nt': - def hires(): - return _time.QueryPerformanceCounter() - elif hasattr(time, "monotonic"): - hires = time.monotonic - elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_REALTIME"): - def hires(): - return time.clock_gettime(time.CLOCK_REALTIME) - -It is not available on all platforms and may raise an OSError. - - -time.try_monotonic() --------------------- - -This clock advances at a steady rate relative to real time. It may be adjusted. -The reference point of the returned value is undefined so only the difference -of consecutive calls is valid. - -Pseudo-code:: - - def try_monotonic(): - if try_monotonic.use_monotonic: + def hires(): + if hires.use_monotonic: try: return time.monotonic() - except (AttributeError, OSError): - try_monotonic.use_monotonic = False - if try_monotonic.use_hires: - try: - return time.hires() - except (AttributeError, OSError): - try_monotonic.use_hires = False + except OSError: + hires.use_monotonic = False return time.time() - try_monotonic.use_monotonic = True - try_monotonic.use_hires = True - - -If available, a monotonic clock is used. The function falls back to another -clock if the monotonic clock failed or is not available. - -This function cannot fail. + hires.use_monotonic = hasattr(time, 'monotonic') Clocks @@ -212,54 +155,75 @@ Monotonic --------- - * mach_absolute_time(): Mac OS X provides a monotonic clock: - mach_absolute_time(). mach_timebase_info() provides a fraction to convert it - to a number of nanoseconds. According to the documentation, - mach_timebase_info() is always equals to one and does never fail, even if - the function may fail according to its prototype. - * clock_gettime(CLOCK_MONOTONIC): Clock that cannot be set and represents - monotonic time since some unspecified starting point. - * clock_gettime(CLOCK_MONOTONIC_RAW), since Linux 2.6.28; Linux-specific: - Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time - that is not subject to NTP adjustments. - * Windows: GetTickCount(), GetTickCount64(). +mach_absolute_time +^^^^^^^^^^^^^^^^^^ -CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW clocks cannot be set. +Mac OS X provides a monotonic clock: mach_absolute_time(). mach_timebase_info() +provides a fraction to convert the clock value to a number of nanoseconds. + +According to the documentation, mach_timebase_info() is always equals to one +and does never fail, even if the function may fail according to its prototype. + +mach_absolute_time() has a resolution of 1 nanosecond. + +CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represents monotonic time since some +unspecified starting point. They cannot be set. + +CLOCK_MONOTONIC_RAW is specific to Linux. It is similar to CLOCK_MONOTONIC, but +provides access to a raw hardware-based time that is not subject to NTP +adjustments. CLOCK_MONOTONIC_RAW requires Linux 2.6.28 or later. On Linux, NTP may adjust CLOCK_MONOTONIC rate, but not jump backward. If available, CLOCK_MONOTONIC_RAW should be used instead of CLOCK_MONOTONIC to -avoid the NTP adjustement. CLOCK_MONOTONIC stops while the machine is -suspended. +avoid the NTP adjustement. -Resolution: +CLOCK_MONOTONIC stops while the machine is suspended. - * mach_absolute_time(): 1 nanosecond - * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW: be read using clock_getres(). - 1 nanosecond on Linux for example. - * GetTickCount(), GetTickCount64(): 1 millisecond +clock_gettime() fails if the system does not support the specified clock, +whereas the standard C library supports it. For example, CLOCK_MONOTONIC_RAW +requires a kernel version 2.6.28 or later. -May fail? - - * mach_absolute_time() cannot fail. According to the documentation, - mach_timebase_info() does never fail, even if the function has a return - value. - * clock_gettime() can fail if the system does not support the specified clock, - whereas the standard C library supports it. For example, CLOCK_MONOTONIC_RAW - requires a kernel version 2.6.28 or later. - * GetTickCount() and GetTickCount64() cannot fail +clock_getres() gives the clock resolution. It is 1 nanosecond on Linux. .. note:: clock_gettime() requires to link the program with the realtime ("rt") library. -.. note:: - GetTickCount64() was added to Windows Vista and Windows Server 2008. +QueryPerformanceCounter +^^^^^^^^^^^^^^^^^^^^^^^ + +High-resolution performance counter. It is monotonic. +QueryPerformanceFrequency() gives its frequency. + + +On Windows XP, QueryPerformanceFrequency() is the processor frequency and +QueryPerformanceCounter() is the TSC of the current processor. Windows XP +had a bug (see `KB896256 `_): on a +multiprocessor computer, QueryPerformanceCounter() returned a different value +for each processor. + +QueryPerformanceFrequency() should only be called once: the frequency will not +change while the system is running. It fails if the installed hardware does not +support a high-resolution performance counter. + + +GetTickCount(), GetTickCount64() +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +GetTickCount() and GetTickCount64() are monotonic and cannot fail. + +GetTickCount64() was added to Windows Vista and Windows Server 2008. + +The clock resolution is 1 millisecond. System time ----------- -System time on Windows -^^^^^^^^^^^^^^^^^^^^^^ +Windows: GetSystemTimeAsFileTime +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The system time can be read using GetSystemTimeAsFileTime(), ftime() and time(). @@ -276,12 +240,12 @@ System time on UNIX ^^^^^^^^^^^^^^^^^^^ -gettimeofday(), ftime(), time() and clock_settime(CLOCK_REALTIME) return the +gettimeofday(), ftime(), time() and clock_gettime(CLOCK_REALTIME) return the system clock. Resolution: - * clock_settime(): clock_getres(CLOCK_REALTIME), 1 nanosecond on Linux + * clock_gettime(): clock_getres(CLOCK_REALTIME), 1 nanosecond on Linux * gettimeofday(): 1 microsecond * ftime(): 1 millisecond * time(): 1 second @@ -299,7 +263,8 @@ ^^^^^^^ * Windows: GetProcessTimes() - * clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process timer from the CPU. + * clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process timer + from the CPU. * clock(): * Windows: The elapsed wall-clock time since the start of the process @@ -331,28 +296,6 @@ See also pthread_getcpuclockid(). -QueryPerformanceCounter ------------------------ - -Windows provides a high-resolution performance counter: -QueryPerformanceCounter(). Its frequency can be retrieved using -QueryPerformanceFrequency(). - -On Windows XP, QueryPerformanceFrequency() is the processor frequency and -QueryPerformanceCounter() is the TSC of the current processor. Windows XP -had a bug (see `KB896256 `_): on a -multiprocessor computer, QueryPerformanceCounter() returned a different value -for each processor. - -QueryPerformanceCounter() is monotonic. - -QueryPerformanceFrequency() fails if the installed hardware does not support a -high-resolution performance counter. - -QueryPerformanceFrequency() should only be called once: the frequency will not -change while the system is running. - - QueryUnbiasedInterruptTime -------------------------- @@ -369,12 +312,12 @@ Alternatives: API design ======================== -One function with a flag: time.try_monotonic(strict=False) +One function with a flag: time.monotonic(strict=False) ---------------------------------------------------------- - * time.try_monotonic(strict=False) falls back to another clock if no monotonic clock + * time.monotonic(strict=False) falls back to another clock if no monotonic clock is not available or does not work, but it does never fail. - * time.try_monotonic(strict=True) raises OSError if monotonic clock fails or + * time.monotonic(strict=True) raises OSError if monotonic clock fails or NotImplementedError if the system does not provide a monotonic clock "A keyword argument that gets passed as a constant in the caller is usually @@ -387,10 +330,10 @@ One function, no flag --------------------- -time.try_monotonic() returns (time: float, is_monotonic: bool). +time.monotonic() returns (time: float, is_monotonic: bool). -An alternative is to use a function attribute: time.try_monotonic.monotonic. The -attribute value would be None before the first call to time.try_monotonic(). +An alternative is to use a function attribute: time.monotonic.is_monotonic. The +attribute value would be None before the first call to time.monotonic(). Working around operating system bugs? -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Mar 28 02:54:55 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 28 Mar 2012 02:54:55 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Document_the_fact_that_mach?= =?utf8?q?=5Ftimebase=5Finfo=28=29_cannot_fail?= Message-ID: http://hg.python.org/cpython/rev/4310cfaa3727 changeset: 75969:4310cfaa3727 user: Victor Stinner date: Wed Mar 28 02:50:46 2012 +0200 summary: Document the fact that mach_timebase_info() cannot fail And call mach_absolute_time() after mach_timebase_info(). files: Modules/timemodule.c | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -768,13 +768,17 @@ #if defined(MS_WINDOWS) && !defined(__BORLANDC__) return win32_clock(!strict); #elif defined(__APPLE__) - uint64_t time = mach_absolute_time(); + static mach_timebase_info_data_t timebase; + uint64_t time; double secs; - static mach_timebase_info_data_t timebase; - if (timebase.denom == 0) - mach_timebase_info(&timebase); + if (timebase.denom == 0) { + /* According to the Technical Q&A QA1398, mach_timebase_info() cannot + fail: https://developer.apple.com/library/mac/#qa/qa1398/ */ + (void)mach_timebase_info(&timebase); + } + time = mach_absolute_time(); secs = (double)time * timebase.numer / timebase.denom * 1e-9; return PyFloat_FromDouble(secs); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 28 02:54:58 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 28 Mar 2012 02:54:58 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_time=2Etime=28=29_now_uses_?= =?utf8?q?clock=5Fgettime=28CLOCK=5FREALTIME=29_if_available?= Message-ID: http://hg.python.org/cpython/rev/e505ce0514ff changeset: 75970:e505ce0514ff user: Victor Stinner date: Wed Mar 28 02:54:15 2012 +0200 summary: time.time() now uses clock_gettime(CLOCK_REALTIME) if available clock_gettime(CLOCK_REALTIME) has a better resolution than gettimeofday(). time.time() falls back on gettimeofday() (and then on other functions) on error. files: Modules/timemodule.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1088,6 +1088,17 @@ floattime(void) { _PyTime_timeval t; +#ifdef HAVE_CLOCK_GETTIME + struct timespec tp; + int ret; + + /* _PyTime_gettimeofday() does not use clock_gettime() + because it would require to link Python to the rt (real-time) + library, at least on Linux */ + ret = clock_gettime(CLOCK_REALTIME, &tp); + if (ret == 0) + return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); +#endif _PyTime_gettimeofday(&t); return PyFloat_FromDouble((double)t.tv_sec + t.tv_usec * 1e-6); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 28 02:59:19 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 28 Mar 2012 02:59:19 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Mention_the_Technic?= =?utf8?q?al_Q=26A_QA1398_for_mach=5Fabsolute=5Ftime=28=29?= Message-ID: http://hg.python.org/peps/rev/05bfb02e57db changeset: 4161:05bfb02e57db user: Victor Stinner date: Wed Mar 28 02:59:01 2012 +0200 summary: PEP 418: Mention the Technical Q&A QA1398 for mach_absolute_time() files: pep-0418.txt | 23 +++++++++++++---------- 1 files changed, 13 insertions(+), 10 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -137,7 +137,7 @@ It is available on all platforms and cannot fail. -Pseudo-code [#pseudo]_: :: +Pseudo-code:: def hires(): if hires.use_monotonic: @@ -158,11 +158,15 @@ mach_absolute_time ^^^^^^^^^^^^^^^^^^ -Mac OS X provides a monotonic clock: mach_absolute_time(). mach_timebase_info() -provides a fraction to convert the clock value to a number of nanoseconds. +Mac OS X provides a monotonic clock: mach_absolute_time(). It is based on +absolute elapsed time delta since system boot. It is not adjusted and cannot be +set. -According to the documentation, mach_timebase_info() is always equals to one -and does never fail, even if the function may fail according to its prototype. +mach_timebase_info() gives a fraction to convert the clock value to a number of +nanoseconds. According to the documentation (`Technical Q&A QA1398 +`_), mach_timebase_info() +is always equals to one and does never fail, even if the function may fail +according to its prototype. mach_absolute_time() has a resolution of 1 nanosecond. @@ -189,7 +193,7 @@ clock_getres() gives the clock resolution. It is 1 nanosecond on Linux. .. note:: - clock_gettime() requires to link the program with the realtime ("rt") library. + clock_gettime() requires to link the program to the rt (real-time) library. QueryPerformanceCounter ^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +201,6 @@ High-resolution performance counter. It is monotonic. QueryPerformanceFrequency() gives its frequency. - On Windows XP, QueryPerformanceFrequency() is the processor frequency and QueryPerformanceCounter() is the TSC of the current processor. Windows XP had a bug (see `KB896256 `_): on a @@ -315,9 +318,9 @@ One function with a flag: time.monotonic(strict=False) ---------------------------------------------------------- - * time.monotonic(strict=False) falls back to another clock if no monotonic clock - is not available or does not work, but it does never fail. - * time.monotonic(strict=True) raises OSError if monotonic clock fails or + * time.monotonic(strict=False) falls back to the system clock if no monotonic + clock is available or if the monotonic clock failed. + * time.monotonic(strict=True) raises OSError if monotonic clock fails and NotImplementedError if the system does not provide a monotonic clock "A keyword argument that gets passed as a constant in the caller is usually -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Wed Mar 28 05:43:08 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 28 Mar 2012 05:43:08 +0200 Subject: [Python-checkins] Daily reference leaks (e505ce0514ff): sum=0 Message-ID: results for e505ce0514ff on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog0kZbsM', '-x'] From python-checkins at python.org Wed Mar 28 15:35:52 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 28 Mar 2012 15:35:52 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Unsplit_unittest=2Emock_doc?= =?utf8?q?umentation?= Message-ID: http://hg.python.org/cpython/rev/1177d215a377 changeset: 75971:1177d215a377 user: Michael Foord date: Wed Mar 28 14:36:02 2012 +0100 summary: Unsplit unittest.mock documentation files: Doc/library/development.rst | 4 - Doc/library/unittest.mock-examples.rst | 425 +++- Doc/library/unittest.mock-getting-started.rst | 417 --- Doc/library/unittest.mock-helpers.rst | 529 ---- Doc/library/unittest.mock-magicmethods.rst | 224 - Doc/library/unittest.mock-patch.rst | 529 ---- Doc/library/unittest.mock.rst | 1285 +++++++++- 7 files changed, 1701 insertions(+), 1712 deletions(-) diff --git a/Doc/library/development.rst b/Doc/library/development.rst --- a/Doc/library/development.rst +++ b/Doc/library/development.rst @@ -20,10 +20,6 @@ doctest.rst unittest.rst unittest.mock.rst - unittest.mock-patch.rst - unittest.mock-magicmethods.rst - unittest.mock-helpers.rst - unittest.mock-getting-started.rst unittest.mock-examples.rst 2to3.rst test.rst diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -1,18 +1,427 @@ -.. _further-examples: +:mod:`unittest.mock` --- getting started +======================================== -:mod:`unittest.mock` --- further examples -========================================= - -.. module:: unittest.mock - :synopsis: Mock object library. .. moduleauthor:: Michael Foord .. currentmodule:: unittest.mock .. versionadded:: 3.3 -Here are some more examples for some slightly more advanced scenarios than in -the :ref:`getting started ` guide. +.. _getting-started: + +Using Mock +---------- + +Mock Patching Methods +~~~~~~~~~~~~~~~~~~~~~ + +Common uses for :class:`Mock` objects include: + +* Patching methods +* Recording method calls on objects + +You might want to replace a method on an object to check that +it is called with the correct arguments by another part of the system: + + >>> real = SomeClass() + >>> real.method = MagicMock(name='method') + >>> real.method(3, 4, 5, key='value') + + +Once our mock has been used (`real.method` in this example) it has methods +and attributes that allow you to make assertions about how it has been used. + +.. note:: + + In most of these examples the :class:`Mock` and :class:`MagicMock` classes + are interchangeable. As the `MagicMock` is the more capable class it makes + a sensible one to use by default. + +Once the mock has been called its :attr:`~Mock.called` attribute is set to +`True`. More importantly we can use the :meth:`~Mock.assert_called_with` or +:meth`~Mock.assert_called_once_with` method to check that it was called with +the correct arguments. + +This example tests that calling `ProductionClass().method` results in a call to +the `something` method: + + >>> class ProductionClass(object): + ... def method(self): + ... self.something(1, 2, 3) + ... def something(self, a, b, c): + ... pass + ... + >>> real = ProductionClass() + >>> real.something = MagicMock() + >>> real.method() + >>> real.something.assert_called_once_with(1, 2, 3) + + + +Mock for Method Calls on an Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the last example we patched a method directly on an object to check that it +was called correctly. Another common use case is to pass an object into a +method (or some part of the system under test) and then check that it is used +in the correct way. + +The simple `ProductionClass` below has a `closer` method. If it is called with +an object then it calls `close` on it. + + >>> class ProductionClass(object): + ... def closer(self, something): + ... something.close() + ... + +So to test it we need to pass in an object with a `close` method and check +that it was called correctly. + + >>> real = ProductionClass() + >>> mock = Mock() + >>> real.closer(mock) + >>> mock.close.assert_called_with() + +We don't have to do any work to provide the 'close' method on our mock. +Accessing close creates it. So, if 'close' hasn't already been called then +accessing it in the test will create it, but :meth:`~Mock.assert_called_with` +will raise a failure exception. + + +Mocking Classes +~~~~~~~~~~~~~~~ + +A common use case is to mock out classes instantiated by your code under test. +When you patch a class, then that class is replaced with a mock. Instances +are created by *calling the class*. This means you access the "mock instance" +by looking at the return value of the mocked class. + +In the example below we have a function `some_function` that instantiates `Foo` +and calls a method on it. The call to `patch` replaces the class `Foo` with a +mock. The `Foo` instance is the result of calling the mock, so it is configured +by modify the mock :attr:`~Mock.return_value`. + + >>> def some_function(): + ... instance = module.Foo() + ... return instance.method() + ... + >>> with patch('module.Foo') as mock: + ... instance = mock.return_value + ... instance.method.return_value = 'the result' + ... result = some_function() + ... assert result == 'the result' + + +Naming your mocks +~~~~~~~~~~~~~~~~~ + +It can be useful to give your mocks a name. The name is shown in the repr of +the mock and can be helpful when the mock appears in test failure messages. The +name is also propagated to attributes or methods of the mock: + + >>> mock = MagicMock(name='foo') + >>> mock + + >>> mock.method + + + +Tracking all Calls +~~~~~~~~~~~~~~~~~~ + +Often you want to track more than a single call to a method. The +:attr:`~Mock.mock_calls` attribute records all calls +to child attributes of the mock - and also to their children. + + >>> mock = MagicMock() + >>> mock.method() + + >>> mock.attribute.method(10, x=53) + + >>> mock.mock_calls + [call.method(), call.attribute.method(10, x=53)] + +If you make an assertion about `mock_calls` and any unexpected methods +have been called, then the assertion will fail. This is useful because as well +as asserting that the calls you expected have been made, you are also checking +that they were made in the right order and with no additional calls: + +You use the :data:`call` object to construct lists for comparing with +`mock_calls`: + + >>> expected = [call.method(), call.attribute.method(10, x=53)] + >>> mock.mock_calls == expected + True + + +Setting Return Values and Attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting the return values on a mock object is trivially easy: + + >>> mock = Mock() + >>> mock.return_value = 3 + >>> mock() + 3 + +Of course you can do the same for methods on the mock: + + >>> mock = Mock() + >>> mock.method.return_value = 3 + >>> mock.method() + 3 + +The return value can also be set in the constructor: + + >>> mock = Mock(return_value=3) + >>> mock() + 3 + +If you need an attribute setting on your mock, just do it: + + >>> mock = Mock() + >>> mock.x = 3 + >>> mock.x + 3 + +Sometimes you want to mock up a more complex situation, like for example +`mock.connection.cursor().execute("SELECT 1")`. If we wanted this call to +return a list, then we have to configure the result of the nested call. + +We can use :data:`call` to construct the set of calls in a "chained call" like +this for easy assertion afterwards: + + >>> mock = Mock() + >>> cursor = mock.connection.cursor.return_value + >>> cursor.execute.return_value = ['foo'] + >>> mock.connection.cursor().execute("SELECT 1") + ['foo'] + >>> expected = call.connection.cursor().execute("SELECT 1").call_list() + >>> mock.mock_calls + [call.connection.cursor(), call.connection.cursor().execute('SELECT 1')] + >>> mock.mock_calls == expected + True + +It is the call to `.call_list()` that turns our call object into a list of +calls representing the chained calls. + + +Raising exceptions with mocks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A useful attribute is :attr:`~Mock.side_effect`. If you set this to an +exception class or instance then the exception will be raised when the mock +is called. + + >>> mock = Mock(side_effect=Exception('Boom!')) + >>> mock() + Traceback (most recent call last): + ... + Exception: Boom! + + +Side effect functions and iterables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`side_effect` can also be set to a function or an iterable. The use case for +`side_effect` as an iterable is where your mock is going to be called several +times, and you want each call to return a different value. When you set +`side_effect` to an iterable every call to the mock returns the next value +from the iterable: + + >>> mock = MagicMock(side_effect=[4, 5, 6]) + >>> mock() + 4 + >>> mock() + 5 + >>> mock() + 6 + + +For more advanced use cases, like dynamically varying the return values +depending on what the mock is called with, `side_effect` can be a function. +The function will be called with the same arguments as the mock. Whatever the +function returns is what the call returns: + + >>> vals = {(1, 2): 1, (2, 3): 2} + >>> def side_effect(*args): + ... return vals[args] + ... + >>> mock = MagicMock(side_effect=side_effect) + >>> mock(1, 2) + 1 + >>> mock(2, 3) + 2 + + +Creating a Mock from an Existing Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One problem with over use of mocking is that it couples your tests to the +implementation of your mocks rather than your real code. Suppose you have a +class that implements `some_method`. In a test for another class, you +provide a mock of this object that *also* provides `some_method`. If later +you refactor the first class, so that it no longer has `some_method` - then +your tests will continue to pass even though your code is now broken! + +`Mock` allows you to provide an object as a specification for the mock, +using the `spec` keyword argument. Accessing methods / attributes on the +mock that don't exist on your specification object will immediately raise an +attribute error. If you change the implementation of your specification, then +tests that use that class will start failing immediately without you having to +instantiate the class in those tests. + + >>> mock = Mock(spec=SomeClass) + >>> mock.old_method() + Traceback (most recent call last): + ... + AttributeError: object has no attribute 'old_method' + +If you want a stronger form of specification that prevents the setting +of arbitrary attributes as well as the getting of them then you can use +`spec_set` instead of `spec`. + + + +Patch Decorators +---------------- + +.. note:: + + With `patch` it matters that you patch objects in the namespace where they + are looked up. This is normally straightforward, but for a quick guide + read :ref:`where to patch `. + + +A common need in tests is to patch a class attribute or a module attribute, +for example patching a builtin or patching a class in a module to test that it +is instantiated. Modules and classes are effectively global, so patching on +them has to be undone after the test or the patch will persist into other +tests and cause hard to diagnose problems. + +mock provides three convenient decorators for this: `patch`, `patch.object` and +`patch.dict`. `patch` takes a single string, of the form +`package.module.Class.attribute` to specify the attribute you are patching. It +also optionally takes a value that you want the attribute (or class or +whatever) to be replaced with. 'patch.object' takes an object and the name of +the attribute you would like patched, plus optionally the value to patch it +with. + +`patch.object`: + + >>> original = SomeClass.attribute + >>> @patch.object(SomeClass, 'attribute', sentinel.attribute) + ... def test(): + ... assert SomeClass.attribute == sentinel.attribute + ... + >>> test() + >>> assert SomeClass.attribute == original + + >>> @patch('package.module.attribute', sentinel.attribute) + ... def test(): + ... from package.module import attribute + ... assert attribute is sentinel.attribute + ... + >>> test() + +If you are patching a module (including `__builtin__`) then use `patch` +instead of `patch.object`: + + >>> mock = MagicMock(return_value = sentinel.file_handle) + >>> with patch('__builtin__.open', mock): + ... handle = open('filename', 'r') + ... + >>> mock.assert_called_with('filename', 'r') + >>> assert handle == sentinel.file_handle, "incorrect file handle returned" + +The module name can be 'dotted', in the form `package.module` if needed: + + >>> @patch('package.module.ClassName.attribute', sentinel.attribute) + ... def test(): + ... from package.module import ClassName + ... assert ClassName.attribute == sentinel.attribute + ... + >>> test() + +A nice pattern is to actually decorate test methods themselves: + + >>> class MyTest(unittest2.TestCase): + ... @patch.object(SomeClass, 'attribute', sentinel.attribute) + ... def test_something(self): + ... self.assertEqual(SomeClass.attribute, sentinel.attribute) + ... + >>> original = SomeClass.attribute + >>> MyTest('test_something').test_something() + >>> assert SomeClass.attribute == original + +If you want to patch with a Mock, you can use `patch` with only one argument +(or `patch.object` with two arguments). The mock will be created for you and +passed into the test function / method: + + >>> class MyTest(unittest2.TestCase): + ... @patch.object(SomeClass, 'static_method') + ... def test_something(self, mock_method): + ... SomeClass.static_method() + ... mock_method.assert_called_with() + ... + >>> MyTest('test_something').test_something() + +You can stack up multiple patch decorators using this pattern: + + >>> class MyTest(unittest2.TestCase): + ... @patch('package.module.ClassName1') + ... @patch('package.module.ClassName2') + ... def test_something(self, MockClass2, MockClass1): + ... self.assertTrue(package.module.ClassName1 is MockClass1) + ... self.assertTrue(package.module.ClassName2 is MockClass2) + ... + >>> MyTest('test_something').test_something() + +When you nest patch decorators the mocks are passed in to the decorated +function in the same order they applied (the normal *python* order that +decorators are applied). This means from the bottom up, so in the example +above the mock for `test_module.ClassName2` is passed in first. + +There is also :func:`patch.dict` for setting values in a dictionary just +during a scope and restoring the dictionary to its original state when the test +ends: + + >>> foo = {'key': 'value'} + >>> original = foo.copy() + >>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True): + ... assert foo == {'newkey': 'newvalue'} + ... + >>> assert foo == original + +`patch`, `patch.object` and `patch.dict` can all be used as context managers. + +Where you use `patch` to create a mock for you, you can get a reference to the +mock using the "as" form of the with statement: + + >>> class ProductionClass(object): + ... def method(self): + ... pass + ... + >>> with patch.object(ProductionClass, 'method') as mock_method: + ... mock_method.return_value = None + ... real = ProductionClass() + ... real.method(1, 2, 3) + ... + >>> mock_method.assert_called_with(1, 2, 3) + + +As an alternative `patch`, `patch.object` and `patch.dict` can be used as +class decorators. When used in this way it is the same as applying the +decorator indvidually to every method whose name starts with "test". + + +.. _further-examples: + +Further Examples +================ + + +Here are some more examples for some slightly more advanced scenarios. Mocking chained calls diff --git a/Doc/library/unittest.mock-getting-started.rst b/Doc/library/unittest.mock-getting-started.rst deleted file mode 100644 --- a/Doc/library/unittest.mock-getting-started.rst +++ /dev/null @@ -1,419 +0,0 @@ -:mod:`unittest.mock` --- getting started -======================================== - -.. module:: unittest.mock - :synopsis: Mock object library. -.. moduleauthor:: Michael Foord -.. currentmodule:: unittest.mock - -.. versionadded:: 3.3 - - -.. _getting-started: - -Using Mock ----------- - -Mock Patching Methods -~~~~~~~~~~~~~~~~~~~~~ - -Common uses for :class:`Mock` objects include: - -* Patching methods -* Recording method calls on objects - -You might want to replace a method on an object to check that -it is called with the correct arguments by another part of the system: - - >>> real = SomeClass() - >>> real.method = MagicMock(name='method') - >>> real.method(3, 4, 5, key='value') - - -Once our mock has been used (`real.method` in this example) it has methods -and attributes that allow you to make assertions about how it has been used. - -.. note:: - - In most of these examples the :class:`Mock` and :class:`MagicMock` classes - are interchangeable. As the `MagicMock` is the more capable class it makes - a sensible one to use by default. - -Once the mock has been called its :attr:`~Mock.called` attribute is set to -`True`. More importantly we can use the :meth:`~Mock.assert_called_with` or -:meth`~Mock.assert_called_once_with` method to check that it was called with -the correct arguments. - -This example tests that calling `ProductionClass().method` results in a call to -the `something` method: - - >>> class ProductionClass(object): - ... def method(self): - ... self.something(1, 2, 3) - ... def something(self, a, b, c): - ... pass - ... - >>> real = ProductionClass() - >>> real.something = MagicMock() - >>> real.method() - >>> real.something.assert_called_once_with(1, 2, 3) - - - -Mock for Method Calls on an Object -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In the last example we patched a method directly on an object to check that it -was called correctly. Another common use case is to pass an object into a -method (or some part of the system under test) and then check that it is used -in the correct way. - -The simple `ProductionClass` below has a `closer` method. If it is called with -an object then it calls `close` on it. - - >>> class ProductionClass(object): - ... def closer(self, something): - ... something.close() - ... - -So to test it we need to pass in an object with a `close` method and check -that it was called correctly. - - >>> real = ProductionClass() - >>> mock = Mock() - >>> real.closer(mock) - >>> mock.close.assert_called_with() - -We don't have to do any work to provide the 'close' method on our mock. -Accessing close creates it. So, if 'close' hasn't already been called then -accessing it in the test will create it, but :meth:`~Mock.assert_called_with` -will raise a failure exception. - - -Mocking Classes -~~~~~~~~~~~~~~~ - -A common use case is to mock out classes instantiated by your code under test. -When you patch a class, then that class is replaced with a mock. Instances -are created by *calling the class*. This means you access the "mock instance" -by looking at the return value of the mocked class. - -In the example below we have a function `some_function` that instantiates `Foo` -and calls a method on it. The call to `patch` replaces the class `Foo` with a -mock. The `Foo` instance is the result of calling the mock, so it is configured -by modify the mock :attr:`~Mock.return_value`. - - >>> def some_function(): - ... instance = module.Foo() - ... return instance.method() - ... - >>> with patch('module.Foo') as mock: - ... instance = mock.return_value - ... instance.method.return_value = 'the result' - ... result = some_function() - ... assert result == 'the result' - - -Naming your mocks -~~~~~~~~~~~~~~~~~ - -It can be useful to give your mocks a name. The name is shown in the repr of -the mock and can be helpful when the mock appears in test failure messages. The -name is also propagated to attributes or methods of the mock: - - >>> mock = MagicMock(name='foo') - >>> mock - - >>> mock.method - - - -Tracking all Calls -~~~~~~~~~~~~~~~~~~ - -Often you want to track more than a single call to a method. The -:attr:`~Mock.mock_calls` attribute records all calls -to child attributes of the mock - and also to their children. - - >>> mock = MagicMock() - >>> mock.method() - - >>> mock.attribute.method(10, x=53) - - >>> mock.mock_calls - [call.method(), call.attribute.method(10, x=53)] - -If you make an assertion about `mock_calls` and any unexpected methods -have been called, then the assertion will fail. This is useful because as well -as asserting that the calls you expected have been made, you are also checking -that they were made in the right order and with no additional calls: - -You use the :data:`call` object to construct lists for comparing with -`mock_calls`: - - >>> expected = [call.method(), call.attribute.method(10, x=53)] - >>> mock.mock_calls == expected - True - - -Setting Return Values and Attributes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Setting the return values on a mock object is trivially easy: - - >>> mock = Mock() - >>> mock.return_value = 3 - >>> mock() - 3 - -Of course you can do the same for methods on the mock: - - >>> mock = Mock() - >>> mock.method.return_value = 3 - >>> mock.method() - 3 - -The return value can also be set in the constructor: - - >>> mock = Mock(return_value=3) - >>> mock() - 3 - -If you need an attribute setting on your mock, just do it: - - >>> mock = Mock() - >>> mock.x = 3 - >>> mock.x - 3 - -Sometimes you want to mock up a more complex situation, like for example -`mock.connection.cursor().execute("SELECT 1")`. If we wanted this call to -return a list, then we have to configure the result of the nested call. - -We can use :data:`call` to construct the set of calls in a "chained call" like -this for easy assertion afterwards: - - >>> mock = Mock() - >>> cursor = mock.connection.cursor.return_value - >>> cursor.execute.return_value = ['foo'] - >>> mock.connection.cursor().execute("SELECT 1") - ['foo'] - >>> expected = call.connection.cursor().execute("SELECT 1").call_list() - >>> mock.mock_calls - [call.connection.cursor(), call.connection.cursor().execute('SELECT 1')] - >>> mock.mock_calls == expected - True - -It is the call to `.call_list()` that turns our call object into a list of -calls representing the chained calls. - - -Raising exceptions with mocks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A useful attribute is :attr:`~Mock.side_effect`. If you set this to an -exception class or instance then the exception will be raised when the mock -is called. - - >>> mock = Mock(side_effect=Exception('Boom!')) - >>> mock() - Traceback (most recent call last): - ... - Exception: Boom! - - -Side effect functions and iterables -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -`side_effect` can also be set to a function or an iterable. The use case for -`side_effect` as an iterable is where your mock is going to be called several -times, and you want each call to return a different value. When you set -`side_effect` to an iterable every call to the mock returns the next value -from the iterable: - - >>> mock = MagicMock(side_effect=[4, 5, 6]) - >>> mock() - 4 - >>> mock() - 5 - >>> mock() - 6 - - -For more advanced use cases, like dynamically varying the return values -depending on what the mock is called with, `side_effect` can be a function. -The function will be called with the same arguments as the mock. Whatever the -function returns is what the call returns: - - >>> vals = {(1, 2): 1, (2, 3): 2} - >>> def side_effect(*args): - ... return vals[args] - ... - >>> mock = MagicMock(side_effect=side_effect) - >>> mock(1, 2) - 1 - >>> mock(2, 3) - 2 - - -Creating a Mock from an Existing Object -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -One problem with over use of mocking is that it couples your tests to the -implementation of your mocks rather than your real code. Suppose you have a -class that implements `some_method`. In a test for another class, you -provide a mock of this object that *also* provides `some_method`. If later -you refactor the first class, so that it no longer has `some_method` - then -your tests will continue to pass even though your code is now broken! - -`Mock` allows you to provide an object as a specification for the mock, -using the `spec` keyword argument. Accessing methods / attributes on the -mock that don't exist on your specification object will immediately raise an -attribute error. If you change the implementation of your specification, then -tests that use that class will start failing immediately without you having to -instantiate the class in those tests. - - >>> mock = Mock(spec=SomeClass) - >>> mock.old_method() - Traceback (most recent call last): - ... - AttributeError: object has no attribute 'old_method' - -If you want a stronger form of specification that prevents the setting -of arbitrary attributes as well as the getting of them then you can use -`spec_set` instead of `spec`. - - - -Patch Decorators ----------------- - -.. note:: - - With `patch` it matters that you patch objects in the namespace where they - are looked up. This is normally straightforward, but for a quick guide - read :ref:`where to patch `. - - -A common need in tests is to patch a class attribute or a module attribute, -for example patching a builtin or patching a class in a module to test that it -is instantiated. Modules and classes are effectively global, so patching on -them has to be undone after the test or the patch will persist into other -tests and cause hard to diagnose problems. - -mock provides three convenient decorators for this: `patch`, `patch.object` and -`patch.dict`. `patch` takes a single string, of the form -`package.module.Class.attribute` to specify the attribute you are patching. It -also optionally takes a value that you want the attribute (or class or -whatever) to be replaced with. 'patch.object' takes an object and the name of -the attribute you would like patched, plus optionally the value to patch it -with. - -`patch.object`: - - >>> original = SomeClass.attribute - >>> @patch.object(SomeClass, 'attribute', sentinel.attribute) - ... def test(): - ... assert SomeClass.attribute == sentinel.attribute - ... - >>> test() - >>> assert SomeClass.attribute == original - - >>> @patch('package.module.attribute', sentinel.attribute) - ... def test(): - ... from package.module import attribute - ... assert attribute is sentinel.attribute - ... - >>> test() - -If you are patching a module (including `__builtin__`) then use `patch` -instead of `patch.object`: - - >>> mock = MagicMock(return_value = sentinel.file_handle) - >>> with patch('__builtin__.open', mock): - ... handle = open('filename', 'r') - ... - >>> mock.assert_called_with('filename', 'r') - >>> assert handle == sentinel.file_handle, "incorrect file handle returned" - -The module name can be 'dotted', in the form `package.module` if needed: - - >>> @patch('package.module.ClassName.attribute', sentinel.attribute) - ... def test(): - ... from package.module import ClassName - ... assert ClassName.attribute == sentinel.attribute - ... - >>> test() - -A nice pattern is to actually decorate test methods themselves: - - >>> class MyTest(unittest2.TestCase): - ... @patch.object(SomeClass, 'attribute', sentinel.attribute) - ... def test_something(self): - ... self.assertEqual(SomeClass.attribute, sentinel.attribute) - ... - >>> original = SomeClass.attribute - >>> MyTest('test_something').test_something() - >>> assert SomeClass.attribute == original - -If you want to patch with a Mock, you can use `patch` with only one argument -(or `patch.object` with two arguments). The mock will be created for you and -passed into the test function / method: - - >>> class MyTest(unittest2.TestCase): - ... @patch.object(SomeClass, 'static_method') - ... def test_something(self, mock_method): - ... SomeClass.static_method() - ... mock_method.assert_called_with() - ... - >>> MyTest('test_something').test_something() - -You can stack up multiple patch decorators using this pattern: - - >>> class MyTest(unittest2.TestCase): - ... @patch('package.module.ClassName1') - ... @patch('package.module.ClassName2') - ... def test_something(self, MockClass2, MockClass1): - ... self.assertTrue(package.module.ClassName1 is MockClass1) - ... self.assertTrue(package.module.ClassName2 is MockClass2) - ... - >>> MyTest('test_something').test_something() - -When you nest patch decorators the mocks are passed in to the decorated -function in the same order they applied (the normal *python* order that -decorators are applied). This means from the bottom up, so in the example -above the mock for `test_module.ClassName2` is passed in first. - -There is also :func:`patch.dict` for setting values in a dictionary just -during a scope and restoring the dictionary to its original state when the test -ends: - - >>> foo = {'key': 'value'} - >>> original = foo.copy() - >>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True): - ... assert foo == {'newkey': 'newvalue'} - ... - >>> assert foo == original - -`patch`, `patch.object` and `patch.dict` can all be used as context managers. - -Where you use `patch` to create a mock for you, you can get a reference to the -mock using the "as" form of the with statement: - - >>> class ProductionClass(object): - ... def method(self): - ... pass - ... - >>> with patch.object(ProductionClass, 'method') as mock_method: - ... mock_method.return_value = None - ... real = ProductionClass() - ... real.method(1, 2, 3) - ... - >>> mock_method.assert_called_with(1, 2, 3) - - -As an alternative `patch`, `patch.object` and `patch.dict` can be used as -class decorators. When used in this way it is the same as applying the -decorator indvidually to every method whose name starts with "test". - -For some more advanced examples, see the :ref:`further-examples` page. diff --git a/Doc/library/unittest.mock-helpers.rst b/Doc/library/unittest.mock-helpers.rst deleted file mode 100644 --- a/Doc/library/unittest.mock-helpers.rst +++ /dev/null @@ -1,537 +0,0 @@ -:mod:`unittest.mock` --- helpers -================================ - -.. module:: unittest.mock - :synopsis: Mock object library. -.. moduleauthor:: Michael Foord -.. currentmodule:: unittest.mock - -.. versionadded:: 3.3 - - -sentinel --------- - -.. data:: sentinel - - The ``sentinel`` object provides a convenient way of providing unique - objects for your tests. - - Attributes are created on demand when you access them by name. Accessing - the same attribute will always return the same object. The objects - returned have a sensible repr so that test failure messages are readable. - -Sometimes when testing you need to test that a specific object is passed as an -argument to another method, or returned. It can be common to create named -sentinel objects to test this. `sentinel` provides a convenient way of -creating and testing the identity of objects like this. - -In this example we monkey patch `method` to return `sentinel.some_object`: - - >>> real = ProductionClass() - >>> real.method = Mock(name="method") - >>> real.method.return_value = sentinel.some_object - >>> result = real.method() - >>> assert result is sentinel.some_object - >>> sentinel.some_object - sentinel.some_object - - -DEFAULT -------- - - -.. data:: DEFAULT - - The `DEFAULT` object is a pre-created sentinel (actually - `sentinel.DEFAULT`). It can be used by :attr:`~Mock.side_effect` - functions to indicate that the normal return value should be used. - - - -call ----- - -.. function:: call(*args, **kwargs) - - `call` is a helper object for making simpler assertions, for comparing - with :attr:`~Mock.call_args`, :attr:`~Mock.call_args_list`, - :attr:`~Mock.mock_calls` and:attr: `~Mock.method_calls`. `call` can also be - used with :meth:`~Mock.assert_has_calls`. - - >>> m = MagicMock(return_value=None) - >>> m(1, 2, a='foo', b='bar') - >>> m() - >>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()] - True - -.. method:: call.call_list() - - For a call object that represents multiple calls, `call_list` - returns a list of all the intermediate calls as well as the - final call. - -`call_list` is particularly useful for making assertions on "chained calls". A -chained call is multiple calls on a single line of code. This results in -multiple entries in :attr:`~Mock.mock_calls` on a mock. Manually constructing -the sequence of calls can be tedious. - -:meth:`~call.call_list` can construct the sequence of calls from the same -chained call: - - >>> m = MagicMock() - >>> m(1).method(arg='foo').other('bar')(2.0) - - >>> kall = call(1).method(arg='foo').other('bar')(2.0) - >>> kall.call_list() - [call(1), - call().method(arg='foo'), - call().method().other('bar'), - call().method().other()(2.0)] - >>> m.mock_calls == kall.call_list() - True - -.. _calls-as-tuples: - -A `call` object is either a tuple of (positional args, keyword args) or -(name, positional args, keyword args) depending on how it was constructed. When -you construct them yourself this isn't particularly interesting, but the `call` -objects that are in the :attr:`Mock.call_args`, :attr:`Mock.call_args_list` and -:attr:`Mock.mock_calls` attributes can be introspected to get at the individual -arguments they contain. - -The `call` objects in :attr:`Mock.call_args` and :attr:`Mock.call_args_list` -are two-tuples of (positional args, keyword args) whereas the `call` objects -in :attr:`Mock.mock_calls`, along with ones you construct yourself, are -three-tuples of (name, positional args, keyword args). - -You can use their "tupleness" to pull out the individual arguments for more -complex introspection and assertions. The positional arguments are a tuple -(an empty tuple if there are no positional arguments) and the keyword -arguments are a dictionary: - - >>> m = MagicMock(return_value=None) - >>> m(1, 2, 3, arg='one', arg2='two') - >>> kall = m.call_args - >>> args, kwargs = kall - >>> args - (1, 2, 3) - >>> kwargs - {'arg2': 'two', 'arg': 'one'} - >>> args is kall[0] - True - >>> kwargs is kall[1] - True - - >>> m = MagicMock() - >>> m.foo(4, 5, 6, arg='two', arg2='three') - - >>> kall = m.mock_calls[0] - >>> name, args, kwargs = kall - >>> name - 'foo' - >>> args - (4, 5, 6) - >>> kwargs - {'arg2': 'three', 'arg': 'two'} - >>> name is m.mock_calls[0][0] - True - - -create_autospec ---------------- - -.. function:: create_autospec(spec, spec_set=False, instance=False, **kwargs) - - Create a mock object using another object as a spec. Attributes on the - mock will use the corresponding attribute on the `spec` object as their - spec. - - Functions or methods being mocked will have their arguments checked to - ensure that they are called with the correct signature. - - If `spec_set` is `True` then attempting to set attributes that don't exist - on the spec object will raise an `AttributeError`. - - If a class is used as a spec then the return value of the mock (the - instance of the class) will have the same spec. You can use a class as the - spec for an instance object by passing `instance=True`. The returned mock - will only be callable if instances of the mock are callable. - - `create_autospec` also takes arbitrary keyword arguments that are passed to - the constructor of the created mock. - -See :ref:`auto-speccing` for examples of how to use auto-speccing with -`create_autospec` and the `autospec` argument to :func:`patch`. - - -ANY ---- - -.. data:: ANY - -Sometimes you may need to make assertions about *some* of the arguments in a -call to mock, but either not care about some of the arguments or want to pull -them individually out of :attr:`~Mock.call_args` and make more complex -assertions on them. - -To ignore certain arguments you can pass in objects that compare equal to -*everything*. Calls to :meth:`~Mock.assert_called_with` and -:meth:`~Mock.assert_called_once_with` will then succeed no matter what was -passed in. - - >>> mock = Mock(return_value=None) - >>> mock('foo', bar=object()) - >>> mock.assert_called_once_with('foo', bar=ANY) - -`ANY` can also be used in comparisons with call lists like -:attr:`~Mock.mock_calls`: - - >>> m = MagicMock(return_value=None) - >>> m(1) - >>> m(1, 2) - >>> m(object()) - >>> m.mock_calls == [call(1), call(1, 2), ANY] - True - - - -FILTER_DIR ----------- - -.. data:: FILTER_DIR - -`FILTER_DIR` is a module level variable that controls the way mock objects -respond to `dir` (only for Python 2.6 or more recent). The default is `True`, -which uses the filtering described below, to only show useful members. If you -dislike this filtering, or need to switch it off for diagnostic purposes, then -set `mock.FILTER_DIR = False`. - -With filtering on, `dir(some_mock)` shows only useful attributes and will -include any dynamically created attributes that wouldn't normally be shown. -If the mock was created with a `spec` (or `autospec` of course) then all the -attributes from the original are shown, even if they haven't been accessed -yet: - - >>> dir(Mock()) - ['assert_any_call', - 'assert_called_once_with', - 'assert_called_with', - 'assert_has_calls', - 'attach_mock', - ... - >>> from urllib import request - >>> dir(Mock(spec=request)) - ['AbstractBasicAuthHandler', - 'AbstractDigestAuthHandler', - 'AbstractHTTPHandler', - 'BaseHandler', - ... - -Many of the not-very-useful (private to `Mock` rather than the thing being -mocked) underscore and double underscore prefixed attributes have been -filtered from the result of calling `dir` on a `Mock`. If you dislike this -behaviour you can switch it off by setting the module level switch -`FILTER_DIR`: - - >>> from unittest import mock - >>> mock.FILTER_DIR = False - >>> dir(mock.Mock()) - ['_NonCallableMock__get_return_value', - '_NonCallableMock__get_side_effect', - '_NonCallableMock__return_value_doc', - '_NonCallableMock__set_return_value', - '_NonCallableMock__set_side_effect', - '__call__', - '__class__', - ... - -Alternatively you can just use `vars(my_mock)` (instance members) and -`dir(type(my_mock))` (type members) to bypass the filtering irrespective of -`mock.FILTER_DIR`. - - -mock_open ---------- - -.. function:: mock_open(mock=None, read_data=None) - - A helper function to create a mock to replace the use of `open`. It works - for `open` called directly or used as a context manager. - - The `mock` argument is the mock object to configure. If `None` (the - default) then a `MagicMock` will be created for you, with the API limited - to methods or attributes available on standard file handles. - - `read_data` is a string for the `read` method of the file handle to return. - This is an empty string by default. - -Using `open` as a context manager is a great way to ensure your file handles -are closed properly and is becoming common:: - - with open('/some/path', 'w') as f: - f.write('something') - -The issue is that even if you mock out the call to `open` it is the -*returned object* that is used as a context manager (and has `__enter__` and -`__exit__` called). - -Mocking context managers with a :class:`MagicMock` is common enough and fiddly -enough that a helper function is useful. - - >>> m = mock_open() - >>> with patch('__main__.open', m, create=True): - ... with open('foo', 'w') as h: - ... h.write('some stuff') - ... - >>> m.mock_calls - [call('foo', 'w'), - call().__enter__(), - call().write('some stuff'), - call().__exit__(None, None, None)] - >>> m.assert_called_once_with('foo', 'w') - >>> handle = m() - >>> handle.write.assert_called_once_with('some stuff') - -And for reading files: - - >>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: - ... with open('foo') as h: - ... result = h.read() - ... - >>> m.assert_called_once_with('foo') - >>> assert result == 'bibble' - - -.. _auto-speccing: - -Autospeccing ------------- - -Autospeccing is based on the existing `spec` feature of mock. It limits the -api of mocks to the api of an original object (the spec), but it is recursive -(implemented lazily) so that attributes of mocks only have the same api as -the attributes of the spec. In addition mocked functions / methods have the -same call signature as the original so they raise a `TypeError` if they are -called incorrectly. - -Before I explain how auto-speccing works, here's why it is needed. - -`Mock` is a very powerful and flexible object, but it suffers from two flaws -when used to mock out objects from a system under test. One of these flaws is -specific to the `Mock` api and the other is a more general problem with using -mock objects. - -First the problem specific to `Mock`. `Mock` has two assert methods that are -extremely handy: :meth:`~Mock.assert_called_with` and -:meth:`~Mock.assert_called_once_with`. - - >>> mock = Mock(name='Thing', return_value=None) - >>> mock(1, 2, 3) - >>> mock.assert_called_once_with(1, 2, 3) - >>> mock(1, 2, 3) - >>> mock.assert_called_once_with(1, 2, 3) - Traceback (most recent call last): - ... - AssertionError: Expected to be called once. Called 2 times. - -Because mocks auto-create attributes on demand, and allow you to call them -with arbitrary arguments, if you misspell one of these assert methods then -your assertion is gone: - -.. code-block:: pycon - - >>> mock = Mock(name='Thing', return_value=None) - >>> mock(1, 2, 3) - >>> mock.assret_called_once_with(4, 5, 6) - -Your tests can pass silently and incorrectly because of the typo. - -The second issue is more general to mocking. If you refactor some of your -code, rename members and so on, any tests for code that is still using the -*old api* but uses mocks instead of the real objects will still pass. This -means your tests can all pass even though your code is broken. - -Note that this is another reason why you need integration tests as well as -unit tests. Testing everything in isolation is all fine and dandy, but if you -don't test how your units are "wired together" there is still lots of room -for bugs that tests might have caught. - -`mock` already provides a feature to help with this, called speccing. If you -use a class or instance as the `spec` for a mock then you can only access -attributes on the mock that exist on the real class: - - >>> from urllib import request - >>> mock = Mock(spec=request.Request) - >>> mock.assret_called_with - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'assret_called_with' - -The spec only applies to the mock itself, so we still have the same issue -with any methods on the mock: - -.. code-block:: pycon - - >>> mock.has_data() - - >>> mock.has_data.assret_called_with() - -Auto-speccing solves this problem. You can either pass `autospec=True` to -`patch` / `patch.object` or use the `create_autospec` function to create a -mock with a spec. If you use the `autospec=True` argument to `patch` then the -object that is being replaced will be used as the spec object. Because the -speccing is done "lazily" (the spec is created as attributes on the mock are -accessed) you can use it with very complex or deeply nested objects (like -modules that import modules that import modules) without a big performance -hit. - -Here's an example of it in use: - - >>> from urllib import request - >>> patcher = patch('__main__.request', autospec=True) - >>> mock_request = patcher.start() - >>> request is mock_request - True - >>> mock_request.Request - - -You can see that `request.Request` has a spec. `request.Request` takes two -arguments in the constructor (one of which is `self`). Here's what happens if -we try to call it incorrectly: - - >>> req = request.Request() - Traceback (most recent call last): - ... - TypeError: () takes at least 2 arguments (1 given) - -The spec also applies to instantiated classes (i.e. the return value of -specced mocks): - - >>> req = request.Request('foo') - >>> req - - -`Request` objects are not callable, so the return value of instantiating our -mocked out `request.Request` is a non-callable mock. With the spec in place -any typos in our asserts will raise the correct error: - - >>> req.add_header('spam', 'eggs') - - >>> req.add_header.assret_called_with - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'assret_called_with' - >>> req.add_header.assert_called_with('spam', 'eggs') - -In many cases you will just be able to add `autospec=True` to your existing -`patch` calls and then be protected against bugs due to typos and api -changes. - -As well as using `autospec` through `patch` there is a -:func:`create_autospec` for creating autospecced mocks directly: - - >>> from urllib import request - >>> mock_request = create_autospec(request) - >>> mock_request.Request('foo', 'bar') - - -This isn't without caveats and limitations however, which is why it is not -the default behaviour. In order to know what attributes are available on the -spec object, autospec has to introspect (access attributes) the spec. As you -traverse attributes on the mock a corresponding traversal of the original -object is happening under the hood. If any of your specced objects have -properties or descriptors that can trigger code execution then you may not be -able to use autospec. On the other hand it is much better to design your -objects so that introspection is safe [#]_. - -A more serious problem is that it is common for instance attributes to be -created in the `__init__` method and not to exist on the class at all. -`autospec` can't know about any dynamically created attributes and restricts -the api to visible attributes. - - >>> class Something(object): - ... def __init__(self): - ... self.a = 33 - ... - >>> with patch('__main__.Something', autospec=True): - ... thing = Something() - ... thing.a - ... - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'a' - -There are a few different ways of resolving this problem. The easiest, but -not necessarily the least annoying, way is to simply set the required -attributes on the mock after creation. Just because `autospec` doesn't allow -you to fetch attributes that don't exist on the spec it doesn't prevent you -setting them: - - >>> with patch('__main__.Something', autospec=True): - ... thing = Something() - ... thing.a = 33 - ... - -There is a more aggressive version of both `spec` and `autospec` that *does* -prevent you setting non-existent attributes. This is useful if you want to -ensure your code only *sets* valid attributes too, but obviously it prevents -this particular scenario: - - >>> with patch('__main__.Something', autospec=True, spec_set=True): - ... thing = Something() - ... thing.a = 33 - ... - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'a' - -Probably the best way of solving the problem is to add class attributes as -default values for instance members initialised in `__init__`. Note that if -you are only setting default attributes in `__init__` then providing them via -class attributes (shared between instances of course) is faster too. e.g. - -.. code-block:: python - - class Something(object): - a = 33 - -This brings up another issue. It is relatively common to provide a default -value of `None` for members that will later be an object of a different type. -`None` would be useless as a spec because it wouldn't let you access *any* -attributes or methods on it. As `None` is *never* going to be useful as a -spec, and probably indicates a member that will normally of some other type, -`autospec` doesn't use a spec for members that are set to `None`. These will -just be ordinary mocks (well - `MagicMocks`): - - >>> class Something(object): - ... member = None - ... - >>> mock = create_autospec(Something) - >>> mock.member.foo.bar.baz() - - -If modifying your production classes to add defaults isn't to your liking -then there are more options. One of these is simply to use an instance as the -spec rather than the class. The other is to create a subclass of the -production class and add the defaults to the subclass without affecting the -production class. Both of these require you to use an alternative object as -the spec. Thankfully `patch` supports this - you can simply pass the -alternative object as the `autospec` argument: - - >>> class Something(object): - ... def __init__(self): - ... self.a = 33 - ... - >>> class SomethingForTest(Something): - ... a = 33 - ... - >>> p = patch('__main__.Something', autospec=SomethingForTest) - >>> mock = p.start() - >>> mock.a - - - -.. [#] This only applies to classes or already instantiated objects. Calling - a mocked class to create a mock instance *does not* create a real instance. - It is only attribute lookups - along with calls to `dir` - that are done. diff --git a/Doc/library/unittest.mock-magicmethods.rst b/Doc/library/unittest.mock-magicmethods.rst deleted file mode 100644 --- a/Doc/library/unittest.mock-magicmethods.rst +++ /dev/null @@ -1,226 +0,0 @@ -:mod:`unittest.mock` --- MagicMock and magic method support -=========================================================== - -.. module:: unittest.mock - :synopsis: Mock object library. -.. moduleauthor:: Michael Foord -.. currentmodule:: unittest.mock - -.. versionadded:: 3.3 - - -.. _magic-methods: - -Mocking Magic Methods ---------------------- - -:class:`Mock` supports mocking the Python protocol methods, also known as -"magic methods". This allows mock objects to replace containers or other -objects that implement Python protocols. - -Because magic methods are looked up differently from normal methods [#]_, this -support has been specially implemented. This means that only specific magic -methods are supported. The supported list includes *almost* all of them. If -there are any missing that you need please let us know. - -You mock magic methods by setting the method you are interested in to a function -or a mock instance. If you are using a function then it *must* take ``self`` as -the first argument [#]_. - - >>> def __str__(self): - ... return 'fooble' - ... - >>> mock = Mock() - >>> mock.__str__ = __str__ - >>> str(mock) - 'fooble' - - >>> mock = Mock() - >>> mock.__str__ = Mock() - >>> mock.__str__.return_value = 'fooble' - >>> str(mock) - 'fooble' - - >>> mock = Mock() - >>> mock.__iter__ = Mock(return_value=iter([])) - >>> list(mock) - [] - -One use case for this is for mocking objects used as context managers in a -`with` statement: - - >>> mock = Mock() - >>> mock.__enter__ = Mock(return_value='foo') - >>> mock.__exit__ = Mock(return_value=False) - >>> with mock as m: - ... assert m == 'foo' - ... - >>> mock.__enter__.assert_called_with() - >>> mock.__exit__.assert_called_with(None, None, None) - -Calls to magic methods do not appear in :attr:`~Mock.method_calls`, but they -are recorded in :attr:`~Mock.mock_calls`. - -.. note:: - - If you use the `spec` keyword argument to create a mock then attempting to - set a magic method that isn't in the spec will raise an `AttributeError`. - -The full list of supported magic methods is: - -* ``__hash__``, ``__sizeof__``, ``__repr__`` and ``__str__`` -* ``__dir__``, ``__format__`` and ``__subclasses__`` -* ``__floor__``, ``__trunc__`` and ``__ceil__`` -* Comparisons: ``__cmp__``, ``__lt__``, ``__gt__``, ``__le__``, ``__ge__``, - ``__eq__`` and ``__ne__`` -* Container methods: ``__getitem__``, ``__setitem__``, ``__delitem__``, - ``__contains__``, ``__len__``, ``__iter__``, ``__getslice__``, - ``__setslice__``, ``__reversed__`` and ``__missing__`` -* Context manager: ``__enter__`` and ``__exit__`` -* Unary numeric methods: ``__neg__``, ``__pos__`` and ``__invert__`` -* The numeric methods (including right hand and in-place variants): - ``__add__``, ``__sub__``, ``__mul__``, ``__div__``, - ``__floordiv__``, ``__mod__``, ``__divmod__``, ``__lshift__``, - ``__rshift__``, ``__and__``, ``__xor__``, ``__or__``, and ``__pow__`` -* Numeric conversion methods: ``__complex__``, ``__int__``, ``__float__``, - ``__index__`` and ``__coerce__`` -* Descriptor methods: ``__get__``, ``__set__`` and ``__delete__`` -* Pickling: ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, - ``__getnewargs__``, ``__getstate__`` and ``__setstate__`` - - -The following methods exist but are *not* supported as they are either in use -by mock, can't be set dynamically, or can cause problems: - -* ``__getattr__``, ``__setattr__``, ``__init__`` and ``__new__`` -* ``__prepare__``, ``__instancecheck__``, ``__subclasscheck__``, ``__del__`` - - - -Magic Mock ----------- - -There are two `MagicMock` variants: `MagicMock` and `NonCallableMagicMock`. - - -.. class:: MagicMock(*args, **kw) - - ``MagicMock`` is a subclass of :class:`Mock` with default implementations - of most of the magic methods. You can use ``MagicMock`` without having to - configure the magic methods yourself. - - The constructor parameters have the same meaning as for :class:`Mock`. - - If you use the `spec` or `spec_set` arguments then *only* magic methods - that exist in the spec will be created. - - -.. class:: NonCallableMagicMock(*args, **kw) - - A non-callable version of `MagicMock`. - - The constructor parameters have the same meaning as for - :class:`MagicMock`, with the exception of `return_value` and - `side_effect` which have no meaning on a non-callable mock. - -The magic methods are setup with `MagicMock` objects, so you can configure them -and use them in the usual way: - - >>> mock = MagicMock() - >>> mock[3] = 'fish' - >>> mock.__setitem__.assert_called_with(3, 'fish') - >>> mock.__getitem__.return_value = 'result' - >>> mock[2] - 'result' - -By default many of the protocol methods are required to return objects of a -specific type. These methods are preconfigured with a default return value, so -that they can be used without you having to do anything if you aren't interested -in the return value. You can still *set* the return value manually if you want -to change the default. - -Methods and their defaults: - -* ``__lt__``: NotImplemented -* ``__gt__``: NotImplemented -* ``__le__``: NotImplemented -* ``__ge__``: NotImplemented -* ``__int__`` : 1 -* ``__contains__`` : False -* ``__len__`` : 1 -* ``__iter__`` : iter([]) -* ``__exit__`` : False -* ``__complex__`` : 1j -* ``__float__`` : 1.0 -* ``__bool__`` : True -* ``__index__`` : 1 -* ``__hash__`` : default hash for the mock -* ``__str__`` : default str for the mock -* ``__sizeof__``: default sizeof for the mock - -For example: - - >>> mock = MagicMock() - >>> int(mock) - 1 - >>> len(mock) - 0 - >>> list(mock) - [] - >>> object() in mock - False - -The two equality method, `__eq__` and `__ne__`, are special. -They do the default equality comparison on identity, using a side -effect, unless you change their return value to return something else: - - >>> MagicMock() == 3 - False - >>> MagicMock() != 3 - True - >>> mock = MagicMock() - >>> mock.__eq__.return_value = True - >>> mock == 3 - True - -The return value of `MagicMock.__iter__` can be any iterable object and isn't -required to be an iterator: - - >>> mock = MagicMock() - >>> mock.__iter__.return_value = ['a', 'b', 'c'] - >>> list(mock) - ['a', 'b', 'c'] - >>> list(mock) - ['a', 'b', 'c'] - -If the return value *is* an iterator, then iterating over it once will consume -it and subsequent iterations will result in an empty list: - - >>> mock.__iter__.return_value = iter(['a', 'b', 'c']) - >>> list(mock) - ['a', 'b', 'c'] - >>> list(mock) - [] - -``MagicMock`` has all of the supported magic methods configured except for some -of the obscure and obsolete ones. You can still set these up if you want. - -Magic methods that are supported but not setup by default in ``MagicMock`` are: - -* ``__subclasses__`` -* ``__dir__`` -* ``__format__`` -* ``__get__``, ``__set__`` and ``__delete__`` -* ``__reversed__`` and ``__missing__`` -* ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, ``__getnewargs__``, - ``__getstate__`` and ``__setstate__`` -* ``__getformat__`` and ``__setformat__`` - - - -.. [#] Magic methods *should* be looked up on the class rather than the - instance. Different versions of Python are inconsistent about applying this - rule. The supported protocol methods should work with all supported versions - of Python. -.. [#] The function is basically hooked up to the class, but each ``Mock`` - instance is kept isolated from the others. diff --git a/Doc/library/unittest.mock-patch.rst b/Doc/library/unittest.mock-patch.rst deleted file mode 100644 --- a/Doc/library/unittest.mock-patch.rst +++ /dev/null @@ -1,538 +0,0 @@ -:mod:`unittest.mock` --- the patchers -===================================== - -.. module:: unittest.mock - :synopsis: Mock object library. -.. moduleauthor:: Michael Foord -.. currentmodule:: unittest.mock - -.. versionadded:: 3.3 - -The patch decorators are used for patching objects only within the scope of -the function they decorate. They automatically handle the unpatching for you, -even if exceptions are raised. All of these functions can also be used in with -statements or as class decorators. - - -patch ------ - -.. note:: - - `patch` is straightforward to use. The key is to do the patching in the - right namespace. See the section `where to patch`_. - -.. function:: patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) - - `patch` acts as a function decorator, class decorator or a context - manager. Inside the body of the function or with statement, the `target` - (specified in the form `'package.module.ClassName'`) is patched - with a `new` object. When the function/with statement exits the patch is - undone. - - The `target` is imported and the specified attribute patched with the new - object, so it must be importable from the environment you are calling the - decorator from. The target is imported when the decorated function is - executed, not at decoration time. - - If `new` is omitted, then a new `MagicMock` is created and passed in as an - extra argument to the decorated function. - - The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` - if patch is creating one for you. - - In addition you can pass `spec=True` or `spec_set=True`, which causes - patch to pass in the object being mocked as the spec/spec_set object. - - `new_callable` allows you to specify a different class, or callable object, - that will be called to create the `new` object. By default `MagicMock` is - used. - - A more powerful form of `spec` is `autospec`. If you set `autospec=True` - then the mock with be created with a spec from the object being replaced. - All attributes of the mock will also have the spec of the corresponding - attribute of the object being replaced. Methods and functions being mocked - will have their arguments checked and will raise a `TypeError` if they are - called with the wrong signature. For mocks - replacing a class, their return value (the 'instance') will have the same - spec as the class. See the :func:`create_autospec` function and - :ref:`auto-speccing`. - - Instead of `autospec=True` you can pass `autospec=some_object` to use an - arbitrary object as the spec instead of the one being replaced. - - By default `patch` will fail to replace attributes that don't exist. If - you pass in `create=True`, and the attribute doesn't exist, patch will - create the attribute for you when the patched function is called, and - delete it again afterwards. This is useful for writing tests against - attributes that your production code creates at runtime. It is off by by - default because it can be dangerous. With it switched on you can write - passing tests against APIs that don't actually exist! - - Patch can be used as a `TestCase` class decorator. It works by - decorating each test method in the class. This reduces the boilerplate - code when your test methods share a common patchings set. `patch` finds - tests by looking for method names that start with `patch.TEST_PREFIX`. - By default this is `test`, which matches the way `unittest` finds tests. - You can specify an alternative prefix by setting `patch.TEST_PREFIX`. - - Patch can be used as a context manager, with the with statement. Here the - patching applies to the indented block after the with statement. If you - use "as" then the patched object will be bound to the name after the - "as"; very useful if `patch` is creating a mock object for you. - - `patch` takes arbitrary keyword arguments. These will be passed to - the `Mock` (or `new_callable`) on construction. - - `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are - available for alternate use-cases. - - -Patching a class replaces the class with a `MagicMock` *instance*. If the -class is instantiated in the code under test then it will be the -:attr:`~Mock.return_value` of the mock that will be used. - -If the class is instantiated multiple times you could use -:attr:`~Mock.side_effect` to return a new mock each time. Alternatively you -can set the `return_value` to be anything you want. - -To configure return values on methods of *instances* on the patched class -you must do this on the `return_value`. For example: - - >>> class Class(object): - ... def method(self): - ... pass - ... - >>> with patch('__main__.Class') as MockClass: - ... instance = MockClass.return_value - ... instance.method.return_value = 'foo' - ... assert Class() is instance - ... assert Class().method() == 'foo' - ... - -If you use `spec` or `spec_set` and `patch` is replacing a *class*, then the -return value of the created mock will have the same spec. - - >>> Original = Class - >>> patcher = patch('__main__.Class', spec=True) - >>> MockClass = patcher.start() - >>> instance = MockClass() - >>> assert isinstance(instance, Original) - >>> patcher.stop() - -The `new_callable` argument is useful where you want to use an alternative -class to the default :class:`MagicMock` for the created mock. For example, if -you wanted a :class:`NonCallableMock` to be used: - - >>> thing = object() - >>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing: - ... assert thing is mock_thing - ... thing() - ... - Traceback (most recent call last): - ... - TypeError: 'NonCallableMock' object is not callable - -Another use case might be to replace an object with a `StringIO` instance: - - >>> from StringIO import StringIO - >>> def foo(): - ... print 'Something' - ... - >>> @patch('sys.stdout', new_callable=StringIO) - ... def test(mock_stdout): - ... foo() - ... assert mock_stdout.getvalue() == 'Something\n' - ... - >>> test() - -When `patch` is creating a mock for you, it is common that the first thing -you need to do is to configure the mock. Some of that configuration can be done -in the call to patch. Any arbitrary keywords you pass into the call will be -used to set attributes on the created mock: - - >>> patcher = patch('__main__.thing', first='one', second='two') - >>> mock_thing = patcher.start() - >>> mock_thing.first - 'one' - >>> mock_thing.second - 'two' - -As well as attributes on the created mock attributes, like the -:attr:`~Mock.return_value` and :attr:`~Mock.side_effect`, of child mocks can -also be configured. These aren't syntactically valid to pass in directly as -keyword arguments, but a dictionary with these as keys can still be expanded -into a `patch` call using `**`: - - >>> config = {'method.return_value': 3, 'other.side_effect': KeyError} - >>> patcher = patch('__main__.thing', **config) - >>> mock_thing = patcher.start() - >>> mock_thing.method() - 3 - >>> mock_thing.other() - Traceback (most recent call last): - ... - KeyError - - -patch.object ------------- - -.. function:: patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) - - patch the named member (`attribute`) on an object (`target`) with a mock - object. - - `patch.object` can be used as a decorator, class decorator or a context - manager. Arguments `new`, `spec`, `create`, `spec_set`, `autospec` and - `new_callable` have the same meaning as for `patch`. Like `patch`, - `patch.object` takes arbitrary keyword arguments for configuring the mock - object it creates. - - When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` - for choosing which methods to wrap. - -You can either call `patch.object` with three arguments or two arguments. The -three argument form takes the object to be patched, the attribute name and the -object to replace the attribute with. - -When calling with the two argument form you omit the replacement object, and a -mock is created for you and passed in as an extra argument to the decorated -function: - - >>> @patch.object(SomeClass, 'class_method') - ... def test(mock_method): - ... SomeClass.class_method(3) - ... mock_method.assert_called_with(3) - ... - >>> test() - -`spec`, `create` and the other arguments to `patch.object` have the same -meaning as they do for `patch`. - - -patch.dict ----------- - -.. function:: patch.dict(in_dict, values=(), clear=False, **kwargs) - - Patch a dictionary, or dictionary like object, and restore the dictionary - to its original state after the test. - - `in_dict` can be a dictionary or a mapping like container. If it is a - mapping then it must at least support getting, setting and deleting items - plus iterating over keys. - - `in_dict` can also be a string specifying the name of the dictionary, which - will then be fetched by importing it. - - `values` can be a dictionary of values to set in the dictionary. `values` - can also be an iterable of `(key, value)` pairs. - - If `clear` is True then the dictionary will be cleared before the new - values are set. - - `patch.dict` can also be called with arbitrary keyword arguments to set - values in the dictionary. - - `patch.dict` can be used as a context manager, decorator or class - decorator. When used as a class decorator `patch.dict` honours - `patch.TEST_PREFIX` for choosing which methods to wrap. - -`patch.dict` can be used to add members to a dictionary, or simply let a test -change a dictionary, and ensure the dictionary is restored when the test -ends. - - >>> foo = {} - >>> with patch.dict(foo, {'newkey': 'newvalue'}): - ... assert foo == {'newkey': 'newvalue'} - ... - >>> assert foo == {} - - >>> import os - >>> with patch.dict('os.environ', {'newkey': 'newvalue'}): - ... print os.environ['newkey'] - ... - newvalue - >>> assert 'newkey' not in os.environ - -Keywords can be used in the `patch.dict` call to set values in the dictionary: - - >>> mymodule = MagicMock() - >>> mymodule.function.return_value = 'fish' - >>> with patch.dict('sys.modules', mymodule=mymodule): - ... import mymodule - ... mymodule.function('some', 'args') - ... - 'fish' - -`patch.dict` can be used with dictionary like objects that aren't actually -dictionaries. At the very minimum they must support item getting, setting, -deleting and either iteration or membership test. This corresponds to the -magic methods `__getitem__`, `__setitem__`, `__delitem__` and either -`__iter__` or `__contains__`. - - >>> class Container(object): - ... def __init__(self): - ... self.values = {} - ... def __getitem__(self, name): - ... return self.values[name] - ... def __setitem__(self, name, value): - ... self.values[name] = value - ... def __delitem__(self, name): - ... del self.values[name] - ... def __iter__(self): - ... return iter(self.values) - ... - >>> thing = Container() - >>> thing['one'] = 1 - >>> with patch.dict(thing, one=2, two=3): - ... assert thing['one'] == 2 - ... assert thing['two'] == 3 - ... - >>> assert thing['one'] == 1 - >>> assert list(thing) == ['one'] - - -patch.multiple --------------- - -.. function:: patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) - - Perform multiple patches in a single call. It takes the object to be - patched (either as an object or a string to fetch the object by importing) - and keyword arguments for the patches:: - - with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): - ... - - Use :data:`DEFAULT` as the value if you want `patch.multiple` to create - mocks for you. In this case the created mocks are passed into a decorated - function by keyword, and a dictionary is returned when `patch.multiple` is - used as a context manager. - - `patch.multiple` can be used as a decorator, class decorator or a context - manager. The arguments `spec`, `spec_set`, `create`, `autospec` and - `new_callable` have the same meaning as for `patch`. These arguments will - be applied to *all* patches done by `patch.multiple`. - - When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` - for choosing which methods to wrap. - -If you want `patch.multiple` to create mocks for you, then you can use -:data:`DEFAULT` as the value. If you use `patch.multiple` as a decorator -then the created mocks are passed into the decorated function by keyword. - - >>> thing = object() - >>> other = object() - - >>> @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) - ... def test_function(thing, other): - ... assert isinstance(thing, MagicMock) - ... assert isinstance(other, MagicMock) - ... - >>> test_function() - -`patch.multiple` can be nested with other `patch` decorators, but put arguments -passed by keyword *after* any of the standard arguments created by `patch`: - - >>> @patch('sys.exit') - ... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) - ... def test_function(mock_exit, other, thing): - ... assert 'other' in repr(other) - ... assert 'thing' in repr(thing) - ... assert 'exit' in repr(mock_exit) - ... - >>> test_function() - -If `patch.multiple` is used as a context manager, the value returned by the -context manger is a dictionary where created mocks are keyed by name: - - >>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values: - ... assert 'other' in repr(values['other']) - ... assert 'thing' in repr(values['thing']) - ... assert values['thing'] is thing - ... assert values['other'] is other - ... - - -.. _start-and-stop: - -patch methods: start and stop ------------------------------ - -All the patchers have `start` and `stop` methods. These make it simpler to do -patching in `setUp` methods or where you want to do multiple patches without -nesting decorators or with statements. - -To use them call `patch`, `patch.object` or `patch.dict` as normal and keep a -reference to the returned `patcher` object. You can then call `start` to put -the patch in place and `stop` to undo it. - -If you are using `patch` to create a mock for you then it will be returned by -the call to `patcher.start`. - - >>> patcher = patch('package.module.ClassName') - >>> from package import module - >>> original = module.ClassName - >>> new_mock = patcher.start() - >>> assert module.ClassName is not original - >>> assert module.ClassName is new_mock - >>> patcher.stop() - >>> assert module.ClassName is original - >>> assert module.ClassName is not new_mock - - -A typical use case for this might be for doing multiple patches in the `setUp` -method of a `TestCase`: - - >>> class MyTest(TestCase): - ... def setUp(self): - ... self.patcher1 = patch('package.module.Class1') - ... self.patcher2 = patch('package.module.Class2') - ... self.MockClass1 = self.patcher1.start() - ... self.MockClass2 = self.patcher2.start() - ... - ... def tearDown(self): - ... self.patcher1.stop() - ... self.patcher2.stop() - ... - ... def test_something(self): - ... assert package.module.Class1 is self.MockClass1 - ... assert package.module.Class2 is self.MockClass2 - ... - >>> MyTest('test_something').run() - -.. caution:: - - If you use this technique you must ensure that the patching is "undone" by - calling `stop`. This can be fiddlier than you might think, because if an - exception is raised in the ``setUp`` then ``tearDown`` is not called. - :meth:`unittest.TestCase.addCleanup` makes this easier: - - >>> class MyTest(TestCase): - ... def setUp(self): - ... patcher = patch('package.module.Class') - ... self.MockClass = patcher.start() - ... self.addCleanup(patcher.stop) - ... - ... def test_something(self): - ... assert package.module.Class is self.MockClass - ... - - As an added bonus you no longer need to keep a reference to the `patcher` - object. - -In fact `start` and `stop` are just aliases for the context manager -`__enter__` and `__exit__` methods. - - -TEST_PREFIX ------------ - -All of the patchers can be used as class decorators. When used in this way -they wrap every test method on the class. The patchers recognise methods that -start with `test` as being test methods. This is the same way that the -:class:`unittest.TestLoader` finds test methods by default. - -It is possible that you want to use a different prefix for your tests. You can -inform the patchers of the different prefix by setting `patch.TEST_PREFIX`: - - >>> patch.TEST_PREFIX = 'foo' - >>> value = 3 - >>> - >>> @patch('__main__.value', 'not three') - ... class Thing(object): - ... def foo_one(self): - ... print value - ... def foo_two(self): - ... print value - ... - >>> - >>> Thing().foo_one() - not three - >>> Thing().foo_two() - not three - >>> value - 3 - - -Nesting Patch Decorators ------------------------- - -If you want to perform multiple patches then you can simply stack up the -decorators. - -You can stack up multiple patch decorators using this pattern: - - >>> @patch.object(SomeClass, 'class_method') - ... @patch.object(SomeClass, 'static_method') - ... def test(mock1, mock2): - ... assert SomeClass.static_method is mock1 - ... assert SomeClass.class_method is mock2 - ... SomeClass.static_method('foo') - ... SomeClass.class_method('bar') - ... return mock1, mock2 - ... - >>> mock1, mock2 = test() - >>> mock1.assert_called_once_with('foo') - >>> mock2.assert_called_once_with('bar') - - -Note that the decorators are applied from the bottom upwards. This is the -standard way that Python applies decorators. The order of the created mocks -passed into your test function matches this order. - - -.. _where-to-patch: - -Where to patch --------------- - -`patch` works by (temporarily) changing the object that a *name* points to with -another one. There can be many names pointing to any individual object, so -for patching to work you must ensure that you patch the name used by the system -under test. - -The basic principle is that you patch where an object is *looked up*, which -is not necessarily the same place as where it is defined. A couple of -examples will help to clarify this. - -Imagine we have a project that we want to test with the following structure:: - - a.py - -> Defines SomeClass - - b.py - -> from a import SomeClass - -> some_function instantiates SomeClass - -Now we want to test `some_function` but we want to mock out `SomeClass` using -`patch`. The problem is that when we import module b, which we will have to -do then it imports `SomeClass` from module a. If we use `patch` to mock out -`a.SomeClass` then it will have no effect on our test; module b already has a -reference to the *real* `SomeClass` and it looks like our patching had no -effect. - -The key is to patch out `SomeClass` where it is used (or where it is looked up -). In this case `some_function` will actually look up `SomeClass` in module b, -where we have imported it. The patching should look like:: - - @patch('b.SomeClass') - -However, consider the alternative scenario where instead of `from a import -SomeClass` module b does `import a` and `some_function` uses `a.SomeClass`. Both -of these import forms are common. In this case the class we want to patch is -being looked up on the a module and so we have to patch `a.SomeClass` instead:: - - @patch('a.SomeClass') - - -Patching Descriptors and Proxy Objects --------------------------------------- - -Both patch_ and patch.object_ correctly patch and restore descriptors: class -methods, static methods and properties. You should patch these on the *class* -rather than an instance. They also work with *some* objects -that proxy attribute access, like the `django setttings object -`_. diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -84,7 +84,6 @@ ... def test(MockClass1, MockClass2): ... module.ClassName1() ... module.ClassName2() - ... assert MockClass1 is module.ClassName1 ... assert MockClass2 is module.ClassName2 ... assert MockClass1.called @@ -898,3 +897,1287 @@ will often implicitly request these methods, and gets *very* confused to get a new Mock object when it expects a magic method. If you need magic method support see :ref:`magic methods `. + + +The patchers +============ + +The patch decorators are used for patching objects only within the scope of +the function they decorate. They automatically handle the unpatching for you, +even if exceptions are raised. All of these functions can also be used in with +statements or as class decorators. + + +patch +----- + +.. note:: + + `patch` is straightforward to use. The key is to do the patching in the + right namespace. See the section `where to patch`_. + +.. function:: patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) + + `patch` acts as a function decorator, class decorator or a context + manager. Inside the body of the function or with statement, the `target` + (specified in the form `'package.module.ClassName'`) is patched + with a `new` object. When the function/with statement exits the patch is + undone. + + The `target` is imported and the specified attribute patched with the new + object, so it must be importable from the environment you are calling the + decorator from. The target is imported when the decorated function is + executed, not at decoration time. + + If `new` is omitted, then a new `MagicMock` is created and passed in as an + extra argument to the decorated function. + + The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` + if patch is creating one for you. + + In addition you can pass `spec=True` or `spec_set=True`, which causes + patch to pass in the object being mocked as the spec/spec_set object. + + `new_callable` allows you to specify a different class, or callable object, + that will be called to create the `new` object. By default `MagicMock` is + used. + + A more powerful form of `spec` is `autospec`. If you set `autospec=True` + then the mock with be created with a spec from the object being replaced. + All attributes of the mock will also have the spec of the corresponding + attribute of the object being replaced. Methods and functions being mocked + will have their arguments checked and will raise a `TypeError` if they are + called with the wrong signature. For mocks + replacing a class, their return value (the 'instance') will have the same + spec as the class. See the :func:`create_autospec` function and + :ref:`auto-speccing`. + + Instead of `autospec=True` you can pass `autospec=some_object` to use an + arbitrary object as the spec instead of the one being replaced. + + By default `patch` will fail to replace attributes that don't exist. If + you pass in `create=True`, and the attribute doesn't exist, patch will + create the attribute for you when the patched function is called, and + delete it again afterwards. This is useful for writing tests against + attributes that your production code creates at runtime. It is off by by + default because it can be dangerous. With it switched on you can write + passing tests against APIs that don't actually exist! + + Patch can be used as a `TestCase` class decorator. It works by + decorating each test method in the class. This reduces the boilerplate + code when your test methods share a common patchings set. `patch` finds + tests by looking for method names that start with `patch.TEST_PREFIX`. + By default this is `test`, which matches the way `unittest` finds tests. + You can specify an alternative prefix by setting `patch.TEST_PREFIX`. + + Patch can be used as a context manager, with the with statement. Here the + patching applies to the indented block after the with statement. If you + use "as" then the patched object will be bound to the name after the + "as"; very useful if `patch` is creating a mock object for you. + + `patch` takes arbitrary keyword arguments. These will be passed to + the `Mock` (or `new_callable`) on construction. + + `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are + available for alternate use-cases. + + +Patching a class replaces the class with a `MagicMock` *instance*. If the +class is instantiated in the code under test then it will be the +:attr:`~Mock.return_value` of the mock that will be used. + +If the class is instantiated multiple times you could use +:attr:`~Mock.side_effect` to return a new mock each time. Alternatively you +can set the `return_value` to be anything you want. + +To configure return values on methods of *instances* on the patched class +you must do this on the `return_value`. For example: + + >>> class Class(object): + ... def method(self): + ... pass + ... + >>> with patch('__main__.Class') as MockClass: + ... instance = MockClass.return_value + ... instance.method.return_value = 'foo' + ... assert Class() is instance + ... assert Class().method() == 'foo' + ... + +If you use `spec` or `spec_set` and `patch` is replacing a *class*, then the +return value of the created mock will have the same spec. + + >>> Original = Class + >>> patcher = patch('__main__.Class', spec=True) + >>> MockClass = patcher.start() + >>> instance = MockClass() + >>> assert isinstance(instance, Original) + >>> patcher.stop() + +The `new_callable` argument is useful where you want to use an alternative +class to the default :class:`MagicMock` for the created mock. For example, if +you wanted a :class:`NonCallableMock` to be used: + + >>> thing = object() + >>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing: + ... assert thing is mock_thing + ... thing() + ... + Traceback (most recent call last): + ... + TypeError: 'NonCallableMock' object is not callable + +Another use case might be to replace an object with a `StringIO` instance: + + >>> from StringIO import StringIO + >>> def foo(): + ... print 'Something' + ... + >>> @patch('sys.stdout', new_callable=StringIO) + ... def test(mock_stdout): + ... foo() + ... assert mock_stdout.getvalue() == 'Something\n' + ... + >>> test() + +When `patch` is creating a mock for you, it is common that the first thing +you need to do is to configure the mock. Some of that configuration can be done +in the call to patch. Any arbitrary keywords you pass into the call will be +used to set attributes on the created mock: + + >>> patcher = patch('__main__.thing', first='one', second='two') + >>> mock_thing = patcher.start() + >>> mock_thing.first + 'one' + >>> mock_thing.second + 'two' + +As well as attributes on the created mock attributes, like the +:attr:`~Mock.return_value` and :attr:`~Mock.side_effect`, of child mocks can +also be configured. These aren't syntactically valid to pass in directly as +keyword arguments, but a dictionary with these as keys can still be expanded +into a `patch` call using `**`: + + >>> config = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> patcher = patch('__main__.thing', **config) + >>> mock_thing = patcher.start() + >>> mock_thing.method() + 3 + >>> mock_thing.other() + Traceback (most recent call last): + ... + KeyError + + +patch.object +------------ + +.. function:: patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) + + patch the named member (`attribute`) on an object (`target`) with a mock + object. + + `patch.object` can be used as a decorator, class decorator or a context + manager. Arguments `new`, `spec`, `create`, `spec_set`, `autospec` and + `new_callable` have the same meaning as for `patch`. Like `patch`, + `patch.object` takes arbitrary keyword arguments for configuring the mock + object it creates. + + When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + +You can either call `patch.object` with three arguments or two arguments. The +three argument form takes the object to be patched, the attribute name and the +object to replace the attribute with. + +When calling with the two argument form you omit the replacement object, and a +mock is created for you and passed in as an extra argument to the decorated +function: + + >>> @patch.object(SomeClass, 'class_method') + ... def test(mock_method): + ... SomeClass.class_method(3) + ... mock_method.assert_called_with(3) + ... + >>> test() + +`spec`, `create` and the other arguments to `patch.object` have the same +meaning as they do for `patch`. + + +patch.dict +---------- + +.. function:: patch.dict(in_dict, values=(), clear=False, **kwargs) + + Patch a dictionary, or dictionary like object, and restore the dictionary + to its original state after the test. + + `in_dict` can be a dictionary or a mapping like container. If it is a + mapping then it must at least support getting, setting and deleting items + plus iterating over keys. + + `in_dict` can also be a string specifying the name of the dictionary, which + will then be fetched by importing it. + + `values` can be a dictionary of values to set in the dictionary. `values` + can also be an iterable of `(key, value)` pairs. + + If `clear` is True then the dictionary will be cleared before the new + values are set. + + `patch.dict` can also be called with arbitrary keyword arguments to set + values in the dictionary. + + `patch.dict` can be used as a context manager, decorator or class + decorator. When used as a class decorator `patch.dict` honours + `patch.TEST_PREFIX` for choosing which methods to wrap. + +`patch.dict` can be used to add members to a dictionary, or simply let a test +change a dictionary, and ensure the dictionary is restored when the test +ends. + + >>> foo = {} + >>> with patch.dict(foo, {'newkey': 'newvalue'}): + ... assert foo == {'newkey': 'newvalue'} + ... + >>> assert foo == {} + + >>> import os + >>> with patch.dict('os.environ', {'newkey': 'newvalue'}): + ... print os.environ['newkey'] + ... + newvalue + >>> assert 'newkey' not in os.environ + +Keywords can be used in the `patch.dict` call to set values in the dictionary: + + >>> mymodule = MagicMock() + >>> mymodule.function.return_value = 'fish' + >>> with patch.dict('sys.modules', mymodule=mymodule): + ... import mymodule + ... mymodule.function('some', 'args') + ... + 'fish' + +`patch.dict` can be used with dictionary like objects that aren't actually +dictionaries. At the very minimum they must support item getting, setting, +deleting and either iteration or membership test. This corresponds to the +magic methods `__getitem__`, `__setitem__`, `__delitem__` and either +`__iter__` or `__contains__`. + + >>> class Container(object): + ... def __init__(self): + ... self.values = {} + ... def __getitem__(self, name): + ... return self.values[name] + ... def __setitem__(self, name, value): + ... self.values[name] = value + ... def __delitem__(self, name): + ... del self.values[name] + ... def __iter__(self): + ... return iter(self.values) + ... + >>> thing = Container() + >>> thing['one'] = 1 + >>> with patch.dict(thing, one=2, two=3): + ... assert thing['one'] == 2 + ... assert thing['two'] == 3 + ... + >>> assert thing['one'] == 1 + >>> assert list(thing) == ['one'] + + +patch.multiple +-------------- + +.. function:: patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) + + Perform multiple patches in a single call. It takes the object to be + patched (either as an object or a string to fetch the object by importing) + and keyword arguments for the patches:: + + with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): + ... + + Use :data:`DEFAULT` as the value if you want `patch.multiple` to create + mocks for you. In this case the created mocks are passed into a decorated + function by keyword, and a dictionary is returned when `patch.multiple` is + used as a context manager. + + `patch.multiple` can be used as a decorator, class decorator or a context + manager. The arguments `spec`, `spec_set`, `create`, `autospec` and + `new_callable` have the same meaning as for `patch`. These arguments will + be applied to *all* patches done by `patch.multiple`. + + When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + +If you want `patch.multiple` to create mocks for you, then you can use +:data:`DEFAULT` as the value. If you use `patch.multiple` as a decorator +then the created mocks are passed into the decorated function by keyword. + + >>> thing = object() + >>> other = object() + + >>> @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) + ... def test_function(thing, other): + ... assert isinstance(thing, MagicMock) + ... assert isinstance(other, MagicMock) + ... + >>> test_function() + +`patch.multiple` can be nested with other `patch` decorators, but put arguments +passed by keyword *after* any of the standard arguments created by `patch`: + + >>> @patch('sys.exit') + ... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) + ... def test_function(mock_exit, other, thing): + ... assert 'other' in repr(other) + ... assert 'thing' in repr(thing) + ... assert 'exit' in repr(mock_exit) + ... + >>> test_function() + +If `patch.multiple` is used as a context manager, the value returned by the +context manger is a dictionary where created mocks are keyed by name: + + >>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values: + ... assert 'other' in repr(values['other']) + ... assert 'thing' in repr(values['thing']) + ... assert values['thing'] is thing + ... assert values['other'] is other + ... + + +.. _start-and-stop: + +patch methods: start and stop +----------------------------- + +All the patchers have `start` and `stop` methods. These make it simpler to do +patching in `setUp` methods or where you want to do multiple patches without +nesting decorators or with statements. + +To use them call `patch`, `patch.object` or `patch.dict` as normal and keep a +reference to the returned `patcher` object. You can then call `start` to put +the patch in place and `stop` to undo it. + +If you are using `patch` to create a mock for you then it will be returned by +the call to `patcher.start`. + + >>> patcher = patch('package.module.ClassName') + >>> from package import module + >>> original = module.ClassName + >>> new_mock = patcher.start() + >>> assert module.ClassName is not original + >>> assert module.ClassName is new_mock + >>> patcher.stop() + >>> assert module.ClassName is original + >>> assert module.ClassName is not new_mock + + +A typical use case for this might be for doing multiple patches in the `setUp` +method of a `TestCase`: + + >>> class MyTest(TestCase): + ... def setUp(self): + ... self.patcher1 = patch('package.module.Class1') + ... self.patcher2 = patch('package.module.Class2') + ... self.MockClass1 = self.patcher1.start() + ... self.MockClass2 = self.patcher2.start() + ... + ... def tearDown(self): + ... self.patcher1.stop() + ... self.patcher2.stop() + ... + ... def test_something(self): + ... assert package.module.Class1 is self.MockClass1 + ... assert package.module.Class2 is self.MockClass2 + ... + >>> MyTest('test_something').run() + +.. caution:: + + If you use this technique you must ensure that the patching is "undone" by + calling `stop`. This can be fiddlier than you might think, because if an + exception is raised in the ``setUp`` then ``tearDown`` is not called. + :meth:`unittest.TestCase.addCleanup` makes this easier: + + >>> class MyTest(TestCase): + ... def setUp(self): + ... patcher = patch('package.module.Class') + ... self.MockClass = patcher.start() + ... self.addCleanup(patcher.stop) + ... + ... def test_something(self): + ... assert package.module.Class is self.MockClass + ... + + As an added bonus you no longer need to keep a reference to the `patcher` + object. + +In fact `start` and `stop` are just aliases for the context manager +`__enter__` and `__exit__` methods. + + +TEST_PREFIX +----------- + +All of the patchers can be used as class decorators. When used in this way +they wrap every test method on the class. The patchers recognise methods that +start with `test` as being test methods. This is the same way that the +:class:`unittest.TestLoader` finds test methods by default. + +It is possible that you want to use a different prefix for your tests. You can +inform the patchers of the different prefix by setting `patch.TEST_PREFIX`: + + >>> patch.TEST_PREFIX = 'foo' + >>> value = 3 + >>> + >>> @patch('__main__.value', 'not three') + ... class Thing(object): + ... def foo_one(self): + ... print value + ... def foo_two(self): + ... print value + ... + >>> + >>> Thing().foo_one() + not three + >>> Thing().foo_two() + not three + >>> value + 3 + + +Nesting Patch Decorators +------------------------ + +If you want to perform multiple patches then you can simply stack up the +decorators. + +You can stack up multiple patch decorators using this pattern: + + >>> @patch.object(SomeClass, 'class_method') + ... @patch.object(SomeClass, 'static_method') + ... def test(mock1, mock2): + ... assert SomeClass.static_method is mock1 + ... assert SomeClass.class_method is mock2 + ... SomeClass.static_method('foo') + ... SomeClass.class_method('bar') + ... return mock1, mock2 + ... + >>> mock1, mock2 = test() + >>> mock1.assert_called_once_with('foo') + >>> mock2.assert_called_once_with('bar') + + +Note that the decorators are applied from the bottom upwards. This is the +standard way that Python applies decorators. The order of the created mocks +passed into your test function matches this order. + + +.. _where-to-patch: + +Where to patch +-------------- + +`patch` works by (temporarily) changing the object that a *name* points to with +another one. There can be many names pointing to any individual object, so +for patching to work you must ensure that you patch the name used by the system +under test. + +The basic principle is that you patch where an object is *looked up*, which +is not necessarily the same place as where it is defined. A couple of +examples will help to clarify this. + +Imagine we have a project that we want to test with the following structure:: + + a.py + -> Defines SomeClass + + b.py + -> from a import SomeClass + -> some_function instantiates SomeClass + +Now we want to test `some_function` but we want to mock out `SomeClass` using +`patch`. The problem is that when we import module b, which we will have to +do then it imports `SomeClass` from module a. If we use `patch` to mock out +`a.SomeClass` then it will have no effect on our test; module b already has a +reference to the *real* `SomeClass` and it looks like our patching had no +effect. + +The key is to patch out `SomeClass` where it is used (or where it is looked up +). In this case `some_function` will actually look up `SomeClass` in module b, +where we have imported it. The patching should look like:: + + @patch('b.SomeClass') + +However, consider the alternative scenario where instead of `from a import +SomeClass` module b does `import a` and `some_function` uses `a.SomeClass`. Both +of these import forms are common. In this case the class we want to patch is +being looked up on the a module and so we have to patch `a.SomeClass` instead:: + + @patch('a.SomeClass') + + +Patching Descriptors and Proxy Objects +-------------------------------------- + +Both patch_ and patch.object_ correctly patch and restore descriptors: class +methods, static methods and properties. You should patch these on the *class* +rather than an instance. They also work with *some* objects +that proxy attribute access, like the `django setttings object +`_. + + +Helpers +======= + +sentinel +-------- + +.. data:: sentinel + + The ``sentinel`` object provides a convenient way of providing unique + objects for your tests. + + Attributes are created on demand when you access them by name. Accessing + the same attribute will always return the same object. The objects + returned have a sensible repr so that test failure messages are readable. + +Sometimes when testing you need to test that a specific object is passed as an +argument to another method, or returned. It can be common to create named +sentinel objects to test this. `sentinel` provides a convenient way of +creating and testing the identity of objects like this. + +In this example we monkey patch `method` to return `sentinel.some_object`: + + >>> real = ProductionClass() + >>> real.method = Mock(name="method") + >>> real.method.return_value = sentinel.some_object + >>> result = real.method() + >>> assert result is sentinel.some_object + >>> sentinel.some_object + sentinel.some_object + + +DEFAULT +------- + + +.. data:: DEFAULT + + The `DEFAULT` object is a pre-created sentinel (actually + `sentinel.DEFAULT`). It can be used by :attr:`~Mock.side_effect` + functions to indicate that the normal return value should be used. + + + +call +---- + +.. function:: call(*args, **kwargs) + + `call` is a helper object for making simpler assertions, for comparing + with :attr:`~Mock.call_args`, :attr:`~Mock.call_args_list`, + :attr:`~Mock.mock_calls` and:attr: `~Mock.method_calls`. `call` can also be + used with :meth:`~Mock.assert_has_calls`. + + >>> m = MagicMock(return_value=None) + >>> m(1, 2, a='foo', b='bar') + >>> m() + >>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()] + True + +.. method:: call.call_list() + + For a call object that represents multiple calls, `call_list` + returns a list of all the intermediate calls as well as the + final call. + +`call_list` is particularly useful for making assertions on "chained calls". A +chained call is multiple calls on a single line of code. This results in +multiple entries in :attr:`~Mock.mock_calls` on a mock. Manually constructing +the sequence of calls can be tedious. + +:meth:`~call.call_list` can construct the sequence of calls from the same +chained call: + + >>> m = MagicMock() + >>> m(1).method(arg='foo').other('bar')(2.0) + + >>> kall = call(1).method(arg='foo').other('bar')(2.0) + >>> kall.call_list() + [call(1), + call().method(arg='foo'), + call().method().other('bar'), + call().method().other()(2.0)] + >>> m.mock_calls == kall.call_list() + True + +.. _calls-as-tuples: + +A `call` object is either a tuple of (positional args, keyword args) or +(name, positional args, keyword args) depending on how it was constructed. When +you construct them yourself this isn't particularly interesting, but the `call` +objects that are in the :attr:`Mock.call_args`, :attr:`Mock.call_args_list` and +:attr:`Mock.mock_calls` attributes can be introspected to get at the individual +arguments they contain. + +The `call` objects in :attr:`Mock.call_args` and :attr:`Mock.call_args_list` +are two-tuples of (positional args, keyword args) whereas the `call` objects +in :attr:`Mock.mock_calls`, along with ones you construct yourself, are +three-tuples of (name, positional args, keyword args). + +You can use their "tupleness" to pull out the individual arguments for more +complex introspection and assertions. The positional arguments are a tuple +(an empty tuple if there are no positional arguments) and the keyword +arguments are a dictionary: + + >>> m = MagicMock(return_value=None) + >>> m(1, 2, 3, arg='one', arg2='two') + >>> kall = m.call_args + >>> args, kwargs = kall + >>> args + (1, 2, 3) + >>> kwargs + {'arg2': 'two', 'arg': 'one'} + >>> args is kall[0] + True + >>> kwargs is kall[1] + True + + >>> m = MagicMock() + >>> m.foo(4, 5, 6, arg='two', arg2='three') + + >>> kall = m.mock_calls[0] + >>> name, args, kwargs = kall + >>> name + 'foo' + >>> args + (4, 5, 6) + >>> kwargs + {'arg2': 'three', 'arg': 'two'} + >>> name is m.mock_calls[0][0] + True + + +create_autospec +--------------- + +.. function:: create_autospec(spec, spec_set=False, instance=False, **kwargs) + + Create a mock object using another object as a spec. Attributes on the + mock will use the corresponding attribute on the `spec` object as their + spec. + + Functions or methods being mocked will have their arguments checked to + ensure that they are called with the correct signature. + + If `spec_set` is `True` then attempting to set attributes that don't exist + on the spec object will raise an `AttributeError`. + + If a class is used as a spec then the return value of the mock (the + instance of the class) will have the same spec. You can use a class as the + spec for an instance object by passing `instance=True`. The returned mock + will only be callable if instances of the mock are callable. + + `create_autospec` also takes arbitrary keyword arguments that are passed to + the constructor of the created mock. + +See :ref:`auto-speccing` for examples of how to use auto-speccing with +`create_autospec` and the `autospec` argument to :func:`patch`. + + +ANY +--- + +.. data:: ANY + +Sometimes you may need to make assertions about *some* of the arguments in a +call to mock, but either not care about some of the arguments or want to pull +them individually out of :attr:`~Mock.call_args` and make more complex +assertions on them. + +To ignore certain arguments you can pass in objects that compare equal to +*everything*. Calls to :meth:`~Mock.assert_called_with` and +:meth:`~Mock.assert_called_once_with` will then succeed no matter what was +passed in. + + >>> mock = Mock(return_value=None) + >>> mock('foo', bar=object()) + >>> mock.assert_called_once_with('foo', bar=ANY) + +`ANY` can also be used in comparisons with call lists like +:attr:`~Mock.mock_calls`: + + >>> m = MagicMock(return_value=None) + >>> m(1) + >>> m(1, 2) + >>> m(object()) + >>> m.mock_calls == [call(1), call(1, 2), ANY] + True + + + +FILTER_DIR +---------- + +.. data:: FILTER_DIR + +`FILTER_DIR` is a module level variable that controls the way mock objects +respond to `dir` (only for Python 2.6 or more recent). The default is `True`, +which uses the filtering described below, to only show useful members. If you +dislike this filtering, or need to switch it off for diagnostic purposes, then +set `mock.FILTER_DIR = False`. + +With filtering on, `dir(some_mock)` shows only useful attributes and will +include any dynamically created attributes that wouldn't normally be shown. +If the mock was created with a `spec` (or `autospec` of course) then all the +attributes from the original are shown, even if they haven't been accessed +yet: + + >>> dir(Mock()) + ['assert_any_call', + 'assert_called_once_with', + 'assert_called_with', + 'assert_has_calls', + 'attach_mock', + ... + >>> from urllib import request + >>> dir(Mock(spec=request)) + ['AbstractBasicAuthHandler', + 'AbstractDigestAuthHandler', + 'AbstractHTTPHandler', + 'BaseHandler', + ... + +Many of the not-very-useful (private to `Mock` rather than the thing being +mocked) underscore and double underscore prefixed attributes have been +filtered from the result of calling `dir` on a `Mock`. If you dislike this +behaviour you can switch it off by setting the module level switch +`FILTER_DIR`: + + >>> from unittest import mock + >>> mock.FILTER_DIR = False + >>> dir(mock.Mock()) + ['_NonCallableMock__get_return_value', + '_NonCallableMock__get_side_effect', + '_NonCallableMock__return_value_doc', + '_NonCallableMock__set_return_value', + '_NonCallableMock__set_side_effect', + '__call__', + '__class__', + ... + +Alternatively you can just use `vars(my_mock)` (instance members) and +`dir(type(my_mock))` (type members) to bypass the filtering irrespective of +`mock.FILTER_DIR`. + + +mock_open +--------- + +.. function:: mock_open(mock=None, read_data=None) + + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` method of the file handle to return. + This is an empty string by default. + +Using `open` as a context manager is a great way to ensure your file handles +are closed properly and is becoming common:: + + with open('/some/path', 'w') as f: + f.write('something') + +The issue is that even if you mock out the call to `open` it is the +*returned object* that is used as a context manager (and has `__enter__` and +`__exit__` called). + +Mocking context managers with a :class:`MagicMock` is common enough and fiddly +enough that a helper function is useful. + + >>> m = mock_open() + >>> with patch('__main__.open', m, create=True): + ... with open('foo', 'w') as h: + ... h.write('some stuff') + ... + >>> m.mock_calls + [call('foo', 'w'), + call().__enter__(), + call().write('some stuff'), + call().__exit__(None, None, None)] + >>> m.assert_called_once_with('foo', 'w') + >>> handle = m() + >>> handle.write.assert_called_once_with('some stuff') + +And for reading files: + + >>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: + ... with open('foo') as h: + ... result = h.read() + ... + >>> m.assert_called_once_with('foo') + >>> assert result == 'bibble' + + +.. _auto-speccing: + +Autospeccing +------------ + +Autospeccing is based on the existing `spec` feature of mock. It limits the +api of mocks to the api of an original object (the spec), but it is recursive +(implemented lazily) so that attributes of mocks only have the same api as +the attributes of the spec. In addition mocked functions / methods have the +same call signature as the original so they raise a `TypeError` if they are +called incorrectly. + +Before I explain how auto-speccing works, here's why it is needed. + +`Mock` is a very powerful and flexible object, but it suffers from two flaws +when used to mock out objects from a system under test. One of these flaws is +specific to the `Mock` api and the other is a more general problem with using +mock objects. + +First the problem specific to `Mock`. `Mock` has two assert methods that are +extremely handy: :meth:`~Mock.assert_called_with` and +:meth:`~Mock.assert_called_once_with`. + + >>> mock = Mock(name='Thing', return_value=None) + >>> mock(1, 2, 3) + >>> mock.assert_called_once_with(1, 2, 3) + >>> mock(1, 2, 3) + >>> mock.assert_called_once_with(1, 2, 3) + Traceback (most recent call last): + ... + AssertionError: Expected to be called once. Called 2 times. + +Because mocks auto-create attributes on demand, and allow you to call them +with arbitrary arguments, if you misspell one of these assert methods then +your assertion is gone: + +.. code-block:: pycon + + >>> mock = Mock(name='Thing', return_value=None) + >>> mock(1, 2, 3) + >>> mock.assret_called_once_with(4, 5, 6) + +Your tests can pass silently and incorrectly because of the typo. + +The second issue is more general to mocking. If you refactor some of your +code, rename members and so on, any tests for code that is still using the +*old api* but uses mocks instead of the real objects will still pass. This +means your tests can all pass even though your code is broken. + +Note that this is another reason why you need integration tests as well as +unit tests. Testing everything in isolation is all fine and dandy, but if you +don't test how your units are "wired together" there is still lots of room +for bugs that tests might have caught. + +`mock` already provides a feature to help with this, called speccing. If you +use a class or instance as the `spec` for a mock then you can only access +attributes on the mock that exist on the real class: + + >>> from urllib import request + >>> mock = Mock(spec=request.Request) + >>> mock.assret_called_with + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'assret_called_with' + +The spec only applies to the mock itself, so we still have the same issue +with any methods on the mock: + +.. code-block:: pycon + + >>> mock.has_data() + + >>> mock.has_data.assret_called_with() + +Auto-speccing solves this problem. You can either pass `autospec=True` to +`patch` / `patch.object` or use the `create_autospec` function to create a +mock with a spec. If you use the `autospec=True` argument to `patch` then the +object that is being replaced will be used as the spec object. Because the +speccing is done "lazily" (the spec is created as attributes on the mock are +accessed) you can use it with very complex or deeply nested objects (like +modules that import modules that import modules) without a big performance +hit. + +Here's an example of it in use: + + >>> from urllib import request + >>> patcher = patch('__main__.request', autospec=True) + >>> mock_request = patcher.start() + >>> request is mock_request + True + >>> mock_request.Request + + +You can see that `request.Request` has a spec. `request.Request` takes two +arguments in the constructor (one of which is `self`). Here's what happens if +we try to call it incorrectly: + + >>> req = request.Request() + Traceback (most recent call last): + ... + TypeError: () takes at least 2 arguments (1 given) + +The spec also applies to instantiated classes (i.e. the return value of +specced mocks): + + >>> req = request.Request('foo') + >>> req + + +`Request` objects are not callable, so the return value of instantiating our +mocked out `request.Request` is a non-callable mock. With the spec in place +any typos in our asserts will raise the correct error: + + >>> req.add_header('spam', 'eggs') + + >>> req.add_header.assret_called_with + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'assret_called_with' + >>> req.add_header.assert_called_with('spam', 'eggs') + +In many cases you will just be able to add `autospec=True` to your existing +`patch` calls and then be protected against bugs due to typos and api +changes. + +As well as using `autospec` through `patch` there is a +:func:`create_autospec` for creating autospecced mocks directly: + + >>> from urllib import request + >>> mock_request = create_autospec(request) + >>> mock_request.Request('foo', 'bar') + + +This isn't without caveats and limitations however, which is why it is not +the default behaviour. In order to know what attributes are available on the +spec object, autospec has to introspect (access attributes) the spec. As you +traverse attributes on the mock a corresponding traversal of the original +object is happening under the hood. If any of your specced objects have +properties or descriptors that can trigger code execution then you may not be +able to use autospec. On the other hand it is much better to design your +objects so that introspection is safe [#]_. + +A more serious problem is that it is common for instance attributes to be +created in the `__init__` method and not to exist on the class at all. +`autospec` can't know about any dynamically created attributes and restricts +the api to visible attributes. + + >>> class Something(object): + ... def __init__(self): + ... self.a = 33 + ... + >>> with patch('__main__.Something', autospec=True): + ... thing = Something() + ... thing.a + ... + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'a' + +There are a few different ways of resolving this problem. The easiest, but +not necessarily the least annoying, way is to simply set the required +attributes on the mock after creation. Just because `autospec` doesn't allow +you to fetch attributes that don't exist on the spec it doesn't prevent you +setting them: + + >>> with patch('__main__.Something', autospec=True): + ... thing = Something() + ... thing.a = 33 + ... + +There is a more aggressive version of both `spec` and `autospec` that *does* +prevent you setting non-existent attributes. This is useful if you want to +ensure your code only *sets* valid attributes too, but obviously it prevents +this particular scenario: + + >>> with patch('__main__.Something', autospec=True, spec_set=True): + ... thing = Something() + ... thing.a = 33 + ... + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'a' + +Probably the best way of solving the problem is to add class attributes as +default values for instance members initialised in `__init__`. Note that if +you are only setting default attributes in `__init__` then providing them via +class attributes (shared between instances of course) is faster too. e.g. + +.. code-block:: python + + class Something(object): + a = 33 + +This brings up another issue. It is relatively common to provide a default +value of `None` for members that will later be an object of a different type. +`None` would be useless as a spec because it wouldn't let you access *any* +attributes or methods on it. As `None` is *never* going to be useful as a +spec, and probably indicates a member that will normally of some other type, +`autospec` doesn't use a spec for members that are set to `None`. These will +just be ordinary mocks (well - `MagicMocks`): + + >>> class Something(object): + ... member = None + ... + >>> mock = create_autospec(Something) + >>> mock.member.foo.bar.baz() + + +If modifying your production classes to add defaults isn't to your liking +then there are more options. One of these is simply to use an instance as the +spec rather than the class. The other is to create a subclass of the +production class and add the defaults to the subclass without affecting the +production class. Both of these require you to use an alternative object as +the spec. Thankfully `patch` supports this - you can simply pass the +alternative object as the `autospec` argument: + + >>> class Something(object): + ... def __init__(self): + ... self.a = 33 + ... + >>> class SomethingForTest(Something): + ... a = 33 + ... + >>> p = patch('__main__.Something', autospec=SomethingForTest) + >>> mock = p.start() + >>> mock.a + + + +.. [#] This only applies to classes or already instantiated objects. Calling + a mocked class to create a mock instance *does not* create a real instance. + It is only attribute lookups - along with calls to `dir` - that are done. + + +MagicMock and magic method support +================================== + +.. _magic-methods: + +Mocking Magic Methods +--------------------- + +:class:`Mock` supports mocking the Python protocol methods, also known as +"magic methods". This allows mock objects to replace containers or other +objects that implement Python protocols. + +Because magic methods are looked up differently from normal methods [#]_, this +support has been specially implemented. This means that only specific magic +methods are supported. The supported list includes *almost* all of them. If +there are any missing that you need please let us know. + +You mock magic methods by setting the method you are interested in to a function +or a mock instance. If you are using a function then it *must* take ``self`` as +the first argument [#]_. + + >>> def __str__(self): + ... return 'fooble' + ... + >>> mock = Mock() + >>> mock.__str__ = __str__ + >>> str(mock) + 'fooble' + + >>> mock = Mock() + >>> mock.__str__ = Mock() + >>> mock.__str__.return_value = 'fooble' + >>> str(mock) + 'fooble' + + >>> mock = Mock() + >>> mock.__iter__ = Mock(return_value=iter([])) + >>> list(mock) + [] + +One use case for this is for mocking objects used as context managers in a +`with` statement: + + >>> mock = Mock() + >>> mock.__enter__ = Mock(return_value='foo') + >>> mock.__exit__ = Mock(return_value=False) + >>> with mock as m: + ... assert m == 'foo' + ... + >>> mock.__enter__.assert_called_with() + >>> mock.__exit__.assert_called_with(None, None, None) + +Calls to magic methods do not appear in :attr:`~Mock.method_calls`, but they +are recorded in :attr:`~Mock.mock_calls`. + +.. note:: + + If you use the `spec` keyword argument to create a mock then attempting to + set a magic method that isn't in the spec will raise an `AttributeError`. + +The full list of supported magic methods is: + +* ``__hash__``, ``__sizeof__``, ``__repr__`` and ``__str__`` +* ``__dir__``, ``__format__`` and ``__subclasses__`` +* ``__floor__``, ``__trunc__`` and ``__ceil__`` +* Comparisons: ``__cmp__``, ``__lt__``, ``__gt__``, ``__le__``, ``__ge__``, + ``__eq__`` and ``__ne__`` +* Container methods: ``__getitem__``, ``__setitem__``, ``__delitem__``, + ``__contains__``, ``__len__``, ``__iter__``, ``__getslice__``, + ``__setslice__``, ``__reversed__`` and ``__missing__`` +* Context manager: ``__enter__`` and ``__exit__`` +* Unary numeric methods: ``__neg__``, ``__pos__`` and ``__invert__`` +* The numeric methods (including right hand and in-place variants): + ``__add__``, ``__sub__``, ``__mul__``, ``__div__``, + ``__floordiv__``, ``__mod__``, ``__divmod__``, ``__lshift__``, + ``__rshift__``, ``__and__``, ``__xor__``, ``__or__``, and ``__pow__`` +* Numeric conversion methods: ``__complex__``, ``__int__``, ``__float__``, + ``__index__`` and ``__coerce__`` +* Descriptor methods: ``__get__``, ``__set__`` and ``__delete__`` +* Pickling: ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, + ``__getnewargs__``, ``__getstate__`` and ``__setstate__`` + + +The following methods exist but are *not* supported as they are either in use +by mock, can't be set dynamically, or can cause problems: + +* ``__getattr__``, ``__setattr__``, ``__init__`` and ``__new__`` +* ``__prepare__``, ``__instancecheck__``, ``__subclasscheck__``, ``__del__`` + + + +Magic Mock +---------- + +There are two `MagicMock` variants: `MagicMock` and `NonCallableMagicMock`. + + +.. class:: MagicMock(*args, **kw) + + ``MagicMock`` is a subclass of :class:`Mock` with default implementations + of most of the magic methods. You can use ``MagicMock`` without having to + configure the magic methods yourself. + + The constructor parameters have the same meaning as for :class:`Mock`. + + If you use the `spec` or `spec_set` arguments then *only* magic methods + that exist in the spec will be created. + + +.. class:: NonCallableMagicMock(*args, **kw) + + A non-callable version of `MagicMock`. + + The constructor parameters have the same meaning as for + :class:`MagicMock`, with the exception of `return_value` and + `side_effect` which have no meaning on a non-callable mock. + +The magic methods are setup with `MagicMock` objects, so you can configure them +and use them in the usual way: + + >>> mock = MagicMock() + >>> mock[3] = 'fish' + >>> mock.__setitem__.assert_called_with(3, 'fish') + >>> mock.__getitem__.return_value = 'result' + >>> mock[2] + 'result' + +By default many of the protocol methods are required to return objects of a +specific type. These methods are preconfigured with a default return value, so +that they can be used without you having to do anything if you aren't interested +in the return value. You can still *set* the return value manually if you want +to change the default. + +Methods and their defaults: + +* ``__lt__``: NotImplemented +* ``__gt__``: NotImplemented +* ``__le__``: NotImplemented +* ``__ge__``: NotImplemented +* ``__int__`` : 1 +* ``__contains__`` : False +* ``__len__`` : 1 +* ``__iter__`` : iter([]) +* ``__exit__`` : False +* ``__complex__`` : 1j +* ``__float__`` : 1.0 +* ``__bool__`` : True +* ``__index__`` : 1 +* ``__hash__`` : default hash for the mock +* ``__str__`` : default str for the mock +* ``__sizeof__``: default sizeof for the mock + +For example: + + >>> mock = MagicMock() + >>> int(mock) + 1 + >>> len(mock) + 0 + >>> list(mock) + [] + >>> object() in mock + False + +The two equality method, `__eq__` and `__ne__`, are special. +They do the default equality comparison on identity, using a side +effect, unless you change their return value to return something else: + + >>> MagicMock() == 3 + False + >>> MagicMock() != 3 + True + >>> mock = MagicMock() + >>> mock.__eq__.return_value = True + >>> mock == 3 + True + +The return value of `MagicMock.__iter__` can be any iterable object and isn't +required to be an iterator: + + >>> mock = MagicMock() + >>> mock.__iter__.return_value = ['a', 'b', 'c'] + >>> list(mock) + ['a', 'b', 'c'] + >>> list(mock) + ['a', 'b', 'c'] + +If the return value *is* an iterator, then iterating over it once will consume +it and subsequent iterations will result in an empty list: + + >>> mock.__iter__.return_value = iter(['a', 'b', 'c']) + >>> list(mock) + ['a', 'b', 'c'] + >>> list(mock) + [] + +``MagicMock`` has all of the supported magic methods configured except for some +of the obscure and obsolete ones. You can still set these up if you want. + +Magic methods that are supported but not setup by default in ``MagicMock`` are: + +* ``__subclasses__`` +* ``__dir__`` +* ``__format__`` +* ``__get__``, ``__set__`` and ``__delete__`` +* ``__reversed__`` and ``__missing__`` +* ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, ``__getnewargs__``, + ``__getstate__`` and ``__setstate__`` +* ``__getformat__`` and ``__setformat__`` + + + +.. [#] Magic methods *should* be looked up on the class rather than the + instance. Different versions of Python are inconsistent about applying this + rule. The supported protocol methods should work with all supported versions + of Python. +.. [#] The function is basically hooked up to the class, but each ``Mock`` + instance is kept isolated from the others. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 28 16:08:05 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 28 Mar 2012 16:08:05 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Minor_unittest=2Emock=2Epat?= =?utf8?q?ch_doc_/_docstring_improvement?= Message-ID: http://hg.python.org/cpython/rev/cd83fe4e3191 changeset: 75972:cd83fe4e3191 user: Michael Foord date: Wed Mar 28 15:08:08 2012 +0100 summary: Minor unittest.mock.patch doc / docstring improvement files: Doc/library/unittest.mock.rst | 25 +++++++++++--------- Lib/unittest/mock.py | 27 +++++++++++++--------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -920,17 +920,20 @@ `patch` acts as a function decorator, class decorator or a context manager. Inside the body of the function or with statement, the `target` - (specified in the form `'package.module.ClassName'`) is patched - with a `new` object. When the function/with statement exits the patch is - undone. - - The `target` is imported and the specified attribute patched with the new - object, so it must be importable from the environment you are calling the - decorator from. The target is imported when the decorated function is - executed, not at decoration time. - - If `new` is omitted, then a new `MagicMock` is created and passed in as an - extra argument to the decorated function. + is patched with a `new` object. When the function/with statement exits + the patch is undone. + + If `new` is omitted, then the target is replaced with a + :class:`MagicMock`. If `patch` is used as a decorator and `new` is + omitted, the created mock is passed in as an extra argument to the + decorated function. If `patch` is used as a context manager the created + mock is returned by the context manager. + + `target` should be a string in the form `'package.module.ClassName'`. The + `target` is imported and the specified object replaced with the `new` + object, so the `target` must be importable from the environment you are + calling `patch` from. The target is imported when the decorated function + is executed, not at decoration time. The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` if patch is creating one for you. diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1351,18 +1351,23 @@ ): """ `patch` acts as a function decorator, class decorator or a context + + `patch` acts as a function decorator, class decorator or a context manager. Inside the body of the function or with statement, the `target` - (specified in the form `'package.module.ClassName'`) is patched - with a `new` object. When the function/with statement exits the patch is - undone. - - The `target` is imported and the specified attribute patched with the new - object, so it must be importable from the environment you are calling the - decorator from. The target is imported when the decorated function is - executed, not at decoration time. - - If `new` is omitted, then a new `MagicMock` is created and passed in as an - extra argument to the decorated function. + is patched with a `new` object. When the function/with statement exits + the patch is undone. + + If `new` is omitted, then the target is replaced with a + `MagicMock`. If `patch` is used as a decorator and `new` is + omitted, the created mock is passed in as an extra argument to the + decorated function. If `patch` is used as a context manager the created + mock is returned by the context manager. + + `target` should be a string in the form `'package.module.ClassName'`. The + `target` is imported and the specified object replaced with the `new` + object, so the `target` must be importable from the environment you are + calling `patch` from. The target is imported when the decorated function + is executed, not at decoration time. The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` if patch is creating one for you. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 28 16:31:58 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 28 Mar 2012 16:31:58 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Adding_an_example_to_unitte?= =?utf8?q?st=2Emock=2Epatch_documentation?= Message-ID: http://hg.python.org/cpython/rev/635fe162934e changeset: 75973:635fe162934e user: Michael Foord date: Wed Mar 28 15:32:08 2012 +0100 summary: Adding an example to unittest.mock.patch documentation files: Doc/library/unittest.mock.rst | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -984,6 +984,15 @@ `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are available for alternate use-cases. +`patch` as function decorator, creating the mock for you and passing it into +the decorated function: + + >>> @patch('__main__.SomeClass') + ... def function(mock_class): + ... print(mock_class is SomeClass) + ... + >>> function() + True Patching a class replaces the class with a `MagicMock` *instance*. If the class is instantiated in the code under test then it will be the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 28 16:38:24 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 28 Mar 2012 16:38:24 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Re-order_unittest=2Emock_do?= =?utf8?q?cumentation_to_put_magic_method_support_before_the?= Message-ID: http://hg.python.org/cpython/rev/05830173b3ce changeset: 75974:05830173b3ce user: Michael Foord date: Wed Mar 28 15:38:36 2012 +0100 summary: Re-order unittest.mock documentation to put magic method support before the helpers files: Doc/library/unittest.mock.rst | 1055 ++++++++++---------- 1 files changed, 532 insertions(+), 523 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -1444,537 +1444,6 @@ `_. -Helpers -======= - -sentinel --------- - -.. data:: sentinel - - The ``sentinel`` object provides a convenient way of providing unique - objects for your tests. - - Attributes are created on demand when you access them by name. Accessing - the same attribute will always return the same object. The objects - returned have a sensible repr so that test failure messages are readable. - -Sometimes when testing you need to test that a specific object is passed as an -argument to another method, or returned. It can be common to create named -sentinel objects to test this. `sentinel` provides a convenient way of -creating and testing the identity of objects like this. - -In this example we monkey patch `method` to return `sentinel.some_object`: - - >>> real = ProductionClass() - >>> real.method = Mock(name="method") - >>> real.method.return_value = sentinel.some_object - >>> result = real.method() - >>> assert result is sentinel.some_object - >>> sentinel.some_object - sentinel.some_object - - -DEFAULT -------- - - -.. data:: DEFAULT - - The `DEFAULT` object is a pre-created sentinel (actually - `sentinel.DEFAULT`). It can be used by :attr:`~Mock.side_effect` - functions to indicate that the normal return value should be used. - - - -call ----- - -.. function:: call(*args, **kwargs) - - `call` is a helper object for making simpler assertions, for comparing - with :attr:`~Mock.call_args`, :attr:`~Mock.call_args_list`, - :attr:`~Mock.mock_calls` and:attr: `~Mock.method_calls`. `call` can also be - used with :meth:`~Mock.assert_has_calls`. - - >>> m = MagicMock(return_value=None) - >>> m(1, 2, a='foo', b='bar') - >>> m() - >>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()] - True - -.. method:: call.call_list() - - For a call object that represents multiple calls, `call_list` - returns a list of all the intermediate calls as well as the - final call. - -`call_list` is particularly useful for making assertions on "chained calls". A -chained call is multiple calls on a single line of code. This results in -multiple entries in :attr:`~Mock.mock_calls` on a mock. Manually constructing -the sequence of calls can be tedious. - -:meth:`~call.call_list` can construct the sequence of calls from the same -chained call: - - >>> m = MagicMock() - >>> m(1).method(arg='foo').other('bar')(2.0) - - >>> kall = call(1).method(arg='foo').other('bar')(2.0) - >>> kall.call_list() - [call(1), - call().method(arg='foo'), - call().method().other('bar'), - call().method().other()(2.0)] - >>> m.mock_calls == kall.call_list() - True - -.. _calls-as-tuples: - -A `call` object is either a tuple of (positional args, keyword args) or -(name, positional args, keyword args) depending on how it was constructed. When -you construct them yourself this isn't particularly interesting, but the `call` -objects that are in the :attr:`Mock.call_args`, :attr:`Mock.call_args_list` and -:attr:`Mock.mock_calls` attributes can be introspected to get at the individual -arguments they contain. - -The `call` objects in :attr:`Mock.call_args` and :attr:`Mock.call_args_list` -are two-tuples of (positional args, keyword args) whereas the `call` objects -in :attr:`Mock.mock_calls`, along with ones you construct yourself, are -three-tuples of (name, positional args, keyword args). - -You can use their "tupleness" to pull out the individual arguments for more -complex introspection and assertions. The positional arguments are a tuple -(an empty tuple if there are no positional arguments) and the keyword -arguments are a dictionary: - - >>> m = MagicMock(return_value=None) - >>> m(1, 2, 3, arg='one', arg2='two') - >>> kall = m.call_args - >>> args, kwargs = kall - >>> args - (1, 2, 3) - >>> kwargs - {'arg2': 'two', 'arg': 'one'} - >>> args is kall[0] - True - >>> kwargs is kall[1] - True - - >>> m = MagicMock() - >>> m.foo(4, 5, 6, arg='two', arg2='three') - - >>> kall = m.mock_calls[0] - >>> name, args, kwargs = kall - >>> name - 'foo' - >>> args - (4, 5, 6) - >>> kwargs - {'arg2': 'three', 'arg': 'two'} - >>> name is m.mock_calls[0][0] - True - - -create_autospec ---------------- - -.. function:: create_autospec(spec, spec_set=False, instance=False, **kwargs) - - Create a mock object using another object as a spec. Attributes on the - mock will use the corresponding attribute on the `spec` object as their - spec. - - Functions or methods being mocked will have their arguments checked to - ensure that they are called with the correct signature. - - If `spec_set` is `True` then attempting to set attributes that don't exist - on the spec object will raise an `AttributeError`. - - If a class is used as a spec then the return value of the mock (the - instance of the class) will have the same spec. You can use a class as the - spec for an instance object by passing `instance=True`. The returned mock - will only be callable if instances of the mock are callable. - - `create_autospec` also takes arbitrary keyword arguments that are passed to - the constructor of the created mock. - -See :ref:`auto-speccing` for examples of how to use auto-speccing with -`create_autospec` and the `autospec` argument to :func:`patch`. - - -ANY ---- - -.. data:: ANY - -Sometimes you may need to make assertions about *some* of the arguments in a -call to mock, but either not care about some of the arguments or want to pull -them individually out of :attr:`~Mock.call_args` and make more complex -assertions on them. - -To ignore certain arguments you can pass in objects that compare equal to -*everything*. Calls to :meth:`~Mock.assert_called_with` and -:meth:`~Mock.assert_called_once_with` will then succeed no matter what was -passed in. - - >>> mock = Mock(return_value=None) - >>> mock('foo', bar=object()) - >>> mock.assert_called_once_with('foo', bar=ANY) - -`ANY` can also be used in comparisons with call lists like -:attr:`~Mock.mock_calls`: - - >>> m = MagicMock(return_value=None) - >>> m(1) - >>> m(1, 2) - >>> m(object()) - >>> m.mock_calls == [call(1), call(1, 2), ANY] - True - - - -FILTER_DIR ----------- - -.. data:: FILTER_DIR - -`FILTER_DIR` is a module level variable that controls the way mock objects -respond to `dir` (only for Python 2.6 or more recent). The default is `True`, -which uses the filtering described below, to only show useful members. If you -dislike this filtering, or need to switch it off for diagnostic purposes, then -set `mock.FILTER_DIR = False`. - -With filtering on, `dir(some_mock)` shows only useful attributes and will -include any dynamically created attributes that wouldn't normally be shown. -If the mock was created with a `spec` (or `autospec` of course) then all the -attributes from the original are shown, even if they haven't been accessed -yet: - - >>> dir(Mock()) - ['assert_any_call', - 'assert_called_once_with', - 'assert_called_with', - 'assert_has_calls', - 'attach_mock', - ... - >>> from urllib import request - >>> dir(Mock(spec=request)) - ['AbstractBasicAuthHandler', - 'AbstractDigestAuthHandler', - 'AbstractHTTPHandler', - 'BaseHandler', - ... - -Many of the not-very-useful (private to `Mock` rather than the thing being -mocked) underscore and double underscore prefixed attributes have been -filtered from the result of calling `dir` on a `Mock`. If you dislike this -behaviour you can switch it off by setting the module level switch -`FILTER_DIR`: - - >>> from unittest import mock - >>> mock.FILTER_DIR = False - >>> dir(mock.Mock()) - ['_NonCallableMock__get_return_value', - '_NonCallableMock__get_side_effect', - '_NonCallableMock__return_value_doc', - '_NonCallableMock__set_return_value', - '_NonCallableMock__set_side_effect', - '__call__', - '__class__', - ... - -Alternatively you can just use `vars(my_mock)` (instance members) and -`dir(type(my_mock))` (type members) to bypass the filtering irrespective of -`mock.FILTER_DIR`. - - -mock_open ---------- - -.. function:: mock_open(mock=None, read_data=None) - - A helper function to create a mock to replace the use of `open`. It works - for `open` called directly or used as a context manager. - - The `mock` argument is the mock object to configure. If `None` (the - default) then a `MagicMock` will be created for you, with the API limited - to methods or attributes available on standard file handles. - - `read_data` is a string for the `read` method of the file handle to return. - This is an empty string by default. - -Using `open` as a context manager is a great way to ensure your file handles -are closed properly and is becoming common:: - - with open('/some/path', 'w') as f: - f.write('something') - -The issue is that even if you mock out the call to `open` it is the -*returned object* that is used as a context manager (and has `__enter__` and -`__exit__` called). - -Mocking context managers with a :class:`MagicMock` is common enough and fiddly -enough that a helper function is useful. - - >>> m = mock_open() - >>> with patch('__main__.open', m, create=True): - ... with open('foo', 'w') as h: - ... h.write('some stuff') - ... - >>> m.mock_calls - [call('foo', 'w'), - call().__enter__(), - call().write('some stuff'), - call().__exit__(None, None, None)] - >>> m.assert_called_once_with('foo', 'w') - >>> handle = m() - >>> handle.write.assert_called_once_with('some stuff') - -And for reading files: - - >>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: - ... with open('foo') as h: - ... result = h.read() - ... - >>> m.assert_called_once_with('foo') - >>> assert result == 'bibble' - - -.. _auto-speccing: - -Autospeccing ------------- - -Autospeccing is based on the existing `spec` feature of mock. It limits the -api of mocks to the api of an original object (the spec), but it is recursive -(implemented lazily) so that attributes of mocks only have the same api as -the attributes of the spec. In addition mocked functions / methods have the -same call signature as the original so they raise a `TypeError` if they are -called incorrectly. - -Before I explain how auto-speccing works, here's why it is needed. - -`Mock` is a very powerful and flexible object, but it suffers from two flaws -when used to mock out objects from a system under test. One of these flaws is -specific to the `Mock` api and the other is a more general problem with using -mock objects. - -First the problem specific to `Mock`. `Mock` has two assert methods that are -extremely handy: :meth:`~Mock.assert_called_with` and -:meth:`~Mock.assert_called_once_with`. - - >>> mock = Mock(name='Thing', return_value=None) - >>> mock(1, 2, 3) - >>> mock.assert_called_once_with(1, 2, 3) - >>> mock(1, 2, 3) - >>> mock.assert_called_once_with(1, 2, 3) - Traceback (most recent call last): - ... - AssertionError: Expected to be called once. Called 2 times. - -Because mocks auto-create attributes on demand, and allow you to call them -with arbitrary arguments, if you misspell one of these assert methods then -your assertion is gone: - -.. code-block:: pycon - - >>> mock = Mock(name='Thing', return_value=None) - >>> mock(1, 2, 3) - >>> mock.assret_called_once_with(4, 5, 6) - -Your tests can pass silently and incorrectly because of the typo. - -The second issue is more general to mocking. If you refactor some of your -code, rename members and so on, any tests for code that is still using the -*old api* but uses mocks instead of the real objects will still pass. This -means your tests can all pass even though your code is broken. - -Note that this is another reason why you need integration tests as well as -unit tests. Testing everything in isolation is all fine and dandy, but if you -don't test how your units are "wired together" there is still lots of room -for bugs that tests might have caught. - -`mock` already provides a feature to help with this, called speccing. If you -use a class or instance as the `spec` for a mock then you can only access -attributes on the mock that exist on the real class: - - >>> from urllib import request - >>> mock = Mock(spec=request.Request) - >>> mock.assret_called_with - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'assret_called_with' - -The spec only applies to the mock itself, so we still have the same issue -with any methods on the mock: - -.. code-block:: pycon - - >>> mock.has_data() - - >>> mock.has_data.assret_called_with() - -Auto-speccing solves this problem. You can either pass `autospec=True` to -`patch` / `patch.object` or use the `create_autospec` function to create a -mock with a spec. If you use the `autospec=True` argument to `patch` then the -object that is being replaced will be used as the spec object. Because the -speccing is done "lazily" (the spec is created as attributes on the mock are -accessed) you can use it with very complex or deeply nested objects (like -modules that import modules that import modules) without a big performance -hit. - -Here's an example of it in use: - - >>> from urllib import request - >>> patcher = patch('__main__.request', autospec=True) - >>> mock_request = patcher.start() - >>> request is mock_request - True - >>> mock_request.Request - - -You can see that `request.Request` has a spec. `request.Request` takes two -arguments in the constructor (one of which is `self`). Here's what happens if -we try to call it incorrectly: - - >>> req = request.Request() - Traceback (most recent call last): - ... - TypeError: () takes at least 2 arguments (1 given) - -The spec also applies to instantiated classes (i.e. the return value of -specced mocks): - - >>> req = request.Request('foo') - >>> req - - -`Request` objects are not callable, so the return value of instantiating our -mocked out `request.Request` is a non-callable mock. With the spec in place -any typos in our asserts will raise the correct error: - - >>> req.add_header('spam', 'eggs') - - >>> req.add_header.assret_called_with - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'assret_called_with' - >>> req.add_header.assert_called_with('spam', 'eggs') - -In many cases you will just be able to add `autospec=True` to your existing -`patch` calls and then be protected against bugs due to typos and api -changes. - -As well as using `autospec` through `patch` there is a -:func:`create_autospec` for creating autospecced mocks directly: - - >>> from urllib import request - >>> mock_request = create_autospec(request) - >>> mock_request.Request('foo', 'bar') - - -This isn't without caveats and limitations however, which is why it is not -the default behaviour. In order to know what attributes are available on the -spec object, autospec has to introspect (access attributes) the spec. As you -traverse attributes on the mock a corresponding traversal of the original -object is happening under the hood. If any of your specced objects have -properties or descriptors that can trigger code execution then you may not be -able to use autospec. On the other hand it is much better to design your -objects so that introspection is safe [#]_. - -A more serious problem is that it is common for instance attributes to be -created in the `__init__` method and not to exist on the class at all. -`autospec` can't know about any dynamically created attributes and restricts -the api to visible attributes. - - >>> class Something(object): - ... def __init__(self): - ... self.a = 33 - ... - >>> with patch('__main__.Something', autospec=True): - ... thing = Something() - ... thing.a - ... - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'a' - -There are a few different ways of resolving this problem. The easiest, but -not necessarily the least annoying, way is to simply set the required -attributes on the mock after creation. Just because `autospec` doesn't allow -you to fetch attributes that don't exist on the spec it doesn't prevent you -setting them: - - >>> with patch('__main__.Something', autospec=True): - ... thing = Something() - ... thing.a = 33 - ... - -There is a more aggressive version of both `spec` and `autospec` that *does* -prevent you setting non-existent attributes. This is useful if you want to -ensure your code only *sets* valid attributes too, but obviously it prevents -this particular scenario: - - >>> with patch('__main__.Something', autospec=True, spec_set=True): - ... thing = Something() - ... thing.a = 33 - ... - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'a' - -Probably the best way of solving the problem is to add class attributes as -default values for instance members initialised in `__init__`. Note that if -you are only setting default attributes in `__init__` then providing them via -class attributes (shared between instances of course) is faster too. e.g. - -.. code-block:: python - - class Something(object): - a = 33 - -This brings up another issue. It is relatively common to provide a default -value of `None` for members that will later be an object of a different type. -`None` would be useless as a spec because it wouldn't let you access *any* -attributes or methods on it. As `None` is *never* going to be useful as a -spec, and probably indicates a member that will normally of some other type, -`autospec` doesn't use a spec for members that are set to `None`. These will -just be ordinary mocks (well - `MagicMocks`): - - >>> class Something(object): - ... member = None - ... - >>> mock = create_autospec(Something) - >>> mock.member.foo.bar.baz() - - -If modifying your production classes to add defaults isn't to your liking -then there are more options. One of these is simply to use an instance as the -spec rather than the class. The other is to create a subclass of the -production class and add the defaults to the subclass without affecting the -production class. Both of these require you to use an alternative object as -the spec. Thankfully `patch` supports this - you can simply pass the -alternative object as the `autospec` argument: - - >>> class Something(object): - ... def __init__(self): - ... self.a = 33 - ... - >>> class SomethingForTest(Something): - ... a = 33 - ... - >>> p = patch('__main__.Something', autospec=SomethingForTest) - >>> mock = p.start() - >>> mock.a - - - -.. [#] This only applies to classes or already instantiated objects. Calling - a mocked class to create a mock instance *does not* create a real instance. - It is only attribute lookups - along with calls to `dir` - that are done. - - MagicMock and magic method support ================================== @@ -2193,3 +1662,535 @@ of Python. .. [#] The function is basically hooked up to the class, but each ``Mock`` instance is kept isolated from the others. + + +Helpers +======= + +sentinel +-------- + +.. data:: sentinel + + The ``sentinel`` object provides a convenient way of providing unique + objects for your tests. + + Attributes are created on demand when you access them by name. Accessing + the same attribute will always return the same object. The objects + returned have a sensible repr so that test failure messages are readable. + +Sometimes when testing you need to test that a specific object is passed as an +argument to another method, or returned. It can be common to create named +sentinel objects to test this. `sentinel` provides a convenient way of +creating and testing the identity of objects like this. + +In this example we monkey patch `method` to return `sentinel.some_object`: + + >>> real = ProductionClass() + >>> real.method = Mock(name="method") + >>> real.method.return_value = sentinel.some_object + >>> result = real.method() + >>> assert result is sentinel.some_object + >>> sentinel.some_object + sentinel.some_object + + +DEFAULT +------- + + +.. data:: DEFAULT + + The `DEFAULT` object is a pre-created sentinel (actually + `sentinel.DEFAULT`). It can be used by :attr:`~Mock.side_effect` + functions to indicate that the normal return value should be used. + + + +call +---- + +.. function:: call(*args, **kwargs) + + `call` is a helper object for making simpler assertions, for comparing + with :attr:`~Mock.call_args`, :attr:`~Mock.call_args_list`, + :attr:`~Mock.mock_calls` and:attr: `~Mock.method_calls`. `call` can also be + used with :meth:`~Mock.assert_has_calls`. + + >>> m = MagicMock(return_value=None) + >>> m(1, 2, a='foo', b='bar') + >>> m() + >>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()] + True + +.. method:: call.call_list() + + For a call object that represents multiple calls, `call_list` + returns a list of all the intermediate calls as well as the + final call. + +`call_list` is particularly useful for making assertions on "chained calls". A +chained call is multiple calls on a single line of code. This results in +multiple entries in :attr:`~Mock.mock_calls` on a mock. Manually constructing +the sequence of calls can be tedious. + +:meth:`~call.call_list` can construct the sequence of calls from the same +chained call: + + >>> m = MagicMock() + >>> m(1).method(arg='foo').other('bar')(2.0) + + >>> kall = call(1).method(arg='foo').other('bar')(2.0) + >>> kall.call_list() + [call(1), + call().method(arg='foo'), + call().method().other('bar'), + call().method().other()(2.0)] + >>> m.mock_calls == kall.call_list() + True + +.. _calls-as-tuples: + +A `call` object is either a tuple of (positional args, keyword args) or +(name, positional args, keyword args) depending on how it was constructed. When +you construct them yourself this isn't particularly interesting, but the `call` +objects that are in the :attr:`Mock.call_args`, :attr:`Mock.call_args_list` and +:attr:`Mock.mock_calls` attributes can be introspected to get at the individual +arguments they contain. + +The `call` objects in :attr:`Mock.call_args` and :attr:`Mock.call_args_list` +are two-tuples of (positional args, keyword args) whereas the `call` objects +in :attr:`Mock.mock_calls`, along with ones you construct yourself, are +three-tuples of (name, positional args, keyword args). + +You can use their "tupleness" to pull out the individual arguments for more +complex introspection and assertions. The positional arguments are a tuple +(an empty tuple if there are no positional arguments) and the keyword +arguments are a dictionary: + + >>> m = MagicMock(return_value=None) + >>> m(1, 2, 3, arg='one', arg2='two') + >>> kall = m.call_args + >>> args, kwargs = kall + >>> args + (1, 2, 3) + >>> kwargs + {'arg2': 'two', 'arg': 'one'} + >>> args is kall[0] + True + >>> kwargs is kall[1] + True + + >>> m = MagicMock() + >>> m.foo(4, 5, 6, arg='two', arg2='three') + + >>> kall = m.mock_calls[0] + >>> name, args, kwargs = kall + >>> name + 'foo' + >>> args + (4, 5, 6) + >>> kwargs + {'arg2': 'three', 'arg': 'two'} + >>> name is m.mock_calls[0][0] + True + + +create_autospec +--------------- + +.. function:: create_autospec(spec, spec_set=False, instance=False, **kwargs) + + Create a mock object using another object as a spec. Attributes on the + mock will use the corresponding attribute on the `spec` object as their + spec. + + Functions or methods being mocked will have their arguments checked to + ensure that they are called with the correct signature. + + If `spec_set` is `True` then attempting to set attributes that don't exist + on the spec object will raise an `AttributeError`. + + If a class is used as a spec then the return value of the mock (the + instance of the class) will have the same spec. You can use a class as the + spec for an instance object by passing `instance=True`. The returned mock + will only be callable if instances of the mock are callable. + + `create_autospec` also takes arbitrary keyword arguments that are passed to + the constructor of the created mock. + +See :ref:`auto-speccing` for examples of how to use auto-speccing with +`create_autospec` and the `autospec` argument to :func:`patch`. + + +ANY +--- + +.. data:: ANY + +Sometimes you may need to make assertions about *some* of the arguments in a +call to mock, but either not care about some of the arguments or want to pull +them individually out of :attr:`~Mock.call_args` and make more complex +assertions on them. + +To ignore certain arguments you can pass in objects that compare equal to +*everything*. Calls to :meth:`~Mock.assert_called_with` and +:meth:`~Mock.assert_called_once_with` will then succeed no matter what was +passed in. + + >>> mock = Mock(return_value=None) + >>> mock('foo', bar=object()) + >>> mock.assert_called_once_with('foo', bar=ANY) + +`ANY` can also be used in comparisons with call lists like +:attr:`~Mock.mock_calls`: + + >>> m = MagicMock(return_value=None) + >>> m(1) + >>> m(1, 2) + >>> m(object()) + >>> m.mock_calls == [call(1), call(1, 2), ANY] + True + + + +FILTER_DIR +---------- + +.. data:: FILTER_DIR + +`FILTER_DIR` is a module level variable that controls the way mock objects +respond to `dir` (only for Python 2.6 or more recent). The default is `True`, +which uses the filtering described below, to only show useful members. If you +dislike this filtering, or need to switch it off for diagnostic purposes, then +set `mock.FILTER_DIR = False`. + +With filtering on, `dir(some_mock)` shows only useful attributes and will +include any dynamically created attributes that wouldn't normally be shown. +If the mock was created with a `spec` (or `autospec` of course) then all the +attributes from the original are shown, even if they haven't been accessed +yet: + + >>> dir(Mock()) + ['assert_any_call', + 'assert_called_once_with', + 'assert_called_with', + 'assert_has_calls', + 'attach_mock', + ... + >>> from urllib import request + >>> dir(Mock(spec=request)) + ['AbstractBasicAuthHandler', + 'AbstractDigestAuthHandler', + 'AbstractHTTPHandler', + 'BaseHandler', + ... + +Many of the not-very-useful (private to `Mock` rather than the thing being +mocked) underscore and double underscore prefixed attributes have been +filtered from the result of calling `dir` on a `Mock`. If you dislike this +behaviour you can switch it off by setting the module level switch +`FILTER_DIR`: + + >>> from unittest import mock + >>> mock.FILTER_DIR = False + >>> dir(mock.Mock()) + ['_NonCallableMock__get_return_value', + '_NonCallableMock__get_side_effect', + '_NonCallableMock__return_value_doc', + '_NonCallableMock__set_return_value', + '_NonCallableMock__set_side_effect', + '__call__', + '__class__', + ... + +Alternatively you can just use `vars(my_mock)` (instance members) and +`dir(type(my_mock))` (type members) to bypass the filtering irrespective of +`mock.FILTER_DIR`. + + +mock_open +--------- + +.. function:: mock_open(mock=None, read_data=None) + + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` method of the file handle to return. + This is an empty string by default. + +Using `open` as a context manager is a great way to ensure your file handles +are closed properly and is becoming common:: + + with open('/some/path', 'w') as f: + f.write('something') + +The issue is that even if you mock out the call to `open` it is the +*returned object* that is used as a context manager (and has `__enter__` and +`__exit__` called). + +Mocking context managers with a :class:`MagicMock` is common enough and fiddly +enough that a helper function is useful. + + >>> m = mock_open() + >>> with patch('__main__.open', m, create=True): + ... with open('foo', 'w') as h: + ... h.write('some stuff') + ... + >>> m.mock_calls + [call('foo', 'w'), + call().__enter__(), + call().write('some stuff'), + call().__exit__(None, None, None)] + >>> m.assert_called_once_with('foo', 'w') + >>> handle = m() + >>> handle.write.assert_called_once_with('some stuff') + +And for reading files: + + >>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: + ... with open('foo') as h: + ... result = h.read() + ... + >>> m.assert_called_once_with('foo') + >>> assert result == 'bibble' + + +.. _auto-speccing: + +Autospeccing +------------ + +Autospeccing is based on the existing `spec` feature of mock. It limits the +api of mocks to the api of an original object (the spec), but it is recursive +(implemented lazily) so that attributes of mocks only have the same api as +the attributes of the spec. In addition mocked functions / methods have the +same call signature as the original so they raise a `TypeError` if they are +called incorrectly. + +Before I explain how auto-speccing works, here's why it is needed. + +`Mock` is a very powerful and flexible object, but it suffers from two flaws +when used to mock out objects from a system under test. One of these flaws is +specific to the `Mock` api and the other is a more general problem with using +mock objects. + +First the problem specific to `Mock`. `Mock` has two assert methods that are +extremely handy: :meth:`~Mock.assert_called_with` and +:meth:`~Mock.assert_called_once_with`. + + >>> mock = Mock(name='Thing', return_value=None) + >>> mock(1, 2, 3) + >>> mock.assert_called_once_with(1, 2, 3) + >>> mock(1, 2, 3) + >>> mock.assert_called_once_with(1, 2, 3) + Traceback (most recent call last): + ... + AssertionError: Expected to be called once. Called 2 times. + +Because mocks auto-create attributes on demand, and allow you to call them +with arbitrary arguments, if you misspell one of these assert methods then +your assertion is gone: + +.. code-block:: pycon + + >>> mock = Mock(name='Thing', return_value=None) + >>> mock(1, 2, 3) + >>> mock.assret_called_once_with(4, 5, 6) + +Your tests can pass silently and incorrectly because of the typo. + +The second issue is more general to mocking. If you refactor some of your +code, rename members and so on, any tests for code that is still using the +*old api* but uses mocks instead of the real objects will still pass. This +means your tests can all pass even though your code is broken. + +Note that this is another reason why you need integration tests as well as +unit tests. Testing everything in isolation is all fine and dandy, but if you +don't test how your units are "wired together" there is still lots of room +for bugs that tests might have caught. + +`mock` already provides a feature to help with this, called speccing. If you +use a class or instance as the `spec` for a mock then you can only access +attributes on the mock that exist on the real class: + + >>> from urllib import request + >>> mock = Mock(spec=request.Request) + >>> mock.assret_called_with + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'assret_called_with' + +The spec only applies to the mock itself, so we still have the same issue +with any methods on the mock: + +.. code-block:: pycon + + >>> mock.has_data() + + >>> mock.has_data.assret_called_with() + +Auto-speccing solves this problem. You can either pass `autospec=True` to +`patch` / `patch.object` or use the `create_autospec` function to create a +mock with a spec. If you use the `autospec=True` argument to `patch` then the +object that is being replaced will be used as the spec object. Because the +speccing is done "lazily" (the spec is created as attributes on the mock are +accessed) you can use it with very complex or deeply nested objects (like +modules that import modules that import modules) without a big performance +hit. + +Here's an example of it in use: + + >>> from urllib import request + >>> patcher = patch('__main__.request', autospec=True) + >>> mock_request = patcher.start() + >>> request is mock_request + True + >>> mock_request.Request + + +You can see that `request.Request` has a spec. `request.Request` takes two +arguments in the constructor (one of which is `self`). Here's what happens if +we try to call it incorrectly: + + >>> req = request.Request() + Traceback (most recent call last): + ... + TypeError: () takes at least 2 arguments (1 given) + +The spec also applies to instantiated classes (i.e. the return value of +specced mocks): + + >>> req = request.Request('foo') + >>> req + + +`Request` objects are not callable, so the return value of instantiating our +mocked out `request.Request` is a non-callable mock. With the spec in place +any typos in our asserts will raise the correct error: + + >>> req.add_header('spam', 'eggs') + + >>> req.add_header.assret_called_with + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'assret_called_with' + >>> req.add_header.assert_called_with('spam', 'eggs') + +In many cases you will just be able to add `autospec=True` to your existing +`patch` calls and then be protected against bugs due to typos and api +changes. + +As well as using `autospec` through `patch` there is a +:func:`create_autospec` for creating autospecced mocks directly: + + >>> from urllib import request + >>> mock_request = create_autospec(request) + >>> mock_request.Request('foo', 'bar') + + +This isn't without caveats and limitations however, which is why it is not +the default behaviour. In order to know what attributes are available on the +spec object, autospec has to introspect (access attributes) the spec. As you +traverse attributes on the mock a corresponding traversal of the original +object is happening under the hood. If any of your specced objects have +properties or descriptors that can trigger code execution then you may not be +able to use autospec. On the other hand it is much better to design your +objects so that introspection is safe [#]_. + +A more serious problem is that it is common for instance attributes to be +created in the `__init__` method and not to exist on the class at all. +`autospec` can't know about any dynamically created attributes and restricts +the api to visible attributes. + + >>> class Something(object): + ... def __init__(self): + ... self.a = 33 + ... + >>> with patch('__main__.Something', autospec=True): + ... thing = Something() + ... thing.a + ... + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'a' + +There are a few different ways of resolving this problem. The easiest, but +not necessarily the least annoying, way is to simply set the required +attributes on the mock after creation. Just because `autospec` doesn't allow +you to fetch attributes that don't exist on the spec it doesn't prevent you +setting them: + + >>> with patch('__main__.Something', autospec=True): + ... thing = Something() + ... thing.a = 33 + ... + +There is a more aggressive version of both `spec` and `autospec` that *does* +prevent you setting non-existent attributes. This is useful if you want to +ensure your code only *sets* valid attributes too, but obviously it prevents +this particular scenario: + + >>> with patch('__main__.Something', autospec=True, spec_set=True): + ... thing = Something() + ... thing.a = 33 + ... + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'a' + +Probably the best way of solving the problem is to add class attributes as +default values for instance members initialised in `__init__`. Note that if +you are only setting default attributes in `__init__` then providing them via +class attributes (shared between instances of course) is faster too. e.g. + +.. code-block:: python + + class Something(object): + a = 33 + +This brings up another issue. It is relatively common to provide a default +value of `None` for members that will later be an object of a different type. +`None` would be useless as a spec because it wouldn't let you access *any* +attributes or methods on it. As `None` is *never* going to be useful as a +spec, and probably indicates a member that will normally of some other type, +`autospec` doesn't use a spec for members that are set to `None`. These will +just be ordinary mocks (well - `MagicMocks`): + + >>> class Something(object): + ... member = None + ... + >>> mock = create_autospec(Something) + >>> mock.member.foo.bar.baz() + + +If modifying your production classes to add defaults isn't to your liking +then there are more options. One of these is simply to use an instance as the +spec rather than the class. The other is to create a subclass of the +production class and add the defaults to the subclass without affecting the +production class. Both of these require you to use an alternative object as +the spec. Thankfully `patch` supports this - you can simply pass the +alternative object as the `autospec` argument: + + >>> class Something(object): + ... def __init__(self): + ... self.a = 33 + ... + >>> class SomethingForTest(Something): + ... a = 33 + ... + >>> p = patch('__main__.Something', autospec=SomethingForTest) + >>> mock = p.start() + >>> mock.a + + + +.. [#] This only applies to classes or already instantiated objects. Calling + a mocked class to create a mock instance *does not* create a real instance. + It is only attribute lookups - along with calls to `dir` - that are done. + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 28 16:41:15 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 28 Mar 2012 16:41:15 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_unittest=2Emock=2Epatch?= =?utf8?q?_docstring?= Message-ID: http://hg.python.org/cpython/rev/5d591507f6fe changeset: 75975:5d591507f6fe user: Michael Foord date: Wed Mar 28 15:41:28 2012 +0100 summary: Fix unittest.mock.patch docstring files: Lib/unittest/mock.py | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1351,8 +1351,6 @@ ): """ `patch` acts as a function decorator, class decorator or a context - - `patch` acts as a function decorator, class decorator or a context manager. Inside the body of the function or with statement, the `target` is patched with a `new` object. When the function/with statement exits the patch is undone. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 28 16:48:57 2012 From: python-checkins at python.org (michael.foord) Date: Wed, 28 Mar 2012 16:48:57 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Update_unittest=2Emock=2Epa?= =?utf8?q?tch_example?= Message-ID: http://hg.python.org/cpython/rev/db20367b20de changeset: 75976:db20367b20de user: Michael Foord date: Wed Mar 28 15:49:08 2012 +0100 summary: Update unittest.mock.patch example files: Doc/library/unittest.mock.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -988,10 +988,10 @@ the decorated function: >>> @patch('__main__.SomeClass') - ... def function(mock_class): + ... def function(normal_argument, mock_class): ... print(mock_class is SomeClass) ... - >>> function() + >>> function(None) True Patching a class replaces the class with a `MagicMock` *instance*. If the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Mar 28 22:49:50 2012 From: python-checkins at python.org (victor.stinner) Date: Wed, 28 Mar 2012 22:49:50 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Rename_time=2Ehires?= =?utf8?q?=28=29_to_time=2Ehighres=28=29=3B_add_Solaris_monotonic_clocks?= Message-ID: http://hg.python.org/peps/rev/843139115afe changeset: 4162:843139115afe user: Victor Stinner date: Wed Mar 28 15:02:58 2012 +0200 summary: PEP 418: Rename time.hires() to time.highres(); add Solaris monotonic clocks Mention also other time.highres() name propositions. files: pep-0418.txt | 102 +++++++++++++++++++++++++++++++------- 1 files changed, 83 insertions(+), 19 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -13,7 +13,7 @@ Abstract ======== -Add time.monotonic() and time.hires() functions to Python 3.3. +Add time.monotonic() and time.highres() functions to Python 3.3. Rationale @@ -23,7 +23,7 @@ * Display the current time to a human (e.g. display a calendar or draw a wall clock): use system clock. time.time() or datetime.datetime.now() - * Benchmark, profiling, timeout: time.hires() + * Benchmark, profiling, timeout: time.highres() * Event scheduler: time.monotonic() @@ -118,19 +118,36 @@ return _time.mach_absolute_time() * monotonic.factor monotonic.factor = None + elif os.name.startswith('sunos'): + def monotonic(): + if monotonic.use_clock_highres: + try: + time.clock_gettime(time.CLOCK_HIGHRES) + except OSError: + monotonic.use_clock_highres = False + return time.gethrtime() + monotonic.use_clock_highres = (hasattr(time, 'clock_gettime') + and hasattr(time, 'CLOCK_HIGHRES')) + elif hasattr(time, "clock_gettime"): def monotonic(): - if monotonic.use_monotonic_raw: + while monotonic.clocks: try: - return time.clock_gettime(time.CLOCK_MONOTONIC_RAW) + clk_id = monotonic.clocks[0] + return time.clock_gettime(clk_id) except OSError: # CLOCK_MONOTONIC_RAW requires a Linux kernel >= 2.6.28 - monotonic.use_monotonic_raw = False + del monotonic.clocks[0] return time.clock_gettime(time.CLOCK_MONOTONIC) - monotonic.use_monotonic_raw = hasattr(time, "CLOCK_MONOTONIC_RAW") + monotonic.clocks = [] + if hasattr(time, 'CLOCK_MONOTONIC_RAW'): + monotonic.clocks.append(time.CLOCK_MONOTONIC_RAW) + if hasattr(time, 'CLOCK_HIGHRES'): + monotonic.clocks.append(time.CLOCK_HIGHRES) -time.hires() ------------- + +time.highres() +-------------- High-resolution clock: use a monotonic clock if available, or fallback to the system time. @@ -139,14 +156,14 @@ Pseudo-code:: - def hires(): - if hires.use_monotonic: + def highres(): + if highres.use_monotonic: try: return time.monotonic() except OSError: - hires.use_monotonic = False + highres.use_monotonic = False return time.time() - hires.use_monotonic = hasattr(time, 'monotonic') + highres.use_monotonic = hasattr(time, 'monotonic') Clocks @@ -195,8 +212,8 @@ .. note:: clock_gettime() requires to link the program to the rt (real-time) library. -QueryPerformanceCounter -^^^^^^^^^^^^^^^^^^^^^^^ +Windows: QueryPerformanceCounter +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ High-resolution performance counter. It is monotonic. QueryPerformanceFrequency() gives its frequency. @@ -212,8 +229,8 @@ support a high-resolution performance counter. -GetTickCount(), GetTickCount64() -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Windows: GetTickCount(), GetTickCount64() +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GetTickCount() and GetTickCount64() are monotonic and cannot fail. @@ -221,6 +238,27 @@ The clock resolution is 1 millisecond. +Solaris: CLOCK_HIGHRES +^^^^^^^^^^^^^^^^^^^^^^ + +The Solaris OS has an CLOCK_HIGHRES timer that attempts to use an optimal +hardware source, and may give close to nanosecond resolution. CLOCK_HIGHRES is +the nonadjustable, high-resolution clock. For timers created with a clockid_t +value of CLOCK_HIGHRES, the system will attempt to use an optimal hardware +source. + +Solaris: gethrtime +^^^^^^^^^^^^^^^^^^ + +The gethrtime() function returns the current high-resolution real time. Time is +expressed as nanoseconds since some arbitrary time in the past; it is not +correlated in any way to the time of day, and thus is not subject to +resetting or drifting by way of adjtime() or settimeofday(). The hires timer +is ideally suited to performance measurement tasks, where cheap, accurate +interval timing is required. + +On Solaris, gethrtime() is the same as clock_gettime(CLOCK_MONOTONIC). + System time ----------- @@ -299,8 +337,8 @@ See also pthread_getcpuclockid(). -QueryUnbiasedInterruptTime --------------------------- +Windows: QueryUnbiasedInterruptTime +----------------------------------- Gets the current unbiased interrupt time from the biased interrupt time and the current sleep bias amount. This time is not affected by power management sleep @@ -311,12 +349,25 @@ QueryUnbiasedInterruptTime() was introduced in Windows 7. - Alternatives: API design ======================== +time.highres() function name +---------------------------- + +Other names were proposed: + + * time.hires(): "hires" can be read as "to hire" as in "he hires a car to go + on holiday", rather than a "HIgh-RESolution clock". + * time.steady(): no OS provides a clock advancing at a steady rate, so + "steady" should be avoided. + * time.try_monotonic(): it is a clear and obvious solution for the use-case of + "I prefer the monotonic clock, if it is available, otherwise I'll take my + chances with a best-effect clock." + * time.wallclock() + One function with a flag: time.monotonic(strict=False) ----------------------------------------------------------- +------------------------------------------------------ * time.monotonic(strict=False) falls back to the system clock if no monotonic clock is available or if the monotonic clock failed. @@ -345,6 +396,10 @@ Should Python ensure manually that a monotonic clock is truly monotonic by computing the maximum with the clock value and the previous value? +Since it's relatively straightforward to cache the last value returned using a +static variable, it might be interesting to use this to make sure that the +values returned are indeed monotonic. + * Virtual machines provide less reliable clocks. * QueryPerformanceCounter() had a bug in 2006 on multiprocessor computers @@ -352,8 +407,8 @@ Footnotes ========= -.. [#pseudo] _time is an hypothetical module used for the example. In practice, - functions will be implemented in C and so don't need a module. +.. [#pseudo] "_time" is an hypothetical module only used for the example. + The time module is implemented in C and so there is no need for such module. Links @@ -365,15 +420,21 @@ `_ * `Issue #14397: Use GetTickCount/GetTickCount64 instead of QueryPerformanceCounter for monotonic clock `_ + * `Issue #14428: Implementation of the PEP 418 + `_ * `python-monotonic-time `_ (`github `_) * `Qt library: QElapsedTimer `_ + * `monotonic_clock + `_ * `Windows: Game Timing and Multicore Processors `_ * `Implement a Continuously Updating, High-Resolution Time Provider for Windows `_ * `Perl: Time::HiRes `_ + * `C++ Timeout Specification + `_ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 29 01:11:35 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 29 Mar 2012 01:11:35 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_list_OSes_supportin?= =?utf8?q?g_or_not_CLOCK=5FMONOTONIC?= Message-ID: http://hg.python.org/peps/rev/1c2347ed2ea6 changeset: 4163:1c2347ed2ea6 user: Victor Stinner date: Thu Mar 29 00:57:15 2012 +0200 summary: PEP 418: list OSes supporting or not CLOCK_MONOTONIC Give also more information about GetTickCount(). files: pep-0418.txt | 54 ++++++++++++++++++++++++++++++++++----- 1 files changed, 47 insertions(+), 7 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -75,7 +75,8 @@ backward. Its rate may be adjusted by NTP. The reference point of the returned value is undefined so only the difference of consecutive calls is valid. -It is not available on all platforms and may raise an OSError. +It is not available on all platforms and may raise an OSError. It is not +available on GNU/Hurd for example. The monotonic clock may stop while the system is suspended. @@ -145,6 +146,13 @@ if hasattr(time, 'CLOCK_HIGHRES'): monotonic.clocks.append(time.CLOCK_HIGHRES) +.. note:: + + time.monotonic() detects GetTickCount() integer overflow (32 bits, roll-over + after 49.7 days): it increases a delta by 2\ :sup:`32` each time than an + overflow is detected. The delta is stored in the process local state and so + time.monotonic() value may be different in two Python processes. + time.highres() -------------- @@ -193,6 +201,19 @@ CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represents monotonic time since some unspecified starting point. They cannot be set. +CLOCK_MONOTONIC is available at least on the following operating systems: + + * DragonFly BSD, FreeBSD >= 5.0, OpenBSD, NetBSD + * Linux + * Solaris + +The following operating systems don't support CLOCK_MONOTONIC: + + + * GNU/Hurd (see `open issues/ clock_gettime `_) + * Mac OS X + * Windows + CLOCK_MONOTONIC_RAW is specific to Linux. It is similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time that is not subject to NTP adjustments. CLOCK_MONOTONIC_RAW requires Linux 2.6.28 or later. @@ -236,7 +257,13 @@ GetTickCount64() was added to Windows Vista and Windows Server 2008. -The clock resolution is 1 millisecond. +The clock resolution is 1 millisecond. Its accuracy is usually around 15 ms. It +is possible to improve the accuracy using the `undocumented +NtSetTimerResolution() function +`_. +There are applications using this undocumented function, example: +`Timer Resolution `_. + Solaris: CLOCK_HIGHRES ^^^^^^^^^^^^^^^^^^^^^^ @@ -414,6 +441,8 @@ Links ===== +Related Python issues: + * `Issue #12822: NewGIL should use CLOCK_MONOTONIC if possible. `_ * `Issue #14222: Use time.steady() to implement timeout @@ -425,16 +454,27 @@ * `python-monotonic-time `_ (`github `_) + +Librairies exposing monotonic clocks: + * `Qt library: QElapsedTimer `_ + * `glib library: g_get_monotonic_time () + `_ + uses GetTickCount64()/GetTickCount() on Windows, + clock_gettime(CLOCK_MONOTONIC) on UNIX or falls back to the system clock * `monotonic_clock - `_ + `_ (Python library) + * `Perl: Time::HiRes + `_ exposes + clock_gettime(CLOCK_MONOTONIC) + +Related documents: + + * `C++ Timeout Specification + `_ * `Windows: Game Timing and Multicore Processors `_ * `Implement a Continuously Updating, High-Resolution Time Provider for Windows `_ - * `Perl: Time::HiRes - `_ - * `C++ Timeout Specification - `_ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 29 01:11:36 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 29 Mar 2012 01:11:36 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_QueryPerformanceCou?= =?utf8?q?nter=28=29_has_a_known_bug?= Message-ID: http://hg.python.org/peps/rev/2dc9466b8917 changeset: 4164:2dc9466b8917 user: Victor Stinner date: Thu Mar 29 01:11:16 2012 +0200 summary: PEP 418: QueryPerformanceCounter() has a known bug files: pep-0418.txt | 21 ++++++++++++++++----- 1 files changed, 16 insertions(+), 5 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -240,15 +240,21 @@ QueryPerformanceFrequency() gives its frequency. On Windows XP, QueryPerformanceFrequency() is the processor frequency and -QueryPerformanceCounter() is the TSC of the current processor. Windows XP -had a bug (see `KB896256 `_): on a -multiprocessor computer, QueryPerformanceCounter() returned a different value -for each processor. +QueryPerformanceCounter() is the TSC of the current processor. + +The performance counter value may unexpectedly leap forward because of a +hardware bug, see the `KB274323`_. + +Windows XP had a bug (see `KB896256`_): on a multiprocessor computer, +QueryPerformanceCounter() returned a different value for each processor. QueryPerformanceFrequency() should only be called once: the frequency will not change while the system is running. It fails if the installed hardware does not support a high-resolution performance counter. +.. _KB896256: http://support.microsoft.com/?id=896256 +.. _KB274323: http://support.microsoft.com/?id=274323 + Windows: GetTickCount(), GetTickCount64() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -428,7 +434,12 @@ values returned are indeed monotonic. * Virtual machines provide less reliable clocks. - * QueryPerformanceCounter() had a bug in 2006 on multiprocessor computers + * QueryPerformanceCounter() has two known bugs: + `KB896256`_ (fixed) and `KB274323`_ + +Python may only workaround a specific known operating system bug: `KB274323`_ +contains a code example to workaround the bug (use GetTickCount() to detect +QueryPerformanceCounter() leap). Footnotes -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 29 01:29:17 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 29 Mar 2012 01:29:17 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Reorder_links?= Message-ID: http://hg.python.org/peps/rev/7dae84552e6f changeset: 4165:7dae84552e6f user: Victor Stinner date: Thu Mar 29 01:29:10 2012 +0200 summary: PEP 418: Reorder links files: pep-0418.txt | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -462,9 +462,6 @@ `_ * `Issue #14428: Implementation of the PEP 418 `_ - * `python-monotonic-time - `_ - (`github `_) Librairies exposing monotonic clocks: @@ -474,8 +471,11 @@ `_ uses GetTickCount64()/GetTickCount() on Windows, clock_gettime(CLOCK_MONOTONIC) on UNIX or falls back to the system clock + * `python-monotonic-time + `_ + (`github `_) * `monotonic_clock - `_ (Python library) + `_ * `Perl: Time::HiRes `_ exposes clock_gettime(CLOCK_MONOTONIC) -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 29 01:57:23 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 29 Mar 2012 01:57:23 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_More_QueryPerforman?= =?utf8?q?ceCounter_bugs?= Message-ID: http://hg.python.org/peps/rev/3206ff015644 changeset: 4166:3206ff015644 user: Victor Stinner date: Thu Mar 29 01:57:15 2012 +0200 summary: PEP 418: More QueryPerformanceCounter bugs files: pep-0418.txt | 31 ++++++++++++++++++++----------- 1 files changed, 20 insertions(+), 11 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -237,21 +237,31 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ High-resolution performance counter. It is monotonic. -QueryPerformanceFrequency() gives its frequency. +QueryPerformanceFrequency() gives its frequency. Hardward clocks used +by QueryPerformanceCounter: -On Windows XP, QueryPerformanceFrequency() is the processor frequency and -QueryPerformanceCounter() is the TSC of the current processor. - -The performance counter value may unexpectedly leap forward because of a -hardware bug, see the `KB274323`_. - -Windows XP had a bug (see `KB896256`_): on a multiprocessor computer, -QueryPerformanceCounter() returned a different value for each processor. + * Windows XP: RDTSC instruction of Intel processors, the clock frequency is + the frequency of the processor + * Windows 2000: ACPI power management timer, frequency = 3,549,545 Hz + * Windows 95/98: 8245 PIT chipset, frequency = 1,193,181 Hz QueryPerformanceFrequency() should only be called once: the frequency will not change while the system is running. It fails if the installed hardware does not support a high-resolution performance counter. +Bugs: + + * The performance counter value may unexpectedly leap forward because of a + hardware bug, see the `KB274323`_. + * On VirtualBox, QueryPerformanceCounter() does not increment the high part + every time the low part overflows, see `Monotonic timers + `_ (2009). + * VirtualBox had a bug in its HPET virtualized device: + QueryPerformanceCounter() did jump forward by approx. 42 seconds (`issue + #8707 `_). + * Windows XP had a bug (see `KB896256`_): on a multiprocessor computer, + QueryPerformanceCounter() returned a different value for each processor. + .. _KB896256: http://support.microsoft.com/?id=896256 .. _KB274323: http://support.microsoft.com/?id=274323 @@ -434,8 +444,7 @@ values returned are indeed monotonic. * Virtual machines provide less reliable clocks. - * QueryPerformanceCounter() has two known bugs: - `KB896256`_ (fixed) and `KB274323`_ + * QueryPerformanceCounter() has known bugs (only one is not fixed yet) Python may only workaround a specific known operating system bug: `KB274323`_ contains a code example to workaround the bug (use GetTickCount() to detect -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Mar 29 02:10:39 2012 From: python-checkins at python.org (victor.stinner) Date: Thu, 29 Mar 2012 02:10:39 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Add_some_links_to_f?= =?utf8?q?unction_documentation?= Message-ID: http://hg.python.org/peps/rev/82affbcd5f2a changeset: 4167:82affbcd5f2a user: Victor Stinner date: Thu Mar 29 02:10:32 2012 +0200 summary: PEP 418: Add some links to function documentation files: pep-0418.txt | 22 +++++++++++++++++++--- 1 files changed, 19 insertions(+), 3 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -201,6 +201,13 @@ CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represents monotonic time since some unspecified starting point. They cannot be set. +Documentation: refer to the manual page of your operating system. Examples: + + * `FreeBSD clock_gettime() manual page + `_ + * `Linux clock_gettime() manual page + `_ + CLOCK_MONOTONIC is available at least on the following operating systems: * DragonFly BSD, FreeBSD >= 5.0, OpenBSD, NetBSD @@ -237,11 +244,20 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ High-resolution performance counter. It is monotonic. -QueryPerformanceFrequency() gives its frequency. Hardward clocks used -by QueryPerformanceCounter: +QueryPerformanceFrequency() gives its frequency. + +Documentation: + + * `MSDN: QueryPerformanceCounter() documentation + `_ + * `MSDN: QueryPerformanceFrequency() documentation + `_ + +Hardware clocks used by QueryPerformanceCounter: * Windows XP: RDTSC instruction of Intel processors, the clock frequency is - the frequency of the processor + the frequency of the processor (between 200 MHz and 3 GHz, usually greater + than 1 GHz nowadays) * Windows 2000: ACPI power management timer, frequency = 3,549,545 Hz * Windows 95/98: 8245 PIT chipset, frequency = 1,193,181 Hz -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Thu Mar 29 05:39:38 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 29 Mar 2012 05:39:38 +0200 Subject: [Python-checkins] Daily reference leaks (db20367b20de): sum=0 Message-ID: results for db20367b20de on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogLFvRdr', '-x'] From python-checkins at python.org Thu Mar 29 09:18:07 2012 From: python-checkins at python.org (georg.brandl) Date: Thu, 29 Mar 2012 09:18:07 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_newlines=2E?= Message-ID: http://hg.python.org/cpython/rev/9304172ee5eb changeset: 75977:9304172ee5eb user: Georg Brandl date: Thu Mar 29 09:18:14 2012 +0200 summary: Fix newlines. files: Doc/library/time.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/time.rst b/Doc/library/time.rst --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -143,12 +143,14 @@ .. versionadded:: 3.3 + .. function:: clock_gettime(clk_id) Return the time of the specified clock *clk_id*. .. versionadded:: 3.3 + .. data:: CLOCK_REALTIME System-wide real-time clock. Setting this clock requires appropriate @@ -156,6 +158,7 @@ .. versionadded:: 3.3 + .. data:: CLOCK_MONOTONIC Clock that cannot be set and represents monotonic time since some @@ -163,6 +166,7 @@ .. versionadded:: 3.3 + .. data:: CLOCK_MONOTONIC_RAW Similar to :data:`CLOCK_MONOTONIC`, but provides access to a raw @@ -172,18 +176,21 @@ .. versionadded:: 3.3 + .. data:: CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU. .. versionadded:: 3.3 + .. data:: CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock. .. versionadded:: 3.3 + .. function:: ctime([secs]) Convert a time expressed in seconds since the epoch to a string representing -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 12:48:22 2012 From: python-checkins at python.org (r.david.murray) Date: Thu, 29 Mar 2012 12:48:22 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzE0NDE2OiBhZGQg?= =?utf8?q?missing_LOG=5FSYSLOG_facility_to_syslog_docs=2E?= Message-ID: http://hg.python.org/cpython/rev/04c19ac9734a changeset: 75978:04c19ac9734a branch: 3.2 parent: 75965:37751d1cb4a8 user: R David Murray date: Thu Mar 29 06:47:35 2012 -0400 summary: #14416: add missing LOG_SYSLOG facility to syslog docs. files: Doc/library/syslog.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -78,7 +78,8 @@ Facilities: :const:`LOG_KERN`, :const:`LOG_USER`, :const:`LOG_MAIL`, :const:`LOG_DAEMON`, :const:`LOG_AUTH`, :const:`LOG_LPR`, :const:`LOG_NEWS`, :const:`LOG_UUCP`, - :const:`LOG_CRON` and :const:`LOG_LOCAL0` to :const:`LOG_LOCAL7`. + :const:`LOG_CRON`, :const:`LOG_SYSLOG` and :const:`LOG_LOCAL0` to + :const:`LOG_LOCAL7`. Log options: :const:`LOG_PID`, :const:`LOG_CONS`, :const:`LOG_NDELAY`, :const:`LOG_NOWAIT` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 12:48:23 2012 From: python-checkins at python.org (r.david.murray) Date: Thu, 29 Mar 2012 12:48:23 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzE0NDE2OiBhZGQg?= =?utf8?q?missing_LOG=5FSYSLOG_facility_to_syslog_docs=2E?= Message-ID: http://hg.python.org/cpython/rev/c40e5120a9b1 changeset: 75979:c40e5120a9b1 branch: 2.7 parent: 75967:39d1c2c7bcf7 user: R David Murray date: Thu Mar 29 06:47:59 2012 -0400 summary: #14416: add missing LOG_SYSLOG facility to syslog docs. files: Doc/library/syslog.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -73,7 +73,8 @@ Facilities: :const:`LOG_KERN`, :const:`LOG_USER`, :const:`LOG_MAIL`, :const:`LOG_DAEMON`, :const:`LOG_AUTH`, :const:`LOG_LPR`, :const:`LOG_NEWS`, :const:`LOG_UUCP`, - :const:`LOG_CRON` and :const:`LOG_LOCAL0` to :const:`LOG_LOCAL7`. + :const:`LOG_CRON`, :const:`LOG_SYSLOG` and :const:`LOG_LOCAL0` to + :const:`LOG_LOCAL7`. Log options: :const:`LOG_PID`, :const:`LOG_CONS`, :const:`LOG_NDELAY`, :const:`LOG_NOWAIT` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 12:49:43 2012 From: python-checkins at python.org (r.david.murray) Date: Thu, 29 Mar 2012 12:49:43 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2314416=3A_add_missing_LOG=5FSYSLOG_facility_to_syslo?= =?utf8?q?g_docs=2E?= Message-ID: http://hg.python.org/cpython/rev/91bafdf7d7a4 changeset: 75980:91bafdf7d7a4 parent: 75977:9304172ee5eb parent: 75978:04c19ac9734a user: R David Murray date: Thu Mar 29 06:49:29 2012 -0400 summary: Merge #14416: add missing LOG_SYSLOG facility to syslog docs. files: Doc/library/syslog.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -78,7 +78,8 @@ Facilities: :const:`LOG_KERN`, :const:`LOG_USER`, :const:`LOG_MAIL`, :const:`LOG_DAEMON`, :const:`LOG_AUTH`, :const:`LOG_LPR`, :const:`LOG_NEWS`, :const:`LOG_UUCP`, - :const:`LOG_CRON` and :const:`LOG_LOCAL0` to :const:`LOG_LOCAL7`. + :const:`LOG_CRON`, :const:`LOG_SYSLOG` and :const:`LOG_LOCAL0` to + :const:`LOG_LOCAL7`. Log options: :const:`LOG_PID`, :const:`LOG_CONS`, :const:`LOG_NDELAY`, :const:`LOG_NOWAIT` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 13:16:19 2012 From: python-checkins at python.org (r.david.murray) Date: Thu, 29 Mar 2012 13:16:19 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_=2314416=3A_conditionally_a?= =?utf8?q?dd_LOG=5FAUTHPRIV_facility_and_LOG=5FODELAY_to_syslog=2E?= Message-ID: http://hg.python.org/cpython/rev/dc8e61044055 changeset: 75981:dc8e61044055 user: R David Murray date: Thu Mar 29 07:15:45 2012 -0400 summary: #14416: conditionally add LOG_AUTHPRIV facility and LOG_ODELAY to syslog. Unlike the other facilities, we don't use a fallback for AUTHPRIV if it doesn't exist. Because it is intended for logging sensitive log messages, it is better that a program trying to log such messages fail than that it log them insecurely. Initial patch by Federico Reghenzani. files: Doc/library/syslog.rst | 10 ++++++---- Misc/ACKS | 1 + Misc/NEWS | 3 +++ Modules/syslogmodule.c | 8 ++++++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -78,12 +78,14 @@ Facilities: :const:`LOG_KERN`, :const:`LOG_USER`, :const:`LOG_MAIL`, :const:`LOG_DAEMON`, :const:`LOG_AUTH`, :const:`LOG_LPR`, :const:`LOG_NEWS`, :const:`LOG_UUCP`, - :const:`LOG_CRON`, :const:`LOG_SYSLOG` and :const:`LOG_LOCAL0` to - :const:`LOG_LOCAL7`. + :const:`LOG_CRON`, :const:`LOG_SYSLOG`, :const:`LOG_LOCAL0` to + :const:`LOG_LOCAL7`, and, if defined in ````, + :const:`LOG_AUTHPRIV`. Log options: - :const:`LOG_PID`, :const:`LOG_CONS`, :const:`LOG_NDELAY`, :const:`LOG_NOWAIT` - and :const:`LOG_PERROR` if defined in ````. + :const:`LOG_PID`, :const:`LOG_CONS`, :const:`LOG_NDELAY`, and, if defined + in ````, :const:`LOG_ODELAY`, :const:`LOG_NOWAIT`, and + :const:`LOG_PERROR`. Examples diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -832,6 +832,7 @@ Gareth Rees Steve Reeves Lennart Regebro +Federico Reghenzani Ofir Reichenberg Sean Reifschneider Michael P. Reilly diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ Library ------- +- Issue #14416: syslog now defines the LOG_ODELAY and LOG_AUTHPRIV constants + if they are defined in . + - IDLE can be launched as python -m idlelib - Issue #14295: Add unittest.mock diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -291,6 +291,9 @@ PyModule_AddIntConstant(m, "LOG_PID", LOG_PID); PyModule_AddIntConstant(m, "LOG_CONS", LOG_CONS); PyModule_AddIntConstant(m, "LOG_NDELAY", LOG_NDELAY); +#ifdef LOG_ODELAY + PyModule_AddIntConstant(m, "LOG_ODELAY", LOG_ODELAY); +#endif #ifdef LOG_NOWAIT PyModule_AddIntConstant(m, "LOG_NOWAIT", LOG_NOWAIT); #endif @@ -331,5 +334,10 @@ PyModule_AddIntConstant(m, "LOG_CRON", LOG_CRON); PyModule_AddIntConstant(m, "LOG_UUCP", LOG_UUCP); PyModule_AddIntConstant(m, "LOG_NEWS", LOG_NEWS); + +#ifdef LOG_AUTHPRIV + PyModule_AddIntConstant(m, "LOG_AUTHPRIV", LOG_AUTHPRIV); +#endif + return m; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 14:46:34 2012 From: python-checkins at python.org (michael.foord) Date: Thu, 29 Mar 2012 14:46:34 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_typo_in_unittest=2Emock?= =?utf8?q?_docs?= Message-ID: http://hg.python.org/cpython/rev/ddddd528b2d2 changeset: 75982:ddddd528b2d2 user: Michael Foord date: Thu Mar 29 13:46:50 2012 +0100 summary: Fix typo in unittest.mock docs files: Doc/library/unittest.mock.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -1714,7 +1714,7 @@ `call` is a helper object for making simpler assertions, for comparing with :attr:`~Mock.call_args`, :attr:`~Mock.call_args_list`, - :attr:`~Mock.mock_calls` and:attr: `~Mock.method_calls`. `call` can also be + :attr:`~Mock.mock_calls` and :attr: `~Mock.method_calls`. `call` can also be used with :meth:`~Mock.assert_has_calls`. >>> m = MagicMock(return_value=None) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 18:01:50 2012 From: python-checkins at python.org (andrew.svetlov) Date: Thu, 29 Mar 2012 18:01:50 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0NDA5?= =?utf8?q?=3A_IDLE_doesn=27t_not_execute_commands_from_shell_with_default?= Message-ID: http://hg.python.org/cpython/rev/26b2407c644e changeset: 75983:26b2407c644e branch: 3.2 parent: 75978:04c19ac9734a user: Andrew Svetlov date: Thu Mar 29 19:01:28 2012 +0300 summary: Issue #14409: IDLE doesn't not execute commands from shell with default keybinding for . Patch by Roger Serwy. files: Lib/idlelib/NEWS.txt | 3 +++ Lib/idlelib/configHandler.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,9 @@ What's New in IDLE 3.2.3? ========================= +- Issue #14409: IDLE doesn't not execute commands from shell, + error with default keybinding for Return. (Patch by Roger Serwy) + - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). diff --git a/Lib/idlelib/configHandler.py b/Lib/idlelib/configHandler.py --- a/Lib/idlelib/configHandler.py +++ b/Lib/idlelib/configHandler.py @@ -595,7 +595,7 @@ '<>': [''], '<>': [''], '<>': [''], - '<>': [' '], + '<>': ['', ''], '<>': [''], '<>': [''], '<>': [''], diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,9 @@ Library ------- +- Issue #14409: IDLE doesn't not execute commands from shell, + error with default keybinding for Return. (Patch by Roger Serwy) + - Issue #10340: asyncore - properly handle EINVAL in dispatcher constructor on OSX; avoid to call handle_connect in case of a disconnected socket which was not meant to connect. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 18:13:02 2012 From: python-checkins at python.org (ross.lagerwall) Date: Thu, 29 Mar 2012 18:13:02 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314442=3A_Add_missi?= =?utf8?q?ng_errno_import_in_test=5Fsmtplib=2E?= Message-ID: http://hg.python.org/cpython/rev/9c2b710da3c7 changeset: 75984:9c2b710da3c7 parent: 75982:ddddd528b2d2 user: Ross Lagerwall date: Thu Mar 29 18:08:48 2012 +0200 summary: Issue #14442: Add missing errno import in test_smtplib. files: Lib/test/test_smtplib.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -9,6 +9,7 @@ import sys import time import select +import errno import unittest from test import support, mock_socket diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -196,6 +196,8 @@ Tests ----- +- Issue #14442: Add missing errno import in test_smtplib. + - Issue #8315: (partial fix) python -m unittest test.test_email now works. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 18:51:05 2012 From: python-checkins at python.org (andrew.svetlov) Date: Thu, 29 Mar 2012 18:51:05 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/971a8d291af9 changeset: 75985:971a8d291af9 parent: 75984:9c2b710da3c7 parent: 75983:26b2407c644e user: Andrew Svetlov date: Thu Mar 29 19:50:46 2012 +0300 summary: Merge with 3.2 files: Lib/idlelib/NEWS.txt | 3 +++ Lib/idlelib/configHandler.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,9 @@ - IDLE can be launched as `python -m idlelib` +- Issue #14409: IDLE doesn't not execute commands from shell, + error with default keybinding for Return. (Patch by Roger Serwy) + - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). diff --git a/Lib/idlelib/configHandler.py b/Lib/idlelib/configHandler.py --- a/Lib/idlelib/configHandler.py +++ b/Lib/idlelib/configHandler.py @@ -596,7 +596,7 @@ '<>': [''], '<>': [''], '<>': [''], - '<>': [' '], + '<>': ['', ''], '<>': [''], '<>': [''], '<>': [''], diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ Library ------- +- Issue #14409: IDLE doesn't not execute commands from shell, + error with default keybinding for Return. (Patch by Roger Serwy) + - Issue #14416: syslog now defines the LOG_ODELAY and LOG_AUTHPRIV constants if they are defined in . -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 18:55:09 2012 From: python-checkins at python.org (andrew.svetlov) Date: Thu, 29 Mar 2012 18:55:09 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Backport_of_Iss?= =?utf8?q?ue_=2314409_to_2=2E7?= Message-ID: http://hg.python.org/cpython/rev/87ada87057a2 changeset: 75986:87ada87057a2 branch: 2.7 parent: 75979:c40e5120a9b1 user: Andrew Svetlov date: Thu Mar 29 19:54:58 2012 +0300 summary: Backport of Issue #14409 to 2.7 IDLE doesn't not execute commands from shell with default keybinding for . Patch by Roger Serwy. files: Lib/idlelib/NEWS.txt | 3 +++ Lib/idlelib/configHandler.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,9 @@ What's New in IDLE 2.7.3? ======================= +- Issue #14409: IDLE doesn't not execute commands from shell, + error with default keybinding for Return. (Patch by Roger Serwy) + - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). diff --git a/Lib/idlelib/configHandler.py b/Lib/idlelib/configHandler.py --- a/Lib/idlelib/configHandler.py +++ b/Lib/idlelib/configHandler.py @@ -595,7 +595,7 @@ '<>': [''], '<>': [''], '<>': [''], - '<>': [' '], + '<>': ['', ''], '<>': [''], '<>': [''], '<>': [''], diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Library ------- +- Issue #14409: IDLE doesn't not execute commands from shell, + error with default keybinding for Return. (Patch by Roger Serwy) + - Issue #10340: asyncore - properly handle EINVAL in dispatcher constructor on OSX; avoid to call handle_connect in case of a disconnected socket which was not meant to connect. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 21:19:02 2012 From: python-checkins at python.org (vinay.sajip) Date: Thu, 29 Mar 2012 21:19:02 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Closes_=2314436?= =?utf8?q?=3A_Convert_msg_+_args_to_string_before_pickling=2E?= Message-ID: http://hg.python.org/cpython/rev/eda0ae0d2c68 changeset: 75987:eda0ae0d2c68 branch: 2.7 user: Vinay Sajip date: Thu Mar 29 20:11:20 2012 +0100 summary: Closes #14436: Convert msg + args to string before pickling. files: Lib/logging/handlers.py | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -528,9 +528,16 @@ """ ei = record.exc_info if ei: - dummy = self.format(record) # just to get traceback text into record.exc_text + # just to get traceback text into record.exc_text ... + dummy = self.format(record) record.exc_info = None # to avoid Unpickleable error - s = cPickle.dumps(record.__dict__, 1) + # See issue #14436: If msg or args are objects, they may not be + # available on the receiving end. So we convert the msg % args + # to a string, save it as msg and zap the args. + d = dict(record.__dict__) + d['msg'] = record.getMessage() + d['args'] = None + s = cPickle.dumps(d, 1) if ei: record.exc_info = ei # for next handler slen = struct.pack(">L", len(s)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 21:19:05 2012 From: python-checkins at python.org (vinay.sajip) Date: Thu, 29 Mar 2012 21:19:05 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Closes_=2314436?= =?utf8?q?=3A_Convert_msg_+_args_to_string_before_pickling=2E?= Message-ID: http://hg.python.org/cpython/rev/cd8347e15f62 changeset: 75988:cd8347e15f62 branch: 3.2 parent: 75983:26b2407c644e user: Vinay Sajip date: Thu Mar 29 20:17:18 2012 +0100 summary: Closes #14436: Convert msg + args to string before pickling. files: Lib/logging/handlers.py | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -519,11 +519,16 @@ """ ei = record.exc_info if ei: - dummy = self.format(record) # just to get traceback text into record.exc_text - record.exc_info = None # to avoid Unpickleable error - s = pickle.dumps(record.__dict__, 1) - if ei: - record.exc_info = ei # for next handler + # just to get traceback text into record.exc_text ... + dummy = self.format(record) + # See issue #14436: If msg or args are objects, they may not be + # available on the receiving end. So we convert the msg % args + # to a string, save it as msg and zap the args. + d = dict(record.__dict__) + d['msg'] = record.getMessage() + d['args'] = None + d['exc_info'] = None + s = pickle.dumps(d, 1) slen = struct.pack(">L", len(s)) return slen + s -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Mar 29 21:19:07 2012 From: python-checkins at python.org (vinay.sajip) Date: Thu, 29 Mar 2012 21:19:07 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Closes_=2314436=3A_merged_fix_from_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/86a1f92c66b3 changeset: 75989:86a1f92c66b3 parent: 75985:971a8d291af9 parent: 75988:cd8347e15f62 user: Vinay Sajip date: Thu Mar 29 20:18:21 2012 +0100 summary: Closes #14436: merged fix from 3.2. files: Lib/logging/handlers.py | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -559,11 +559,16 @@ """ ei = record.exc_info if ei: - dummy = self.format(record) # just to get traceback text into record.exc_text - record.exc_info = None # to avoid Unpickleable error - s = pickle.dumps(record.__dict__, 1) - if ei: - record.exc_info = ei # for next handler + # just to get traceback text into record.exc_text ... + dummy = self.format(record) + # See issue #14436: If msg or args are objects, they may not be + # available on the receiving end. So we convert the msg % args + # to a string, save it as msg and zap the args. + d = dict(record.__dict__) + d['msg'] = record.getMessage() + d['args'] = None + d['exc_info'] = None + s = pickle.dumps(d, 1) slen = struct.pack(">L", len(s)) return slen + s -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 30 03:41:14 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 30 Mar 2012 03:41:14 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_more_links=2C_Java_?= =?utf8?q?and_Ruby?= Message-ID: http://hg.python.org/peps/rev/29507c4289ed changeset: 4168:29507c4289ed user: Victor Stinner date: Fri Mar 30 01:53:38 2012 +0200 summary: PEP 418: more links, Java and Ruby files: pep-0418.txt | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -490,6 +490,8 @@ Librairies exposing monotonic clocks: + * `Java: System.nanoTime + `_ * `Qt library: QElapsedTimer `_ * `glib library: g_get_monotonic_time () @@ -504,6 +506,11 @@ * `Perl: Time::HiRes `_ exposes clock_gettime(CLOCK_MONOTONIC) + * `Ruby: AbsoluteTime.now + `_: use + clock_gettime(CLOCK_MONOTONIC), mach_absolute_time() or gettimeofday(). + "AbsoluteTime.monotonic?" method indicates if AbsoluteTime.now is monotonic + or not. Related documents: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Mar 30 03:41:15 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 30 Mar 2012 03:41:15 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_more_data_about_OS_?= =?utf8?q?monotonic_clocks?= Message-ID: http://hg.python.org/peps/rev/3a06ab0d4568 changeset: 4169:3a06ab0d4568 user: Victor Stinner date: Fri Mar 30 03:41:03 2012 +0200 summary: PEP 418: more data about OS monotonic clocks files: pep-0418.txt | 79 +++++++++++++++++++++++++++++++++++++-- 1 files changed, 74 insertions(+), 5 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -180,6 +180,25 @@ Monotonic --------- +Summary +^^^^^^^ + +Table summarizing all monotonic clocks: + + +========================= =============== ================ ================= +Name Resolution Adjusted by NTP? Action on suspend +========================= =============== ================ ================= +CLOCK_MONOTONIC_RAW 1 ns No ? +gethrtime 1 ns ? ? +mach_absolute_time() 1 ns ? ? +CLOCK_HIGHRES 1 ns ? ? +CLOCK_MONOTONIC 1 ns Yes on Linux Stopped on Linux +QueryPerformanceCounter() 0.3 ns - 5 ns No ? +GetTickCount[64]() 1 ms - 15 ms No ? +timeGetTime() 1 ms - 15 ms ? ? +========================= =============== ================ ================= + mach_absolute_time ^^^^^^^^^^^^^^^^^^ @@ -246,6 +265,10 @@ High-resolution performance counter. It is monotonic. QueryPerformanceFrequency() gives its frequency. +It has much higher resolution, but has lower long term accuracy than +GetTickCount() and timeGetTime() clocks. For example, it will drift compared to +the low precision clocks. + Documentation: * `MSDN: QueryPerformanceCounter() documentation @@ -258,13 +281,18 @@ * Windows XP: RDTSC instruction of Intel processors, the clock frequency is the frequency of the processor (between 200 MHz and 3 GHz, usually greater than 1 GHz nowadays) - * Windows 2000: ACPI power management timer, frequency = 3,549,545 Hz + * Windows 2000: ACPI power management timer, frequency = 3,549,545 Hz. It can + be forced through the "/usepmtimer" flag in boot.ini * Windows 95/98: 8245 PIT chipset, frequency = 1,193,181 Hz QueryPerformanceFrequency() should only be called once: the frequency will not change while the system is running. It fails if the installed hardware does not support a high-resolution performance counter. +QueryPerformanceCounter() cannot be adjusted: `SetSystemTimeAdjustment() +`_ +does only adjust the system time. + Bugs: * The performance counter value may unexpectedly leap forward because of a @@ -277,6 +305,7 @@ #8707 `_). * Windows XP had a bug (see `KB896256`_): on a multiprocessor computer, QueryPerformanceCounter() returned a different value for each processor. + The bug was fixed in Windows XP SP2. .. _KB896256: http://support.microsoft.com/?id=896256 .. _KB274323: http://support.microsoft.com/?id=274323 @@ -285,7 +314,10 @@ Windows: GetTickCount(), GetTickCount64() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -GetTickCount() and GetTickCount64() are monotonic and cannot fail. +GetTickCount() and GetTickCount64() are monotonic, cannot fail and are not +adjusted by SetSystemTimeAdjustment(). MSDN documentation: +`GetTickCount() `_, +`GetTickCount64() `_. GetTickCount64() was added to Windows Vista and Windows Server 2008. @@ -297,6 +329,29 @@ `Timer Resolution `_. +Windows: timeGetTime +^^^^^^^^^^^^^^^^^^^^ + +The timeGetTime function retrieves the system time, in milliseconds. The system +time is the time elapsed since Windows was started. Read the `timeGetTime() +documentation +`_. + +The return type of timeGetTime() is a 32-bit unsigned integer. As +GetTickCount(), timeGetTime() rolls over after 2^32 milliseconds (49.7 days). + +The default precision of the timeGetTime function can be five milliseconds or +more, depending on the machine. + +timeBeginPeriod() can be used to increase the precision of timeGetTime() up to +1 millisecond. + +.. note:: + timeGetTime() and timeBeginPeriod() are part the Windows multimedia library + and so require to link the program with winmm or to load dynamically the + library. + + Solaris: CLOCK_HIGHRES ^^^^^^^^^^^^^^^^^^^^^^ @@ -329,7 +384,7 @@ time(). The system time resolution can be read using GetSystemTimeAdjustment(). The -accurary is usually between 0.5 millisecond and 15 milliseconds. Resolution: +accurary is usually between 1 millisecond and 15 milliseconds. Resolution: * GetSystemTimeAsFileTime(): 100 nanoseconds * ftime(): 1 millisecond @@ -495,7 +550,7 @@ * `Qt library: QElapsedTimer `_ * `glib library: g_get_monotonic_time () - `_ + `_ uses GetTickCount64()/GetTickCount() on Windows, clock_gettime(CLOCK_MONOTONIC) on UNIX or falls back to the system clock * `python-monotonic-time @@ -512,7 +567,7 @@ "AbsoluteTime.monotonic?" method indicates if AbsoluteTime.now is monotonic or not. -Related documents: +Time: * `C++ Timeout Specification `_ @@ -520,4 +575,18 @@ `_ * `Implement a Continuously Updating, High-Resolution Time Provider for Windows `_ + * `clockspeed `_ uses a hardware tick counter + to compensate for a persistently fast or slow system clock + * `Retrieving system time + `_ + lists hardware clocks and time functions with their resolution + and epoch or range + * On Windows, the JavaScript runtime of Firefox interpolates + GetSystemTimeAsFileTime() with QueryPerformanceCounter() to get + an higher resolution. See the `Bug 363258 - bad millisecond resolution for + (new Date).getTime() / Date.now() on Windows + `_. + * `When microseconds matter + `_: How the IBM High + Resolution Time Stamp Facility accurately measures itty bits of time -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Mar 30 04:21:22 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 30 Mar 2012 04:21:22 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Fill_the_=22Adjuste?= =?utf8?q?d_by_NTP=22_column_of_the_summary_table?= Message-ID: http://hg.python.org/peps/rev/2b798036b339 changeset: 4170:2b798036b339 user: Victor Stinner date: Fri Mar 30 03:55:35 2012 +0200 summary: PEP 418: Fill the "Adjusted by NTP" column of the summary table files: pep-0418.txt | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -190,13 +190,13 @@ Name Resolution Adjusted by NTP? Action on suspend ========================= =============== ================ ================= CLOCK_MONOTONIC_RAW 1 ns No ? -gethrtime 1 ns ? ? -mach_absolute_time() 1 ns ? ? -CLOCK_HIGHRES 1 ns ? ? +gethrtime 1 ns No ? +mach_absolute_time() 1 ns No ? +CLOCK_HIGHRES 1 ns No ? CLOCK_MONOTONIC 1 ns Yes on Linux Stopped on Linux QueryPerformanceCounter() 0.3 ns - 5 ns No ? GetTickCount[64]() 1 ms - 15 ms No ? -timeGetTime() 1 ms - 15 ms ? ? +timeGetTime() 1 ms - 15 ms No ? ========================= =============== ================ ================= mach_absolute_time @@ -371,6 +371,9 @@ is ideally suited to performance measurement tasks, where cheap, accurate interval timing is required. +Read the `gethrtime() manual page of Solaris 11 +`_. + On Solaris, gethrtime() is the same as clock_gettime(CLOCK_MONOTONIC). -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Mar 30 04:21:24 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 30 Mar 2012 04:21:24 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Try_to_fill_the_=22?= =?utf8?q?Action_on_suspend=22_column?= Message-ID: http://hg.python.org/peps/rev/f0a64781e500 changeset: 4171:f0a64781e500 user: Victor Stinner date: Fri Mar 30 04:21:11 2012 +0200 summary: PEP 418: Try to fill the "Action on suspend" column files: pep-0418.txt | 29 +++++++++++++++++++++-------- 1 files changed, 21 insertions(+), 8 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -186,18 +186,18 @@ Table summarizing all monotonic clocks: -========================= =============== ================ ================= +========================= =============== ================ ==================== Name Resolution Adjusted by NTP? Action on suspend -========================= =============== ================ ================= -CLOCK_MONOTONIC_RAW 1 ns No ? -gethrtime 1 ns No ? +========================= =============== ================ ==================== +CLOCK_MONOTONIC_RAW 1 ns No Stopped +gethrtime 1 ns No Not stopped mach_absolute_time() 1 ns No ? CLOCK_HIGHRES 1 ns No ? CLOCK_MONOTONIC 1 ns Yes on Linux Stopped on Linux -QueryPerformanceCounter() 0.3 ns - 5 ns No ? -GetTickCount[64]() 1 ms - 15 ms No ? +QueryPerformanceCounter() 0.3 ns - 5 ns No Accuracy issue +GetTickCount[64]() 1 ms - 15 ms No Include suspend time timeGetTime() 1 ms - 15 ms No ? -========================= =============== ================ ================= +========================= =============== ================ ==================== mach_absolute_time ^^^^^^^^^^^^^^^^^^ @@ -212,6 +212,10 @@ is always equals to one and does never fail, even if the function may fail according to its prototype. +mach_absolute_time() stops during a sleep on PowerPC CPU, but not on Intel CPU: +`Different behaviour of mach_absolute_time() on i386 / ppc +`_. + mach_absolute_time() has a resolution of 1 nanosecond. CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW @@ -319,6 +323,9 @@ `GetTickCount() `_, `GetTickCount64() `_. +The elapsed time retrieved by GetTickCount or GetTickCount64 includes time the +system spends in sleep or hibernation. + GetTickCount64() was added to Windows Vista and Windows Server 2008. The clock resolution is 1 millisecond. Its accuracy is usually around 15 ms. It @@ -371,6 +378,9 @@ is ideally suited to performance measurement tasks, where cheap, accurate interval timing is required. +The linearity of gethrtime() is not preserved accross cpr suspend-resume cycle +(`Bug 4272663 `_). + Read the `gethrtime() manual page of Solaris 11 `_. @@ -455,13 +465,15 @@ Windows: QueryUnbiasedInterruptTime ------------------------------------ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Gets the current unbiased interrupt time from the biased interrupt time and the current sleep bias amount. This time is not affected by power management sleep transitions. -Is it monotonic? +The elapsed time retrieved by the QueryUnbiasedInterruptTime function includes +only time that the system spends in the working state. +QueryUnbiasedInterruptTime() is not monotonic. QueryUnbiasedInterruptTime() was introduced in Windows 7. -- Repository URL: http://hg.python.org/peps From ncoghlan at gmail.com Fri Mar 30 05:12:18 2012 From: ncoghlan at gmail.com (Nick Coghlan) Date: Fri, 30 Mar 2012 13:12:18 +1000 Subject: [Python-checkins] cpython (3.2): Issue #14409: IDLE doesn't not execute commands from shell with default In-Reply-To: References: Message-ID: On Fri, Mar 30, 2012 at 2:01 AM, andrew.svetlov wrote: > +- Issue #14409: IDLE doesn't not execute commands from shell, > + ?error with default keybinding for Return. (Patch by Roger Serwy) The double negative here makes this impossible to understand. Could we please get an updated NEWS entry that explains what actually changed in IDLE to fix this? Perhaps something like "IDLE now always sets the default keybind for Return correctly, ensuring commands can be executed in the IDLE shell window"? (assuming that's what happened). This is important, folks: NEWS entries need to be comprehensible for people that *haven't* read the associated tracker issue. This means that issue titles (which generally describe a problem someone was having) are often inappropriate as NEWS items. NEWS items should be short descriptions that clearly describe *what changed*, perhaps with some additional information to explain a bit about why the change was made. Regards, Nick. -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From solipsis at pitrou.net Fri Mar 30 05:38:40 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 30 Mar 2012 05:38:40 +0200 Subject: [Python-checkins] Daily reference leaks (86a1f92c66b3): sum=0 Message-ID: results for 86a1f92c66b3 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogD5LtOI', '-x'] From martin at v.loewis.de Fri Mar 30 06:12:22 2012 From: martin at v.loewis.de (martin at v.loewis.de) Date: Fri, 30 Mar 2012 06:12:22 +0200 Subject: [Python-checkins] cpython (3.2): Issue #14409: IDLE doesn't not execute commands from shell with default In-Reply-To: References: Message-ID: <20120330061222.Horde.L8aPH7uWis5PdTKmYa9VVjA@webmail.df.eu> Zitat von Nick Coghlan : > On Fri, Mar 30, 2012 at 2:01 AM, andrew.svetlov > wrote: >> +- Issue #14409: IDLE doesn't not execute commands from shell, >> + ?error with default keybinding for Return. (Patch by Roger Serwy) > > The double negative here makes this impossible to understand. Could we > please get an updated NEWS entry that explains what actually changed > in IDLE to fix this? Please consider that Andrew is not a native speaker of English. So it's unfair to ask him to rewrite the NEWS entry. That can only be done by a native speaker. > Perhaps something like "IDLE now always sets the default keybind for > Return correctly, ensuring commands can be executed in the IDLE shell > window"? (assuming that's what happened). > > This is important, folks: NEWS entries need to be comprehensible for > people that *haven't* read the associated tracker issue. People can do that if you can accept that NEWS items are in ukrainian. Regards, Martin From ncoghlan at gmail.com Fri Mar 30 07:33:41 2012 From: ncoghlan at gmail.com (Nick Coghlan) Date: Fri, 30 Mar 2012 15:33:41 +1000 Subject: [Python-checkins] cpython (3.2): Issue #14409: IDLE doesn't not execute commands from shell with default In-Reply-To: <20120330061222.Horde.L8aPH7uWis5PdTKmYa9VVjA@webmail.df.eu> References: <20120330061222.Horde.L8aPH7uWis5PdTKmYa9VVjA@webmail.df.eu> Message-ID: On Fri, Mar 30, 2012 at 2:12 PM, wrote: > > Zitat von Nick Coghlan : > > >> On Fri, Mar 30, 2012 at 2:01 AM, andrew.svetlov >> wrote: >>> >>> +- Issue #14409: IDLE doesn't not execute commands from shell, >>> + ?error with default keybinding for Return. (Patch by Roger Serwy) >> >> >> The double negative here makes this impossible to understand. Could we >> please get an updated NEWS entry that explains what actually changed >> in IDLE to fix this? > > > Please consider that Andrew is not a native speaker of English. So > it's unfair to ask him to rewrite the NEWS entry. That can only > be done by a native speaker. The NEWS entries need to be treated as being at least close to on par with the rest of the docs - it's OK if someone can't come up with the words themselves, but if that's the case, then it's preferable to ask for help with the wording explicitly. Is my suggested rephrasing correct? I don't know, as I'm not familiar with either the original problem or what was done to fix it. Regards, Nick. -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From python-checkins at python.org Fri Mar 30 09:27:08 2012 From: python-checkins at python.org (georg.brandl) Date: Fri, 30 Mar 2012 09:27:08 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_Small_fixes=2E?= Message-ID: http://hg.python.org/peps/rev/cc171a07720a changeset: 4172:cc171a07720a user: Georg Brandl date: Fri Mar 30 09:27:16 2012 +0200 summary: Small fixes. files: pep-0411.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0411.txt b/pep-0411.txt --- a/pep-0411.txt +++ b/pep-0411.txt @@ -63,11 +63,11 @@ "provisional package", defined as: A provisional package is one which has been deliberately excluded from the - standard library's normal backwards compatibility guarantees. While major + standard library's backwards compatibility guarantees. While major changes to such packages are not expected, as long as they are marked provisional, backwards incompatible changes (up to and including removal of the package) may occur if deemed necessary by core developers. Such changes - will not be made gratuitously - they will occur only if serious flaws are + will not be made gratuitously -- they will occur only if serious flaws are uncovered that were missed prior to the inclusion of the package. This process allows the standard library to continue to evolve over time, -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Mar 30 09:48:02 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 30 Mar 2012 09:48:02 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_fix_a_tiny_typo?= Message-ID: http://hg.python.org/peps/rev/6c1e4170d717 changeset: 4173:6c1e4170d717 user: Eli Bendersky date: Fri Mar 30 10:46:49 2012 +0300 summary: fix a tiny typo files: pep-0411.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0411.txt b/pep-0411.txt --- a/pep-0411.txt +++ b/pep-0411.txt @@ -74,7 +74,7 @@ without locking in problematic design errors for extended periods of time. See PEP 411 for more details. -The following will be added to the start of the packages's docstring: +The following will be added to the start of the package's docstring: The API of this package is currently provisional. Refer to the documentation for details. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Mar 30 09:53:43 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 30 Mar 2012 09:53:43 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Added_the_=22provisional_pa?= =?utf8?q?ckage=22_glossary_term_from_PEP_411?= Message-ID: http://hg.python.org/cpython/rev/f29401c581a0 changeset: 75990:f29401c581a0 user: Eli Bendersky date: Fri Mar 30 10:52:25 2012 +0300 summary: Added the "provisional package" glossary term from PEP 411 files: Doc/glossary.rst | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -523,6 +523,20 @@ definition), or pass several arguments as a list to a function. See :term:`argument`. + provisional package + A provisional package is one which has been deliberately excluded from the + standard library's backwards compatibility guarantees. While major + changes to such packages are not expected, as long as they are marked + provisional, backwards incompatible changes (up to and including removal + of the package) may occur if deemed necessary by core developers. Such + changes will not be made gratuitously -- they will occur only if serious + flaws are uncovered that were missed prior to the inclusion of the + package. + + This process allows the standard library to continue to evolve over time, + without locking in problematic design errors for extended periods of time. + See :pep:`411` for more details. + Python 3000 Nickname for the Python 3.x release line (coined long ago when the release of version 3 was something in the distant future.) This is also -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 30 10:03:19 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 30 Mar 2012 10:03:19 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_typo_in_glossary?= Message-ID: http://hg.python.org/cpython/rev/c4bd68be5fc6 changeset: 75991:c4bd68be5fc6 user: Eli Bendersky date: Fri Mar 30 11:02:05 2012 +0300 summary: fix typo in glossary files: Doc/glossary.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -194,7 +194,7 @@ An object exposing a file-oriented API (with methods such as :meth:`read()` or :meth:`write()`) to an underlying resource. Depending on the way it was created, a file object can mediate access to a real - on-disk file or to another other type of storage or communication device + on-disk file or to another type of storage or communication device (for example standard input/output, in-memory buffers, sockets, pipes, etc.). File objects are also called :dfn:`file-like objects` or :dfn:`streams`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 30 10:45:31 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 30 Mar 2012 10:45:31 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314006=3A_improve_t?= =?utf8?q?he_documentation_of_xml=2Eetree=2EElementTree?= Message-ID: http://hg.python.org/cpython/rev/78038b6e0a85 changeset: 75992:78038b6e0a85 user: Eli Bendersky date: Fri Mar 30 11:44:15 2012 +0300 summary: Issue #14006: improve the documentation of xml.etree.ElementTree Removed the useless explanation of the Element data structure that started the documentation page. Instead, the documentation now starts with a brief tutorial skimming some of the capabilities of the module. The tutorial can be followed by additional topic-specific sections (such as XPath support), and eventually by a reference that goes over the module's classes and functions, as usual. files: Doc/library/xml.etree.elementtree.rst | 177 +++++++++---- 1 files changed, 126 insertions(+), 51 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -5,65 +5,40 @@ :synopsis: Implementation of the ElementTree API. .. moduleauthor:: Fredrik Lundh -**Source code:** :source:`Lib/xml/etree/ElementTree.py` - --------------- - -The :class:`Element` type is a flexible container object, designed to store -hierarchical data structures in memory. The type can be described as a cross -between a list and a dictionary. - -Each element has a number of properties associated with it: - -* a tag which is a string identifying what kind of data this element represents - (the element type, in other words). - -* a number of attributes, stored in a Python dictionary. - -* a text string. - -* an optional tail string. - -* a number of child elements, stored in a Python sequence - -To create an element instance, use the :class:`Element` constructor or the -:func:`SubElement` factory function. - -The :class:`ElementTree` class can be used to wrap an element structure, and -convert it from and to XML. - -See http://effbot.org/zone/element-index.htm for tutorials and links to other -docs. - -.. versionchanged:: 3.2 - The ElementTree API is updated to 1.3. For more information, see - `Introducing ElementTree 1.3 - `_. +The :mod:`xml.etree.ElementTree` module implements a simple and efficient API +for parsing and creating XML data. .. versionchanged:: 3.3 This module will use a fast implementation whenever available. The :mod:`xml.etree.cElementTree` module is deprecated. +Tutorial +-------- -.. _elementtree-xpath: +This is a short tutorial for using :mod:`xml.etree.ElementTree` (``ET`` in +short). The goal is to demonstrate some of the building blocks and basic +concepts of the module. -XPath support -------------- +XML tree and elements +^^^^^^^^^^^^^^^^^^^^^ -This module provides limited support for -`XPath expressions `_ for locating elements in a -tree. The goal is to support a small subset of the abbreviated syntax; a full -XPath engine is outside the scope of the module. +XML is an inherently hierarchical data format, and the most natural way to +represent it is with a tree. ``ET`` has two classes for this purpose - +:class:`ElementTree` represents the whole XML document as a tree, and +:class:`Element` represents a single node in this tree. Interactions with +the whole document (reading and writing to/from files) are usually done +on the :class:`ElementTree` level. Interactions with a single XML element +and its sub-elements are done on the :class:`Element` level. -Example -^^^^^^^ +.. _elementtree-parsing-xml: -Here's an example that demonstrates some of the XPath capabilities of the -module:: +Parsing XML +^^^^^^^^^^^ - import xml.etree.ElementTree as ET +We'll be using the following XML document contained in a Python string as the +sample data for this section:: - xml = r''' + countrydata = r''' 1 @@ -88,23 +63,121 @@ ''' - tree = ET.fromstring(xml) +First, import the module and parse the data:: + + import xml.etree.ElementTree as ET + + root = ET.fromstring(countrydata) + +:func:`fromstring` parses XML from a string directly into an :class:`Element`, +which is the root element of the parsed tree. Other parsing functions may +create an :class:`ElementTree`. Make sure to check the documentation to be +sure. + +As an :class:`Element`, ``root`` has a tag and a dictionary of attributes:: + + >>> root.tag + 'data' + >>> root.attrib + {} + +It also has children nodes over which we can iterate:: + + >>> for child in root: + ... print(child.tag, child.attrib) + ... + country {'name': 'Liechtenshtein'} + country {'name': 'Singapore'} + country {'name': 'Panama'} + +Children are nested, and we can access specific child nodes by index:: + + >>> root[0][1].text + '2008' + +Finding interesting elements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:class:`Element` has some useful methods that help iterate recursively over all +the sub-tree below it (its children, their children, and so on). For example, +:meth:`Element.iter`:: + + >>> for neighbor in root.iter('neighbor'): + ... print(neighbor.attrib) + ... + {'name': 'Austria', 'direction': 'E'} + {'name': 'Switzerland', 'direction': 'W'} + {'name': 'Malaysia', 'direction': 'N'} + {'name': 'Costa Rica', 'direction': 'W'} + {'name': 'Colombia', 'direction': 'E'} + +More sophisticated specification of which elements to look for is possible by +using :ref:`XPath `. + +Building XML documents +^^^^^^^^^^^^^^^^^^^^^^ + +``ET`` provides a simple way to build XML documents and write them to files. +The :meth:`ElementTree.write` method serves this purpose. + +Once created, an :class:`Element` object may be manipulated by directly changing +its fields (such as :attr:`Element.text`), adding and modifying attributes +(:meth:`Element.set` method), as well as adding new children (for example +with :meth:`Element.append`). + +The :func:`SubElement` function also provides a convenient way to create new +sub-elements for a given element:: + + >>> a = ET.Element('a') + >>> b = ET.SubElement(a, 'b') + >>> c = ET.SubElement(a, 'c') + >>> d = ET.SubElement(c, 'd') + >>> ET.dump(a) + + +Additional resources +^^^^^^^^^^^^^^^^^^^^ + +See http://effbot.org/zone/element-index.htm for tutorials and links to other +docs. + + +.. _elementtree-xpath: + +XPath support +------------- + +This module provides limited support for +`XPath expressions `_ for locating elements in a +tree. The goal is to support a small subset of the abbreviated syntax; a full +XPath engine is outside the scope of the module. + +Example +^^^^^^^ + +Here's an example that demonstrates some of the XPath capabilities of the +module. We'll be using the ``countrydata`` XML document from the +:ref:`Parsing XML ` section:: + + import xml.etree.ElementTree as ET + + root = ET.fromstring(countrydata) # Top-level elements - tree.findall(".") + root.findall(".") # All 'neighbor' grand-children of 'country' children of the top-level # elements - tree.findall("./country/neighbor") + root.findall("./country/neighbor") # Nodes with name='Singapore' that have a 'year' child - tree.findall(".//year/..[@name='Singapore']") + root.findall(".//year/..[@name='Singapore']") # 'year' nodes that are children of nodes with name='Singapore' - tree.findall(".//*[@name='Singapore']/year") + root.findall(".//*[@name='Singapore']/year") # All 'neighbor' nodes that are the second child of their parent - tree.findall(".//neighbor[2]") + root.findall(".//neighbor[2]") Supported XPath syntax ^^^^^^^^^^^^^^^^^^^^^^ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 30 11:19:53 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Fri, 30 Mar 2012 11:19:53 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314435=3A_Remove_sp?= =?utf8?q?ecial_block_allocation_code_from_floatobject=2Ec?= Message-ID: http://hg.python.org/cpython/rev/37ebe64d39d2 changeset: 75993:37ebe64d39d2 user: Kristj?n Valur J?nsson date: Fri Mar 30 09:18:15 2012 +0000 summary: Issue #14435: Remove special block allocation code from floatobject.c PyFloatObjects are now allocated using PyObject_MALLOC like all other internal types, but maintain a limited freelist of objects at hand for performance. This will result in more consistent memory usage by Python. files: Objects/floatobject.c | 158 +++++------------------------ 1 files changed, 27 insertions(+), 131 deletions(-) diff --git a/Objects/floatobject.c b/Objects/floatobject.c --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -16,53 +16,16 @@ /* Special free list - - Since some Python programs can spend much of their time allocating - and deallocating floats, these operations should be very fast. - Therefore we use a dedicated allocation scheme with a much lower - overhead (in space and time) than straight malloc(): a simple - dedicated free list, filled when necessary with memory from malloc(). - - block_list is a singly-linked list of all PyFloatBlocks ever allocated, - linked via their next members. PyFloatBlocks are never returned to the - system before shutdown (PyFloat_Fini). - free_list is a singly-linked list of available PyFloatObjects, linked via abuse of their ob_type members. */ -#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ -#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ -#define N_FLOATOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyFloatObject)) - -struct _floatblock { - struct _floatblock *next; - PyFloatObject objects[N_FLOATOBJECTS]; -}; - -typedef struct _floatblock PyFloatBlock; - -static PyFloatBlock *block_list = NULL; +#ifndef PyFloat_MAXFREELIST +#define PyFloat_MAXFREELIST 100 +#endif +static int numfree = 0; static PyFloatObject *free_list = NULL; -static PyFloatObject * -fill_free_list(void) -{ - PyFloatObject *p, *q; - /* XXX Float blocks escape the object heap. Use PyObject_MALLOC ??? */ - p = (PyFloatObject *) PyMem_MALLOC(sizeof(PyFloatBlock)); - if (p == NULL) - return (PyFloatObject *) PyErr_NoMemory(); - ((PyFloatBlock *)p)->next = block_list; - block_list = (PyFloatBlock *)p; - p = &((PyFloatBlock *)p)->objects[0]; - q = p + N_FLOATOBJECTS; - while (--q > p) - Py_TYPE(q) = (struct _typeobject *)(q-1); - Py_TYPE(q) = NULL; - return p + N_FLOATOBJECTS - 1; -} - double PyFloat_GetMax(void) { @@ -151,14 +114,16 @@ PyObject * PyFloat_FromDouble(double fval) { - register PyFloatObject *op; - if (free_list == NULL) { - if ((free_list = fill_free_list()) == NULL) - return NULL; + register PyFloatObject *op = free_list; + if (op != NULL) { + free_list = (PyFloatObject *) Py_TYPE(op); + numfree--; + } else { + op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject)); + if (!op) + return PyErr_NoMemory(); } /* Inline PyObject_New */ - op = free_list; - free_list = (PyFloatObject *)Py_TYPE(op); PyObject_INIT(op, &PyFloat_Type); op->ob_fval = fval; return (PyObject *) op; @@ -217,6 +182,11 @@ float_dealloc(PyFloatObject *op) { if (PyFloat_CheckExact(op)) { + if (numfree >= PyFloat_MAXFREELIST) { + PyObject_FREE(op); + return; + } + numfree++; Py_TYPE(op) = (struct _typeobject *)free_list; free_list = op; } @@ -1932,96 +1902,22 @@ int PyFloat_ClearFreeList(void) { - PyFloatObject *p; - PyFloatBlock *list, *next; - int i; - int u; /* remaining unfreed floats per block */ - int freelist_size = 0; - - list = block_list; - block_list = NULL; + PyFloatObject *f = free_list, *next; + int i = numfree; + while (f) { + next = (PyFloatObject*) Py_TYPE(f); + PyObject_FREE(f); + f = next; + } free_list = NULL; - while (list != NULL) { - u = 0; - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0) - u++; - } - next = list->next; - if (u) { - list->next = block_list; - block_list = list; - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (!PyFloat_CheckExact(p) || - Py_REFCNT(p) == 0) { - Py_TYPE(p) = (struct _typeobject *) - free_list; - free_list = p; - } - } - } - else { - PyMem_FREE(list); - } - freelist_size += u; - list = next; - } - return freelist_size; + numfree = 0; + return i; } void PyFloat_Fini(void) { - PyFloatObject *p; - PyFloatBlock *list; - int i; - int u; /* total unfreed floats per block */ - - u = PyFloat_ClearFreeList(); - - if (!Py_VerboseFlag) - return; - fprintf(stderr, "# cleanup floats"); - if (!u) { - fprintf(stderr, "\n"); - } - else { - fprintf(stderr, - ": %d unfreed float%s\n", - u, u == 1 ? "" : "s"); - } - if (Py_VerboseFlag > 1) { - list = block_list; - while (list != NULL) { - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (PyFloat_CheckExact(p) && - Py_REFCNT(p) != 0) { - char *buf = PyOS_double_to_string( - PyFloat_AS_DOUBLE(p), 'r', - 0, 0, NULL); - if (buf) { - /* XXX(twouters) cast - refcount to long - until %zd is - universally - available - */ - fprintf(stderr, - "# \n", - p, (long)Py_REFCNT(p), buf); - PyMem_Free(buf); - } - } - } - list = list->next; - } - } + (void)PyFloat_ClearFreeList(); } /*---------------------------------------------------------------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 30 13:53:12 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 30 Mar 2012 13:53:12 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_split_resolution/ac?= =?utf8?q?curacy_in_the_able=3B_add_a_section_on_Linux_timers?= Message-ID: http://hg.python.org/peps/rev/9c08fc65b371 changeset: 4174:9c08fc65b371 user: Victor Stinner date: Fri Mar 30 13:53:40 2012 +0200 summary: PEP 418: split resolution/accuracy in the able; add a section on Linux timers files: pep-0418.txt | 83 +++++++++++++++++++++++++++++++++------ 1 files changed, 70 insertions(+), 13 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -186,18 +186,29 @@ Table summarizing all monotonic clocks: -========================= =============== ================ ==================== -Name Resolution Adjusted by NTP? Action on suspend -========================= =============== ================ ==================== -CLOCK_MONOTONIC_RAW 1 ns No Stopped -gethrtime 1 ns No Not stopped -mach_absolute_time() 1 ns No ? -CLOCK_HIGHRES 1 ns No ? -CLOCK_MONOTONIC 1 ns Yes on Linux Stopped on Linux -QueryPerformanceCounter() 0.3 ns - 5 ns No Accuracy issue -GetTickCount[64]() 1 ms - 15 ms No Include suspend time -timeGetTime() 1 ms - 15 ms No ? -========================= =============== ================ ==================== +========================= =============== =============== ================ ==================== +Name Resolution Accuracy Adjusted by NTP? Action on suspend +========================= =============== =============== ================ ==================== +CLOCK_MONOTONIC_RAW 1 ns ? No Stopped +gethrtime 1 ns ? No Not stopped +mach_absolute_time() 1 ns ? No ? +CLOCK_HIGHRES 1 ns ? No ? +CLOCK_MONOTONIC 1 ns ? Yes on Linux Stopped on Linux +QueryPerformanceCounter() \- 0.3 ns - 5 ns No Accuracy issue +GetTickCount[64]() 1 ms 1 ms - 15 ms No Include suspend time +timeGetTime() 1 ms 1 ms - 15 ms No ? +========================= =============== =============== ================ ==================== + +The resolution is the smallest difference between two timestamps supported by +the format used by the clock. For example, clock_gettime() uses a timespec +structure which has two integer fileds, tv_sec and tv_nsec, so the resolution +is 1 nanosecond. + +The accuracy is the effective smallest difference of two timestamps of the +clock. It does not reflect the stability the clock rate. For example, +QueryPerformanceCounter() has a good accuracy but is known to not have a steady +rate. + mach_absolute_time ^^^^^^^^^^^^^^^^^^ @@ -351,7 +362,7 @@ more, depending on the machine. timeBeginPeriod() can be used to increase the precision of timeGetTime() up to -1 millisecond. +1 millisecond, but it negatively affects power consumption. .. note:: timeGetTime() and timeBeginPeriod() are part the Windows multimedia library @@ -477,6 +488,50 @@ QueryUnbiasedInterruptTime() was introduced in Windows 7. +Linux timers +------------ + +There were 4 implementations of the time in the Linux kernel: UTIME (1996), +timer wheel (1997), HRT (2001) and hrtimers (2007). The later is the result of +the "high-res-timers" project started by George Anzinger in 2001, contributed +by Thomas Gleixner and Douglas Niehaus. hrtimers implementation was merged into +Linux 2.6.21 released in 2007. + +hrtimers supports various clock sources. It sets a priority to each source to +decide which one will be used. + + * TSC (Time Stamp Counter): Internal processor clock incremented at each + processor cycle. Its frequency is the processor frequency and so usually + higher than 1 GHz. Its priority is 300 by default, but falls to 0 if the + processor frequency changes and the counter becomes unstable. + * HPET: An HPET chip consists of a 64-bit up-counter (main counter) counting + at least at 10 MHz and a set of up to 256 comparators (at least 3). Each + HPET can have up to 32 timers. + * PIT (programmable interrupt timer): Intel 8253/8254 chipsets with a + configurable frequecency in range 18.2 Hz - 1.2 MHz. Linux uses the + frequency: 1,193,181.8 Hz. It is a 16-bit counter. + * PMTMR (power management timer): ACPI 24-bit timer with a frequency of 3.5 + MHz (3,579,545 Hz). Its priority is 200 by default, but changes to 110 if + the chipset is broken and need a software workaround. HPET can cause around + 3 seconds of drift per day. + * Cyclone: The Cyclone timer uses a 32-bit counter on IBM Extended + X-Architecture (EXA) chipsets which include computers that use the IBM + "Summit" series chipsets (ex: x440). This is available in IA32 and IA64 + architectures. + +High-resolution timers are not supported on all hardware architectures. They +are at least provided on x86/x86_64, ARM and PowerPC. + +The list of available clock sources can be read in +/sys/devices/system/clocksource/clocksource0/available_clocksource. It is +possible to force a clocksource at runtime by writing its name into +/sys/devices/system/clocksource/clocksource0/current_clocksource. +/proc/timer_list contains the list of all hardware timers. + +Read also the `time(7) manual page +`_: +"overview of time and timers". + Alternatives: API design ======================== @@ -584,6 +639,8 @@ Time: + * `hrtimers - subsystem for high-resolution kernel timers + `_ * `C++ Timeout Specification `_ * `Windows: Game Timing and Multicore Processors -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Mar 30 14:21:01 2012 From: python-checkins at python.org (stefan.krah) Date: Fri, 30 Mar 2012 14:21:01 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Use_abort=28=29_rather_than?= =?utf8?q?_exit=28=29_to_appease_tools_like_rpmlint=2E_abort=28=29_is_used?= Message-ID: http://hg.python.org/cpython/rev/3a83264ebcd6 changeset: 75994:3a83264ebcd6 parent: 75970:e505ce0514ff user: Stefan Krah date: Fri Mar 30 14:12:20 2012 +0200 summary: Use abort() rather than exit() to appease tools like rpmlint. abort() is used in libmpdec to prevent undefined behavior if an invalid context is used. This cannot occur for the _decimal module since user input for the context is validated. files: Modules/_decimal/libmpdec/mpdecimal.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h --- a/Modules/_decimal/libmpdec/mpdecimal.h +++ b/Modules/_decimal/libmpdec/mpdecimal.h @@ -751,7 +751,7 @@ #define mpd_err_fatal(...) \ do {fprintf(stderr, "%s:%d: error: ", __FILE__, __LINE__); \ fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); \ - exit(1); \ + abort(); \ } while (0) #define mpd_err_warn(...) \ do {fprintf(stderr, "%s:%d: warning: ", __FILE__, __LINE__); \ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 30 14:21:02 2012 From: python-checkins at python.org (stefan.krah) Date: Fri, 30 Mar 2012 14:21:02 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?b?KTogTWVyZ2Uu?= Message-ID: http://hg.python.org/cpython/rev/cf2e74e0b7d4 changeset: 75995:cf2e74e0b7d4 parent: 75994:3a83264ebcd6 parent: 75993:37ebe64d39d2 user: Stefan Krah date: Fri Mar 30 14:19:21 2012 +0200 summary: Merge. files: Doc/glossary.rst | 16 +- Doc/library/development.rst | 4 - Doc/library/syslog.rst | 9 +- Doc/library/time.rst | 7 + Doc/library/unittest.mock-examples.rst | 425 +++- Doc/library/unittest.mock-getting-started.rst | 417 --- Doc/library/unittest.mock-helpers.rst | 529 ---- Doc/library/unittest.mock-magicmethods.rst | 224 - Doc/library/unittest.mock-patch.rst | 529 ---- Doc/library/unittest.mock.rst | 1298 +++++++++- Doc/library/xml.etree.elementtree.rst | 177 +- Lib/idlelib/NEWS.txt | 3 + Lib/idlelib/configHandler.py | 2 +- Lib/logging/handlers.py | 15 +- Lib/test/test_smtplib.py | 1 + Lib/unittest/mock.py | 25 +- Misc/ACKS | 1 + Misc/NEWS | 8 + Modules/syslogmodule.c | 8 + Objects/floatobject.c | 158 +- 20 files changed, 1941 insertions(+), 1915 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -194,7 +194,7 @@ An object exposing a file-oriented API (with methods such as :meth:`read()` or :meth:`write()`) to an underlying resource. Depending on the way it was created, a file object can mediate access to a real - on-disk file or to another other type of storage or communication device + on-disk file or to another type of storage or communication device (for example standard input/output, in-memory buffers, sockets, pipes, etc.). File objects are also called :dfn:`file-like objects` or :dfn:`streams`. @@ -523,6 +523,20 @@ definition), or pass several arguments as a list to a function. See :term:`argument`. + provisional package + A provisional package is one which has been deliberately excluded from the + standard library's backwards compatibility guarantees. While major + changes to such packages are not expected, as long as they are marked + provisional, backwards incompatible changes (up to and including removal + of the package) may occur if deemed necessary by core developers. Such + changes will not be made gratuitously -- they will occur only if serious + flaws are uncovered that were missed prior to the inclusion of the + package. + + This process allows the standard library to continue to evolve over time, + without locking in problematic design errors for extended periods of time. + See :pep:`411` for more details. + Python 3000 Nickname for the Python 3.x release line (coined long ago when the release of version 3 was something in the distant future.) This is also diff --git a/Doc/library/development.rst b/Doc/library/development.rst --- a/Doc/library/development.rst +++ b/Doc/library/development.rst @@ -20,10 +20,6 @@ doctest.rst unittest.rst unittest.mock.rst - unittest.mock-patch.rst - unittest.mock-magicmethods.rst - unittest.mock-helpers.rst - unittest.mock-getting-started.rst unittest.mock-examples.rst 2to3.rst test.rst diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -78,11 +78,14 @@ Facilities: :const:`LOG_KERN`, :const:`LOG_USER`, :const:`LOG_MAIL`, :const:`LOG_DAEMON`, :const:`LOG_AUTH`, :const:`LOG_LPR`, :const:`LOG_NEWS`, :const:`LOG_UUCP`, - :const:`LOG_CRON` and :const:`LOG_LOCAL0` to :const:`LOG_LOCAL7`. + :const:`LOG_CRON`, :const:`LOG_SYSLOG`, :const:`LOG_LOCAL0` to + :const:`LOG_LOCAL7`, and, if defined in ````, + :const:`LOG_AUTHPRIV`. Log options: - :const:`LOG_PID`, :const:`LOG_CONS`, :const:`LOG_NDELAY`, :const:`LOG_NOWAIT` - and :const:`LOG_PERROR` if defined in ````. + :const:`LOG_PID`, :const:`LOG_CONS`, :const:`LOG_NDELAY`, and, if defined + in ````, :const:`LOG_ODELAY`, :const:`LOG_NOWAIT`, and + :const:`LOG_PERROR`. Examples diff --git a/Doc/library/time.rst b/Doc/library/time.rst --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -143,12 +143,14 @@ .. versionadded:: 3.3 + .. function:: clock_gettime(clk_id) Return the time of the specified clock *clk_id*. .. versionadded:: 3.3 + .. data:: CLOCK_REALTIME System-wide real-time clock. Setting this clock requires appropriate @@ -156,6 +158,7 @@ .. versionadded:: 3.3 + .. data:: CLOCK_MONOTONIC Clock that cannot be set and represents monotonic time since some @@ -163,6 +166,7 @@ .. versionadded:: 3.3 + .. data:: CLOCK_MONOTONIC_RAW Similar to :data:`CLOCK_MONOTONIC`, but provides access to a raw @@ -172,18 +176,21 @@ .. versionadded:: 3.3 + .. data:: CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU. .. versionadded:: 3.3 + .. data:: CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock. .. versionadded:: 3.3 + .. function:: ctime([secs]) Convert a time expressed in seconds since the epoch to a string representing diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -1,18 +1,427 @@ -.. _further-examples: +:mod:`unittest.mock` --- getting started +======================================== -:mod:`unittest.mock` --- further examples -========================================= - -.. module:: unittest.mock - :synopsis: Mock object library. .. moduleauthor:: Michael Foord .. currentmodule:: unittest.mock .. versionadded:: 3.3 -Here are some more examples for some slightly more advanced scenarios than in -the :ref:`getting started ` guide. +.. _getting-started: + +Using Mock +---------- + +Mock Patching Methods +~~~~~~~~~~~~~~~~~~~~~ + +Common uses for :class:`Mock` objects include: + +* Patching methods +* Recording method calls on objects + +You might want to replace a method on an object to check that +it is called with the correct arguments by another part of the system: + + >>> real = SomeClass() + >>> real.method = MagicMock(name='method') + >>> real.method(3, 4, 5, key='value') + + +Once our mock has been used (`real.method` in this example) it has methods +and attributes that allow you to make assertions about how it has been used. + +.. note:: + + In most of these examples the :class:`Mock` and :class:`MagicMock` classes + are interchangeable. As the `MagicMock` is the more capable class it makes + a sensible one to use by default. + +Once the mock has been called its :attr:`~Mock.called` attribute is set to +`True`. More importantly we can use the :meth:`~Mock.assert_called_with` or +:meth`~Mock.assert_called_once_with` method to check that it was called with +the correct arguments. + +This example tests that calling `ProductionClass().method` results in a call to +the `something` method: + + >>> class ProductionClass(object): + ... def method(self): + ... self.something(1, 2, 3) + ... def something(self, a, b, c): + ... pass + ... + >>> real = ProductionClass() + >>> real.something = MagicMock() + >>> real.method() + >>> real.something.assert_called_once_with(1, 2, 3) + + + +Mock for Method Calls on an Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the last example we patched a method directly on an object to check that it +was called correctly. Another common use case is to pass an object into a +method (or some part of the system under test) and then check that it is used +in the correct way. + +The simple `ProductionClass` below has a `closer` method. If it is called with +an object then it calls `close` on it. + + >>> class ProductionClass(object): + ... def closer(self, something): + ... something.close() + ... + +So to test it we need to pass in an object with a `close` method and check +that it was called correctly. + + >>> real = ProductionClass() + >>> mock = Mock() + >>> real.closer(mock) + >>> mock.close.assert_called_with() + +We don't have to do any work to provide the 'close' method on our mock. +Accessing close creates it. So, if 'close' hasn't already been called then +accessing it in the test will create it, but :meth:`~Mock.assert_called_with` +will raise a failure exception. + + +Mocking Classes +~~~~~~~~~~~~~~~ + +A common use case is to mock out classes instantiated by your code under test. +When you patch a class, then that class is replaced with a mock. Instances +are created by *calling the class*. This means you access the "mock instance" +by looking at the return value of the mocked class. + +In the example below we have a function `some_function` that instantiates `Foo` +and calls a method on it. The call to `patch` replaces the class `Foo` with a +mock. The `Foo` instance is the result of calling the mock, so it is configured +by modify the mock :attr:`~Mock.return_value`. + + >>> def some_function(): + ... instance = module.Foo() + ... return instance.method() + ... + >>> with patch('module.Foo') as mock: + ... instance = mock.return_value + ... instance.method.return_value = 'the result' + ... result = some_function() + ... assert result == 'the result' + + +Naming your mocks +~~~~~~~~~~~~~~~~~ + +It can be useful to give your mocks a name. The name is shown in the repr of +the mock and can be helpful when the mock appears in test failure messages. The +name is also propagated to attributes or methods of the mock: + + >>> mock = MagicMock(name='foo') + >>> mock + + >>> mock.method + + + +Tracking all Calls +~~~~~~~~~~~~~~~~~~ + +Often you want to track more than a single call to a method. The +:attr:`~Mock.mock_calls` attribute records all calls +to child attributes of the mock - and also to their children. + + >>> mock = MagicMock() + >>> mock.method() + + >>> mock.attribute.method(10, x=53) + + >>> mock.mock_calls + [call.method(), call.attribute.method(10, x=53)] + +If you make an assertion about `mock_calls` and any unexpected methods +have been called, then the assertion will fail. This is useful because as well +as asserting that the calls you expected have been made, you are also checking +that they were made in the right order and with no additional calls: + +You use the :data:`call` object to construct lists for comparing with +`mock_calls`: + + >>> expected = [call.method(), call.attribute.method(10, x=53)] + >>> mock.mock_calls == expected + True + + +Setting Return Values and Attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting the return values on a mock object is trivially easy: + + >>> mock = Mock() + >>> mock.return_value = 3 + >>> mock() + 3 + +Of course you can do the same for methods on the mock: + + >>> mock = Mock() + >>> mock.method.return_value = 3 + >>> mock.method() + 3 + +The return value can also be set in the constructor: + + >>> mock = Mock(return_value=3) + >>> mock() + 3 + +If you need an attribute setting on your mock, just do it: + + >>> mock = Mock() + >>> mock.x = 3 + >>> mock.x + 3 + +Sometimes you want to mock up a more complex situation, like for example +`mock.connection.cursor().execute("SELECT 1")`. If we wanted this call to +return a list, then we have to configure the result of the nested call. + +We can use :data:`call` to construct the set of calls in a "chained call" like +this for easy assertion afterwards: + + >>> mock = Mock() + >>> cursor = mock.connection.cursor.return_value + >>> cursor.execute.return_value = ['foo'] + >>> mock.connection.cursor().execute("SELECT 1") + ['foo'] + >>> expected = call.connection.cursor().execute("SELECT 1").call_list() + >>> mock.mock_calls + [call.connection.cursor(), call.connection.cursor().execute('SELECT 1')] + >>> mock.mock_calls == expected + True + +It is the call to `.call_list()` that turns our call object into a list of +calls representing the chained calls. + + +Raising exceptions with mocks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A useful attribute is :attr:`~Mock.side_effect`. If you set this to an +exception class or instance then the exception will be raised when the mock +is called. + + >>> mock = Mock(side_effect=Exception('Boom!')) + >>> mock() + Traceback (most recent call last): + ... + Exception: Boom! + + +Side effect functions and iterables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`side_effect` can also be set to a function or an iterable. The use case for +`side_effect` as an iterable is where your mock is going to be called several +times, and you want each call to return a different value. When you set +`side_effect` to an iterable every call to the mock returns the next value +from the iterable: + + >>> mock = MagicMock(side_effect=[4, 5, 6]) + >>> mock() + 4 + >>> mock() + 5 + >>> mock() + 6 + + +For more advanced use cases, like dynamically varying the return values +depending on what the mock is called with, `side_effect` can be a function. +The function will be called with the same arguments as the mock. Whatever the +function returns is what the call returns: + + >>> vals = {(1, 2): 1, (2, 3): 2} + >>> def side_effect(*args): + ... return vals[args] + ... + >>> mock = MagicMock(side_effect=side_effect) + >>> mock(1, 2) + 1 + >>> mock(2, 3) + 2 + + +Creating a Mock from an Existing Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One problem with over use of mocking is that it couples your tests to the +implementation of your mocks rather than your real code. Suppose you have a +class that implements `some_method`. In a test for another class, you +provide a mock of this object that *also* provides `some_method`. If later +you refactor the first class, so that it no longer has `some_method` - then +your tests will continue to pass even though your code is now broken! + +`Mock` allows you to provide an object as a specification for the mock, +using the `spec` keyword argument. Accessing methods / attributes on the +mock that don't exist on your specification object will immediately raise an +attribute error. If you change the implementation of your specification, then +tests that use that class will start failing immediately without you having to +instantiate the class in those tests. + + >>> mock = Mock(spec=SomeClass) + >>> mock.old_method() + Traceback (most recent call last): + ... + AttributeError: object has no attribute 'old_method' + +If you want a stronger form of specification that prevents the setting +of arbitrary attributes as well as the getting of them then you can use +`spec_set` instead of `spec`. + + + +Patch Decorators +---------------- + +.. note:: + + With `patch` it matters that you patch objects in the namespace where they + are looked up. This is normally straightforward, but for a quick guide + read :ref:`where to patch `. + + +A common need in tests is to patch a class attribute or a module attribute, +for example patching a builtin or patching a class in a module to test that it +is instantiated. Modules and classes are effectively global, so patching on +them has to be undone after the test or the patch will persist into other +tests and cause hard to diagnose problems. + +mock provides three convenient decorators for this: `patch`, `patch.object` and +`patch.dict`. `patch` takes a single string, of the form +`package.module.Class.attribute` to specify the attribute you are patching. It +also optionally takes a value that you want the attribute (or class or +whatever) to be replaced with. 'patch.object' takes an object and the name of +the attribute you would like patched, plus optionally the value to patch it +with. + +`patch.object`: + + >>> original = SomeClass.attribute + >>> @patch.object(SomeClass, 'attribute', sentinel.attribute) + ... def test(): + ... assert SomeClass.attribute == sentinel.attribute + ... + >>> test() + >>> assert SomeClass.attribute == original + + >>> @patch('package.module.attribute', sentinel.attribute) + ... def test(): + ... from package.module import attribute + ... assert attribute is sentinel.attribute + ... + >>> test() + +If you are patching a module (including `__builtin__`) then use `patch` +instead of `patch.object`: + + >>> mock = MagicMock(return_value = sentinel.file_handle) + >>> with patch('__builtin__.open', mock): + ... handle = open('filename', 'r') + ... + >>> mock.assert_called_with('filename', 'r') + >>> assert handle == sentinel.file_handle, "incorrect file handle returned" + +The module name can be 'dotted', in the form `package.module` if needed: + + >>> @patch('package.module.ClassName.attribute', sentinel.attribute) + ... def test(): + ... from package.module import ClassName + ... assert ClassName.attribute == sentinel.attribute + ... + >>> test() + +A nice pattern is to actually decorate test methods themselves: + + >>> class MyTest(unittest2.TestCase): + ... @patch.object(SomeClass, 'attribute', sentinel.attribute) + ... def test_something(self): + ... self.assertEqual(SomeClass.attribute, sentinel.attribute) + ... + >>> original = SomeClass.attribute + >>> MyTest('test_something').test_something() + >>> assert SomeClass.attribute == original + +If you want to patch with a Mock, you can use `patch` with only one argument +(or `patch.object` with two arguments). The mock will be created for you and +passed into the test function / method: + + >>> class MyTest(unittest2.TestCase): + ... @patch.object(SomeClass, 'static_method') + ... def test_something(self, mock_method): + ... SomeClass.static_method() + ... mock_method.assert_called_with() + ... + >>> MyTest('test_something').test_something() + +You can stack up multiple patch decorators using this pattern: + + >>> class MyTest(unittest2.TestCase): + ... @patch('package.module.ClassName1') + ... @patch('package.module.ClassName2') + ... def test_something(self, MockClass2, MockClass1): + ... self.assertTrue(package.module.ClassName1 is MockClass1) + ... self.assertTrue(package.module.ClassName2 is MockClass2) + ... + >>> MyTest('test_something').test_something() + +When you nest patch decorators the mocks are passed in to the decorated +function in the same order they applied (the normal *python* order that +decorators are applied). This means from the bottom up, so in the example +above the mock for `test_module.ClassName2` is passed in first. + +There is also :func:`patch.dict` for setting values in a dictionary just +during a scope and restoring the dictionary to its original state when the test +ends: + + >>> foo = {'key': 'value'} + >>> original = foo.copy() + >>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True): + ... assert foo == {'newkey': 'newvalue'} + ... + >>> assert foo == original + +`patch`, `patch.object` and `patch.dict` can all be used as context managers. + +Where you use `patch` to create a mock for you, you can get a reference to the +mock using the "as" form of the with statement: + + >>> class ProductionClass(object): + ... def method(self): + ... pass + ... + >>> with patch.object(ProductionClass, 'method') as mock_method: + ... mock_method.return_value = None + ... real = ProductionClass() + ... real.method(1, 2, 3) + ... + >>> mock_method.assert_called_with(1, 2, 3) + + +As an alternative `patch`, `patch.object` and `patch.dict` can be used as +class decorators. When used in this way it is the same as applying the +decorator indvidually to every method whose name starts with "test". + + +.. _further-examples: + +Further Examples +================ + + +Here are some more examples for some slightly more advanced scenarios. Mocking chained calls diff --git a/Doc/library/unittest.mock-getting-started.rst b/Doc/library/unittest.mock-getting-started.rst deleted file mode 100644 --- a/Doc/library/unittest.mock-getting-started.rst +++ /dev/null @@ -1,419 +0,0 @@ -:mod:`unittest.mock` --- getting started -======================================== - -.. module:: unittest.mock - :synopsis: Mock object library. -.. moduleauthor:: Michael Foord -.. currentmodule:: unittest.mock - -.. versionadded:: 3.3 - - -.. _getting-started: - -Using Mock ----------- - -Mock Patching Methods -~~~~~~~~~~~~~~~~~~~~~ - -Common uses for :class:`Mock` objects include: - -* Patching methods -* Recording method calls on objects - -You might want to replace a method on an object to check that -it is called with the correct arguments by another part of the system: - - >>> real = SomeClass() - >>> real.method = MagicMock(name='method') - >>> real.method(3, 4, 5, key='value') - - -Once our mock has been used (`real.method` in this example) it has methods -and attributes that allow you to make assertions about how it has been used. - -.. note:: - - In most of these examples the :class:`Mock` and :class:`MagicMock` classes - are interchangeable. As the `MagicMock` is the more capable class it makes - a sensible one to use by default. - -Once the mock has been called its :attr:`~Mock.called` attribute is set to -`True`. More importantly we can use the :meth:`~Mock.assert_called_with` or -:meth`~Mock.assert_called_once_with` method to check that it was called with -the correct arguments. - -This example tests that calling `ProductionClass().method` results in a call to -the `something` method: - - >>> class ProductionClass(object): - ... def method(self): - ... self.something(1, 2, 3) - ... def something(self, a, b, c): - ... pass - ... - >>> real = ProductionClass() - >>> real.something = MagicMock() - >>> real.method() - >>> real.something.assert_called_once_with(1, 2, 3) - - - -Mock for Method Calls on an Object -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In the last example we patched a method directly on an object to check that it -was called correctly. Another common use case is to pass an object into a -method (or some part of the system under test) and then check that it is used -in the correct way. - -The simple `ProductionClass` below has a `closer` method. If it is called with -an object then it calls `close` on it. - - >>> class ProductionClass(object): - ... def closer(self, something): - ... something.close() - ... - -So to test it we need to pass in an object with a `close` method and check -that it was called correctly. - - >>> real = ProductionClass() - >>> mock = Mock() - >>> real.closer(mock) - >>> mock.close.assert_called_with() - -We don't have to do any work to provide the 'close' method on our mock. -Accessing close creates it. So, if 'close' hasn't already been called then -accessing it in the test will create it, but :meth:`~Mock.assert_called_with` -will raise a failure exception. - - -Mocking Classes -~~~~~~~~~~~~~~~ - -A common use case is to mock out classes instantiated by your code under test. -When you patch a class, then that class is replaced with a mock. Instances -are created by *calling the class*. This means you access the "mock instance" -by looking at the return value of the mocked class. - -In the example below we have a function `some_function` that instantiates `Foo` -and calls a method on it. The call to `patch` replaces the class `Foo` with a -mock. The `Foo` instance is the result of calling the mock, so it is configured -by modify the mock :attr:`~Mock.return_value`. - - >>> def some_function(): - ... instance = module.Foo() - ... return instance.method() - ... - >>> with patch('module.Foo') as mock: - ... instance = mock.return_value - ... instance.method.return_value = 'the result' - ... result = some_function() - ... assert result == 'the result' - - -Naming your mocks -~~~~~~~~~~~~~~~~~ - -It can be useful to give your mocks a name. The name is shown in the repr of -the mock and can be helpful when the mock appears in test failure messages. The -name is also propagated to attributes or methods of the mock: - - >>> mock = MagicMock(name='foo') - >>> mock - - >>> mock.method - - - -Tracking all Calls -~~~~~~~~~~~~~~~~~~ - -Often you want to track more than a single call to a method. The -:attr:`~Mock.mock_calls` attribute records all calls -to child attributes of the mock - and also to their children. - - >>> mock = MagicMock() - >>> mock.method() - - >>> mock.attribute.method(10, x=53) - - >>> mock.mock_calls - [call.method(), call.attribute.method(10, x=53)] - -If you make an assertion about `mock_calls` and any unexpected methods -have been called, then the assertion will fail. This is useful because as well -as asserting that the calls you expected have been made, you are also checking -that they were made in the right order and with no additional calls: - -You use the :data:`call` object to construct lists for comparing with -`mock_calls`: - - >>> expected = [call.method(), call.attribute.method(10, x=53)] - >>> mock.mock_calls == expected - True - - -Setting Return Values and Attributes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Setting the return values on a mock object is trivially easy: - - >>> mock = Mock() - >>> mock.return_value = 3 - >>> mock() - 3 - -Of course you can do the same for methods on the mock: - - >>> mock = Mock() - >>> mock.method.return_value = 3 - >>> mock.method() - 3 - -The return value can also be set in the constructor: - - >>> mock = Mock(return_value=3) - >>> mock() - 3 - -If you need an attribute setting on your mock, just do it: - - >>> mock = Mock() - >>> mock.x = 3 - >>> mock.x - 3 - -Sometimes you want to mock up a more complex situation, like for example -`mock.connection.cursor().execute("SELECT 1")`. If we wanted this call to -return a list, then we have to configure the result of the nested call. - -We can use :data:`call` to construct the set of calls in a "chained call" like -this for easy assertion afterwards: - - >>> mock = Mock() - >>> cursor = mock.connection.cursor.return_value - >>> cursor.execute.return_value = ['foo'] - >>> mock.connection.cursor().execute("SELECT 1") - ['foo'] - >>> expected = call.connection.cursor().execute("SELECT 1").call_list() - >>> mock.mock_calls - [call.connection.cursor(), call.connection.cursor().execute('SELECT 1')] - >>> mock.mock_calls == expected - True - -It is the call to `.call_list()` that turns our call object into a list of -calls representing the chained calls. - - -Raising exceptions with mocks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A useful attribute is :attr:`~Mock.side_effect`. If you set this to an -exception class or instance then the exception will be raised when the mock -is called. - - >>> mock = Mock(side_effect=Exception('Boom!')) - >>> mock() - Traceback (most recent call last): - ... - Exception: Boom! - - -Side effect functions and iterables -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -`side_effect` can also be set to a function or an iterable. The use case for -`side_effect` as an iterable is where your mock is going to be called several -times, and you want each call to return a different value. When you set -`side_effect` to an iterable every call to the mock returns the next value -from the iterable: - - >>> mock = MagicMock(side_effect=[4, 5, 6]) - >>> mock() - 4 - >>> mock() - 5 - >>> mock() - 6 - - -For more advanced use cases, like dynamically varying the return values -depending on what the mock is called with, `side_effect` can be a function. -The function will be called with the same arguments as the mock. Whatever the -function returns is what the call returns: - - >>> vals = {(1, 2): 1, (2, 3): 2} - >>> def side_effect(*args): - ... return vals[args] - ... - >>> mock = MagicMock(side_effect=side_effect) - >>> mock(1, 2) - 1 - >>> mock(2, 3) - 2 - - -Creating a Mock from an Existing Object -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -One problem with over use of mocking is that it couples your tests to the -implementation of your mocks rather than your real code. Suppose you have a -class that implements `some_method`. In a test for another class, you -provide a mock of this object that *also* provides `some_method`. If later -you refactor the first class, so that it no longer has `some_method` - then -your tests will continue to pass even though your code is now broken! - -`Mock` allows you to provide an object as a specification for the mock, -using the `spec` keyword argument. Accessing methods / attributes on the -mock that don't exist on your specification object will immediately raise an -attribute error. If you change the implementation of your specification, then -tests that use that class will start failing immediately without you having to -instantiate the class in those tests. - - >>> mock = Mock(spec=SomeClass) - >>> mock.old_method() - Traceback (most recent call last): - ... - AttributeError: object has no attribute 'old_method' - -If you want a stronger form of specification that prevents the setting -of arbitrary attributes as well as the getting of them then you can use -`spec_set` instead of `spec`. - - - -Patch Decorators ----------------- - -.. note:: - - With `patch` it matters that you patch objects in the namespace where they - are looked up. This is normally straightforward, but for a quick guide - read :ref:`where to patch `. - - -A common need in tests is to patch a class attribute or a module attribute, -for example patching a builtin or patching a class in a module to test that it -is instantiated. Modules and classes are effectively global, so patching on -them has to be undone after the test or the patch will persist into other -tests and cause hard to diagnose problems. - -mock provides three convenient decorators for this: `patch`, `patch.object` and -`patch.dict`. `patch` takes a single string, of the form -`package.module.Class.attribute` to specify the attribute you are patching. It -also optionally takes a value that you want the attribute (or class or -whatever) to be replaced with. 'patch.object' takes an object and the name of -the attribute you would like patched, plus optionally the value to patch it -with. - -`patch.object`: - - >>> original = SomeClass.attribute - >>> @patch.object(SomeClass, 'attribute', sentinel.attribute) - ... def test(): - ... assert SomeClass.attribute == sentinel.attribute - ... - >>> test() - >>> assert SomeClass.attribute == original - - >>> @patch('package.module.attribute', sentinel.attribute) - ... def test(): - ... from package.module import attribute - ... assert attribute is sentinel.attribute - ... - >>> test() - -If you are patching a module (including `__builtin__`) then use `patch` -instead of `patch.object`: - - >>> mock = MagicMock(return_value = sentinel.file_handle) - >>> with patch('__builtin__.open', mock): - ... handle = open('filename', 'r') - ... - >>> mock.assert_called_with('filename', 'r') - >>> assert handle == sentinel.file_handle, "incorrect file handle returned" - -The module name can be 'dotted', in the form `package.module` if needed: - - >>> @patch('package.module.ClassName.attribute', sentinel.attribute) - ... def test(): - ... from package.module import ClassName - ... assert ClassName.attribute == sentinel.attribute - ... - >>> test() - -A nice pattern is to actually decorate test methods themselves: - - >>> class MyTest(unittest2.TestCase): - ... @patch.object(SomeClass, 'attribute', sentinel.attribute) - ... def test_something(self): - ... self.assertEqual(SomeClass.attribute, sentinel.attribute) - ... - >>> original = SomeClass.attribute - >>> MyTest('test_something').test_something() - >>> assert SomeClass.attribute == original - -If you want to patch with a Mock, you can use `patch` with only one argument -(or `patch.object` with two arguments). The mock will be created for you and -passed into the test function / method: - - >>> class MyTest(unittest2.TestCase): - ... @patch.object(SomeClass, 'static_method') - ... def test_something(self, mock_method): - ... SomeClass.static_method() - ... mock_method.assert_called_with() - ... - >>> MyTest('test_something').test_something() - -You can stack up multiple patch decorators using this pattern: - - >>> class MyTest(unittest2.TestCase): - ... @patch('package.module.ClassName1') - ... @patch('package.module.ClassName2') - ... def test_something(self, MockClass2, MockClass1): - ... self.assertTrue(package.module.ClassName1 is MockClass1) - ... self.assertTrue(package.module.ClassName2 is MockClass2) - ... - >>> MyTest('test_something').test_something() - -When you nest patch decorators the mocks are passed in to the decorated -function in the same order they applied (the normal *python* order that -decorators are applied). This means from the bottom up, so in the example -above the mock for `test_module.ClassName2` is passed in first. - -There is also :func:`patch.dict` for setting values in a dictionary just -during a scope and restoring the dictionary to its original state when the test -ends: - - >>> foo = {'key': 'value'} - >>> original = foo.copy() - >>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True): - ... assert foo == {'newkey': 'newvalue'} - ... - >>> assert foo == original - -`patch`, `patch.object` and `patch.dict` can all be used as context managers. - -Where you use `patch` to create a mock for you, you can get a reference to the -mock using the "as" form of the with statement: - - >>> class ProductionClass(object): - ... def method(self): - ... pass - ... - >>> with patch.object(ProductionClass, 'method') as mock_method: - ... mock_method.return_value = None - ... real = ProductionClass() - ... real.method(1, 2, 3) - ... - >>> mock_method.assert_called_with(1, 2, 3) - - -As an alternative `patch`, `patch.object` and `patch.dict` can be used as -class decorators. When used in this way it is the same as applying the -decorator indvidually to every method whose name starts with "test". - -For some more advanced examples, see the :ref:`further-examples` page. diff --git a/Doc/library/unittest.mock-helpers.rst b/Doc/library/unittest.mock-helpers.rst deleted file mode 100644 --- a/Doc/library/unittest.mock-helpers.rst +++ /dev/null @@ -1,537 +0,0 @@ -:mod:`unittest.mock` --- helpers -================================ - -.. module:: unittest.mock - :synopsis: Mock object library. -.. moduleauthor:: Michael Foord -.. currentmodule:: unittest.mock - -.. versionadded:: 3.3 - - -sentinel --------- - -.. data:: sentinel - - The ``sentinel`` object provides a convenient way of providing unique - objects for your tests. - - Attributes are created on demand when you access them by name. Accessing - the same attribute will always return the same object. The objects - returned have a sensible repr so that test failure messages are readable. - -Sometimes when testing you need to test that a specific object is passed as an -argument to another method, or returned. It can be common to create named -sentinel objects to test this. `sentinel` provides a convenient way of -creating and testing the identity of objects like this. - -In this example we monkey patch `method` to return `sentinel.some_object`: - - >>> real = ProductionClass() - >>> real.method = Mock(name="method") - >>> real.method.return_value = sentinel.some_object - >>> result = real.method() - >>> assert result is sentinel.some_object - >>> sentinel.some_object - sentinel.some_object - - -DEFAULT -------- - - -.. data:: DEFAULT - - The `DEFAULT` object is a pre-created sentinel (actually - `sentinel.DEFAULT`). It can be used by :attr:`~Mock.side_effect` - functions to indicate that the normal return value should be used. - - - -call ----- - -.. function:: call(*args, **kwargs) - - `call` is a helper object for making simpler assertions, for comparing - with :attr:`~Mock.call_args`, :attr:`~Mock.call_args_list`, - :attr:`~Mock.mock_calls` and:attr: `~Mock.method_calls`. `call` can also be - used with :meth:`~Mock.assert_has_calls`. - - >>> m = MagicMock(return_value=None) - >>> m(1, 2, a='foo', b='bar') - >>> m() - >>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()] - True - -.. method:: call.call_list() - - For a call object that represents multiple calls, `call_list` - returns a list of all the intermediate calls as well as the - final call. - -`call_list` is particularly useful for making assertions on "chained calls". A -chained call is multiple calls on a single line of code. This results in -multiple entries in :attr:`~Mock.mock_calls` on a mock. Manually constructing -the sequence of calls can be tedious. - -:meth:`~call.call_list` can construct the sequence of calls from the same -chained call: - - >>> m = MagicMock() - >>> m(1).method(arg='foo').other('bar')(2.0) - - >>> kall = call(1).method(arg='foo').other('bar')(2.0) - >>> kall.call_list() - [call(1), - call().method(arg='foo'), - call().method().other('bar'), - call().method().other()(2.0)] - >>> m.mock_calls == kall.call_list() - True - -.. _calls-as-tuples: - -A `call` object is either a tuple of (positional args, keyword args) or -(name, positional args, keyword args) depending on how it was constructed. When -you construct them yourself this isn't particularly interesting, but the `call` -objects that are in the :attr:`Mock.call_args`, :attr:`Mock.call_args_list` and -:attr:`Mock.mock_calls` attributes can be introspected to get at the individual -arguments they contain. - -The `call` objects in :attr:`Mock.call_args` and :attr:`Mock.call_args_list` -are two-tuples of (positional args, keyword args) whereas the `call` objects -in :attr:`Mock.mock_calls`, along with ones you construct yourself, are -three-tuples of (name, positional args, keyword args). - -You can use their "tupleness" to pull out the individual arguments for more -complex introspection and assertions. The positional arguments are a tuple -(an empty tuple if there are no positional arguments) and the keyword -arguments are a dictionary: - - >>> m = MagicMock(return_value=None) - >>> m(1, 2, 3, arg='one', arg2='two') - >>> kall = m.call_args - >>> args, kwargs = kall - >>> args - (1, 2, 3) - >>> kwargs - {'arg2': 'two', 'arg': 'one'} - >>> args is kall[0] - True - >>> kwargs is kall[1] - True - - >>> m = MagicMock() - >>> m.foo(4, 5, 6, arg='two', arg2='three') - - >>> kall = m.mock_calls[0] - >>> name, args, kwargs = kall - >>> name - 'foo' - >>> args - (4, 5, 6) - >>> kwargs - {'arg2': 'three', 'arg': 'two'} - >>> name is m.mock_calls[0][0] - True - - -create_autospec ---------------- - -.. function:: create_autospec(spec, spec_set=False, instance=False, **kwargs) - - Create a mock object using another object as a spec. Attributes on the - mock will use the corresponding attribute on the `spec` object as their - spec. - - Functions or methods being mocked will have their arguments checked to - ensure that they are called with the correct signature. - - If `spec_set` is `True` then attempting to set attributes that don't exist - on the spec object will raise an `AttributeError`. - - If a class is used as a spec then the return value of the mock (the - instance of the class) will have the same spec. You can use a class as the - spec for an instance object by passing `instance=True`. The returned mock - will only be callable if instances of the mock are callable. - - `create_autospec` also takes arbitrary keyword arguments that are passed to - the constructor of the created mock. - -See :ref:`auto-speccing` for examples of how to use auto-speccing with -`create_autospec` and the `autospec` argument to :func:`patch`. - - -ANY ---- - -.. data:: ANY - -Sometimes you may need to make assertions about *some* of the arguments in a -call to mock, but either not care about some of the arguments or want to pull -them individually out of :attr:`~Mock.call_args` and make more complex -assertions on them. - -To ignore certain arguments you can pass in objects that compare equal to -*everything*. Calls to :meth:`~Mock.assert_called_with` and -:meth:`~Mock.assert_called_once_with` will then succeed no matter what was -passed in. - - >>> mock = Mock(return_value=None) - >>> mock('foo', bar=object()) - >>> mock.assert_called_once_with('foo', bar=ANY) - -`ANY` can also be used in comparisons with call lists like -:attr:`~Mock.mock_calls`: - - >>> m = MagicMock(return_value=None) - >>> m(1) - >>> m(1, 2) - >>> m(object()) - >>> m.mock_calls == [call(1), call(1, 2), ANY] - True - - - -FILTER_DIR ----------- - -.. data:: FILTER_DIR - -`FILTER_DIR` is a module level variable that controls the way mock objects -respond to `dir` (only for Python 2.6 or more recent). The default is `True`, -which uses the filtering described below, to only show useful members. If you -dislike this filtering, or need to switch it off for diagnostic purposes, then -set `mock.FILTER_DIR = False`. - -With filtering on, `dir(some_mock)` shows only useful attributes and will -include any dynamically created attributes that wouldn't normally be shown. -If the mock was created with a `spec` (or `autospec` of course) then all the -attributes from the original are shown, even if they haven't been accessed -yet: - - >>> dir(Mock()) - ['assert_any_call', - 'assert_called_once_with', - 'assert_called_with', - 'assert_has_calls', - 'attach_mock', - ... - >>> from urllib import request - >>> dir(Mock(spec=request)) - ['AbstractBasicAuthHandler', - 'AbstractDigestAuthHandler', - 'AbstractHTTPHandler', - 'BaseHandler', - ... - -Many of the not-very-useful (private to `Mock` rather than the thing being -mocked) underscore and double underscore prefixed attributes have been -filtered from the result of calling `dir` on a `Mock`. If you dislike this -behaviour you can switch it off by setting the module level switch -`FILTER_DIR`: - - >>> from unittest import mock - >>> mock.FILTER_DIR = False - >>> dir(mock.Mock()) - ['_NonCallableMock__get_return_value', - '_NonCallableMock__get_side_effect', - '_NonCallableMock__return_value_doc', - '_NonCallableMock__set_return_value', - '_NonCallableMock__set_side_effect', - '__call__', - '__class__', - ... - -Alternatively you can just use `vars(my_mock)` (instance members) and -`dir(type(my_mock))` (type members) to bypass the filtering irrespective of -`mock.FILTER_DIR`. - - -mock_open ---------- - -.. function:: mock_open(mock=None, read_data=None) - - A helper function to create a mock to replace the use of `open`. It works - for `open` called directly or used as a context manager. - - The `mock` argument is the mock object to configure. If `None` (the - default) then a `MagicMock` will be created for you, with the API limited - to methods or attributes available on standard file handles. - - `read_data` is a string for the `read` method of the file handle to return. - This is an empty string by default. - -Using `open` as a context manager is a great way to ensure your file handles -are closed properly and is becoming common:: - - with open('/some/path', 'w') as f: - f.write('something') - -The issue is that even if you mock out the call to `open` it is the -*returned object* that is used as a context manager (and has `__enter__` and -`__exit__` called). - -Mocking context managers with a :class:`MagicMock` is common enough and fiddly -enough that a helper function is useful. - - >>> m = mock_open() - >>> with patch('__main__.open', m, create=True): - ... with open('foo', 'w') as h: - ... h.write('some stuff') - ... - >>> m.mock_calls - [call('foo', 'w'), - call().__enter__(), - call().write('some stuff'), - call().__exit__(None, None, None)] - >>> m.assert_called_once_with('foo', 'w') - >>> handle = m() - >>> handle.write.assert_called_once_with('some stuff') - -And for reading files: - - >>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: - ... with open('foo') as h: - ... result = h.read() - ... - >>> m.assert_called_once_with('foo') - >>> assert result == 'bibble' - - -.. _auto-speccing: - -Autospeccing ------------- - -Autospeccing is based on the existing `spec` feature of mock. It limits the -api of mocks to the api of an original object (the spec), but it is recursive -(implemented lazily) so that attributes of mocks only have the same api as -the attributes of the spec. In addition mocked functions / methods have the -same call signature as the original so they raise a `TypeError` if they are -called incorrectly. - -Before I explain how auto-speccing works, here's why it is needed. - -`Mock` is a very powerful and flexible object, but it suffers from two flaws -when used to mock out objects from a system under test. One of these flaws is -specific to the `Mock` api and the other is a more general problem with using -mock objects. - -First the problem specific to `Mock`. `Mock` has two assert methods that are -extremely handy: :meth:`~Mock.assert_called_with` and -:meth:`~Mock.assert_called_once_with`. - - >>> mock = Mock(name='Thing', return_value=None) - >>> mock(1, 2, 3) - >>> mock.assert_called_once_with(1, 2, 3) - >>> mock(1, 2, 3) - >>> mock.assert_called_once_with(1, 2, 3) - Traceback (most recent call last): - ... - AssertionError: Expected to be called once. Called 2 times. - -Because mocks auto-create attributes on demand, and allow you to call them -with arbitrary arguments, if you misspell one of these assert methods then -your assertion is gone: - -.. code-block:: pycon - - >>> mock = Mock(name='Thing', return_value=None) - >>> mock(1, 2, 3) - >>> mock.assret_called_once_with(4, 5, 6) - -Your tests can pass silently and incorrectly because of the typo. - -The second issue is more general to mocking. If you refactor some of your -code, rename members and so on, any tests for code that is still using the -*old api* but uses mocks instead of the real objects will still pass. This -means your tests can all pass even though your code is broken. - -Note that this is another reason why you need integration tests as well as -unit tests. Testing everything in isolation is all fine and dandy, but if you -don't test how your units are "wired together" there is still lots of room -for bugs that tests might have caught. - -`mock` already provides a feature to help with this, called speccing. If you -use a class or instance as the `spec` for a mock then you can only access -attributes on the mock that exist on the real class: - - >>> from urllib import request - >>> mock = Mock(spec=request.Request) - >>> mock.assret_called_with - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'assret_called_with' - -The spec only applies to the mock itself, so we still have the same issue -with any methods on the mock: - -.. code-block:: pycon - - >>> mock.has_data() - - >>> mock.has_data.assret_called_with() - -Auto-speccing solves this problem. You can either pass `autospec=True` to -`patch` / `patch.object` or use the `create_autospec` function to create a -mock with a spec. If you use the `autospec=True` argument to `patch` then the -object that is being replaced will be used as the spec object. Because the -speccing is done "lazily" (the spec is created as attributes on the mock are -accessed) you can use it with very complex or deeply nested objects (like -modules that import modules that import modules) without a big performance -hit. - -Here's an example of it in use: - - >>> from urllib import request - >>> patcher = patch('__main__.request', autospec=True) - >>> mock_request = patcher.start() - >>> request is mock_request - True - >>> mock_request.Request - - -You can see that `request.Request` has a spec. `request.Request` takes two -arguments in the constructor (one of which is `self`). Here's what happens if -we try to call it incorrectly: - - >>> req = request.Request() - Traceback (most recent call last): - ... - TypeError: () takes at least 2 arguments (1 given) - -The spec also applies to instantiated classes (i.e. the return value of -specced mocks): - - >>> req = request.Request('foo') - >>> req - - -`Request` objects are not callable, so the return value of instantiating our -mocked out `request.Request` is a non-callable mock. With the spec in place -any typos in our asserts will raise the correct error: - - >>> req.add_header('spam', 'eggs') - - >>> req.add_header.assret_called_with - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'assret_called_with' - >>> req.add_header.assert_called_with('spam', 'eggs') - -In many cases you will just be able to add `autospec=True` to your existing -`patch` calls and then be protected against bugs due to typos and api -changes. - -As well as using `autospec` through `patch` there is a -:func:`create_autospec` for creating autospecced mocks directly: - - >>> from urllib import request - >>> mock_request = create_autospec(request) - >>> mock_request.Request('foo', 'bar') - - -This isn't without caveats and limitations however, which is why it is not -the default behaviour. In order to know what attributes are available on the -spec object, autospec has to introspect (access attributes) the spec. As you -traverse attributes on the mock a corresponding traversal of the original -object is happening under the hood. If any of your specced objects have -properties or descriptors that can trigger code execution then you may not be -able to use autospec. On the other hand it is much better to design your -objects so that introspection is safe [#]_. - -A more serious problem is that it is common for instance attributes to be -created in the `__init__` method and not to exist on the class at all. -`autospec` can't know about any dynamically created attributes and restricts -the api to visible attributes. - - >>> class Something(object): - ... def __init__(self): - ... self.a = 33 - ... - >>> with patch('__main__.Something', autospec=True): - ... thing = Something() - ... thing.a - ... - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'a' - -There are a few different ways of resolving this problem. The easiest, but -not necessarily the least annoying, way is to simply set the required -attributes on the mock after creation. Just because `autospec` doesn't allow -you to fetch attributes that don't exist on the spec it doesn't prevent you -setting them: - - >>> with patch('__main__.Something', autospec=True): - ... thing = Something() - ... thing.a = 33 - ... - -There is a more aggressive version of both `spec` and `autospec` that *does* -prevent you setting non-existent attributes. This is useful if you want to -ensure your code only *sets* valid attributes too, but obviously it prevents -this particular scenario: - - >>> with patch('__main__.Something', autospec=True, spec_set=True): - ... thing = Something() - ... thing.a = 33 - ... - Traceback (most recent call last): - ... - AttributeError: Mock object has no attribute 'a' - -Probably the best way of solving the problem is to add class attributes as -default values for instance members initialised in `__init__`. Note that if -you are only setting default attributes in `__init__` then providing them via -class attributes (shared between instances of course) is faster too. e.g. - -.. code-block:: python - - class Something(object): - a = 33 - -This brings up another issue. It is relatively common to provide a default -value of `None` for members that will later be an object of a different type. -`None` would be useless as a spec because it wouldn't let you access *any* -attributes or methods on it. As `None` is *never* going to be useful as a -spec, and probably indicates a member that will normally of some other type, -`autospec` doesn't use a spec for members that are set to `None`. These will -just be ordinary mocks (well - `MagicMocks`): - - >>> class Something(object): - ... member = None - ... - >>> mock = create_autospec(Something) - >>> mock.member.foo.bar.baz() - - -If modifying your production classes to add defaults isn't to your liking -then there are more options. One of these is simply to use an instance as the -spec rather than the class. The other is to create a subclass of the -production class and add the defaults to the subclass without affecting the -production class. Both of these require you to use an alternative object as -the spec. Thankfully `patch` supports this - you can simply pass the -alternative object as the `autospec` argument: - - >>> class Something(object): - ... def __init__(self): - ... self.a = 33 - ... - >>> class SomethingForTest(Something): - ... a = 33 - ... - >>> p = patch('__main__.Something', autospec=SomethingForTest) - >>> mock = p.start() - >>> mock.a - - - -.. [#] This only applies to classes or already instantiated objects. Calling - a mocked class to create a mock instance *does not* create a real instance. - It is only attribute lookups - along with calls to `dir` - that are done. diff --git a/Doc/library/unittest.mock-magicmethods.rst b/Doc/library/unittest.mock-magicmethods.rst deleted file mode 100644 --- a/Doc/library/unittest.mock-magicmethods.rst +++ /dev/null @@ -1,226 +0,0 @@ -:mod:`unittest.mock` --- MagicMock and magic method support -=========================================================== - -.. module:: unittest.mock - :synopsis: Mock object library. -.. moduleauthor:: Michael Foord -.. currentmodule:: unittest.mock - -.. versionadded:: 3.3 - - -.. _magic-methods: - -Mocking Magic Methods ---------------------- - -:class:`Mock` supports mocking the Python protocol methods, also known as -"magic methods". This allows mock objects to replace containers or other -objects that implement Python protocols. - -Because magic methods are looked up differently from normal methods [#]_, this -support has been specially implemented. This means that only specific magic -methods are supported. The supported list includes *almost* all of them. If -there are any missing that you need please let us know. - -You mock magic methods by setting the method you are interested in to a function -or a mock instance. If you are using a function then it *must* take ``self`` as -the first argument [#]_. - - >>> def __str__(self): - ... return 'fooble' - ... - >>> mock = Mock() - >>> mock.__str__ = __str__ - >>> str(mock) - 'fooble' - - >>> mock = Mock() - >>> mock.__str__ = Mock() - >>> mock.__str__.return_value = 'fooble' - >>> str(mock) - 'fooble' - - >>> mock = Mock() - >>> mock.__iter__ = Mock(return_value=iter([])) - >>> list(mock) - [] - -One use case for this is for mocking objects used as context managers in a -`with` statement: - - >>> mock = Mock() - >>> mock.__enter__ = Mock(return_value='foo') - >>> mock.__exit__ = Mock(return_value=False) - >>> with mock as m: - ... assert m == 'foo' - ... - >>> mock.__enter__.assert_called_with() - >>> mock.__exit__.assert_called_with(None, None, None) - -Calls to magic methods do not appear in :attr:`~Mock.method_calls`, but they -are recorded in :attr:`~Mock.mock_calls`. - -.. note:: - - If you use the `spec` keyword argument to create a mock then attempting to - set a magic method that isn't in the spec will raise an `AttributeError`. - -The full list of supported magic methods is: - -* ``__hash__``, ``__sizeof__``, ``__repr__`` and ``__str__`` -* ``__dir__``, ``__format__`` and ``__subclasses__`` -* ``__floor__``, ``__trunc__`` and ``__ceil__`` -* Comparisons: ``__cmp__``, ``__lt__``, ``__gt__``, ``__le__``, ``__ge__``, - ``__eq__`` and ``__ne__`` -* Container methods: ``__getitem__``, ``__setitem__``, ``__delitem__``, - ``__contains__``, ``__len__``, ``__iter__``, ``__getslice__``, - ``__setslice__``, ``__reversed__`` and ``__missing__`` -* Context manager: ``__enter__`` and ``__exit__`` -* Unary numeric methods: ``__neg__``, ``__pos__`` and ``__invert__`` -* The numeric methods (including right hand and in-place variants): - ``__add__``, ``__sub__``, ``__mul__``, ``__div__``, - ``__floordiv__``, ``__mod__``, ``__divmod__``, ``__lshift__``, - ``__rshift__``, ``__and__``, ``__xor__``, ``__or__``, and ``__pow__`` -* Numeric conversion methods: ``__complex__``, ``__int__``, ``__float__``, - ``__index__`` and ``__coerce__`` -* Descriptor methods: ``__get__``, ``__set__`` and ``__delete__`` -* Pickling: ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, - ``__getnewargs__``, ``__getstate__`` and ``__setstate__`` - - -The following methods exist but are *not* supported as they are either in use -by mock, can't be set dynamically, or can cause problems: - -* ``__getattr__``, ``__setattr__``, ``__init__`` and ``__new__`` -* ``__prepare__``, ``__instancecheck__``, ``__subclasscheck__``, ``__del__`` - - - -Magic Mock ----------- - -There are two `MagicMock` variants: `MagicMock` and `NonCallableMagicMock`. - - -.. class:: MagicMock(*args, **kw) - - ``MagicMock`` is a subclass of :class:`Mock` with default implementations - of most of the magic methods. You can use ``MagicMock`` without having to - configure the magic methods yourself. - - The constructor parameters have the same meaning as for :class:`Mock`. - - If you use the `spec` or `spec_set` arguments then *only* magic methods - that exist in the spec will be created. - - -.. class:: NonCallableMagicMock(*args, **kw) - - A non-callable version of `MagicMock`. - - The constructor parameters have the same meaning as for - :class:`MagicMock`, with the exception of `return_value` and - `side_effect` which have no meaning on a non-callable mock. - -The magic methods are setup with `MagicMock` objects, so you can configure them -and use them in the usual way: - - >>> mock = MagicMock() - >>> mock[3] = 'fish' - >>> mock.__setitem__.assert_called_with(3, 'fish') - >>> mock.__getitem__.return_value = 'result' - >>> mock[2] - 'result' - -By default many of the protocol methods are required to return objects of a -specific type. These methods are preconfigured with a default return value, so -that they can be used without you having to do anything if you aren't interested -in the return value. You can still *set* the return value manually if you want -to change the default. - -Methods and their defaults: - -* ``__lt__``: NotImplemented -* ``__gt__``: NotImplemented -* ``__le__``: NotImplemented -* ``__ge__``: NotImplemented -* ``__int__`` : 1 -* ``__contains__`` : False -* ``__len__`` : 1 -* ``__iter__`` : iter([]) -* ``__exit__`` : False -* ``__complex__`` : 1j -* ``__float__`` : 1.0 -* ``__bool__`` : True -* ``__index__`` : 1 -* ``__hash__`` : default hash for the mock -* ``__str__`` : default str for the mock -* ``__sizeof__``: default sizeof for the mock - -For example: - - >>> mock = MagicMock() - >>> int(mock) - 1 - >>> len(mock) - 0 - >>> list(mock) - [] - >>> object() in mock - False - -The two equality method, `__eq__` and `__ne__`, are special. -They do the default equality comparison on identity, using a side -effect, unless you change their return value to return something else: - - >>> MagicMock() == 3 - False - >>> MagicMock() != 3 - True - >>> mock = MagicMock() - >>> mock.__eq__.return_value = True - >>> mock == 3 - True - -The return value of `MagicMock.__iter__` can be any iterable object and isn't -required to be an iterator: - - >>> mock = MagicMock() - >>> mock.__iter__.return_value = ['a', 'b', 'c'] - >>> list(mock) - ['a', 'b', 'c'] - >>> list(mock) - ['a', 'b', 'c'] - -If the return value *is* an iterator, then iterating over it once will consume -it and subsequent iterations will result in an empty list: - - >>> mock.__iter__.return_value = iter(['a', 'b', 'c']) - >>> list(mock) - ['a', 'b', 'c'] - >>> list(mock) - [] - -``MagicMock`` has all of the supported magic methods configured except for some -of the obscure and obsolete ones. You can still set these up if you want. - -Magic methods that are supported but not setup by default in ``MagicMock`` are: - -* ``__subclasses__`` -* ``__dir__`` -* ``__format__`` -* ``__get__``, ``__set__`` and ``__delete__`` -* ``__reversed__`` and ``__missing__`` -* ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, ``__getnewargs__``, - ``__getstate__`` and ``__setstate__`` -* ``__getformat__`` and ``__setformat__`` - - - -.. [#] Magic methods *should* be looked up on the class rather than the - instance. Different versions of Python are inconsistent about applying this - rule. The supported protocol methods should work with all supported versions - of Python. -.. [#] The function is basically hooked up to the class, but each ``Mock`` - instance is kept isolated from the others. diff --git a/Doc/library/unittest.mock-patch.rst b/Doc/library/unittest.mock-patch.rst deleted file mode 100644 --- a/Doc/library/unittest.mock-patch.rst +++ /dev/null @@ -1,538 +0,0 @@ -:mod:`unittest.mock` --- the patchers -===================================== - -.. module:: unittest.mock - :synopsis: Mock object library. -.. moduleauthor:: Michael Foord -.. currentmodule:: unittest.mock - -.. versionadded:: 3.3 - -The patch decorators are used for patching objects only within the scope of -the function they decorate. They automatically handle the unpatching for you, -even if exceptions are raised. All of these functions can also be used in with -statements or as class decorators. - - -patch ------ - -.. note:: - - `patch` is straightforward to use. The key is to do the patching in the - right namespace. See the section `where to patch`_. - -.. function:: patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) - - `patch` acts as a function decorator, class decorator or a context - manager. Inside the body of the function or with statement, the `target` - (specified in the form `'package.module.ClassName'`) is patched - with a `new` object. When the function/with statement exits the patch is - undone. - - The `target` is imported and the specified attribute patched with the new - object, so it must be importable from the environment you are calling the - decorator from. The target is imported when the decorated function is - executed, not at decoration time. - - If `new` is omitted, then a new `MagicMock` is created and passed in as an - extra argument to the decorated function. - - The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` - if patch is creating one for you. - - In addition you can pass `spec=True` or `spec_set=True`, which causes - patch to pass in the object being mocked as the spec/spec_set object. - - `new_callable` allows you to specify a different class, or callable object, - that will be called to create the `new` object. By default `MagicMock` is - used. - - A more powerful form of `spec` is `autospec`. If you set `autospec=True` - then the mock with be created with a spec from the object being replaced. - All attributes of the mock will also have the spec of the corresponding - attribute of the object being replaced. Methods and functions being mocked - will have their arguments checked and will raise a `TypeError` if they are - called with the wrong signature. For mocks - replacing a class, their return value (the 'instance') will have the same - spec as the class. See the :func:`create_autospec` function and - :ref:`auto-speccing`. - - Instead of `autospec=True` you can pass `autospec=some_object` to use an - arbitrary object as the spec instead of the one being replaced. - - By default `patch` will fail to replace attributes that don't exist. If - you pass in `create=True`, and the attribute doesn't exist, patch will - create the attribute for you when the patched function is called, and - delete it again afterwards. This is useful for writing tests against - attributes that your production code creates at runtime. It is off by by - default because it can be dangerous. With it switched on you can write - passing tests against APIs that don't actually exist! - - Patch can be used as a `TestCase` class decorator. It works by - decorating each test method in the class. This reduces the boilerplate - code when your test methods share a common patchings set. `patch` finds - tests by looking for method names that start with `patch.TEST_PREFIX`. - By default this is `test`, which matches the way `unittest` finds tests. - You can specify an alternative prefix by setting `patch.TEST_PREFIX`. - - Patch can be used as a context manager, with the with statement. Here the - patching applies to the indented block after the with statement. If you - use "as" then the patched object will be bound to the name after the - "as"; very useful if `patch` is creating a mock object for you. - - `patch` takes arbitrary keyword arguments. These will be passed to - the `Mock` (or `new_callable`) on construction. - - `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are - available for alternate use-cases. - - -Patching a class replaces the class with a `MagicMock` *instance*. If the -class is instantiated in the code under test then it will be the -:attr:`~Mock.return_value` of the mock that will be used. - -If the class is instantiated multiple times you could use -:attr:`~Mock.side_effect` to return a new mock each time. Alternatively you -can set the `return_value` to be anything you want. - -To configure return values on methods of *instances* on the patched class -you must do this on the `return_value`. For example: - - >>> class Class(object): - ... def method(self): - ... pass - ... - >>> with patch('__main__.Class') as MockClass: - ... instance = MockClass.return_value - ... instance.method.return_value = 'foo' - ... assert Class() is instance - ... assert Class().method() == 'foo' - ... - -If you use `spec` or `spec_set` and `patch` is replacing a *class*, then the -return value of the created mock will have the same spec. - - >>> Original = Class - >>> patcher = patch('__main__.Class', spec=True) - >>> MockClass = patcher.start() - >>> instance = MockClass() - >>> assert isinstance(instance, Original) - >>> patcher.stop() - -The `new_callable` argument is useful where you want to use an alternative -class to the default :class:`MagicMock` for the created mock. For example, if -you wanted a :class:`NonCallableMock` to be used: - - >>> thing = object() - >>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing: - ... assert thing is mock_thing - ... thing() - ... - Traceback (most recent call last): - ... - TypeError: 'NonCallableMock' object is not callable - -Another use case might be to replace an object with a `StringIO` instance: - - >>> from StringIO import StringIO - >>> def foo(): - ... print 'Something' - ... - >>> @patch('sys.stdout', new_callable=StringIO) - ... def test(mock_stdout): - ... foo() - ... assert mock_stdout.getvalue() == 'Something\n' - ... - >>> test() - -When `patch` is creating a mock for you, it is common that the first thing -you need to do is to configure the mock. Some of that configuration can be done -in the call to patch. Any arbitrary keywords you pass into the call will be -used to set attributes on the created mock: - - >>> patcher = patch('__main__.thing', first='one', second='two') - >>> mock_thing = patcher.start() - >>> mock_thing.first - 'one' - >>> mock_thing.second - 'two' - -As well as attributes on the created mock attributes, like the -:attr:`~Mock.return_value` and :attr:`~Mock.side_effect`, of child mocks can -also be configured. These aren't syntactically valid to pass in directly as -keyword arguments, but a dictionary with these as keys can still be expanded -into a `patch` call using `**`: - - >>> config = {'method.return_value': 3, 'other.side_effect': KeyError} - >>> patcher = patch('__main__.thing', **config) - >>> mock_thing = patcher.start() - >>> mock_thing.method() - 3 - >>> mock_thing.other() - Traceback (most recent call last): - ... - KeyError - - -patch.object ------------- - -.. function:: patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) - - patch the named member (`attribute`) on an object (`target`) with a mock - object. - - `patch.object` can be used as a decorator, class decorator or a context - manager. Arguments `new`, `spec`, `create`, `spec_set`, `autospec` and - `new_callable` have the same meaning as for `patch`. Like `patch`, - `patch.object` takes arbitrary keyword arguments for configuring the mock - object it creates. - - When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` - for choosing which methods to wrap. - -You can either call `patch.object` with three arguments or two arguments. The -three argument form takes the object to be patched, the attribute name and the -object to replace the attribute with. - -When calling with the two argument form you omit the replacement object, and a -mock is created for you and passed in as an extra argument to the decorated -function: - - >>> @patch.object(SomeClass, 'class_method') - ... def test(mock_method): - ... SomeClass.class_method(3) - ... mock_method.assert_called_with(3) - ... - >>> test() - -`spec`, `create` and the other arguments to `patch.object` have the same -meaning as they do for `patch`. - - -patch.dict ----------- - -.. function:: patch.dict(in_dict, values=(), clear=False, **kwargs) - - Patch a dictionary, or dictionary like object, and restore the dictionary - to its original state after the test. - - `in_dict` can be a dictionary or a mapping like container. If it is a - mapping then it must at least support getting, setting and deleting items - plus iterating over keys. - - `in_dict` can also be a string specifying the name of the dictionary, which - will then be fetched by importing it. - - `values` can be a dictionary of values to set in the dictionary. `values` - can also be an iterable of `(key, value)` pairs. - - If `clear` is True then the dictionary will be cleared before the new - values are set. - - `patch.dict` can also be called with arbitrary keyword arguments to set - values in the dictionary. - - `patch.dict` can be used as a context manager, decorator or class - decorator. When used as a class decorator `patch.dict` honours - `patch.TEST_PREFIX` for choosing which methods to wrap. - -`patch.dict` can be used to add members to a dictionary, or simply let a test -change a dictionary, and ensure the dictionary is restored when the test -ends. - - >>> foo = {} - >>> with patch.dict(foo, {'newkey': 'newvalue'}): - ... assert foo == {'newkey': 'newvalue'} - ... - >>> assert foo == {} - - >>> import os - >>> with patch.dict('os.environ', {'newkey': 'newvalue'}): - ... print os.environ['newkey'] - ... - newvalue - >>> assert 'newkey' not in os.environ - -Keywords can be used in the `patch.dict` call to set values in the dictionary: - - >>> mymodule = MagicMock() - >>> mymodule.function.return_value = 'fish' - >>> with patch.dict('sys.modules', mymodule=mymodule): - ... import mymodule - ... mymodule.function('some', 'args') - ... - 'fish' - -`patch.dict` can be used with dictionary like objects that aren't actually -dictionaries. At the very minimum they must support item getting, setting, -deleting and either iteration or membership test. This corresponds to the -magic methods `__getitem__`, `__setitem__`, `__delitem__` and either -`__iter__` or `__contains__`. - - >>> class Container(object): - ... def __init__(self): - ... self.values = {} - ... def __getitem__(self, name): - ... return self.values[name] - ... def __setitem__(self, name, value): - ... self.values[name] = value - ... def __delitem__(self, name): - ... del self.values[name] - ... def __iter__(self): - ... return iter(self.values) - ... - >>> thing = Container() - >>> thing['one'] = 1 - >>> with patch.dict(thing, one=2, two=3): - ... assert thing['one'] == 2 - ... assert thing['two'] == 3 - ... - >>> assert thing['one'] == 1 - >>> assert list(thing) == ['one'] - - -patch.multiple --------------- - -.. function:: patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) - - Perform multiple patches in a single call. It takes the object to be - patched (either as an object or a string to fetch the object by importing) - and keyword arguments for the patches:: - - with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): - ... - - Use :data:`DEFAULT` as the value if you want `patch.multiple` to create - mocks for you. In this case the created mocks are passed into a decorated - function by keyword, and a dictionary is returned when `patch.multiple` is - used as a context manager. - - `patch.multiple` can be used as a decorator, class decorator or a context - manager. The arguments `spec`, `spec_set`, `create`, `autospec` and - `new_callable` have the same meaning as for `patch`. These arguments will - be applied to *all* patches done by `patch.multiple`. - - When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` - for choosing which methods to wrap. - -If you want `patch.multiple` to create mocks for you, then you can use -:data:`DEFAULT` as the value. If you use `patch.multiple` as a decorator -then the created mocks are passed into the decorated function by keyword. - - >>> thing = object() - >>> other = object() - - >>> @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) - ... def test_function(thing, other): - ... assert isinstance(thing, MagicMock) - ... assert isinstance(other, MagicMock) - ... - >>> test_function() - -`patch.multiple` can be nested with other `patch` decorators, but put arguments -passed by keyword *after* any of the standard arguments created by `patch`: - - >>> @patch('sys.exit') - ... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) - ... def test_function(mock_exit, other, thing): - ... assert 'other' in repr(other) - ... assert 'thing' in repr(thing) - ... assert 'exit' in repr(mock_exit) - ... - >>> test_function() - -If `patch.multiple` is used as a context manager, the value returned by the -context manger is a dictionary where created mocks are keyed by name: - - >>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values: - ... assert 'other' in repr(values['other']) - ... assert 'thing' in repr(values['thing']) - ... assert values['thing'] is thing - ... assert values['other'] is other - ... - - -.. _start-and-stop: - -patch methods: start and stop ------------------------------ - -All the patchers have `start` and `stop` methods. These make it simpler to do -patching in `setUp` methods or where you want to do multiple patches without -nesting decorators or with statements. - -To use them call `patch`, `patch.object` or `patch.dict` as normal and keep a -reference to the returned `patcher` object. You can then call `start` to put -the patch in place and `stop` to undo it. - -If you are using `patch` to create a mock for you then it will be returned by -the call to `patcher.start`. - - >>> patcher = patch('package.module.ClassName') - >>> from package import module - >>> original = module.ClassName - >>> new_mock = patcher.start() - >>> assert module.ClassName is not original - >>> assert module.ClassName is new_mock - >>> patcher.stop() - >>> assert module.ClassName is original - >>> assert module.ClassName is not new_mock - - -A typical use case for this might be for doing multiple patches in the `setUp` -method of a `TestCase`: - - >>> class MyTest(TestCase): - ... def setUp(self): - ... self.patcher1 = patch('package.module.Class1') - ... self.patcher2 = patch('package.module.Class2') - ... self.MockClass1 = self.patcher1.start() - ... self.MockClass2 = self.patcher2.start() - ... - ... def tearDown(self): - ... self.patcher1.stop() - ... self.patcher2.stop() - ... - ... def test_something(self): - ... assert package.module.Class1 is self.MockClass1 - ... assert package.module.Class2 is self.MockClass2 - ... - >>> MyTest('test_something').run() - -.. caution:: - - If you use this technique you must ensure that the patching is "undone" by - calling `stop`. This can be fiddlier than you might think, because if an - exception is raised in the ``setUp`` then ``tearDown`` is not called. - :meth:`unittest.TestCase.addCleanup` makes this easier: - - >>> class MyTest(TestCase): - ... def setUp(self): - ... patcher = patch('package.module.Class') - ... self.MockClass = patcher.start() - ... self.addCleanup(patcher.stop) - ... - ... def test_something(self): - ... assert package.module.Class is self.MockClass - ... - - As an added bonus you no longer need to keep a reference to the `patcher` - object. - -In fact `start` and `stop` are just aliases for the context manager -`__enter__` and `__exit__` methods. - - -TEST_PREFIX ------------ - -All of the patchers can be used as class decorators. When used in this way -they wrap every test method on the class. The patchers recognise methods that -start with `test` as being test methods. This is the same way that the -:class:`unittest.TestLoader` finds test methods by default. - -It is possible that you want to use a different prefix for your tests. You can -inform the patchers of the different prefix by setting `patch.TEST_PREFIX`: - - >>> patch.TEST_PREFIX = 'foo' - >>> value = 3 - >>> - >>> @patch('__main__.value', 'not three') - ... class Thing(object): - ... def foo_one(self): - ... print value - ... def foo_two(self): - ... print value - ... - >>> - >>> Thing().foo_one() - not three - >>> Thing().foo_two() - not three - >>> value - 3 - - -Nesting Patch Decorators ------------------------- - -If you want to perform multiple patches then you can simply stack up the -decorators. - -You can stack up multiple patch decorators using this pattern: - - >>> @patch.object(SomeClass, 'class_method') - ... @patch.object(SomeClass, 'static_method') - ... def test(mock1, mock2): - ... assert SomeClass.static_method is mock1 - ... assert SomeClass.class_method is mock2 - ... SomeClass.static_method('foo') - ... SomeClass.class_method('bar') - ... return mock1, mock2 - ... - >>> mock1, mock2 = test() - >>> mock1.assert_called_once_with('foo') - >>> mock2.assert_called_once_with('bar') - - -Note that the decorators are applied from the bottom upwards. This is the -standard way that Python applies decorators. The order of the created mocks -passed into your test function matches this order. - - -.. _where-to-patch: - -Where to patch --------------- - -`patch` works by (temporarily) changing the object that a *name* points to with -another one. There can be many names pointing to any individual object, so -for patching to work you must ensure that you patch the name used by the system -under test. - -The basic principle is that you patch where an object is *looked up*, which -is not necessarily the same place as where it is defined. A couple of -examples will help to clarify this. - -Imagine we have a project that we want to test with the following structure:: - - a.py - -> Defines SomeClass - - b.py - -> from a import SomeClass - -> some_function instantiates SomeClass - -Now we want to test `some_function` but we want to mock out `SomeClass` using -`patch`. The problem is that when we import module b, which we will have to -do then it imports `SomeClass` from module a. If we use `patch` to mock out -`a.SomeClass` then it will have no effect on our test; module b already has a -reference to the *real* `SomeClass` and it looks like our patching had no -effect. - -The key is to patch out `SomeClass` where it is used (or where it is looked up -). In this case `some_function` will actually look up `SomeClass` in module b, -where we have imported it. The patching should look like:: - - @patch('b.SomeClass') - -However, consider the alternative scenario where instead of `from a import -SomeClass` module b does `import a` and `some_function` uses `a.SomeClass`. Both -of these import forms are common. In this case the class we want to patch is -being looked up on the a module and so we have to patch `a.SomeClass` instead:: - - @patch('a.SomeClass') - - -Patching Descriptors and Proxy Objects --------------------------------------- - -Both patch_ and patch.object_ correctly patch and restore descriptors: class -methods, static methods and properties. You should patch these on the *class* -rather than an instance. They also work with *some* objects -that proxy attribute access, like the `django setttings object -`_. diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -84,7 +84,6 @@ ... def test(MockClass1, MockClass2): ... module.ClassName1() ... module.ClassName2() - ... assert MockClass1 is module.ClassName1 ... assert MockClass2 is module.ClassName2 ... assert MockClass1.called @@ -898,3 +897,1300 @@ will often implicitly request these methods, and gets *very* confused to get a new Mock object when it expects a magic method. If you need magic method support see :ref:`magic methods `. + + +The patchers +============ + +The patch decorators are used for patching objects only within the scope of +the function they decorate. They automatically handle the unpatching for you, +even if exceptions are raised. All of these functions can also be used in with +statements or as class decorators. + + +patch +----- + +.. note:: + + `patch` is straightforward to use. The key is to do the patching in the + right namespace. See the section `where to patch`_. + +.. function:: patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) + + `patch` acts as a function decorator, class decorator or a context + manager. Inside the body of the function or with statement, the `target` + is patched with a `new` object. When the function/with statement exits + the patch is undone. + + If `new` is omitted, then the target is replaced with a + :class:`MagicMock`. If `patch` is used as a decorator and `new` is + omitted, the created mock is passed in as an extra argument to the + decorated function. If `patch` is used as a context manager the created + mock is returned by the context manager. + + `target` should be a string in the form `'package.module.ClassName'`. The + `target` is imported and the specified object replaced with the `new` + object, so the `target` must be importable from the environment you are + calling `patch` from. The target is imported when the decorated function + is executed, not at decoration time. + + The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` + if patch is creating one for you. + + In addition you can pass `spec=True` or `spec_set=True`, which causes + patch to pass in the object being mocked as the spec/spec_set object. + + `new_callable` allows you to specify a different class, or callable object, + that will be called to create the `new` object. By default `MagicMock` is + used. + + A more powerful form of `spec` is `autospec`. If you set `autospec=True` + then the mock with be created with a spec from the object being replaced. + All attributes of the mock will also have the spec of the corresponding + attribute of the object being replaced. Methods and functions being mocked + will have their arguments checked and will raise a `TypeError` if they are + called with the wrong signature. For mocks + replacing a class, their return value (the 'instance') will have the same + spec as the class. See the :func:`create_autospec` function and + :ref:`auto-speccing`. + + Instead of `autospec=True` you can pass `autospec=some_object` to use an + arbitrary object as the spec instead of the one being replaced. + + By default `patch` will fail to replace attributes that don't exist. If + you pass in `create=True`, and the attribute doesn't exist, patch will + create the attribute for you when the patched function is called, and + delete it again afterwards. This is useful for writing tests against + attributes that your production code creates at runtime. It is off by by + default because it can be dangerous. With it switched on you can write + passing tests against APIs that don't actually exist! + + Patch can be used as a `TestCase` class decorator. It works by + decorating each test method in the class. This reduces the boilerplate + code when your test methods share a common patchings set. `patch` finds + tests by looking for method names that start with `patch.TEST_PREFIX`. + By default this is `test`, which matches the way `unittest` finds tests. + You can specify an alternative prefix by setting `patch.TEST_PREFIX`. + + Patch can be used as a context manager, with the with statement. Here the + patching applies to the indented block after the with statement. If you + use "as" then the patched object will be bound to the name after the + "as"; very useful if `patch` is creating a mock object for you. + + `patch` takes arbitrary keyword arguments. These will be passed to + the `Mock` (or `new_callable`) on construction. + + `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are + available for alternate use-cases. + +`patch` as function decorator, creating the mock for you and passing it into +the decorated function: + + >>> @patch('__main__.SomeClass') + ... def function(normal_argument, mock_class): + ... print(mock_class is SomeClass) + ... + >>> function(None) + True + +Patching a class replaces the class with a `MagicMock` *instance*. If the +class is instantiated in the code under test then it will be the +:attr:`~Mock.return_value` of the mock that will be used. + +If the class is instantiated multiple times you could use +:attr:`~Mock.side_effect` to return a new mock each time. Alternatively you +can set the `return_value` to be anything you want. + +To configure return values on methods of *instances* on the patched class +you must do this on the `return_value`. For example: + + >>> class Class(object): + ... def method(self): + ... pass + ... + >>> with patch('__main__.Class') as MockClass: + ... instance = MockClass.return_value + ... instance.method.return_value = 'foo' + ... assert Class() is instance + ... assert Class().method() == 'foo' + ... + +If you use `spec` or `spec_set` and `patch` is replacing a *class*, then the +return value of the created mock will have the same spec. + + >>> Original = Class + >>> patcher = patch('__main__.Class', spec=True) + >>> MockClass = patcher.start() + >>> instance = MockClass() + >>> assert isinstance(instance, Original) + >>> patcher.stop() + +The `new_callable` argument is useful where you want to use an alternative +class to the default :class:`MagicMock` for the created mock. For example, if +you wanted a :class:`NonCallableMock` to be used: + + >>> thing = object() + >>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing: + ... assert thing is mock_thing + ... thing() + ... + Traceback (most recent call last): + ... + TypeError: 'NonCallableMock' object is not callable + +Another use case might be to replace an object with a `StringIO` instance: + + >>> from StringIO import StringIO + >>> def foo(): + ... print 'Something' + ... + >>> @patch('sys.stdout', new_callable=StringIO) + ... def test(mock_stdout): + ... foo() + ... assert mock_stdout.getvalue() == 'Something\n' + ... + >>> test() + +When `patch` is creating a mock for you, it is common that the first thing +you need to do is to configure the mock. Some of that configuration can be done +in the call to patch. Any arbitrary keywords you pass into the call will be +used to set attributes on the created mock: + + >>> patcher = patch('__main__.thing', first='one', second='two') + >>> mock_thing = patcher.start() + >>> mock_thing.first + 'one' + >>> mock_thing.second + 'two' + +As well as attributes on the created mock attributes, like the +:attr:`~Mock.return_value` and :attr:`~Mock.side_effect`, of child mocks can +also be configured. These aren't syntactically valid to pass in directly as +keyword arguments, but a dictionary with these as keys can still be expanded +into a `patch` call using `**`: + + >>> config = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> patcher = patch('__main__.thing', **config) + >>> mock_thing = patcher.start() + >>> mock_thing.method() + 3 + >>> mock_thing.other() + Traceback (most recent call last): + ... + KeyError + + +patch.object +------------ + +.. function:: patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) + + patch the named member (`attribute`) on an object (`target`) with a mock + object. + + `patch.object` can be used as a decorator, class decorator or a context + manager. Arguments `new`, `spec`, `create`, `spec_set`, `autospec` and + `new_callable` have the same meaning as for `patch`. Like `patch`, + `patch.object` takes arbitrary keyword arguments for configuring the mock + object it creates. + + When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + +You can either call `patch.object` with three arguments or two arguments. The +three argument form takes the object to be patched, the attribute name and the +object to replace the attribute with. + +When calling with the two argument form you omit the replacement object, and a +mock is created for you and passed in as an extra argument to the decorated +function: + + >>> @patch.object(SomeClass, 'class_method') + ... def test(mock_method): + ... SomeClass.class_method(3) + ... mock_method.assert_called_with(3) + ... + >>> test() + +`spec`, `create` and the other arguments to `patch.object` have the same +meaning as they do for `patch`. + + +patch.dict +---------- + +.. function:: patch.dict(in_dict, values=(), clear=False, **kwargs) + + Patch a dictionary, or dictionary like object, and restore the dictionary + to its original state after the test. + + `in_dict` can be a dictionary or a mapping like container. If it is a + mapping then it must at least support getting, setting and deleting items + plus iterating over keys. + + `in_dict` can also be a string specifying the name of the dictionary, which + will then be fetched by importing it. + + `values` can be a dictionary of values to set in the dictionary. `values` + can also be an iterable of `(key, value)` pairs. + + If `clear` is True then the dictionary will be cleared before the new + values are set. + + `patch.dict` can also be called with arbitrary keyword arguments to set + values in the dictionary. + + `patch.dict` can be used as a context manager, decorator or class + decorator. When used as a class decorator `patch.dict` honours + `patch.TEST_PREFIX` for choosing which methods to wrap. + +`patch.dict` can be used to add members to a dictionary, or simply let a test +change a dictionary, and ensure the dictionary is restored when the test +ends. + + >>> foo = {} + >>> with patch.dict(foo, {'newkey': 'newvalue'}): + ... assert foo == {'newkey': 'newvalue'} + ... + >>> assert foo == {} + + >>> import os + >>> with patch.dict('os.environ', {'newkey': 'newvalue'}): + ... print os.environ['newkey'] + ... + newvalue + >>> assert 'newkey' not in os.environ + +Keywords can be used in the `patch.dict` call to set values in the dictionary: + + >>> mymodule = MagicMock() + >>> mymodule.function.return_value = 'fish' + >>> with patch.dict('sys.modules', mymodule=mymodule): + ... import mymodule + ... mymodule.function('some', 'args') + ... + 'fish' + +`patch.dict` can be used with dictionary like objects that aren't actually +dictionaries. At the very minimum they must support item getting, setting, +deleting and either iteration or membership test. This corresponds to the +magic methods `__getitem__`, `__setitem__`, `__delitem__` and either +`__iter__` or `__contains__`. + + >>> class Container(object): + ... def __init__(self): + ... self.values = {} + ... def __getitem__(self, name): + ... return self.values[name] + ... def __setitem__(self, name, value): + ... self.values[name] = value + ... def __delitem__(self, name): + ... del self.values[name] + ... def __iter__(self): + ... return iter(self.values) + ... + >>> thing = Container() + >>> thing['one'] = 1 + >>> with patch.dict(thing, one=2, two=3): + ... assert thing['one'] == 2 + ... assert thing['two'] == 3 + ... + >>> assert thing['one'] == 1 + >>> assert list(thing) == ['one'] + + +patch.multiple +-------------- + +.. function:: patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs) + + Perform multiple patches in a single call. It takes the object to be + patched (either as an object or a string to fetch the object by importing) + and keyword arguments for the patches:: + + with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): + ... + + Use :data:`DEFAULT` as the value if you want `patch.multiple` to create + mocks for you. In this case the created mocks are passed into a decorated + function by keyword, and a dictionary is returned when `patch.multiple` is + used as a context manager. + + `patch.multiple` can be used as a decorator, class decorator or a context + manager. The arguments `spec`, `spec_set`, `create`, `autospec` and + `new_callable` have the same meaning as for `patch`. These arguments will + be applied to *all* patches done by `patch.multiple`. + + When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + +If you want `patch.multiple` to create mocks for you, then you can use +:data:`DEFAULT` as the value. If you use `patch.multiple` as a decorator +then the created mocks are passed into the decorated function by keyword. + + >>> thing = object() + >>> other = object() + + >>> @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) + ... def test_function(thing, other): + ... assert isinstance(thing, MagicMock) + ... assert isinstance(other, MagicMock) + ... + >>> test_function() + +`patch.multiple` can be nested with other `patch` decorators, but put arguments +passed by keyword *after* any of the standard arguments created by `patch`: + + >>> @patch('sys.exit') + ... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) + ... def test_function(mock_exit, other, thing): + ... assert 'other' in repr(other) + ... assert 'thing' in repr(thing) + ... assert 'exit' in repr(mock_exit) + ... + >>> test_function() + +If `patch.multiple` is used as a context manager, the value returned by the +context manger is a dictionary where created mocks are keyed by name: + + >>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values: + ... assert 'other' in repr(values['other']) + ... assert 'thing' in repr(values['thing']) + ... assert values['thing'] is thing + ... assert values['other'] is other + ... + + +.. _start-and-stop: + +patch methods: start and stop +----------------------------- + +All the patchers have `start` and `stop` methods. These make it simpler to do +patching in `setUp` methods or where you want to do multiple patches without +nesting decorators or with statements. + +To use them call `patch`, `patch.object` or `patch.dict` as normal and keep a +reference to the returned `patcher` object. You can then call `start` to put +the patch in place and `stop` to undo it. + +If you are using `patch` to create a mock for you then it will be returned by +the call to `patcher.start`. + + >>> patcher = patch('package.module.ClassName') + >>> from package import module + >>> original = module.ClassName + >>> new_mock = patcher.start() + >>> assert module.ClassName is not original + >>> assert module.ClassName is new_mock + >>> patcher.stop() + >>> assert module.ClassName is original + >>> assert module.ClassName is not new_mock + + +A typical use case for this might be for doing multiple patches in the `setUp` +method of a `TestCase`: + + >>> class MyTest(TestCase): + ... def setUp(self): + ... self.patcher1 = patch('package.module.Class1') + ... self.patcher2 = patch('package.module.Class2') + ... self.MockClass1 = self.patcher1.start() + ... self.MockClass2 = self.patcher2.start() + ... + ... def tearDown(self): + ... self.patcher1.stop() + ... self.patcher2.stop() + ... + ... def test_something(self): + ... assert package.module.Class1 is self.MockClass1 + ... assert package.module.Class2 is self.MockClass2 + ... + >>> MyTest('test_something').run() + +.. caution:: + + If you use this technique you must ensure that the patching is "undone" by + calling `stop`. This can be fiddlier than you might think, because if an + exception is raised in the ``setUp`` then ``tearDown`` is not called. + :meth:`unittest.TestCase.addCleanup` makes this easier: + + >>> class MyTest(TestCase): + ... def setUp(self): + ... patcher = patch('package.module.Class') + ... self.MockClass = patcher.start() + ... self.addCleanup(patcher.stop) + ... + ... def test_something(self): + ... assert package.module.Class is self.MockClass + ... + + As an added bonus you no longer need to keep a reference to the `patcher` + object. + +In fact `start` and `stop` are just aliases for the context manager +`__enter__` and `__exit__` methods. + + +TEST_PREFIX +----------- + +All of the patchers can be used as class decorators. When used in this way +they wrap every test method on the class. The patchers recognise methods that +start with `test` as being test methods. This is the same way that the +:class:`unittest.TestLoader` finds test methods by default. + +It is possible that you want to use a different prefix for your tests. You can +inform the patchers of the different prefix by setting `patch.TEST_PREFIX`: + + >>> patch.TEST_PREFIX = 'foo' + >>> value = 3 + >>> + >>> @patch('__main__.value', 'not three') + ... class Thing(object): + ... def foo_one(self): + ... print value + ... def foo_two(self): + ... print value + ... + >>> + >>> Thing().foo_one() + not three + >>> Thing().foo_two() + not three + >>> value + 3 + + +Nesting Patch Decorators +------------------------ + +If you want to perform multiple patches then you can simply stack up the +decorators. + +You can stack up multiple patch decorators using this pattern: + + >>> @patch.object(SomeClass, 'class_method') + ... @patch.object(SomeClass, 'static_method') + ... def test(mock1, mock2): + ... assert SomeClass.static_method is mock1 + ... assert SomeClass.class_method is mock2 + ... SomeClass.static_method('foo') + ... SomeClass.class_method('bar') + ... return mock1, mock2 + ... + >>> mock1, mock2 = test() + >>> mock1.assert_called_once_with('foo') + >>> mock2.assert_called_once_with('bar') + + +Note that the decorators are applied from the bottom upwards. This is the +standard way that Python applies decorators. The order of the created mocks +passed into your test function matches this order. + + +.. _where-to-patch: + +Where to patch +-------------- + +`patch` works by (temporarily) changing the object that a *name* points to with +another one. There can be many names pointing to any individual object, so +for patching to work you must ensure that you patch the name used by the system +under test. + +The basic principle is that you patch where an object is *looked up*, which +is not necessarily the same place as where it is defined. A couple of +examples will help to clarify this. + +Imagine we have a project that we want to test with the following structure:: + + a.py + -> Defines SomeClass + + b.py + -> from a import SomeClass + -> some_function instantiates SomeClass + +Now we want to test `some_function` but we want to mock out `SomeClass` using +`patch`. The problem is that when we import module b, which we will have to +do then it imports `SomeClass` from module a. If we use `patch` to mock out +`a.SomeClass` then it will have no effect on our test; module b already has a +reference to the *real* `SomeClass` and it looks like our patching had no +effect. + +The key is to patch out `SomeClass` where it is used (or where it is looked up +). In this case `some_function` will actually look up `SomeClass` in module b, +where we have imported it. The patching should look like:: + + @patch('b.SomeClass') + +However, consider the alternative scenario where instead of `from a import +SomeClass` module b does `import a` and `some_function` uses `a.SomeClass`. Both +of these import forms are common. In this case the class we want to patch is +being looked up on the a module and so we have to patch `a.SomeClass` instead:: + + @patch('a.SomeClass') + + +Patching Descriptors and Proxy Objects +-------------------------------------- + +Both patch_ and patch.object_ correctly patch and restore descriptors: class +methods, static methods and properties. You should patch these on the *class* +rather than an instance. They also work with *some* objects +that proxy attribute access, like the `django setttings object +`_. + + +MagicMock and magic method support +================================== + +.. _magic-methods: + +Mocking Magic Methods +--------------------- + +:class:`Mock` supports mocking the Python protocol methods, also known as +"magic methods". This allows mock objects to replace containers or other +objects that implement Python protocols. + +Because magic methods are looked up differently from normal methods [#]_, this +support has been specially implemented. This means that only specific magic +methods are supported. The supported list includes *almost* all of them. If +there are any missing that you need please let us know. + +You mock magic methods by setting the method you are interested in to a function +or a mock instance. If you are using a function then it *must* take ``self`` as +the first argument [#]_. + + >>> def __str__(self): + ... return 'fooble' + ... + >>> mock = Mock() + >>> mock.__str__ = __str__ + >>> str(mock) + 'fooble' + + >>> mock = Mock() + >>> mock.__str__ = Mock() + >>> mock.__str__.return_value = 'fooble' + >>> str(mock) + 'fooble' + + >>> mock = Mock() + >>> mock.__iter__ = Mock(return_value=iter([])) + >>> list(mock) + [] + +One use case for this is for mocking objects used as context managers in a +`with` statement: + + >>> mock = Mock() + >>> mock.__enter__ = Mock(return_value='foo') + >>> mock.__exit__ = Mock(return_value=False) + >>> with mock as m: + ... assert m == 'foo' + ... + >>> mock.__enter__.assert_called_with() + >>> mock.__exit__.assert_called_with(None, None, None) + +Calls to magic methods do not appear in :attr:`~Mock.method_calls`, but they +are recorded in :attr:`~Mock.mock_calls`. + +.. note:: + + If you use the `spec` keyword argument to create a mock then attempting to + set a magic method that isn't in the spec will raise an `AttributeError`. + +The full list of supported magic methods is: + +* ``__hash__``, ``__sizeof__``, ``__repr__`` and ``__str__`` +* ``__dir__``, ``__format__`` and ``__subclasses__`` +* ``__floor__``, ``__trunc__`` and ``__ceil__`` +* Comparisons: ``__cmp__``, ``__lt__``, ``__gt__``, ``__le__``, ``__ge__``, + ``__eq__`` and ``__ne__`` +* Container methods: ``__getitem__``, ``__setitem__``, ``__delitem__``, + ``__contains__``, ``__len__``, ``__iter__``, ``__getslice__``, + ``__setslice__``, ``__reversed__`` and ``__missing__`` +* Context manager: ``__enter__`` and ``__exit__`` +* Unary numeric methods: ``__neg__``, ``__pos__`` and ``__invert__`` +* The numeric methods (including right hand and in-place variants): + ``__add__``, ``__sub__``, ``__mul__``, ``__div__``, + ``__floordiv__``, ``__mod__``, ``__divmod__``, ``__lshift__``, + ``__rshift__``, ``__and__``, ``__xor__``, ``__or__``, and ``__pow__`` +* Numeric conversion methods: ``__complex__``, ``__int__``, ``__float__``, + ``__index__`` and ``__coerce__`` +* Descriptor methods: ``__get__``, ``__set__`` and ``__delete__`` +* Pickling: ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, + ``__getnewargs__``, ``__getstate__`` and ``__setstate__`` + + +The following methods exist but are *not* supported as they are either in use +by mock, can't be set dynamically, or can cause problems: + +* ``__getattr__``, ``__setattr__``, ``__init__`` and ``__new__`` +* ``__prepare__``, ``__instancecheck__``, ``__subclasscheck__``, ``__del__`` + + + +Magic Mock +---------- + +There are two `MagicMock` variants: `MagicMock` and `NonCallableMagicMock`. + + +.. class:: MagicMock(*args, **kw) + + ``MagicMock`` is a subclass of :class:`Mock` with default implementations + of most of the magic methods. You can use ``MagicMock`` without having to + configure the magic methods yourself. + + The constructor parameters have the same meaning as for :class:`Mock`. + + If you use the `spec` or `spec_set` arguments then *only* magic methods + that exist in the spec will be created. + + +.. class:: NonCallableMagicMock(*args, **kw) + + A non-callable version of `MagicMock`. + + The constructor parameters have the same meaning as for + :class:`MagicMock`, with the exception of `return_value` and + `side_effect` which have no meaning on a non-callable mock. + +The magic methods are setup with `MagicMock` objects, so you can configure them +and use them in the usual way: + + >>> mock = MagicMock() + >>> mock[3] = 'fish' + >>> mock.__setitem__.assert_called_with(3, 'fish') + >>> mock.__getitem__.return_value = 'result' + >>> mock[2] + 'result' + +By default many of the protocol methods are required to return objects of a +specific type. These methods are preconfigured with a default return value, so +that they can be used without you having to do anything if you aren't interested +in the return value. You can still *set* the return value manually if you want +to change the default. + +Methods and their defaults: + +* ``__lt__``: NotImplemented +* ``__gt__``: NotImplemented +* ``__le__``: NotImplemented +* ``__ge__``: NotImplemented +* ``__int__`` : 1 +* ``__contains__`` : False +* ``__len__`` : 1 +* ``__iter__`` : iter([]) +* ``__exit__`` : False +* ``__complex__`` : 1j +* ``__float__`` : 1.0 +* ``__bool__`` : True +* ``__index__`` : 1 +* ``__hash__`` : default hash for the mock +* ``__str__`` : default str for the mock +* ``__sizeof__``: default sizeof for the mock + +For example: + + >>> mock = MagicMock() + >>> int(mock) + 1 + >>> len(mock) + 0 + >>> list(mock) + [] + >>> object() in mock + False + +The two equality method, `__eq__` and `__ne__`, are special. +They do the default equality comparison on identity, using a side +effect, unless you change their return value to return something else: + + >>> MagicMock() == 3 + False + >>> MagicMock() != 3 + True + >>> mock = MagicMock() + >>> mock.__eq__.return_value = True + >>> mock == 3 + True + +The return value of `MagicMock.__iter__` can be any iterable object and isn't +required to be an iterator: + + >>> mock = MagicMock() + >>> mock.__iter__.return_value = ['a', 'b', 'c'] + >>> list(mock) + ['a', 'b', 'c'] + >>> list(mock) + ['a', 'b', 'c'] + +If the return value *is* an iterator, then iterating over it once will consume +it and subsequent iterations will result in an empty list: + + >>> mock.__iter__.return_value = iter(['a', 'b', 'c']) + >>> list(mock) + ['a', 'b', 'c'] + >>> list(mock) + [] + +``MagicMock`` has all of the supported magic methods configured except for some +of the obscure and obsolete ones. You can still set these up if you want. + +Magic methods that are supported but not setup by default in ``MagicMock`` are: + +* ``__subclasses__`` +* ``__dir__`` +* ``__format__`` +* ``__get__``, ``__set__`` and ``__delete__`` +* ``__reversed__`` and ``__missing__`` +* ``__reduce__``, ``__reduce_ex__``, ``__getinitargs__``, ``__getnewargs__``, + ``__getstate__`` and ``__setstate__`` +* ``__getformat__`` and ``__setformat__`` + + + +.. [#] Magic methods *should* be looked up on the class rather than the + instance. Different versions of Python are inconsistent about applying this + rule. The supported protocol methods should work with all supported versions + of Python. +.. [#] The function is basically hooked up to the class, but each ``Mock`` + instance is kept isolated from the others. + + +Helpers +======= + +sentinel +-------- + +.. data:: sentinel + + The ``sentinel`` object provides a convenient way of providing unique + objects for your tests. + + Attributes are created on demand when you access them by name. Accessing + the same attribute will always return the same object. The objects + returned have a sensible repr so that test failure messages are readable. + +Sometimes when testing you need to test that a specific object is passed as an +argument to another method, or returned. It can be common to create named +sentinel objects to test this. `sentinel` provides a convenient way of +creating and testing the identity of objects like this. + +In this example we monkey patch `method` to return `sentinel.some_object`: + + >>> real = ProductionClass() + >>> real.method = Mock(name="method") + >>> real.method.return_value = sentinel.some_object + >>> result = real.method() + >>> assert result is sentinel.some_object + >>> sentinel.some_object + sentinel.some_object + + +DEFAULT +------- + + +.. data:: DEFAULT + + The `DEFAULT` object is a pre-created sentinel (actually + `sentinel.DEFAULT`). It can be used by :attr:`~Mock.side_effect` + functions to indicate that the normal return value should be used. + + + +call +---- + +.. function:: call(*args, **kwargs) + + `call` is a helper object for making simpler assertions, for comparing + with :attr:`~Mock.call_args`, :attr:`~Mock.call_args_list`, + :attr:`~Mock.mock_calls` and :attr: `~Mock.method_calls`. `call` can also be + used with :meth:`~Mock.assert_has_calls`. + + >>> m = MagicMock(return_value=None) + >>> m(1, 2, a='foo', b='bar') + >>> m() + >>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()] + True + +.. method:: call.call_list() + + For a call object that represents multiple calls, `call_list` + returns a list of all the intermediate calls as well as the + final call. + +`call_list` is particularly useful for making assertions on "chained calls". A +chained call is multiple calls on a single line of code. This results in +multiple entries in :attr:`~Mock.mock_calls` on a mock. Manually constructing +the sequence of calls can be tedious. + +:meth:`~call.call_list` can construct the sequence of calls from the same +chained call: + + >>> m = MagicMock() + >>> m(1).method(arg='foo').other('bar')(2.0) + + >>> kall = call(1).method(arg='foo').other('bar')(2.0) + >>> kall.call_list() + [call(1), + call().method(arg='foo'), + call().method().other('bar'), + call().method().other()(2.0)] + >>> m.mock_calls == kall.call_list() + True + +.. _calls-as-tuples: + +A `call` object is either a tuple of (positional args, keyword args) or +(name, positional args, keyword args) depending on how it was constructed. When +you construct them yourself this isn't particularly interesting, but the `call` +objects that are in the :attr:`Mock.call_args`, :attr:`Mock.call_args_list` and +:attr:`Mock.mock_calls` attributes can be introspected to get at the individual +arguments they contain. + +The `call` objects in :attr:`Mock.call_args` and :attr:`Mock.call_args_list` +are two-tuples of (positional args, keyword args) whereas the `call` objects +in :attr:`Mock.mock_calls`, along with ones you construct yourself, are +three-tuples of (name, positional args, keyword args). + +You can use their "tupleness" to pull out the individual arguments for more +complex introspection and assertions. The positional arguments are a tuple +(an empty tuple if there are no positional arguments) and the keyword +arguments are a dictionary: + + >>> m = MagicMock(return_value=None) + >>> m(1, 2, 3, arg='one', arg2='two') + >>> kall = m.call_args + >>> args, kwargs = kall + >>> args + (1, 2, 3) + >>> kwargs + {'arg2': 'two', 'arg': 'one'} + >>> args is kall[0] + True + >>> kwargs is kall[1] + True + + >>> m = MagicMock() + >>> m.foo(4, 5, 6, arg='two', arg2='three') + + >>> kall = m.mock_calls[0] + >>> name, args, kwargs = kall + >>> name + 'foo' + >>> args + (4, 5, 6) + >>> kwargs + {'arg2': 'three', 'arg': 'two'} + >>> name is m.mock_calls[0][0] + True + + +create_autospec +--------------- + +.. function:: create_autospec(spec, spec_set=False, instance=False, **kwargs) + + Create a mock object using another object as a spec. Attributes on the + mock will use the corresponding attribute on the `spec` object as their + spec. + + Functions or methods being mocked will have their arguments checked to + ensure that they are called with the correct signature. + + If `spec_set` is `True` then attempting to set attributes that don't exist + on the spec object will raise an `AttributeError`. + + If a class is used as a spec then the return value of the mock (the + instance of the class) will have the same spec. You can use a class as the + spec for an instance object by passing `instance=True`. The returned mock + will only be callable if instances of the mock are callable. + + `create_autospec` also takes arbitrary keyword arguments that are passed to + the constructor of the created mock. + +See :ref:`auto-speccing` for examples of how to use auto-speccing with +`create_autospec` and the `autospec` argument to :func:`patch`. + + +ANY +--- + +.. data:: ANY + +Sometimes you may need to make assertions about *some* of the arguments in a +call to mock, but either not care about some of the arguments or want to pull +them individually out of :attr:`~Mock.call_args` and make more complex +assertions on them. + +To ignore certain arguments you can pass in objects that compare equal to +*everything*. Calls to :meth:`~Mock.assert_called_with` and +:meth:`~Mock.assert_called_once_with` will then succeed no matter what was +passed in. + + >>> mock = Mock(return_value=None) + >>> mock('foo', bar=object()) + >>> mock.assert_called_once_with('foo', bar=ANY) + +`ANY` can also be used in comparisons with call lists like +:attr:`~Mock.mock_calls`: + + >>> m = MagicMock(return_value=None) + >>> m(1) + >>> m(1, 2) + >>> m(object()) + >>> m.mock_calls == [call(1), call(1, 2), ANY] + True + + + +FILTER_DIR +---------- + +.. data:: FILTER_DIR + +`FILTER_DIR` is a module level variable that controls the way mock objects +respond to `dir` (only for Python 2.6 or more recent). The default is `True`, +which uses the filtering described below, to only show useful members. If you +dislike this filtering, or need to switch it off for diagnostic purposes, then +set `mock.FILTER_DIR = False`. + +With filtering on, `dir(some_mock)` shows only useful attributes and will +include any dynamically created attributes that wouldn't normally be shown. +If the mock was created with a `spec` (or `autospec` of course) then all the +attributes from the original are shown, even if they haven't been accessed +yet: + + >>> dir(Mock()) + ['assert_any_call', + 'assert_called_once_with', + 'assert_called_with', + 'assert_has_calls', + 'attach_mock', + ... + >>> from urllib import request + >>> dir(Mock(spec=request)) + ['AbstractBasicAuthHandler', + 'AbstractDigestAuthHandler', + 'AbstractHTTPHandler', + 'BaseHandler', + ... + +Many of the not-very-useful (private to `Mock` rather than the thing being +mocked) underscore and double underscore prefixed attributes have been +filtered from the result of calling `dir` on a `Mock`. If you dislike this +behaviour you can switch it off by setting the module level switch +`FILTER_DIR`: + + >>> from unittest import mock + >>> mock.FILTER_DIR = False + >>> dir(mock.Mock()) + ['_NonCallableMock__get_return_value', + '_NonCallableMock__get_side_effect', + '_NonCallableMock__return_value_doc', + '_NonCallableMock__set_return_value', + '_NonCallableMock__set_side_effect', + '__call__', + '__class__', + ... + +Alternatively you can just use `vars(my_mock)` (instance members) and +`dir(type(my_mock))` (type members) to bypass the filtering irrespective of +`mock.FILTER_DIR`. + + +mock_open +--------- + +.. function:: mock_open(mock=None, read_data=None) + + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` method of the file handle to return. + This is an empty string by default. + +Using `open` as a context manager is a great way to ensure your file handles +are closed properly and is becoming common:: + + with open('/some/path', 'w') as f: + f.write('something') + +The issue is that even if you mock out the call to `open` it is the +*returned object* that is used as a context manager (and has `__enter__` and +`__exit__` called). + +Mocking context managers with a :class:`MagicMock` is common enough and fiddly +enough that a helper function is useful. + + >>> m = mock_open() + >>> with patch('__main__.open', m, create=True): + ... with open('foo', 'w') as h: + ... h.write('some stuff') + ... + >>> m.mock_calls + [call('foo', 'w'), + call().__enter__(), + call().write('some stuff'), + call().__exit__(None, None, None)] + >>> m.assert_called_once_with('foo', 'w') + >>> handle = m() + >>> handle.write.assert_called_once_with('some stuff') + +And for reading files: + + >>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: + ... with open('foo') as h: + ... result = h.read() + ... + >>> m.assert_called_once_with('foo') + >>> assert result == 'bibble' + + +.. _auto-speccing: + +Autospeccing +------------ + +Autospeccing is based on the existing `spec` feature of mock. It limits the +api of mocks to the api of an original object (the spec), but it is recursive +(implemented lazily) so that attributes of mocks only have the same api as +the attributes of the spec. In addition mocked functions / methods have the +same call signature as the original so they raise a `TypeError` if they are +called incorrectly. + +Before I explain how auto-speccing works, here's why it is needed. + +`Mock` is a very powerful and flexible object, but it suffers from two flaws +when used to mock out objects from a system under test. One of these flaws is +specific to the `Mock` api and the other is a more general problem with using +mock objects. + +First the problem specific to `Mock`. `Mock` has two assert methods that are +extremely handy: :meth:`~Mock.assert_called_with` and +:meth:`~Mock.assert_called_once_with`. + + >>> mock = Mock(name='Thing', return_value=None) + >>> mock(1, 2, 3) + >>> mock.assert_called_once_with(1, 2, 3) + >>> mock(1, 2, 3) + >>> mock.assert_called_once_with(1, 2, 3) + Traceback (most recent call last): + ... + AssertionError: Expected to be called once. Called 2 times. + +Because mocks auto-create attributes on demand, and allow you to call them +with arbitrary arguments, if you misspell one of these assert methods then +your assertion is gone: + +.. code-block:: pycon + + >>> mock = Mock(name='Thing', return_value=None) + >>> mock(1, 2, 3) + >>> mock.assret_called_once_with(4, 5, 6) + +Your tests can pass silently and incorrectly because of the typo. + +The second issue is more general to mocking. If you refactor some of your +code, rename members and so on, any tests for code that is still using the +*old api* but uses mocks instead of the real objects will still pass. This +means your tests can all pass even though your code is broken. + +Note that this is another reason why you need integration tests as well as +unit tests. Testing everything in isolation is all fine and dandy, but if you +don't test how your units are "wired together" there is still lots of room +for bugs that tests might have caught. + +`mock` already provides a feature to help with this, called speccing. If you +use a class or instance as the `spec` for a mock then you can only access +attributes on the mock that exist on the real class: + + >>> from urllib import request + >>> mock = Mock(spec=request.Request) + >>> mock.assret_called_with + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'assret_called_with' + +The spec only applies to the mock itself, so we still have the same issue +with any methods on the mock: + +.. code-block:: pycon + + >>> mock.has_data() + + >>> mock.has_data.assret_called_with() + +Auto-speccing solves this problem. You can either pass `autospec=True` to +`patch` / `patch.object` or use the `create_autospec` function to create a +mock with a spec. If you use the `autospec=True` argument to `patch` then the +object that is being replaced will be used as the spec object. Because the +speccing is done "lazily" (the spec is created as attributes on the mock are +accessed) you can use it with very complex or deeply nested objects (like +modules that import modules that import modules) without a big performance +hit. + +Here's an example of it in use: + + >>> from urllib import request + >>> patcher = patch('__main__.request', autospec=True) + >>> mock_request = patcher.start() + >>> request is mock_request + True + >>> mock_request.Request + + +You can see that `request.Request` has a spec. `request.Request` takes two +arguments in the constructor (one of which is `self`). Here's what happens if +we try to call it incorrectly: + + >>> req = request.Request() + Traceback (most recent call last): + ... + TypeError: () takes at least 2 arguments (1 given) + +The spec also applies to instantiated classes (i.e. the return value of +specced mocks): + + >>> req = request.Request('foo') + >>> req + + +`Request` objects are not callable, so the return value of instantiating our +mocked out `request.Request` is a non-callable mock. With the spec in place +any typos in our asserts will raise the correct error: + + >>> req.add_header('spam', 'eggs') + + >>> req.add_header.assret_called_with + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'assret_called_with' + >>> req.add_header.assert_called_with('spam', 'eggs') + +In many cases you will just be able to add `autospec=True` to your existing +`patch` calls and then be protected against bugs due to typos and api +changes. + +As well as using `autospec` through `patch` there is a +:func:`create_autospec` for creating autospecced mocks directly: + + >>> from urllib import request + >>> mock_request = create_autospec(request) + >>> mock_request.Request('foo', 'bar') + + +This isn't without caveats and limitations however, which is why it is not +the default behaviour. In order to know what attributes are available on the +spec object, autospec has to introspect (access attributes) the spec. As you +traverse attributes on the mock a corresponding traversal of the original +object is happening under the hood. If any of your specced objects have +properties or descriptors that can trigger code execution then you may not be +able to use autospec. On the other hand it is much better to design your +objects so that introspection is safe [#]_. + +A more serious problem is that it is common for instance attributes to be +created in the `__init__` method and not to exist on the class at all. +`autospec` can't know about any dynamically created attributes and restricts +the api to visible attributes. + + >>> class Something(object): + ... def __init__(self): + ... self.a = 33 + ... + >>> with patch('__main__.Something', autospec=True): + ... thing = Something() + ... thing.a + ... + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'a' + +There are a few different ways of resolving this problem. The easiest, but +not necessarily the least annoying, way is to simply set the required +attributes on the mock after creation. Just because `autospec` doesn't allow +you to fetch attributes that don't exist on the spec it doesn't prevent you +setting them: + + >>> with patch('__main__.Something', autospec=True): + ... thing = Something() + ... thing.a = 33 + ... + +There is a more aggressive version of both `spec` and `autospec` that *does* +prevent you setting non-existent attributes. This is useful if you want to +ensure your code only *sets* valid attributes too, but obviously it prevents +this particular scenario: + + >>> with patch('__main__.Something', autospec=True, spec_set=True): + ... thing = Something() + ... thing.a = 33 + ... + Traceback (most recent call last): + ... + AttributeError: Mock object has no attribute 'a' + +Probably the best way of solving the problem is to add class attributes as +default values for instance members initialised in `__init__`. Note that if +you are only setting default attributes in `__init__` then providing them via +class attributes (shared between instances of course) is faster too. e.g. + +.. code-block:: python + + class Something(object): + a = 33 + +This brings up another issue. It is relatively common to provide a default +value of `None` for members that will later be an object of a different type. +`None` would be useless as a spec because it wouldn't let you access *any* +attributes or methods on it. As `None` is *never* going to be useful as a +spec, and probably indicates a member that will normally of some other type, +`autospec` doesn't use a spec for members that are set to `None`. These will +just be ordinary mocks (well - `MagicMocks`): + + >>> class Something(object): + ... member = None + ... + >>> mock = create_autospec(Something) + >>> mock.member.foo.bar.baz() + + +If modifying your production classes to add defaults isn't to your liking +then there are more options. One of these is simply to use an instance as the +spec rather than the class. The other is to create a subclass of the +production class and add the defaults to the subclass without affecting the +production class. Both of these require you to use an alternative object as +the spec. Thankfully `patch` supports this - you can simply pass the +alternative object as the `autospec` argument: + + >>> class Something(object): + ... def __init__(self): + ... self.a = 33 + ... + >>> class SomethingForTest(Something): + ... a = 33 + ... + >>> p = patch('__main__.Something', autospec=SomethingForTest) + >>> mock = p.start() + >>> mock.a + + + +.. [#] This only applies to classes or already instantiated objects. Calling + a mocked class to create a mock instance *does not* create a real instance. + It is only attribute lookups - along with calls to `dir` - that are done. + diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -5,65 +5,40 @@ :synopsis: Implementation of the ElementTree API. .. moduleauthor:: Fredrik Lundh -**Source code:** :source:`Lib/xml/etree/ElementTree.py` - --------------- - -The :class:`Element` type is a flexible container object, designed to store -hierarchical data structures in memory. The type can be described as a cross -between a list and a dictionary. - -Each element has a number of properties associated with it: - -* a tag which is a string identifying what kind of data this element represents - (the element type, in other words). - -* a number of attributes, stored in a Python dictionary. - -* a text string. - -* an optional tail string. - -* a number of child elements, stored in a Python sequence - -To create an element instance, use the :class:`Element` constructor or the -:func:`SubElement` factory function. - -The :class:`ElementTree` class can be used to wrap an element structure, and -convert it from and to XML. - -See http://effbot.org/zone/element-index.htm for tutorials and links to other -docs. - -.. versionchanged:: 3.2 - The ElementTree API is updated to 1.3. For more information, see - `Introducing ElementTree 1.3 - `_. +The :mod:`xml.etree.ElementTree` module implements a simple and efficient API +for parsing and creating XML data. .. versionchanged:: 3.3 This module will use a fast implementation whenever available. The :mod:`xml.etree.cElementTree` module is deprecated. +Tutorial +-------- -.. _elementtree-xpath: +This is a short tutorial for using :mod:`xml.etree.ElementTree` (``ET`` in +short). The goal is to demonstrate some of the building blocks and basic +concepts of the module. -XPath support -------------- +XML tree and elements +^^^^^^^^^^^^^^^^^^^^^ -This module provides limited support for -`XPath expressions `_ for locating elements in a -tree. The goal is to support a small subset of the abbreviated syntax; a full -XPath engine is outside the scope of the module. +XML is an inherently hierarchical data format, and the most natural way to +represent it is with a tree. ``ET`` has two classes for this purpose - +:class:`ElementTree` represents the whole XML document as a tree, and +:class:`Element` represents a single node in this tree. Interactions with +the whole document (reading and writing to/from files) are usually done +on the :class:`ElementTree` level. Interactions with a single XML element +and its sub-elements are done on the :class:`Element` level. -Example -^^^^^^^ +.. _elementtree-parsing-xml: -Here's an example that demonstrates some of the XPath capabilities of the -module:: +Parsing XML +^^^^^^^^^^^ - import xml.etree.ElementTree as ET +We'll be using the following XML document contained in a Python string as the +sample data for this section:: - xml = r''' + countrydata = r''' 1 @@ -88,23 +63,121 @@ ''' - tree = ET.fromstring(xml) +First, import the module and parse the data:: + + import xml.etree.ElementTree as ET + + root = ET.fromstring(countrydata) + +:func:`fromstring` parses XML from a string directly into an :class:`Element`, +which is the root element of the parsed tree. Other parsing functions may +create an :class:`ElementTree`. Make sure to check the documentation to be +sure. + +As an :class:`Element`, ``root`` has a tag and a dictionary of attributes:: + + >>> root.tag + 'data' + >>> root.attrib + {} + +It also has children nodes over which we can iterate:: + + >>> for child in root: + ... print(child.tag, child.attrib) + ... + country {'name': 'Liechtenshtein'} + country {'name': 'Singapore'} + country {'name': 'Panama'} + +Children are nested, and we can access specific child nodes by index:: + + >>> root[0][1].text + '2008' + +Finding interesting elements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:class:`Element` has some useful methods that help iterate recursively over all +the sub-tree below it (its children, their children, and so on). For example, +:meth:`Element.iter`:: + + >>> for neighbor in root.iter('neighbor'): + ... print(neighbor.attrib) + ... + {'name': 'Austria', 'direction': 'E'} + {'name': 'Switzerland', 'direction': 'W'} + {'name': 'Malaysia', 'direction': 'N'} + {'name': 'Costa Rica', 'direction': 'W'} + {'name': 'Colombia', 'direction': 'E'} + +More sophisticated specification of which elements to look for is possible by +using :ref:`XPath `. + +Building XML documents +^^^^^^^^^^^^^^^^^^^^^^ + +``ET`` provides a simple way to build XML documents and write them to files. +The :meth:`ElementTree.write` method serves this purpose. + +Once created, an :class:`Element` object may be manipulated by directly changing +its fields (such as :attr:`Element.text`), adding and modifying attributes +(:meth:`Element.set` method), as well as adding new children (for example +with :meth:`Element.append`). + +The :func:`SubElement` function also provides a convenient way to create new +sub-elements for a given element:: + + >>> a = ET.Element('a') + >>> b = ET.SubElement(a, 'b') + >>> c = ET.SubElement(a, 'c') + >>> d = ET.SubElement(c, 'd') + >>> ET.dump(a) + + +Additional resources +^^^^^^^^^^^^^^^^^^^^ + +See http://effbot.org/zone/element-index.htm for tutorials and links to other +docs. + + +.. _elementtree-xpath: + +XPath support +------------- + +This module provides limited support for +`XPath expressions `_ for locating elements in a +tree. The goal is to support a small subset of the abbreviated syntax; a full +XPath engine is outside the scope of the module. + +Example +^^^^^^^ + +Here's an example that demonstrates some of the XPath capabilities of the +module. We'll be using the ``countrydata`` XML document from the +:ref:`Parsing XML ` section:: + + import xml.etree.ElementTree as ET + + root = ET.fromstring(countrydata) # Top-level elements - tree.findall(".") + root.findall(".") # All 'neighbor' grand-children of 'country' children of the top-level # elements - tree.findall("./country/neighbor") + root.findall("./country/neighbor") # Nodes with name='Singapore' that have a 'year' child - tree.findall(".//year/..[@name='Singapore']") + root.findall(".//year/..[@name='Singapore']") # 'year' nodes that are children of nodes with name='Singapore' - tree.findall(".//*[@name='Singapore']/year") + root.findall(".//*[@name='Singapore']/year") # All 'neighbor' nodes that are the second child of their parent - tree.findall(".//neighbor[2]") + root.findall(".//neighbor[2]") Supported XPath syntax ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,6 +3,9 @@ - IDLE can be launched as `python -m idlelib` +- Issue #14409: IDLE doesn't not execute commands from shell, + error with default keybinding for Return. (Patch by Roger Serwy) + - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). diff --git a/Lib/idlelib/configHandler.py b/Lib/idlelib/configHandler.py --- a/Lib/idlelib/configHandler.py +++ b/Lib/idlelib/configHandler.py @@ -596,7 +596,7 @@ '<>': [''], '<>': [''], '<>': [''], - '<>': [' '], + '<>': ['', ''], '<>': [''], '<>': [''], '<>': [''], diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -559,11 +559,16 @@ """ ei = record.exc_info if ei: - dummy = self.format(record) # just to get traceback text into record.exc_text - record.exc_info = None # to avoid Unpickleable error - s = pickle.dumps(record.__dict__, 1) - if ei: - record.exc_info = ei # for next handler + # just to get traceback text into record.exc_text ... + dummy = self.format(record) + # See issue #14436: If msg or args are objects, they may not be + # available on the receiving end. So we convert the msg % args + # to a string, save it as msg and zap the args. + d = dict(record.__dict__) + d['msg'] = record.getMessage() + d['args'] = None + d['exc_info'] = None + s = pickle.dumps(d, 1) slen = struct.pack(">L", len(s)) return slen + s diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -9,6 +9,7 @@ import sys import time import select +import errno import unittest from test import support, mock_socket diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1352,17 +1352,20 @@ """ `patch` acts as a function decorator, class decorator or a context manager. Inside the body of the function or with statement, the `target` - (specified in the form `'package.module.ClassName'`) is patched - with a `new` object. When the function/with statement exits the patch is - undone. - - The `target` is imported and the specified attribute patched with the new - object, so it must be importable from the environment you are calling the - decorator from. The target is imported when the decorated function is - executed, not at decoration time. - - If `new` is omitted, then a new `MagicMock` is created and passed in as an - extra argument to the decorated function. + is patched with a `new` object. When the function/with statement exits + the patch is undone. + + If `new` is omitted, then the target is replaced with a + `MagicMock`. If `patch` is used as a decorator and `new` is + omitted, the created mock is passed in as an extra argument to the + decorated function. If `patch` is used as a context manager the created + mock is returned by the context manager. + + `target` should be a string in the form `'package.module.ClassName'`. The + `target` is imported and the specified object replaced with the `new` + object, so the `target` must be importable from the environment you are + calling `patch` from. The target is imported when the decorated function + is executed, not at decoration time. The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` if patch is creating one for you. diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -832,6 +832,7 @@ Gareth Rees Steve Reeves Lennart Regebro +Federico Reghenzani Ofir Reichenberg Sean Reifschneider Michael P. Reilly diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,12 @@ Library ------- +- Issue #14409: IDLE doesn't not execute commands from shell, + error with default keybinding for Return. (Patch by Roger Serwy) + +- Issue #14416: syslog now defines the LOG_ODELAY and LOG_AUTHPRIV constants + if they are defined in . + - IDLE can be launched as python -m idlelib - Issue #14295: Add unittest.mock @@ -193,6 +199,8 @@ Tests ----- +- Issue #14442: Add missing errno import in test_smtplib. + - Issue #8315: (partial fix) python -m unittest test.test_email now works. diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -291,6 +291,9 @@ PyModule_AddIntConstant(m, "LOG_PID", LOG_PID); PyModule_AddIntConstant(m, "LOG_CONS", LOG_CONS); PyModule_AddIntConstant(m, "LOG_NDELAY", LOG_NDELAY); +#ifdef LOG_ODELAY + PyModule_AddIntConstant(m, "LOG_ODELAY", LOG_ODELAY); +#endif #ifdef LOG_NOWAIT PyModule_AddIntConstant(m, "LOG_NOWAIT", LOG_NOWAIT); #endif @@ -331,5 +334,10 @@ PyModule_AddIntConstant(m, "LOG_CRON", LOG_CRON); PyModule_AddIntConstant(m, "LOG_UUCP", LOG_UUCP); PyModule_AddIntConstant(m, "LOG_NEWS", LOG_NEWS); + +#ifdef LOG_AUTHPRIV + PyModule_AddIntConstant(m, "LOG_AUTHPRIV", LOG_AUTHPRIV); +#endif + return m; } diff --git a/Objects/floatobject.c b/Objects/floatobject.c --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -16,53 +16,16 @@ /* Special free list - - Since some Python programs can spend much of their time allocating - and deallocating floats, these operations should be very fast. - Therefore we use a dedicated allocation scheme with a much lower - overhead (in space and time) than straight malloc(): a simple - dedicated free list, filled when necessary with memory from malloc(). - - block_list is a singly-linked list of all PyFloatBlocks ever allocated, - linked via their next members. PyFloatBlocks are never returned to the - system before shutdown (PyFloat_Fini). - free_list is a singly-linked list of available PyFloatObjects, linked via abuse of their ob_type members. */ -#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ -#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ -#define N_FLOATOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyFloatObject)) - -struct _floatblock { - struct _floatblock *next; - PyFloatObject objects[N_FLOATOBJECTS]; -}; - -typedef struct _floatblock PyFloatBlock; - -static PyFloatBlock *block_list = NULL; +#ifndef PyFloat_MAXFREELIST +#define PyFloat_MAXFREELIST 100 +#endif +static int numfree = 0; static PyFloatObject *free_list = NULL; -static PyFloatObject * -fill_free_list(void) -{ - PyFloatObject *p, *q; - /* XXX Float blocks escape the object heap. Use PyObject_MALLOC ??? */ - p = (PyFloatObject *) PyMem_MALLOC(sizeof(PyFloatBlock)); - if (p == NULL) - return (PyFloatObject *) PyErr_NoMemory(); - ((PyFloatBlock *)p)->next = block_list; - block_list = (PyFloatBlock *)p; - p = &((PyFloatBlock *)p)->objects[0]; - q = p + N_FLOATOBJECTS; - while (--q > p) - Py_TYPE(q) = (struct _typeobject *)(q-1); - Py_TYPE(q) = NULL; - return p + N_FLOATOBJECTS - 1; -} - double PyFloat_GetMax(void) { @@ -151,14 +114,16 @@ PyObject * PyFloat_FromDouble(double fval) { - register PyFloatObject *op; - if (free_list == NULL) { - if ((free_list = fill_free_list()) == NULL) - return NULL; + register PyFloatObject *op = free_list; + if (op != NULL) { + free_list = (PyFloatObject *) Py_TYPE(op); + numfree--; + } else { + op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject)); + if (!op) + return PyErr_NoMemory(); } /* Inline PyObject_New */ - op = free_list; - free_list = (PyFloatObject *)Py_TYPE(op); PyObject_INIT(op, &PyFloat_Type); op->ob_fval = fval; return (PyObject *) op; @@ -217,6 +182,11 @@ float_dealloc(PyFloatObject *op) { if (PyFloat_CheckExact(op)) { + if (numfree >= PyFloat_MAXFREELIST) { + PyObject_FREE(op); + return; + } + numfree++; Py_TYPE(op) = (struct _typeobject *)free_list; free_list = op; } @@ -1932,96 +1902,22 @@ int PyFloat_ClearFreeList(void) { - PyFloatObject *p; - PyFloatBlock *list, *next; - int i; - int u; /* remaining unfreed floats per block */ - int freelist_size = 0; - - list = block_list; - block_list = NULL; + PyFloatObject *f = free_list, *next; + int i = numfree; + while (f) { + next = (PyFloatObject*) Py_TYPE(f); + PyObject_FREE(f); + f = next; + } free_list = NULL; - while (list != NULL) { - u = 0; - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0) - u++; - } - next = list->next; - if (u) { - list->next = block_list; - block_list = list; - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (!PyFloat_CheckExact(p) || - Py_REFCNT(p) == 0) { - Py_TYPE(p) = (struct _typeobject *) - free_list; - free_list = p; - } - } - } - else { - PyMem_FREE(list); - } - freelist_size += u; - list = next; - } - return freelist_size; + numfree = 0; + return i; } void PyFloat_Fini(void) { - PyFloatObject *p; - PyFloatBlock *list; - int i; - int u; /* total unfreed floats per block */ - - u = PyFloat_ClearFreeList(); - - if (!Py_VerboseFlag) - return; - fprintf(stderr, "# cleanup floats"); - if (!u) { - fprintf(stderr, "\n"); - } - else { - fprintf(stderr, - ": %d unfreed float%s\n", - u, u == 1 ? "" : "s"); - } - if (Py_VerboseFlag > 1) { - list = block_list; - while (list != NULL) { - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (PyFloat_CheckExact(p) && - Py_REFCNT(p) != 0) { - char *buf = PyOS_double_to_string( - PyFloat_AS_DOUBLE(p), 'r', - 0, 0, NULL); - if (buf) { - /* XXX(twouters) cast - refcount to long - until %zd is - universally - available - */ - fprintf(stderr, - "# \n", - p, (long)Py_REFCNT(p), buf); - PyMem_Free(buf); - } - } - } - list = list->next; - } - } + (void)PyFloat_ClearFreeList(); } /*---------------------------------------------------------------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 30 14:45:28 2012 From: python-checkins at python.org (alex.gaynor) Date: Fri, 30 Mar 2012 14:45:28 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Added_a_new_cra?= =?utf8?q?sher_that_targets_mutating_the_underlying_storage_of_a_buffer=2E?= Message-ID: http://hg.python.org/cpython/rev/5aad56eb471c changeset: 75996:5aad56eb471c branch: 2.7 parent: 75987:eda0ae0d2c68 user: Alex Gaynor date: Fri Mar 30 08:45:25 2012 -0400 summary: Added a new crasher that targets mutating the underlying storage of a buffer. All work done by Armin Rigo. files: Lib/test/crashers/buffer_mutate.py | 30 ++++++++++++++++++ 1 files changed, 30 insertions(+), 0 deletions(-) diff --git a/Lib/test/crashers/buffer_mutate.py b/Lib/test/crashers/buffer_mutate.py new file mode 100644 --- /dev/null +++ b/Lib/test/crashers/buffer_mutate.py @@ -0,0 +1,30 @@ +# +# The various methods of bufferobject.c (here buffer_subscript()) call +# get_buf() before calling potentially more Python code (here via +# PySlice_GetIndicesEx()). But get_buf() already returned a void* +# pointer. This void* pointer can become invalid if the object +# underlying the buffer is mutated (here a bytearray object). +# +# As usual, please keep in mind that the three "here" in the sentence +# above are only examples. Each can be changed easily and lead to +# another crasher. +# +# This crashes for me on Linux 32-bits with CPython 2.6 and 2.7 +# with a segmentation fault. +# + + +class PseudoIndex(object): + def __index__(self): + for c in "foobar"*n: + a.append(c) + return n * 4 + + +for n in range(1, 100000, 100): + a = bytearray("test"*n) + buf = buffer(a) + + s = buf[:PseudoIndex():1] + #print repr(s) + #assert s == "test"*n -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 30 15:39:50 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 30 Mar 2012 15:39:50 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314065=3A_Added_cyc?= =?utf8?q?lic_GC_support_to_ET=2EElement?= Message-ID: http://hg.python.org/cpython/rev/0ca32013d77e changeset: 75997:0ca32013d77e parent: 75995:cf2e74e0b7d4 user: Eli Bendersky date: Fri Mar 30 16:38:33 2012 +0300 summary: Issue #14065: Added cyclic GC support to ET.Element files: Lib/test/test_xml_etree.py | 27 ++++++++++- Modules/_elementtree.c | 63 +++++++++++++++++++------ 2 files changed, 74 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -14,9 +14,10 @@ # Don't re-import "xml.etree.ElementTree" module in the docstring, # except if the test is specific to the Python implementation. -import sys +import gc import html import io +import sys import unittest from test import support @@ -1846,6 +1847,30 @@ self.assertRaises(TypeError, e.extend, [ET.Element('bar'), 'foo']) self.assertRaises(TypeError, e.insert, 0, 'foo') + def test_cyclic_gc(self): + class ShowGC: + def __init__(self, flaglist): + self.flaglist = flaglist + def __del__(self): + self.flaglist.append(1) + + # Test the shortest cycle: lst->element->lst + fl = [] + lst = [ShowGC(fl)] + lst.append(ET.Element('joe', attr=lst)) + del lst + gc.collect() + self.assertEqual(fl, [1]) + + # A longer cycle: lst->e->e2->lst + fl = [] + e = ET.Element('joe') + lst = [ShowGC(fl), e] + e2 = ET.SubElement(e, 'foo', attr=lst) + del lst, e, e2 + gc.collect() + self.assertEqual(fl, [1]) + class ElementTreeTest(unittest.TestCase): def test_istype(self): diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -282,7 +282,7 @@ { ElementObject* self; - self = PyObject_New(ElementObject, &Element_Type); + self = PyObject_GC_New(ElementObject, &Element_Type); if (self == NULL) return NULL; @@ -309,7 +309,7 @@ self->tail = Py_None; ALLOC(sizeof(ElementObject), "create element"); - + PyObject_GC_Track(self); return (PyObject*) self; } @@ -556,19 +556,51 @@ return elem; } +static int +element_gc_traverse(ElementObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->tag); + Py_VISIT(JOIN_OBJ(self->text)); + Py_VISIT(JOIN_OBJ(self->tail)); + + if (self->extra) { + int i; + Py_VISIT(self->extra->attrib); + + for (i = 0; i < self->extra->length; ++i) + Py_VISIT(self->extra->children[i]); + } + return 0; +} + +static int +element_gc_clear(ElementObject *self) +{ + PyObject *text = JOIN_OBJ(self->text); + PyObject *tail = JOIN_OBJ(self->tail); + Py_CLEAR(self->tag); + Py_CLEAR(text); + Py_CLEAR(tail); + + /* After dropping all references from extra, it's no longer valid anyway, + ** so fully deallocate it (see also element_clearmethod) + */ + if (self->extra) { + dealloc_extra(self); + self->extra = NULL; + } + return 0; +} + static void element_dealloc(ElementObject* self) { - if (self->extra) - dealloc_extra(self); - - /* discard attributes */ - Py_DECREF(self->tag); - Py_DECREF(JOIN_OBJ(self->text)); - Py_DECREF(JOIN_OBJ(self->tail)); + PyObject_GC_UnTrack(self); + /* element_gc_clear clears all references and deallocates extra + */ + element_gc_clear(self); RELEASE(sizeof(ElementObject), "destroy element"); - Py_TYPE(self)->tp_free((PyObject *)self); } @@ -589,7 +621,7 @@ } static PyObject* -element_clear(ElementObject* self, PyObject* args) +element_clearmethod(ElementObject* self, PyObject* args) { if (!PyArg_ParseTuple(args, ":clear")) return NULL; @@ -1505,7 +1537,7 @@ static PyMethodDef element_methods[] = { - {"clear", (PyCFunction) element_clear, METH_VARARGS}, + {"clear", (PyCFunction) element_clearmethod, METH_VARARGS}, {"get", (PyCFunction) element_get, METH_VARARGS}, {"set", (PyCFunction) element_set, METH_VARARGS}, @@ -1655,10 +1687,11 @@ (getattrofunc)element_getattro, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + /* tp_flags */ 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ + (traverseproc)element_gc_traverse, /* tp_traverse */ + (inquiry)element_gc_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ -- Repository URL: http://hg.python.org/cpython From andrew.svetlov at gmail.com Fri Mar 30 20:31:01 2012 From: andrew.svetlov at gmail.com (Andrew Svetlov) Date: Fri, 30 Mar 2012 21:31:01 +0300 Subject: [Python-checkins] cpython (3.2): Issue #14409: IDLE doesn't not execute commands from shell with default In-Reply-To: References: Message-ID: Thank you for mentoring. I will fix NEWS if you help me with better text. The bug fixed is that commit is: IDLE has 3 configs: user, system default and hardcoded in python code. Last one had bad binding for key. Usually this config is never used: user or system ones overrides former. But if IDLE cannot open config files by some reason it switches to hardcoded configs and user got broken IDLE. Can anybody guess me short and descriptive message describing what fix well? On Fri, Mar 30, 2012 at 6:12 AM, Nick Coghlan wrote: > On Fri, Mar 30, 2012 at 2:01 AM, andrew.svetlov > wrote: >> +- Issue #14409: IDLE doesn't not execute commands from shell, >> + ?error with default keybinding for Return. (Patch by Roger Serwy) > > The double negative here makes this impossible to understand. Could we > please get an updated NEWS entry that explains what actually changed > in IDLE to fix this? > > Perhaps something like "IDLE now always sets the default keybind for > Return correctly, ensuring commands can be executed in the IDLE shell > window"? (assuming that's what happened). > > This is important, folks: NEWS entries need to be comprehensible for > people that *haven't* read the associated tracker issue. This means > that issue titles (which generally describe a problem someone was > having) are often inappropriate as NEWS items. NEWS items should be > short descriptions that clearly describe *what changed*, perhaps with > some additional information to explain a bit about why the change was > made. > > Regards, > Nick. > > -- > Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins -- Thanks, Andrew Svetlov From benjamin at python.org Fri Mar 30 21:30:59 2012 From: benjamin at python.org (Benjamin Peterson) Date: Fri, 30 Mar 2012 15:30:59 -0400 Subject: [Python-checkins] cpython: Issue #14065: Added cyclic GC support to ET.Element In-Reply-To: References: Message-ID: 2012/3/30 eli.bendersky : > http://hg.python.org/cpython/rev/0ca32013d77e > changeset: ? 75997:0ca32013d77e > parent: ? ? ?75995:cf2e74e0b7d4 > user: ? ? ? ?Eli Bendersky > date: ? ? ? ?Fri Mar 30 16:38:33 2012 +0300 > summary: > ?Issue #14065: Added cyclic GC support to ET.Element > > files: > ?Lib/test/test_xml_etree.py | ?27 ++++++++++- > ?Modules/_elementtree.c ? ? | ?63 +++++++++++++++++++------ > ?2 files changed, 74 insertions(+), 16 deletions(-) > > > diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py > --- a/Lib/test/test_xml_etree.py > +++ b/Lib/test/test_xml_etree.py > @@ -14,9 +14,10 @@ > ?# Don't re-import "xml.etree.ElementTree" module in the docstring, > ?# except if the test is specific to the Python implementation. > > -import sys > +import gc > ?import html > ?import io > +import sys > ?import unittest > > ?from test import support > @@ -1846,6 +1847,30 @@ > ? ? ? ? self.assertRaises(TypeError, e.extend, [ET.Element('bar'), 'foo']) > ? ? ? ? self.assertRaises(TypeError, e.insert, 0, 'foo') > > + ? ?def test_cyclic_gc(self): > + ? ? ? ?class ShowGC: > + ? ? ? ? ? ?def __init__(self, flaglist): > + ? ? ? ? ? ? ? ?self.flaglist = flaglist > + ? ? ? ? ? ?def __del__(self): > + ? ? ? ? ? ? ? ?self.flaglist.append(1) I think a nicer way to check for cyclic collection is to take a weakref to an object, call the GC, then check to make sure the weakref is broken. > + > + ? ? ? ?# Test the shortest cycle: lst->element->lst > + ? ? ? ?fl = [] > + ? ? ? ?lst = [ShowGC(fl)] > + ? ? ? ?lst.append(ET.Element('joe', attr=lst)) > + ? ? ? ?del lst > + ? ? ? ?gc.collect() support.gc_collect() is preferable > + ? ? ? ?self.assertEqual(fl, [1]) > + > + ? ? ? ?# A longer cycle: lst->e->e2->lst > + ? ? ? ?fl = [] > + ? ? ? ?e = ET.Element('joe') > + ? ? ? ?lst = [ShowGC(fl), e] > + ? ? ? ?e2 = ET.SubElement(e, 'foo', attr=lst) > + ? ? ? ?del lst, e, e2 > + ? ? ? ?gc.collect() > + ? ? ? ?self.assertEqual(fl, [1]) -- Regards, Benjamin From python-checkins at python.org Fri Mar 30 22:16:25 2012 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 30 Mar 2012 22:16:25 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Minor_cleanup=3A_add_whites?= =?utf8?q?pace=2C_add_comments=2C_bring_function_attribute_updates?= Message-ID: http://hg.python.org/cpython/rev/123cf2192c79 changeset: 75998:123cf2192c79 user: Raymond Hettinger date: Fri Mar 30 13:15:48 2012 -0700 summary: Minor cleanup: add whitespace, add comments, bring function attribute updates together. files: Lib/functools.py | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -161,6 +161,7 @@ See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used """ + # Users should only access the lru_cache through its public API: # cache_info, cache_clear, and f.__wrapped__ # The internals of the lru_cache are encapsulated for thread safety and @@ -192,7 +193,6 @@ if maxsize == 0: - @wraps(user_function) def wrapper(*args, **kwds): # no caching, just do a statistics update after a successful call nonlocal misses @@ -202,7 +202,6 @@ elif maxsize is None: - @wraps(user_function) def wrapper(*args, **kwds): # simple caching without ordering or size limit nonlocal hits, misses @@ -218,7 +217,6 @@ else: - @wraps(user_function) def wrapper(*args, **kwds): # size limited caching that tracks accesses by recency nonlocal hits, misses @@ -238,11 +236,12 @@ return result result = user_function(*args, **kwds) with lock: + # put result in a new link at the front of the list last = root[PREV] link = [last, root, key, result] cache[key] = last[NEXT] = root[PREV] = link if _len(cache) > maxsize: - # purge least recently used cache entry + # purge the least recently used cache entry old_prev, old_next, old_key, old_result = root[NEXT] root[NEXT] = old_next old_next[PREV] = root @@ -265,6 +264,6 @@ wrapper.cache_info = cache_info wrapper.cache_clear = cache_clear - return wrapper + return update_wrapper(wrapper, user_function) return decorating_function -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Mar 30 23:16:21 2012 From: python-checkins at python.org (victor.stinner) Date: Fri, 30 Mar 2012 23:16:21 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Add_a_table_summari?= =?utf8?q?zing_system_clocks?= Message-ID: http://hg.python.org/peps/rev/215b14945a3f changeset: 4175:215b14945a3f user: Victor Stinner date: Fri Mar 30 23:16:06 2012 +0200 summary: PEP 418: Add a table summarizing system clocks files: pep-0418.txt | 41 +++++++++++++++++++++++++++++++++++---- 1 files changed, 36 insertions(+), 5 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -185,20 +185,25 @@ Table summarizing all monotonic clocks: - ========================= =============== =============== ================ ==================== Name Resolution Accuracy Adjusted by NTP? Action on suspend ========================= =============== =============== ================ ==================== -CLOCK_MONOTONIC_RAW 1 ns ? No Stopped -gethrtime 1 ns ? No Not stopped +CLOCK_MONOTONIC_RAW 1 ns (*) No Stopped +gethrtime 1 ns (*) No Not stopped +CLOCK_HIGHRES 1 ns (*) No ? +CLOCK_MONOTONIC 1 ns (*) Yes on Linux Stopped on Linux mach_absolute_time() 1 ns ? No ? -CLOCK_HIGHRES 1 ns ? No ? -CLOCK_MONOTONIC 1 ns ? Yes on Linux Stopped on Linux QueryPerformanceCounter() \- 0.3 ns - 5 ns No Accuracy issue GetTickCount[64]() 1 ms 1 ms - 15 ms No Include suspend time timeGetTime() 1 ms 1 ms - 15 ms No ? ========================= =============== =============== ================ ==================== +(*) The accurary of monotonic clocks depends on the operating system. + + * Linux: ? + * FreeBSD: ? + * Solaris: ? + The resolution is the smallest difference between two timestamps supported by the format used by the clock. For example, clock_gettime() uses a timespec structure which has two integer fileds, tv_sec and tv_nsec, so the resolution @@ -401,6 +406,32 @@ System time ----------- +The system time can be set manually by the system administrator or +automatically by a NTP daemon. + +Summary +^^^^^^^ + +Table summarizing all system time clocks: + +========================= =============== =============== +Name Resolution Accuracy +========================= =============== =============== +CLOCK_REALTIME 1 ns (*) +GetSystemTimeAsFileTime 100 ns 1 ms - 15 ms +gettimeofday() 1 ?s (*) +ftime() 1 ms (*) +time() 1 sec 1 sec +========================= =============== =============== + +(*) The accurary of system clocks depends on the operating system. + + * Windows: 1 ms - 15 ms + * Linux: ? + * Mac OS X: ? + * FreeBSD: ? + + Windows: GetSystemTimeAsFileTime ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- Repository URL: http://hg.python.org/peps From tjreedy at udel.edu Fri Mar 30 23:59:21 2012 From: tjreedy at udel.edu (Terry Reedy) Date: Fri, 30 Mar 2012 17:59:21 -0400 Subject: [Python-checkins] cpython (3.2): Issue #14409: IDLE doesn't not execute commands from shell with default In-Reply-To: References: Message-ID: On 3/30/2012 2:31 PM, Andrew Svetlov wrote: > Thank you for mentoring. > > I will fix NEWS if you help me with better text. I believe a succint message would be Issue 14409: IDLE now properly executes commands in the Shell window when it cannot read the normal config files on startup and has to use the built-in default key bindings. There was previously a bug in one of the defaults. > The bug fixed is that commit is: > IDLE has 3 configs: user, system default and hardcoded in python code. > Last one had bad binding for key. > Usually this config is never used: user or system ones overrides former. > But if IDLE cannot open config files by some reason it switches to > hardcoded configs and user got broken IDLE. > > Can anybody guess me short and descriptive message describing what fix well? > > On Fri, Mar 30, 2012 at 6:12 AM, Nick Coghlan wrote: >> On Fri, Mar 30, 2012 at 2:01 AM, andrew.svetlov >> wrote: >>> +- Issue #14409: IDLE doesn't not execute commands from shell, >>> + error with default keybinding for Return. (Patch by Roger Serwy) >> >> The double negative here makes this impossible to understand. Could we >> please get an updated NEWS entry that explains what actually changed >> in IDLE to fix this? >> >> Perhaps something like "IDLE now always sets the default keybind for >> Return correctly, ensuring commands can be executed in the IDLE shell >> window"? (assuming that's what happened). >> >> This is important, folks: NEWS entries need to be comprehensible for >> people that *haven't* read the associated tracker issue. This means >> that issue titles (which generally describe a problem someone was >> having) are often inappropriate as NEWS items. NEWS items should be >> short descriptions that clearly describe *what changed*, perhaps with >> some additional information to explain a bit about why the change was >> made. -- Terry Jan Reedy From python-checkins at python.org Sat Mar 31 00:09:39 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 31 Mar 2012 00:09:39 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzEwNDIzOiBjbGFy?= =?utf8?q?ify_options_vs_args_in_argparse_discussion_of_optparse?= Message-ID: http://hg.python.org/cpython/rev/dee1597b3ce3 changeset: 75999:dee1597b3ce3 branch: 3.2 parent: 75988:cd8347e15f62 user: R David Murray date: Fri Mar 30 18:07:42 2012 -0400 summary: #10423: clarify options vs args in argparse discussion of optparse Patch by Sandro Tosi. files: Doc/library/argparse.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1833,9 +1833,10 @@ * Replace all :meth:`optparse.OptionParser.add_option` calls with :meth:`ArgumentParser.add_argument` calls. -* Replace ``options, args = parser.parse_args()`` with ``args = +* Replace ``(options, args) = parser.parse_args()`` with ``args = parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` - calls for the positional arguments. + calls for the positional arguments. Keep in mind that what was previously + called ``options``, now in :mod:`argparse` context is called ``args``. * Replace callback actions and the ``callback_*`` keyword arguments with ``type`` or ``action`` arguments. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 00:09:40 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 31 Mar 2012 00:09:40 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2310423=3A_clarify_options_vs_args_in_argparse_discus?= =?utf8?q?sion_of_optparse?= Message-ID: http://hg.python.org/cpython/rev/7ad1728691b2 changeset: 76000:7ad1728691b2 parent: 75998:123cf2192c79 parent: 75999:dee1597b3ce3 user: R David Murray date: Fri Mar 30 18:08:29 2012 -0400 summary: Merge #10423: clarify options vs args in argparse discussion of optparse Patch by Sandro Tosi. files: Doc/library/argparse.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1852,9 +1852,10 @@ * Replace all :meth:`optparse.OptionParser.add_option` calls with :meth:`ArgumentParser.add_argument` calls. -* Replace ``options, args = parser.parse_args()`` with ``args = +* Replace ``(options, args) = parser.parse_args()`` with ``args = parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` - calls for the positional arguments. + calls for the positional arguments. Keep in mind that what was previously + called ``options``, now in :mod:`argparse` context is called ``args``. * Replace callback actions and the ``callback_*`` keyword arguments with ``type`` or ``action`` arguments. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 00:09:41 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 31 Mar 2012 00:09:41 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzEwNDIzOiBjbGFy?= =?utf8?q?ify_options_vs_args_in_argparse_discussion_of_optparse?= Message-ID: http://hg.python.org/cpython/rev/cb5214e6c287 changeset: 76001:cb5214e6c287 branch: 2.7 parent: 75996:5aad56eb471c user: R David Murray date: Fri Mar 30 18:09:07 2012 -0400 summary: #10423: clarify options vs args in argparse discussion of optparse Patch by Sandro Tosi. files: Doc/library/argparse.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1826,9 +1826,10 @@ * Replace all :meth:`optparse.OptionParser.add_option` calls with :meth:`ArgumentParser.add_argument` calls. -* Replace ``options, args = parser.parse_args()`` with ``args = +* Replace ``(options, args) = parser.parse_args()`` with ``args = parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` - calls for the positional arguments. + calls for the positional arguments. Keep in mind that what was previously + called ``options``, now in :mod:`argparse` context is called ``args``. * Replace callback actions and the ``callback_*`` keyword arguments with ``type`` or ``action`` arguments. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 01:21:28 2012 From: python-checkins at python.org (victor.stinner) Date: Sat, 31 Mar 2012 01:21:28 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Add_fallback=3DTrue?= =?utf8?q?_argument_to_time=2Emonotonic=28=29?= Message-ID: http://hg.python.org/peps/rev/9e1dfb3d8c50 changeset: 4176:9e1dfb3d8c50 user: Victor Stinner date: Sat Mar 31 00:50:05 2012 +0200 summary: PEP 418: Add fallback=True argument to time.monotonic() * time.monotonic() doesn't use QPC anymore * Rewrite also time.monotonic() and time.highres() definitions. files: pep-0418.txt | 88 ++++++++++++++++++++++++--------------- 1 files changed, 53 insertions(+), 35 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -13,7 +13,7 @@ Abstract ======== -Add time.monotonic() and time.highres() functions to Python 3.3. +Add time.monotonic(fallback=True) and time.highres() functions to Python 3.3. Rationale @@ -24,12 +24,19 @@ * Display the current time to a human (e.g. display a calendar or draw a wall clock): use system clock. time.time() or datetime.datetime.now() * Benchmark, profiling, timeout: time.highres() - * Event scheduler: time.monotonic() + * Event scheduler: time.monotonic(), or time.monotonic(fallback=False) Functions ========= + * time.time(): system clock, "wall clock" + * time.highres(): clock with the best accuracy + * time.monotonic(fallback=True): monotonic clock. If no monotonic clock is + available, falls back to system clock by default, or raises an OSError if + *fallback* is False. time.monotonic(fallback=True) cannot go backward. + + time.time() ----------- @@ -68,12 +75,12 @@ return _time.time() -time.monotonic() ----------------- +time.monotonic(fallback=True) +----------------------------- -Clock advancing at a monotonic rate relative to real time. It cannot go -backward. Its rate may be adjusted by NTP. The reference point of the returned -value is undefined so only the difference of consecutive calls is valid. +Clock that cannot go backward, its rate is as steady as possible. Its rate may +be adjusted by NTP. The reference point of the returned value is undefined so +only the difference of consecutive calls is valid. It is not available on all platforms and may raise an OSError. It is not available on GNU/Hurd for example. @@ -85,34 +92,21 @@ if os.name == 'nt': # GetTickCount64() requires Windows Vista, Server 2008 or later if hasattr(time, '_GetTickCount64'): - _get_tick_count = _time.GetTickCount64 + def monotonic(fallback=True): + return _time.GetTickCount64() else: - def _get_tick_count(): + def monotonic(fallback=True): ticks = _time.GetTickCount() - if ticks < _get_tick_count.last: + if ticks < monotonic.last: # Integer overflow detected - _get_tick_count.delta += 2**32 - _get_tick_count.last = ticks - return ticks + _get_tick_count.delta - _get_tick_count.last = 0 - _get_tick_count.delta = 0 - - def monotonic(): - if monotonic.use_performance_counter: - try: - return _time.QueryPerformanceCounter() - except OSError: - # QueryPerformanceFrequency() may fail, if the installed - # hardware does not support a high-resolution performance - # counter for example - monotonic.use_performance_counter = False - # Fallback to GetTickCount/GetTickCount64 which has - # a lower resolution - return _get_tick_count() - monotonic.use_performance_counter = True + monotonic.delta += 2**32 + monotonic.last = ticks + return ticks + monotonic.delta + monotonic.last = 0 + monotonic.delta = 0 elif os.name == 'mac': - def monotonic(): + def monotonic(fallback=True): if monotonic.factor is None: factor = _time.mach_timebase_info() monotonic.factor = timebase[0] / timebase[1] @@ -120,31 +114,45 @@ monotonic.factor = None elif os.name.startswith('sunos'): - def monotonic(): + def monotonic(fallback=True): if monotonic.use_clock_highres: try: time.clock_gettime(time.CLOCK_HIGHRES) except OSError: monotonic.use_clock_highres = False - return time.gethrtime() + if monotonic.use_gethrtime: + try: + return time.gethrtime() + except OSError: + if not fallback: + raise + monotonic.use_gethrtime = False + return time.time() monotonic.use_clock_highres = (hasattr(time, 'clock_gettime') and hasattr(time, 'CLOCK_HIGHRES')) + monotonic.use_gethrtime = True elif hasattr(time, "clock_gettime"): - def monotonic(): + def monotonic(fallback=True): while monotonic.clocks: try: clk_id = monotonic.clocks[0] return time.clock_gettime(clk_id) except OSError: # CLOCK_MONOTONIC_RAW requires a Linux kernel >= 2.6.28 + if len(monotonic.clocks) == 1 and not fallback: + raise del monotonic.clocks[0] - return time.clock_gettime(time.CLOCK_MONOTONIC) + return time.time() monotonic.clocks = [] if hasattr(time, 'CLOCK_MONOTONIC_RAW'): monotonic.clocks.append(time.CLOCK_MONOTONIC_RAW) if hasattr(time, 'CLOCK_HIGHRES'): monotonic.clocks.append(time.CLOCK_HIGHRES) + monotonic.clocks.append(time.CLOCK_MONOTONIC) + +On Windows, QueryPerformanceCounter() is not used even if it has a better +resolution than GetTickCount(). It is not reliable and has too much issues. .. note:: @@ -157,20 +165,29 @@ time.highres() -------------- -High-resolution clock: use a monotonic clock if available, or fallback to the -system time. +Clock with the best available resolution. It is available on all platforms and cannot fail. Pseudo-code:: def highres(): + if monotonic.use_performance_counter: + try: + return _time.QueryPerformanceCounter() + except OSError: + # QueryPerformanceFrequency() may fail, if the installed + # hardware does not support a high-resolution performance + # counter for example + monotonic.use_performance_counter = False if highres.use_monotonic: + # Monotonic clock is preferred over system clock try: return time.monotonic() except OSError: highres.use_monotonic = False return time.time() + highres.use_performance_counter = (os.name == 'nt') highres.use_monotonic = hasattr(time, 'monotonic') -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 31 01:39:58 2012 From: python-checkins at python.org (victor.stinner) Date: Sat, 31 Mar 2012 01:39:58 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Fix_time=2Ehighres?= =?utf8?q?=28=29_pseudo_code?= Message-ID: http://hg.python.org/peps/rev/85b9c7f214d4 changeset: 4177:85b9c7f214d4 user: Victor Stinner date: Sat Mar 31 01:39:46 2012 +0200 summary: PEP 418: Fix time.highres() pseudo code files: pep-0418.txt | 38 ++++++++++---------------------------- 1 files changed, 10 insertions(+), 28 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -172,14 +172,14 @@ Pseudo-code:: def highres(): - if monotonic.use_performance_counter: + if highres.use_performance_counter: try: return _time.QueryPerformanceCounter() except OSError: # QueryPerformanceFrequency() may fail, if the installed # hardware does not support a high-resolution performance # counter for example - monotonic.use_performance_counter = False + highres.use_performance_counter = False if highres.use_monotonic: # Monotonic clock is preferred over system clock try: @@ -194,13 +194,8 @@ Clocks ====== -Monotonic ---------- - -Summary -^^^^^^^ - -Table summarizing all monotonic clocks: +Monotonic clocks +---------------- ========================= =============== =============== ================ ==================== Name Resolution Accuracy Adjusted by NTP? Action on suspend @@ -215,11 +210,8 @@ timeGetTime() 1 ms 1 ms - 15 ms No ? ========================= =============== =============== ================ ==================== -(*) The accurary of monotonic clocks depends on the operating system. - - * Linux: ? - * FreeBSD: ? - * Solaris: ? +(*) The accurary of monotonic clocks depends on the operating system and the +hardware clock. The resolution is the smallest difference between two timestamps supported by the format used by the clock. For example, clock_gettime() uses a timespec @@ -420,16 +412,8 @@ On Solaris, gethrtime() is the same as clock_gettime(CLOCK_MONOTONIC). -System time ------------ - -The system time can be set manually by the system administrator or -automatically by a NTP daemon. - -Summary -^^^^^^^ - -Table summarizing all system time clocks: +System time clocks +------------------ ========================= =============== =============== Name Resolution Accuracy @@ -441,12 +425,8 @@ time() 1 sec 1 sec ========================= =============== =============== -(*) The accurary of system clocks depends on the operating system. - - * Windows: 1 ms - 15 ms - * Linux: ? - * Mac OS X: ? - * FreeBSD: ? +(*) The accurary of system clocks depends on the operating system and the +hardware clock. On Windows, the accuracy is in the range 1 ms - 15 ms. Windows: GetSystemTimeAsFileTime -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 31 02:00:50 2012 From: python-checkins at python.org (victor.stinner) Date: Sat, 31 Mar 2012 02:00:50 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_Cleanup_after_reint?= =?utf8?q?roduction_of_fallback=3DTrue?= Message-ID: http://hg.python.org/peps/rev/011c7b9559b7 changeset: 4178:011c7b9559b7 user: Victor Stinner date: Sat Mar 31 02:00:43 2012 +0200 summary: PEP 418: Cleanup after reintroduction of fallback=True files: pep-0418.txt | 34 ++++++++++++++++------------------ 1 files changed, 16 insertions(+), 18 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -82,10 +82,14 @@ be adjusted by NTP. The reference point of the returned value is undefined so only the difference of consecutive calls is valid. -It is not available on all platforms and may raise an OSError. It is not -available on GNU/Hurd for example. +By default, it falls back to the system clock if no monotonic clock is +available or if the monotonic clock failed, and so it cannot fail. If fallback +is False, it raises OSError if the monotonic clock failed and +NotImplementedError if the platform does not provide a monotonic clock (ex: +GNU/Hurd). -The monotonic clock may stop while the system is suspended. +The elapsed time may or may not include time the system spends in sleep or +hibernation, it depends on the operating system. Pseudo-code [#pseudo]_: :: @@ -151,6 +155,12 @@ monotonic.clocks.append(time.CLOCK_HIGHRES) monotonic.clocks.append(time.CLOCK_MONOTONIC) + else: + def monotonic(fallback=True): + if not fallback: + raise NotImplementedError("you platform does not provide any monotonic clock") + return time.time() + On Windows, QueryPerformanceCounter() is not used even if it has a better resolution than GetTickCount(). It is not reliable and has too much issues. @@ -204,7 +214,7 @@ gethrtime 1 ns (*) No Not stopped CLOCK_HIGHRES 1 ns (*) No ? CLOCK_MONOTONIC 1 ns (*) Yes on Linux Stopped on Linux -mach_absolute_time() 1 ns ? No ? +mach_absolute_time() 1 ns (*) No ? QueryPerformanceCounter() \- 0.3 ns - 5 ns No Accuracy issue GetTickCount[64]() 1 ms 1 ms - 15 ms No Include suspend time timeGetTime() 1 ms 1 ms - 15 ms No ? @@ -564,8 +574,8 @@ Alternatives: API design ======================== -time.highres() function name ----------------------------- +Name of the "monotonic or fallback" function name +------------------------------------------------- Other names were proposed: @@ -578,20 +588,6 @@ chances with a best-effect clock." * time.wallclock() -One function with a flag: time.monotonic(strict=False) ------------------------------------------------------- - - * time.monotonic(strict=False) falls back to the system clock if no monotonic - clock is available or if the monotonic clock failed. - * time.monotonic(strict=True) raises OSError if monotonic clock fails and - NotImplementedError if the system does not provide a monotonic clock - -"A keyword argument that gets passed as a constant in the caller is usually -poor API." - -Raising NotImplementedError for a function is something uncommon in Python and -should be avoided. - One function, no flag --------------------- -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 31 04:15:43 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 31 Mar 2012 04:15:43 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_No_need_to_create_and_destr?= =?utf8?q?oy_links_when_updating_a_fixed-sized_circular_queue=2E?= Message-ID: http://hg.python.org/cpython/rev/476f641a0455 changeset: 76002:476f641a0455 parent: 76000:7ad1728691b2 user: Raymond Hettinger date: Fri Mar 30 19:15:18 2012 -0700 summary: No need to create and destroy links when updating a fixed-sized circular queue. files: Lib/functools.py | 27 ++++++++++++++++----------- 1 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -219,7 +219,7 @@ def wrapper(*args, **kwds): # size limited caching that tracks accesses by recency - nonlocal hits, misses + nonlocal root, hits, misses key = make_key(args, kwds, typed) if kwds or typed else args with lock: link = cache_get(key) @@ -236,16 +236,21 @@ return result result = user_function(*args, **kwds) with lock: - # put result in a new link at the front of the list - last = root[PREV] - link = [last, root, key, result] - cache[key] = last[NEXT] = root[PREV] = link - if _len(cache) > maxsize: - # purge the least recently used cache entry - old_prev, old_next, old_key, old_result = root[NEXT] - root[NEXT] = old_next - old_next[PREV] = root - del cache[old_key] + if _len(cache) < maxsize: + # put result in a new link at the front of the list + last = root[PREV] + link = [last, root, key, result] + cache[key] = last[NEXT] = root[PREV] = link + else: + # use root to store the new key and result + root[KEY] = key + root[RESULT] = result + cache[key] = root + # empty the oldest link and make it the new root + root = root[NEXT] + del cache[root[KEY]] + root[KEY] = None + root[RESULT] = None misses += 1 return result -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Mar 31 05:38:55 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 31 Mar 2012 05:38:55 +0200 Subject: [Python-checkins] Daily reference leaks (7ad1728691b2): sum=-6 Message-ID: results for 7ad1728691b2 on branch "default" -------------------------------------------- test_xml_etree_c leaked [-2, -2, -2] references, sum=-6 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogNkcEOA', '-x'] From python-checkins at python.org Sat Mar 31 06:51:10 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 31 Mar 2012 06:51:10 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix-up_comments_and_add_a_s?= =?utf8?q?entinel_variable_for_clarity=2E?= Message-ID: http://hg.python.org/cpython/rev/387dcd8d7dec changeset: 76003:387dcd8d7dec user: Raymond Hettinger date: Fri Mar 30 21:50:40 2012 -0700 summary: Fix-up comments and add a sentinel variable for clarity. files: Lib/functools.py | 33 +++++++++++++++++---------------- 1 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -154,8 +154,8 @@ Arguments to the cached function must be hashable. - View the cache statistics named tuple (hits, misses, maxsize, currsize) with - f.cache_info(). Clear the cache and statistics with f.cache_clear(). + View the cache statistics named tuple (hits, misses, maxsize, currsize) + with f.cache_info(). Clear the cache and statistics with f.cache_clear(). Access the underlying function with f.__wrapped__. See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used @@ -169,18 +169,19 @@ def decorating_function(user_function): - cache = dict() + cache = {} hits = misses = 0 - kwd_mark = (object(),) # separate positional and keyword args - cache_get = cache.get # bound method to lookup key or return None - _len = len # localize the global len() function - lock = Lock() # because linkedlist updates aren't threadsafe - root = [] # root of the circular doubly linked list - root[:] = [root, root, None, None] # initialize by pointing to self - PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields + kwd_mark = (object(),) # separate positional and keyword args + cache_get = cache.get # bound method to lookup key or return None + sentinel = object() # unique object used with cache_get + _len = len # localize the global len() function + lock = Lock() # because linkedlist updates aren't threadsafe + root = [] # root of the circular doubly linked list + root[:] = [root, root, None, None] # initialize by pointing to self + PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields def make_key(args, kwds, typed, tuple=tuple, sorted=sorted, type=type): - # helper function to build a cache key from positional and keyword args + # build a cache key from positional and keyword args key = args if kwds: sorted_items = tuple(sorted(kwds.items())) @@ -194,7 +195,7 @@ if maxsize == 0: def wrapper(*args, **kwds): - # no caching, just do a statistics update after a successful call + # no caching, just a statistics update after a successful call nonlocal misses result = user_function(*args, **kwds) misses += 1 @@ -206,8 +207,8 @@ # simple caching without ordering or size limit nonlocal hits, misses key = make_key(args, kwds, typed) if kwds or typed else args - result = cache_get(key, root) # root used here as a unique not-found sentinel - if result is not root: + result = cache_get(key, sentinel) + if result is not sentinel: hits += 1 return result result = user_function(*args, **kwds) @@ -224,7 +225,7 @@ with lock: link = cache_get(key) if link is not None: - # record recent use of the key by moving it to the front of the list + # move the link to the front of the circular queue link_prev, link_next, key, result = link link_prev[NEXT] = link_next link_next[PREV] = link_prev @@ -237,7 +238,7 @@ result = user_function(*args, **kwds) with lock: if _len(cache) < maxsize: - # put result in a new link at the front of the list + # put result in a new link at the front of the queue last = root[PREV] link = [last, root, key, result] cache[key] = last[NEXT] = root[PREV] = link -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 08:38:32 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2012 08:38:32 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_Edit_PEP_418=3A_add_missing_co?= =?utf8?q?pyright_and_file_variable_footer=2C_fix_line_length?= Message-ID: http://hg.python.org/peps/rev/c13ca10a1904 changeset: 4179:c13ca10a1904 user: Georg Brandl date: Sat Mar 31 08:38:41 2012 +0200 summary: Edit PEP 418: add missing copyright and file variable footer, fix line length and indentation of bullet lists, fix grammar and spelling files: pep-0418.txt | 610 +++++++++++++++++++++----------------- 1 files changed, 330 insertions(+), 280 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -13,7 +13,8 @@ Abstract ======== -Add time.monotonic(fallback=True) and time.highres() functions to Python 3.3. +Add time.monotonic(fallback=True) and time.highres() functions to +Python 3.3. Rationale @@ -21,32 +22,34 @@ Use cases: - * Display the current time to a human (e.g. display a calendar or draw a wall - clock): use system clock. time.time() or datetime.datetime.now() - * Benchmark, profiling, timeout: time.highres() - * Event scheduler: time.monotonic(), or time.monotonic(fallback=False) +* Display the current time to a human (e.g. display a calendar or draw + a wall clock): use system clock. time.time() or + datetime.datetime.now() +* Benchmark, profiling, timeout: time.highres() +* Event scheduler: time.monotonic(), or time.monotonic(fallback=False) Functions ========= - * time.time(): system clock, "wall clock" - * time.highres(): clock with the best accuracy - * time.monotonic(fallback=True): monotonic clock. If no monotonic clock is - available, falls back to system clock by default, or raises an OSError if - *fallback* is False. time.monotonic(fallback=True) cannot go backward. +* time.time(): system clock, "wall clock" +* time.highres(): clock with the best accuracy +* time.monotonic(fallback=True): monotonic clock. If no monotonic + clock is available, falls back to system clock by default, or raises + an OSError if *fallback* is False. time.monotonic(fallback=True) + cannot go backward. time.time() ----------- -The system time is the "wall clock". It can be set manually by the system -administrator or automatically by a NTP daemon. It can jump backward and -forward. It is not monotonic. +The system time is the "wall clock". It can be set manually by the +system administrator or automatically by a NTP daemon. It can jump +backward and forward. It is not monotonic. It is available on all platforms and cannot fail. -Pseudo-code [#pseudo]_: :: +Pseudo-code [#pseudo]_:: if os.name == "nt": def time(): @@ -78,20 +81,21 @@ time.monotonic(fallback=True) ----------------------------- -Clock that cannot go backward, its rate is as steady as possible. Its rate may -be adjusted by NTP. The reference point of the returned value is undefined so -only the difference of consecutive calls is valid. +Clock that cannot go backward, its rate is as steady as possible. Its +rate may be adjusted by NTP. The reference point of the returned +value is undefined so only the difference of consecutive calls is +valid. By default, it falls back to the system clock if no monotonic clock is -available or if the monotonic clock failed, and so it cannot fail. If fallback -is False, it raises OSError if the monotonic clock failed and -NotImplementedError if the platform does not provide a monotonic clock (ex: -GNU/Hurd). +available or if the monotonic clock failed, and so it cannot fail. If +fallback is False, it raises OSError if the monotonic clock failed and +NotImplementedError if the platform does not provide a monotonic clock +(ex: GNU/Hurd). -The elapsed time may or may not include time the system spends in sleep or -hibernation, it depends on the operating system. +The elapsed time may or may not include time the system spends in +sleep or hibernation, it depends on the operating system. -Pseudo-code [#pseudo]_: :: +Pseudo-code [#pseudo]_:: if os.name == 'nt': # GetTickCount64() requires Windows Vista, Server 2008 or later @@ -161,15 +165,17 @@ raise NotImplementedError("you platform does not provide any monotonic clock") return time.time() -On Windows, QueryPerformanceCounter() is not used even if it has a better -resolution than GetTickCount(). It is not reliable and has too much issues. +On Windows, QueryPerformanceCounter() is not used even if it has a +better resolution than GetTickCount(). It is not reliable and has too +much issues. .. note:: - time.monotonic() detects GetTickCount() integer overflow (32 bits, roll-over - after 49.7 days): it increases a delta by 2\ :sup:`32` each time than an - overflow is detected. The delta is stored in the process local state and so - time.monotonic() value may be different in two Python processes. + time.monotonic() detects GetTickCount() integer overflow (32 bits, + roll-over after 49.7 days): it increases a delta by 2\ :sup:`32` + each time than an overflow is detected. The delta is stored in the + process local state and so time.monotonic() value may be different + in two Python processes. time.highres() @@ -220,35 +226,35 @@ timeGetTime() 1 ms 1 ms - 15 ms No ? ========================= =============== =============== ================ ==================== -(*) The accurary of monotonic clocks depends on the operating system and the -hardware clock. +(*) The accuracy of monotonic clocks depends on the operating system +and the hardware clock. -The resolution is the smallest difference between two timestamps supported by -the format used by the clock. For example, clock_gettime() uses a timespec -structure which has two integer fileds, tv_sec and tv_nsec, so the resolution -is 1 nanosecond. +The resolution is the smallest difference between two timestamps +supported by the format used by the clock. For example, +clock_gettime() uses a timespec structure which has two integer +fields, tv_sec and tv_nsec, so the resolution is 1 nanosecond. -The accuracy is the effective smallest difference of two timestamps of the -clock. It does not reflect the stability the clock rate. For example, -QueryPerformanceCounter() has a good accuracy but is known to not have a steady -rate. +The accuracy is the effective smallest difference of two timestamps of +the clock. It does not reflect the stability the clock rate. For +example, QueryPerformanceCounter() has a good accuracy but is known to +not have a steady rate. mach_absolute_time ^^^^^^^^^^^^^^^^^^ -Mac OS X provides a monotonic clock: mach_absolute_time(). It is based on -absolute elapsed time delta since system boot. It is not adjusted and cannot be -set. +Mac OS X provides a monotonic clock: mach_absolute_time(). It is +based on absolute elapsed time delta since system boot. It is not +adjusted and cannot be set. -mach_timebase_info() gives a fraction to convert the clock value to a number of -nanoseconds. According to the documentation (`Technical Q&A QA1398 -`_), mach_timebase_info() -is always equals to one and does never fail, even if the function may fail -according to its prototype. +mach_timebase_info() gives a fraction to convert the clock value to a +number of nanoseconds. According to the documentation (`Technical Q&A +QA1398 `_), +mach_timebase_info() is always equals to one and does never fail, even +if the function may fail according to its prototype. -mach_absolute_time() stops during a sleep on PowerPC CPU, but not on Intel CPU: -`Different behaviour of mach_absolute_time() on i386 / ppc +mach_absolute_time() stops during a sleep on PowerPC CPU, but not on +Intel CPU: `Different behaviour of mach_absolute_time() on i386 / ppc `_. mach_absolute_time() has a resolution of 1 nanosecond. @@ -256,95 +262,104 @@ CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represents monotonic time since some -unspecified starting point. They cannot be set. +CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represents monotonic time +since some unspecified starting point. They cannot be set. -Documentation: refer to the manual page of your operating system. Examples: +Documentation: refer to the manual page of your operating system. +Examples: - * `FreeBSD clock_gettime() manual page - `_ - * `Linux clock_gettime() manual page - `_ +* `FreeBSD clock_gettime() manual page + `_ +* `Linux clock_gettime() manual page + `_ CLOCK_MONOTONIC is available at least on the following operating systems: - * DragonFly BSD, FreeBSD >= 5.0, OpenBSD, NetBSD - * Linux - * Solaris +* DragonFly BSD, FreeBSD >= 5.0, OpenBSD, NetBSD +* Linux +* Solaris The following operating systems don't support CLOCK_MONOTONIC: +* GNU/Hurd (see `open issues/ clock_gettime + `_) +* Mac OS X +* Windows - * GNU/Hurd (see `open issues/ clock_gettime `_) - * Mac OS X - * Windows +CLOCK_MONOTONIC_RAW is specific to Linux. It is similar to +CLOCK_MONOTONIC, but provides access to a raw hardware-based time that +is not subject to NTP adjustments. CLOCK_MONOTONIC_RAW requires Linux +2.6.28 or later. -CLOCK_MONOTONIC_RAW is specific to Linux. It is similar to CLOCK_MONOTONIC, but -provides access to a raw hardware-based time that is not subject to NTP -adjustments. CLOCK_MONOTONIC_RAW requires Linux 2.6.28 or later. - -On Linux, NTP may adjust CLOCK_MONOTONIC rate, but not jump backward. If -available, CLOCK_MONOTONIC_RAW should be used instead of CLOCK_MONOTONIC to -avoid the NTP adjustement. +On Linux, NTP may adjust CLOCK_MONOTONIC rate, but not jump backward. +If available, CLOCK_MONOTONIC_RAW should be used instead of +CLOCK_MONOTONIC to avoid the NTP adjustment. CLOCK_MONOTONIC stops while the machine is suspended. -clock_gettime() fails if the system does not support the specified clock, -whereas the standard C library supports it. For example, CLOCK_MONOTONIC_RAW -requires a kernel version 2.6.28 or later. +clock_gettime() fails if the system does not support the specified +clock, whereas the standard C library supports it. For example, +CLOCK_MONOTONIC_RAW requires a kernel version 2.6.28 or later. -clock_getres() gives the clock resolution. It is 1 nanosecond on Linux. +clock_getres() gives the clock resolution. It is 1 nanosecond on +Linux. .. note:: - clock_gettime() requires to link the program to the rt (real-time) library. + clock_gettime() requires to link the program to the rt (real-time) + library. + Windows: QueryPerformanceCounter ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -High-resolution performance counter. It is monotonic. +High-resolution performance counter. It is monotonic. QueryPerformanceFrequency() gives its frequency. It has much higher resolution, but has lower long term accuracy than -GetTickCount() and timeGetTime() clocks. For example, it will drift compared to -the low precision clocks. +GetTickCount() and timeGetTime() clocks. For example, it will drift +compared to the low precision clocks. Documentation: - * `MSDN: QueryPerformanceCounter() documentation - `_ - * `MSDN: QueryPerformanceFrequency() documentation - `_ +* `MSDN: QueryPerformanceCounter() documentation + `_ +* `MSDN: QueryPerformanceFrequency() documentation + `_ Hardware clocks used by QueryPerformanceCounter: - * Windows XP: RDTSC instruction of Intel processors, the clock frequency is - the frequency of the processor (between 200 MHz and 3 GHz, usually greater - than 1 GHz nowadays) - * Windows 2000: ACPI power management timer, frequency = 3,549,545 Hz. It can - be forced through the "/usepmtimer" flag in boot.ini - * Windows 95/98: 8245 PIT chipset, frequency = 1,193,181 Hz +* Windows XP: RDTSC instruction of Intel processors, the clock + frequency is the frequency of the processor (between 200 MHz and 3 + GHz, usually greater than 1 GHz nowadays) +* Windows 2000: ACPI power management timer, frequency = 3,549,545 + Hz. It can be forced through the "/usepmtimer" flag in boot.ini -QueryPerformanceFrequency() should only be called once: the frequency will not -change while the system is running. It fails if the installed hardware does not -support a high-resolution performance counter. +.. * Windows 95/98: 8245 PIT chipset, frequency = 1,193,181 Hz -QueryPerformanceCounter() cannot be adjusted: `SetSystemTimeAdjustment() +QueryPerformanceFrequency() should only be called once: the frequency +will not change while the system is running. It fails if the +installed hardware does not support a high-resolution performance +counter. + +QueryPerformanceCounter() cannot be adjusted: +`SetSystemTimeAdjustment() `_ does only adjust the system time. Bugs: - * The performance counter value may unexpectedly leap forward because of a - hardware bug, see the `KB274323`_. - * On VirtualBox, QueryPerformanceCounter() does not increment the high part - every time the low part overflows, see `Monotonic timers - `_ (2009). - * VirtualBox had a bug in its HPET virtualized device: - QueryPerformanceCounter() did jump forward by approx. 42 seconds (`issue - #8707 `_). - * Windows XP had a bug (see `KB896256`_): on a multiprocessor computer, - QueryPerformanceCounter() returned a different value for each processor. - The bug was fixed in Windows XP SP2. +* The performance counter value may unexpectedly leap forward because + of a hardware bug, see the `KB274323`_. +* On VirtualBox, QueryPerformanceCounter() does not increment the high + part every time the low part overflows, see `Monotonic timers + `_ + (2009). +* VirtualBox had a bug in its HPET virtualized device: + QueryPerformanceCounter() did jump forward by approx. 42 seconds (`issue + #8707 `_). +* Windows XP had a bug (see `KB896256`_): on a multiprocessor + computer, QueryPerformanceCounter() returned a different value for + each processor. The bug was fixed in Windows XP SP2. .. _KB896256: http://support.microsoft.com/?id=896256 .. _KB274323: http://support.microsoft.com/?id=274323 @@ -353,18 +368,20 @@ Windows: GetTickCount(), GetTickCount64() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -GetTickCount() and GetTickCount64() are monotonic, cannot fail and are not -adjusted by SetSystemTimeAdjustment(). MSDN documentation: -`GetTickCount() `_, -`GetTickCount64() `_. +GetTickCount() and GetTickCount64() are monotonic, cannot fail and are +not adjusted by SetSystemTimeAdjustment(). MSDN documentation: +`GetTickCount() +`_, +`GetTickCount64() +`_. -The elapsed time retrieved by GetTickCount or GetTickCount64 includes time the -system spends in sleep or hibernation. +The elapsed time retrieved by GetTickCount or GetTickCount64 includes +time the system spends in sleep or hibernation. GetTickCount64() was added to Windows Vista and Windows Server 2008. -The clock resolution is 1 millisecond. Its accuracy is usually around 15 ms. It -is possible to improve the accuracy using the `undocumented +The clock resolution is 1 millisecond. Its accuracy is usually around +15 ms. It is possible to improve the accuracy using the `undocumented NtSetTimerResolution() function `_. There are applications using this undocumented function, example: @@ -374,47 +391,50 @@ Windows: timeGetTime ^^^^^^^^^^^^^^^^^^^^ -The timeGetTime function retrieves the system time, in milliseconds. The system -time is the time elapsed since Windows was started. Read the `timeGetTime() -documentation +The timeGetTime function retrieves the system time, in milliseconds. +The system time is the time elapsed since Windows was started. Read +the `timeGetTime() documentation `_. -The return type of timeGetTime() is a 32-bit unsigned integer. As -GetTickCount(), timeGetTime() rolls over after 2^32 milliseconds (49.7 days). +The return type of timeGetTime() is a 32-bit unsigned integer. As +GetTickCount(), timeGetTime() rolls over after 2^32 milliseconds (49.7 +days). -The default precision of the timeGetTime function can be five milliseconds or -more, depending on the machine. +The default precision of the timeGetTime function can be five +milliseconds or more, depending on the machine. -timeBeginPeriod() can be used to increase the precision of timeGetTime() up to -1 millisecond, but it negatively affects power consumption. +timeBeginPeriod() can be used to increase the precision of +timeGetTime() up to 1 millisecond, but it negatively affects power +consumption. .. note:: - timeGetTime() and timeBeginPeriod() are part the Windows multimedia library - and so require to link the program with winmm or to load dynamically the - library. + timeGetTime() and timeBeginPeriod() are part the Windows multimedia + library and so require to link the program with winmm or to load + dynamically the library. Solaris: CLOCK_HIGHRES ^^^^^^^^^^^^^^^^^^^^^^ -The Solaris OS has an CLOCK_HIGHRES timer that attempts to use an optimal -hardware source, and may give close to nanosecond resolution. CLOCK_HIGHRES is -the nonadjustable, high-resolution clock. For timers created with a clockid_t -value of CLOCK_HIGHRES, the system will attempt to use an optimal hardware -source. +The Solaris OS has an CLOCK_HIGHRES timer that attempts to use an +optimal hardware source, and may give close to nanosecond resolution. +CLOCK_HIGHRES is the nonadjustable, high-resolution clock. For timers +created with a clockid_t value of CLOCK_HIGHRES, the system will +attempt to use an optimal hardware source. Solaris: gethrtime ^^^^^^^^^^^^^^^^^^ -The gethrtime() function returns the current high-resolution real time. Time is -expressed as nanoseconds since some arbitrary time in the past; it is not -correlated in any way to the time of day, and thus is not subject to -resetting or drifting by way of adjtime() or settimeofday(). The hires timer -is ideally suited to performance measurement tasks, where cheap, accurate -interval timing is required. +The gethrtime() function returns the current high-resolution real +time. Time is expressed as nanoseconds since some arbitrary time in +the past; it is not correlated in any way to the time of day, and thus +is not subject to resetting or drifting by way of adjtime() or +settimeofday(). The hires timer is ideally suited to performance +measurement tasks, where cheap, accurate interval timing is required. -The linearity of gethrtime() is not preserved accross cpr suspend-resume cycle -(`Bug 4272663 `_). +The linearity of gethrtime() is not preserved accross cpr +suspend-resume cycle (`Bug 4272663 +`_). Read the `gethrtime() manual page of Solaris 11 `_. @@ -435,80 +455,87 @@ time() 1 sec 1 sec ========================= =============== =============== -(*) The accurary of system clocks depends on the operating system and the -hardware clock. On Windows, the accuracy is in the range 1 ms - 15 ms. +(*) The accuracy of system clocks depends on the operating system and +the hardware clock. On Windows, the accuracy is in the range 1 ms - +15 ms. Windows: GetSystemTimeAsFileTime ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The system time can be read using GetSystemTimeAsFileTime(), ftime() and -time(). +The system time can be read using GetSystemTimeAsFileTime(), ftime() +and time(). -The system time resolution can be read using GetSystemTimeAdjustment(). The -accurary is usually between 1 millisecond and 15 milliseconds. Resolution: +The system time resolution can be read using +GetSystemTimeAdjustment(). The accuracy is usually between 1 +millisecond and 15 milliseconds. Resolution: - * GetSystemTimeAsFileTime(): 100 nanoseconds - * ftime(): 1 millisecond - * time(): 1 second +* GetSystemTimeAsFileTime(): 100 nanoseconds +* ftime(): 1 millisecond +* time(): 1 second The system time can be set using SetSystemTime(). System time on UNIX ^^^^^^^^^^^^^^^^^^^ -gettimeofday(), ftime(), time() and clock_gettime(CLOCK_REALTIME) return the -system clock. +gettimeofday(), ftime(), time() and clock_gettime(CLOCK_REALTIME) +return the system clock. Resolution: - * clock_gettime(): clock_getres(CLOCK_REALTIME), 1 nanosecond on Linux - * gettimeofday(): 1 microsecond - * ftime(): 1 millisecond - * time(): 1 second +* clock_gettime(): clock_getres(CLOCK_REALTIME), 1 nanosecond on Linux +* gettimeofday(): 1 microsecond +* ftime(): 1 millisecond +* time(): 1 second -The system time can be set using settimeofday() or clock_settime(CLOCK_REALTIME). +The system time can be set using settimeofday() or +clock_settime(CLOCK_REALTIME). Process and thread time ----------------------- -The process and thread time cannot be set. They are not monotonic: the clocks -stop while the process/thread is idle. +The process and thread time cannot be set. They are not monotonic: +the clocks stop while the process/thread is idle. Process ^^^^^^^ - * Windows: GetProcessTimes() - * clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process timer - from the CPU. - * clock(): +* Windows: GetProcessTimes() +* clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process + timer from the CPU. +* clock(): - * Windows: The elapsed wall-clock time since the start of the process - (elapsed time in seconds times CLOCKS_PER_SEC). It can fail. - * UNIX: returns an approximation of processor time used by the program. + * Windows: The elapsed wall-clock time since the start of the + process (elapsed time in seconds times CLOCKS_PER_SEC). It can + fail. + * UNIX: returns an approximation of processor time used by the + program. - * times() - * getrusage(): ru_utime and ru_stime fields +* times() +* getrusage(): ru_utime and ru_stime fields Resolution: - * clock() rate is CLOCKS_PER_SEC. It was called CLK_TCK in Microsoft C before - 6.0. On Linux 3, clock() has a resolution of 1 microsecond - * The clock resolution can be read using clock_getres(). - clock_getres(CLOCK_REALTIME) is 1 nanosecond on Linux - * GetProcessTimes(): call GetSystemTimeAdjustment() +* clock() rate is CLOCKS_PER_SEC. It was called CLK_TCK in Microsoft + C before 6.0. On Linux 3, clock() has a resolution of 1 microsecond +* The clock resolution can be read using clock_getres(). + clock_getres(CLOCK_REALTIME) is 1 nanosecond on Linux +* GetProcessTimes(): call GetSystemTimeAdjustment() Thread ^^^^^^ - * Windows: GetThreadTimes() - * clock_gettime(CLOCK_THREAD_CPUTIME_ID): Thread-specific CPU-time clock. +* Windows: GetThreadTimes() +* clock_gettime(CLOCK_THREAD_CPUTIME_ID): Thread-specific CPU-time + clock. Resolution: - * CLOCK_THREAD_CPUTIME_ID: call clock_getres(). 1 nanosecond on Linux. - * GetThreadTimes(): call GetSystemTimeAdjustment() +* CLOCK_THREAD_CPUTIME_ID: call clock_getres(). 1 nanosecond on + Linux. +* GetThreadTimes(): call GetSystemTimeAdjustment() See also pthread_getcpuclockid(). @@ -516,12 +543,12 @@ Windows: QueryUnbiasedInterruptTime ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Gets the current unbiased interrupt time from the biased interrupt time and the -current sleep bias amount. This time is not affected by power management sleep -transitions. +Gets the current unbiased interrupt time from the biased interrupt +time and the current sleep bias amount. This time is not affected by +power management sleep transitions. -The elapsed time retrieved by the QueryUnbiasedInterruptTime function includes -only time that the system spends in the working state. +The elapsed time retrieved by the QueryUnbiasedInterruptTime function +includes only time that the system spends in the working state. QueryUnbiasedInterruptTime() is not monotonic. QueryUnbiasedInterruptTime() was introduced in Windows 7. @@ -529,41 +556,43 @@ Linux timers ------------ -There were 4 implementations of the time in the Linux kernel: UTIME (1996), -timer wheel (1997), HRT (2001) and hrtimers (2007). The later is the result of -the "high-res-timers" project started by George Anzinger in 2001, contributed -by Thomas Gleixner and Douglas Niehaus. hrtimers implementation was merged into -Linux 2.6.21 released in 2007. +There were 4 implementations of the time in the Linux kernel: UTIME +(1996), timer wheel (1997), HRT (2001) and hrtimers (2007). The later +is the result of the "high-res-timers" project started by George +Anzinger in 2001, contributed by Thomas Gleixner and Douglas Niehaus. +hrtimers implementation was merged into Linux 2.6.21 released in 2007. -hrtimers supports various clock sources. It sets a priority to each source to -decide which one will be used. +hrtimers supports various clock sources. It sets a priority to each +source to decide which one will be used. - * TSC (Time Stamp Counter): Internal processor clock incremented at each - processor cycle. Its frequency is the processor frequency and so usually - higher than 1 GHz. Its priority is 300 by default, but falls to 0 if the - processor frequency changes and the counter becomes unstable. - * HPET: An HPET chip consists of a 64-bit up-counter (main counter) counting - at least at 10 MHz and a set of up to 256 comparators (at least 3). Each - HPET can have up to 32 timers. - * PIT (programmable interrupt timer): Intel 8253/8254 chipsets with a - configurable frequecency in range 18.2 Hz - 1.2 MHz. Linux uses the - frequency: 1,193,181.8 Hz. It is a 16-bit counter. - * PMTMR (power management timer): ACPI 24-bit timer with a frequency of 3.5 - MHz (3,579,545 Hz). Its priority is 200 by default, but changes to 110 if - the chipset is broken and need a software workaround. HPET can cause around - 3 seconds of drift per day. - * Cyclone: The Cyclone timer uses a 32-bit counter on IBM Extended - X-Architecture (EXA) chipsets which include computers that use the IBM - "Summit" series chipsets (ex: x440). This is available in IA32 and IA64 - architectures. +* TSC (Time Stamp Counter): Internal processor clock incremented at + each processor cycle. Its frequency is the processor frequency and + so usually higher than 1 GHz. Its priority is 300 by default, but + falls to 0 if the processor frequency changes and the counter + becomes unstable. +* HPET: An HPET chip consists of a 64-bit up-counter (main counter) + counting at least at 10 MHz and a set of up to 256 comparators (at + least 3). Each HPET can have up to 32 timers. +* PIT (programmable interrupt timer): Intel 8253/8254 chipsets with a + configurable frequency in range 18.2 Hz - 1.2 MHz. Linux uses the + frequency 1,193,181.8 Hz. It is a 16-bit counter. +* PMTMR (power management timer): ACPI 24-bit timer with a frequency + of 3.5 MHz (3,579,545 Hz). Its priority is 200 by default, but + changes to 110 if the chipset is broken and need a software + workaround. HPET can cause around 3 seconds of drift per day. +* Cyclone: The Cyclone timer uses a 32-bit counter on IBM Extended + X-Architecture (EXA) chipsets which include computers that use the + IBM "Summit" series chipsets (ex: x440). This is available in IA32 + and IA64 architectures. -High-resolution timers are not supported on all hardware architectures. They -are at least provided on x86/x86_64, ARM and PowerPC. +High-resolution timers are not supported on all hardware +architectures. They are at least provided on x86/x86_64, ARM and +PowerPC. The list of available clock sources can be read in -/sys/devices/system/clocksource/clocksource0/available_clocksource. It is -possible to force a clocksource at runtime by writing its name into -/sys/devices/system/clocksource/clocksource0/current_clocksource. +/sys/devices/system/clocksource/clocksource0/available_clocksource. +It is possible to force a clocksource at runtime by writing its name +into /sys/devices/system/clocksource/clocksource0/current_clocksource. /proc/timer_list contains the list of all hardware timers. Read also the `time(7) manual page @@ -579,14 +608,14 @@ Other names were proposed: - * time.hires(): "hires" can be read as "to hire" as in "he hires a car to go - on holiday", rather than a "HIgh-RESolution clock". - * time.steady(): no OS provides a clock advancing at a steady rate, so - "steady" should be avoided. - * time.try_monotonic(): it is a clear and obvious solution for the use-case of - "I prefer the monotonic clock, if it is available, otherwise I'll take my - chances with a best-effect clock." - * time.wallclock() +* time.hires(): "hires" can be read as "to hire" as in "he hires a car + to go on holiday", rather than a "HIgh-RESolution clock". +* time.steady(): no OS provides a clock advancing at a steady rate, so + "steady" should be avoided. +* time.try_monotonic(): it is a clear and obvious solution for the + use-case of "I prefer the monotonic clock, if it is available, + otherwise I'll take my chances with a best-effect clock." +* time.wallclock() One function, no flag @@ -594,33 +623,36 @@ time.monotonic() returns (time: float, is_monotonic: bool). -An alternative is to use a function attribute: time.monotonic.is_monotonic. The -attribute value would be None before the first call to time.monotonic(). +An alternative is to use a function attribute: +time.monotonic.is_monotonic. The attribute value would be None before +the first call to time.monotonic(). Working around operating system bugs? ===================================== -Should Python ensure manually that a monotonic clock is truly monotonic by -computing the maximum with the clock value and the previous value? +Should Python ensure manually that a monotonic clock is truly +monotonic by computing the maximum with the clock value and the +previous value? -Since it's relatively straightforward to cache the last value returned using a -static variable, it might be interesting to use this to make sure that the -values returned are indeed monotonic. +Since it's relatively straightforward to cache the last value returned +using a static variable, it might be interesting to use this to make +sure that the values returned are indeed monotonic. - * Virtual machines provide less reliable clocks. - * QueryPerformanceCounter() has known bugs (only one is not fixed yet) +* Virtual machines provide less reliable clocks. +* QueryPerformanceCounter() has known bugs (only one is not fixed yet) -Python may only workaround a specific known operating system bug: `KB274323`_ -contains a code example to workaround the bug (use GetTickCount() to detect -QueryPerformanceCounter() leap). +Python may only workaround a specific known operating system bug: +`KB274323`_ contains a code example to workaround the bug (use +GetTickCount() to detect QueryPerformanceCounter() leap). Footnotes ========= .. [#pseudo] "_time" is an hypothetical module only used for the example. - The time module is implemented in C and so there is no need for such module. + The time module is implemented in C and so there is no need for + such module. Links @@ -628,61 +660,79 @@ Related Python issues: - * `Issue #12822: NewGIL should use CLOCK_MONOTONIC if possible. - `_ - * `Issue #14222: Use time.steady() to implement timeout - `_ - * `Issue #14397: Use GetTickCount/GetTickCount64 instead of QueryPerformanceCounter for monotonic clock - `_ - * `Issue #14428: Implementation of the PEP 418 - `_ +* `Issue #12822: NewGIL should use CLOCK_MONOTONIC if possible. + `_ +* `Issue #14222: Use time.steady() to implement timeout + `_ +* `Issue #14397: Use GetTickCount/GetTickCount64 instead of + QueryPerformanceCounter for monotonic clock + `_ +* `Issue #14428: Implementation of the PEP 418 + `_ -Librairies exposing monotonic clocks: +Libraries exposing monotonic clocks: - * `Java: System.nanoTime - `_ - * `Qt library: QElapsedTimer - `_ - * `glib library: g_get_monotonic_time () - `_ - uses GetTickCount64()/GetTickCount() on Windows, - clock_gettime(CLOCK_MONOTONIC) on UNIX or falls back to the system clock - * `python-monotonic-time - `_ - (`github `_) - * `monotonic_clock - `_ - * `Perl: Time::HiRes - `_ exposes - clock_gettime(CLOCK_MONOTONIC) - * `Ruby: AbsoluteTime.now - `_: use - clock_gettime(CLOCK_MONOTONIC), mach_absolute_time() or gettimeofday(). - "AbsoluteTime.monotonic?" method indicates if AbsoluteTime.now is monotonic - or not. +* `Java: System.nanoTime + `_ +* `Qt library: QElapsedTimer + `_ +* `glib library: g_get_monotonic_time () + `_ + uses GetTickCount64()/GetTickCount() on Windows, + clock_gettime(CLOCK_MONOTONIC) on UNIX or falls back to the system + clock +* `python-monotonic-time + `_ (`github + `_) +* `monotonic_clock `_ +* `Perl: Time::HiRes `_ + exposes clock_gettime(CLOCK_MONOTONIC) +* `Ruby: AbsoluteTime.now + `_: use + clock_gettime(CLOCK_MONOTONIC), mach_absolute_time() or + gettimeofday(). "AbsoluteTime.monotonic?" method indicates if + AbsoluteTime.now is monotonic or not. Time: - * `hrtimers - subsystem for high-resolution kernel timers - `_ - * `C++ Timeout Specification - `_ - * `Windows: Game Timing and Multicore Processors - `_ - * `Implement a Continuously Updating, High-Resolution Time Provider for Windows - `_ - * `clockspeed `_ uses a hardware tick counter - to compensate for a persistently fast or slow system clock - * `Retrieving system time - `_ - lists hardware clocks and time functions with their resolution - and epoch or range - * On Windows, the JavaScript runtime of Firefox interpolates - GetSystemTimeAsFileTime() with QueryPerformanceCounter() to get - an higher resolution. See the `Bug 363258 - bad millisecond resolution for - (new Date).getTime() / Date.now() on Windows - `_. - * `When microseconds matter - `_: How the IBM High - Resolution Time Stamp Facility accurately measures itty bits of time +* `hrtimers - subsystem for high-resolution kernel timers + `_ +* `C++ Timeout Specification + `_ +* `Windows: Game Timing and Multicore Processors + `_ +* `Implement a Continuously Updating, High-Resolution Time Provider + for Windows + `_ +* `clockspeed `_ uses a hardware tick + counter to compensate for a persistently fast or slow system clock +* `Retrieving system time + `_ + lists hardware clocks and time functions with their resolution and + epoch or range +* On Windows, the JavaScript runtime of Firefox interpolates + GetSystemTimeAsFileTime() with QueryPerformanceCounter() to get an + higher resolution. See the `Bug 363258 - bad millisecond resolution + for (new Date).getTime() / Date.now() on Windows + `_. +* `When microseconds matter + `_: How the + IBM High Resolution Time Stamp Facility accurately measures itty + bits of time + +Copyright +========= + +This document has been placed in the public domain. + + + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 31 08:52:59 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2012 08:52:59 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_418=3A_more_grammar_fixes?= Message-ID: http://hg.python.org/peps/rev/39c8c00a854d changeset: 4180:39c8c00a854d user: Georg Brandl date: Sat Mar 31 08:53:07 2012 +0200 summary: PEP 418: more grammar fixes files: pep-0418.txt | 101 ++++++++++++++++++++------------------ 1 files changed, 54 insertions(+), 47 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -23,20 +23,22 @@ Use cases: * Display the current time to a human (e.g. display a calendar or draw - a wall clock): use system clock. time.time() or - datetime.datetime.now() -* Benchmark, profiling, timeout: time.highres() -* Event scheduler: time.monotonic(), or time.monotonic(fallback=False) + a wall clock): use system clock, i.e. time.time() or + datetime.datetime.now(). +* Benchmark, profiling, timeout: time.highres(). +* Event scheduler: time.monotonic(), or time.monotonic(fallback=False). Functions ========= -* time.time(): system clock, "wall clock" -* time.highres(): clock with the best accuracy +To fulfill the use cases, the functions' properties are: + +* time.time(): system clock, "wall clock". +* time.highres(): clock with the best accuracy. * time.monotonic(fallback=True): monotonic clock. If no monotonic clock is available, falls back to system clock by default, or raises - an OSError if *fallback* is False. time.monotonic(fallback=True) + an OSError if *fallback* is False. time.monotonic(fallback=True) cannot go backward. @@ -45,7 +47,7 @@ The system time is the "wall clock". It can be set manually by the system administrator or automatically by a NTP daemon. It can jump -backward and forward. It is not monotonic. +backward and forward. It is not monotonic. It is available on all platforms and cannot fail. @@ -90,10 +92,10 @@ available or if the monotonic clock failed, and so it cannot fail. If fallback is False, it raises OSError if the monotonic clock failed and NotImplementedError if the platform does not provide a monotonic clock -(ex: GNU/Hurd). +(e.g. on GNU/Hurd). The elapsed time may or may not include time the system spends in -sleep or hibernation, it depends on the operating system. +sleep or hibernation; this depends on the operating system. Pseudo-code [#pseudo]_:: @@ -165,17 +167,17 @@ raise NotImplementedError("you platform does not provide any monotonic clock") return time.time() -On Windows, QueryPerformanceCounter() is not used even if it has a +On Windows, QueryPerformanceCounter() is not used even though it has a better resolution than GetTickCount(). It is not reliable and has too -much issues. +many issues. .. note:: time.monotonic() detects GetTickCount() integer overflow (32 bits, roll-over after 49.7 days): it increases a delta by 2\ :sup:`32` each time than an overflow is detected. The delta is stored in the - process local state and so time.monotonic() value may be different - in two Python processes. + process-local state and so the value of time.monotonic() may be + different in two Python processes. time.highres() @@ -250,11 +252,11 @@ mach_timebase_info() gives a fraction to convert the clock value to a number of nanoseconds. According to the documentation (`Technical Q&A QA1398 `_), -mach_timebase_info() is always equals to one and does never fail, even +mach_timebase_info() is always equal to one and never fails, even if the function may fail according to its prototype. -mach_absolute_time() stops during a sleep on PowerPC CPU, but not on -Intel CPU: `Different behaviour of mach_absolute_time() on i386 / ppc +mach_absolute_time() stops during a sleep on a PowerPC CPU, but not on +an Intel CPU: `Different behaviour of mach_absolute_time() on i386/ppc `_. mach_absolute_time() has a resolution of 1 nanosecond. @@ -262,8 +264,8 @@ CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represents monotonic time -since some unspecified starting point. They cannot be set. +CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represent monotonic time since +some unspecified starting point. They cannot be set. Documentation: refer to the manual page of your operating system. Examples: @@ -291,22 +293,23 @@ is not subject to NTP adjustments. CLOCK_MONOTONIC_RAW requires Linux 2.6.28 or later. -On Linux, NTP may adjust CLOCK_MONOTONIC rate, but not jump backward. -If available, CLOCK_MONOTONIC_RAW should be used instead of +On Linux, NTP may adjust the CLOCK_MONOTONIC rate, but it cannot jump +backward. If available, CLOCK_MONOTONIC_RAW should be used instead of CLOCK_MONOTONIC to avoid the NTP adjustment. CLOCK_MONOTONIC stops while the machine is suspended. clock_gettime() fails if the system does not support the specified -clock, whereas the standard C library supports it. For example, +clock, even if the standard C library supports it. For example, CLOCK_MONOTONIC_RAW requires a kernel version 2.6.28 or later. clock_getres() gives the clock resolution. It is 1 nanosecond on Linux. .. note:: - clock_gettime() requires to link the program to the rt (real-time) - library. + + clock_gettime() requires to link the program against the rt + (real-time) library. Windows: QueryPerformanceCounter @@ -315,7 +318,7 @@ High-resolution performance counter. It is monotonic. QueryPerformanceFrequency() gives its frequency. -It has much higher resolution, but has lower long term accuracy than +It has a much higher resolution, but has lower long term accuracy than GetTickCount() and timeGetTime() clocks. For example, it will drift compared to the low precision clocks. @@ -330,9 +333,9 @@ * Windows XP: RDTSC instruction of Intel processors, the clock frequency is the frequency of the processor (between 200 MHz and 3 - GHz, usually greater than 1 GHz nowadays) -* Windows 2000: ACPI power management timer, frequency = 3,549,545 - Hz. It can be forced through the "/usepmtimer" flag in boot.ini + GHz, usually greater than 1 GHz nowadays). +* Windows 2000: ACPI power management timer, frequency = 3,549,545 Hz. + It can be forced through the "/usepmtimer" flag in boot.ini. .. * Windows 95/98: 8245 PIT chipset, frequency = 1,193,181 Hz @@ -344,12 +347,12 @@ QueryPerformanceCounter() cannot be adjusted: `SetSystemTimeAdjustment() `_ -does only adjust the system time. +only adjusts the system time. Bugs: * The performance counter value may unexpectedly leap forward because - of a hardware bug, see the `KB274323`_. + of a hardware bug, see `KB274323`_. * On VirtualBox, QueryPerformanceCounter() does not increment the high part every time the low part overflows, see `Monotonic timers `_ @@ -375,13 +378,13 @@ `GetTickCount64() `_. -The elapsed time retrieved by GetTickCount or GetTickCount64 includes -time the system spends in sleep or hibernation. +The elapsed time retrieved by GetTickCount() or GetTickCount64() +includes time the system spends in sleep or hibernation. GetTickCount64() was added to Windows Vista and Windows Server 2008. The clock resolution is 1 millisecond. Its accuracy is usually around -15 ms. It is possible to improve the accuracy using the `undocumented +15 ms. It is possible to improve the accuracy using the `undocumented NtSetTimerResolution() function `_. There are applications using this undocumented function, example: @@ -392,7 +395,7 @@ ^^^^^^^^^^^^^^^^^^^^ The timeGetTime function retrieves the system time, in milliseconds. -The system time is the time elapsed since Windows was started. Read +The system time is the time elapsed since Windows was started. Read the `timeGetTime() documentation `_. @@ -408,15 +411,16 @@ consumption. .. note:: + timeGetTime() and timeBeginPeriod() are part the Windows multimedia - library and so require to link the program with winmm or to load - dynamically the library. + library and so require to link the program against winmm or to + dynamically load the library. Solaris: CLOCK_HIGHRES ^^^^^^^^^^^^^^^^^^^^^^ -The Solaris OS has an CLOCK_HIGHRES timer that attempts to use an +The Solaris OS has a CLOCK_HIGHRES timer that attempts to use an optimal hardware source, and may give close to nanosecond resolution. CLOCK_HIGHRES is the nonadjustable, high-resolution clock. For timers created with a clockid_t value of CLOCK_HIGHRES, the system will @@ -468,7 +472,7 @@ The system time resolution can be read using GetSystemTimeAdjustment(). The accuracy is usually between 1 -millisecond and 15 milliseconds. Resolution: +millisecond and 15 milliseconds. Resolution: * GetSystemTimeAsFileTime(): 100 nanoseconds * ftime(): 1 millisecond @@ -508,7 +512,7 @@ * clock(): * Windows: The elapsed wall-clock time since the start of the - process (elapsed time in seconds times CLOCKS_PER_SEC). It can + process (elapsed time in seconds times CLOCKS_PER_SEC). It can fail. * UNIX: returns an approximation of processor time used by the program. @@ -519,10 +523,11 @@ Resolution: * clock() rate is CLOCKS_PER_SEC. It was called CLK_TCK in Microsoft - C before 6.0. On Linux 3, clock() has a resolution of 1 microsecond + C before 6.0. On Linux 3, clock() has a resolution of 1 + microsecond. * The clock resolution can be read using clock_getres(). - clock_getres(CLOCK_REALTIME) is 1 nanosecond on Linux -* GetProcessTimes(): call GetSystemTimeAdjustment() + clock_getres(CLOCK_REALTIME) is 1 nanosecond on Linux. +* GetProcessTimes(): call GetSystemTimeAdjustment(). Thread ^^^^^^ @@ -553,14 +558,16 @@ QueryUnbiasedInterruptTime() was introduced in Windows 7. + Linux timers ------------ There were 4 implementations of the time in the Linux kernel: UTIME -(1996), timer wheel (1997), HRT (2001) and hrtimers (2007). The later -is the result of the "high-res-timers" project started by George -Anzinger in 2001, contributed by Thomas Gleixner and Douglas Niehaus. -hrtimers implementation was merged into Linux 2.6.21 released in 2007. +(1996), timer wheel (1997), HRT (2001) and hrtimers (2007). The +latter is the result of the "high-res-timers" project started by +George Anzinger in 2001, with contributions by Thomas Gleixner and +Douglas Niehaus. hrtimers implementation was merged into Linux +2.6.21, released in 2007. hrtimers supports various clock sources. It sets a priority to each source to decide which one will be used. @@ -642,7 +649,7 @@ * Virtual machines provide less reliable clocks. * QueryPerformanceCounter() has known bugs (only one is not fixed yet) -Python may only workaround a specific known operating system bug: +Python may only work around a specific known operating system bug: `KB274323`_ contains a code example to workaround the bug (use GetTickCount() to detect QueryPerformanceCounter() leap). -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 31 11:19:42 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 31 Mar 2012 11:19:42 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix-up_a_comment?= Message-ID: http://hg.python.org/cpython/rev/1c22c1109824 changeset: 76004:1c22c1109824 user: Raymond Hettinger date: Sat Mar 31 02:19:06 2012 -0700 summary: Fix-up a comment files: Lib/functools.py | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -172,7 +172,7 @@ cache = {} hits = misses = 0 kwd_mark = (object(),) # separate positional and keyword args - cache_get = cache.get # bound method to lookup key or return None + cache_get = cache.get # bound method to lookup a key or return None sentinel = object() # unique object used with cache_get _len = len # localize the global len() function lock = Lock() # because linkedlist updates aren't threadsafe @@ -250,8 +250,7 @@ # empty the oldest link and make it the new root root = root[NEXT] del cache[root[KEY]] - root[KEY] = None - root[RESULT] = None + root[KEY] = root[RESULT] = None misses += 1 return result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 12:57:01 2012 From: python-checkins at python.org (eli.bendersky) Date: Sat, 31 Mar 2012 12:57:01 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_the_tests_of_GC_collect?= =?utf8?q?ion_in_ET=2EElement_according_to_Benjamin=27s?= Message-ID: http://hg.python.org/cpython/rev/5b3a44f22470 changeset: 76005:5b3a44f22470 user: Eli Bendersky date: Sat Mar 31 13:55:38 2012 +0300 summary: Fix the tests of GC collection in ET.Element according to Benjamin's recommendations files: Lib/test/test_xml_etree.py | 40 ++++++++++++------------- 1 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -14,14 +14,14 @@ # Don't re-import "xml.etree.ElementTree" module in the docstring, # except if the test is specific to the Python implementation. -import gc import html import io import sys import unittest +import weakref from test import support -from test.support import findfile, import_fresh_module +from test.support import findfile, import_fresh_module, gc_collect pyET = import_fresh_module('xml.etree.ElementTree', blocked=['_elementtree']) @@ -1848,28 +1848,26 @@ self.assertRaises(TypeError, e.insert, 0, 'foo') def test_cyclic_gc(self): - class ShowGC: - def __init__(self, flaglist): - self.flaglist = flaglist - def __del__(self): - self.flaglist.append(1) + class Dummy: + pass - # Test the shortest cycle: lst->element->lst - fl = [] - lst = [ShowGC(fl)] - lst.append(ET.Element('joe', attr=lst)) - del lst - gc.collect() - self.assertEqual(fl, [1]) + # Test the shortest cycle: d->element->d + d = Dummy() + d.dummyref = ET.Element('joe', attr=d) + wref = weakref.ref(d) + del d + gc_collect() + self.assertIsNone(wref()) - # A longer cycle: lst->e->e2->lst - fl = [] + # A longer cycle: d->e->e2->d e = ET.Element('joe') - lst = [ShowGC(fl), e] - e2 = ET.SubElement(e, 'foo', attr=lst) - del lst, e, e2 - gc.collect() - self.assertEqual(fl, [1]) + d = Dummy() + d.dummyref = e + wref = weakref.ref(d) + e2 = ET.SubElement(e, 'foo', attr=d) + del d, e, e2 + gc_collect() + self.assertIsNone(wref()) class ElementTreeTest(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 13:20:26 2012 From: python-checkins at python.org (andrew.svetlov) Date: Sat, 31 Mar 2012 13:20:26 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_update_NEWS_as_?= =?utf8?q?Terry_Reedy_proposed?= Message-ID: http://hg.python.org/cpython/rev/ba32b8c7f5be changeset: 76006:ba32b8c7f5be branch: 3.2 parent: 75999:dee1597b3ce3 user: Andrew Svetlov date: Sat Mar 31 14:10:10 2012 +0300 summary: update NEWS as Terry Reedy proposed files: Lib/idlelib/NEWS.txt | 6 ++++-- Misc/NEWS | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,8 +1,10 @@ What's New in IDLE 3.2.3? ========================= -- Issue #14409: IDLE doesn't not execute commands from shell, - error with default keybinding for Return. (Patch by Roger Serwy) +- Issue #14409: IDLE now properly executes commands in the Shell window + when it cannot read the normal config files on startup and + has to use the built-in default key bindings. + There was previously a bug in one of the defaults. - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,8 +31,10 @@ Library ------- -- Issue #14409: IDLE doesn't not execute commands from shell, - error with default keybinding for Return. (Patch by Roger Serwy) +- Issue #14409: IDLE now properly executes commands in the Shell window + when it cannot read the normal config files on startup and + has to use the built-in default key bindings. + There was previously a bug in one of the defaults. - Issue #10340: asyncore - properly handle EINVAL in dispatcher constructor on OSX; avoid to call handle_connect in case of a disconnected socket which -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 13:20:27 2012 From: python-checkins at python.org (andrew.svetlov) Date: Sat, 31 Mar 2012 13:20:27 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_from_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/ec99fd5b5e60 changeset: 76007:ec99fd5b5e60 parent: 76005:5b3a44f22470 parent: 76006:ba32b8c7f5be user: Andrew Svetlov date: Sat Mar 31 14:20:19 2012 +0300 summary: Merge from 3.2 files: Lib/idlelib/NEWS.txt | 6 ++++-- Misc/NEWS | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -3,8 +3,10 @@ - IDLE can be launched as `python -m idlelib` -- Issue #14409: IDLE doesn't not execute commands from shell, - error with default keybinding for Return. (Patch by Roger Serwy) +- Issue #14409: IDLE now properly executes commands in the Shell window + when it cannot read the normal config files on startup and + has to use the built-in default key bindings. + There was previously a bug in one of the defaults. - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,8 +34,10 @@ Library ------- -- Issue #14409: IDLE doesn't not execute commands from shell, - error with default keybinding for Return. (Patch by Roger Serwy) +- Issue #14409: IDLE now properly executes commands in the Shell window + when it cannot read the normal config files on startup and + has to use the built-in default key bindings. + There was previously a bug in one of the defaults. - Issue #14416: syslog now defines the LOG_ODELAY and LOG_AUTHPRIV constants if they are defined in . -- Repository URL: http://hg.python.org/cpython From andrew.svetlov at gmail.com Sat Mar 31 13:21:14 2012 From: andrew.svetlov at gmail.com (Andrew Svetlov) Date: Sat, 31 Mar 2012 14:21:14 +0300 Subject: [Python-checkins] cpython (3.2): Issue #14409: IDLE doesn't not execute commands from shell with default In-Reply-To: References: Message-ID: Updated NEWS as Terry Reedy recommended. Thank you, Terry. On Sat, Mar 31, 2012 at 12:59 AM, Terry Reedy wrote: > On 3/30/2012 2:31 PM, Andrew Svetlov wrote: >> >> Thank you for mentoring. >> >> I will fix NEWS if you help me with better text. > > > I believe a succint message would be > > Issue 14409: IDLE now properly executes commands in the Shell window when it > cannot read the normal config files on startup and has to use the built-in > default key bindings. There was previously a bug in one of the defaults. > > >> The bug fixed is that commit is: >> IDLE has 3 configs: user, system default and hardcoded in python code. >> Last one had bad binding for ?key. >> Usually this config is never used: user or system ones overrides former. >> But if IDLE cannot open config files by some reason it switches to >> hardcoded configs and user got broken IDLE. >> >> Can anybody guess me short and descriptive message describing what fix >> well? >> >> On Fri, Mar 30, 2012 at 6:12 AM, Nick Coghlan ?wrote: >>> >>> On Fri, Mar 30, 2012 at 2:01 AM, andrew.svetlov >>> ?wrote: >>>> >>>> +- Issue #14409: IDLE doesn't not execute commands from shell, >>>> + ?error with default keybinding for Return. (Patch by Roger Serwy) >>> >>> >>> The double negative here makes this impossible to understand. Could we >>> please get an updated NEWS entry that explains what actually changed >>> in IDLE to fix this? >>> >>> Perhaps something like "IDLE now always sets the default keybind for >>> Return correctly, ensuring commands can be executed in the IDLE shell >>> window"? (assuming that's what happened). >>> >>> This is important, folks: NEWS entries need to be comprehensible for >>> people that *haven't* read the associated tracker issue. This means >>> that issue titles (which generally describe a problem someone was >>> having) are often inappropriate as NEWS items. NEWS items should be >>> short descriptions that clearly describe *what changed*, perhaps with >>> some additional information to explain a bit about why the change was >>> made. > > > -- > Terry Jan Reedy > > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins -- Thanks, Andrew Svetlov From python-checkins at python.org Sat Mar 31 13:34:58 2012 From: python-checkins at python.org (andrew.svetlov) Date: Sat, 31 Mar 2012 13:34:58 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_update_NEWS_for?= =?utf8?q?_2=2E7_as_Terry_Reedy_proposed?= Message-ID: http://hg.python.org/cpython/rev/7c61fe5b4640 changeset: 76008:7c61fe5b4640 branch: 2.7 parent: 76001:cb5214e6c287 user: Andrew Svetlov date: Sat Mar 31 14:34:16 2012 +0300 summary: update NEWS for 2.7 as Terry Reedy proposed files: Lib/idlelib/NEWS.txt | 6 ++++-- Misc/NEWS | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,8 +1,10 @@ What's New in IDLE 2.7.3? ======================= -- Issue #14409: IDLE doesn't not execute commands from shell, - error with default keybinding for Return. (Patch by Roger Serwy) +- Issue #14409: IDLE now properly executes commands in the Shell window + when it cannot read the normal config files on startup and + has to use the built-in default key bindings. + There was previously a bug in one of the defaults. - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,8 +35,10 @@ Library ------- -- Issue #14409: IDLE doesn't not execute commands from shell, - error with default keybinding for Return. (Patch by Roger Serwy) +- Issue #14409: IDLE now properly executes commands in the Shell window + when it cannot read the normal config files on startup and + has to use the built-in default key bindings. + There was previously a bug in one of the defaults. - Issue #10340: asyncore - properly handle EINVAL in dispatcher constructor on OSX; avoid to call handle_connect in case of a disconnected socket which -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 13:57:26 2012 From: python-checkins at python.org (andrew.svetlov) Date: Sat, 31 Mar 2012 13:57:26 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_issue_=233035=3A_update_Pen?= =?utf8?q?dingDeprecationWarning_to_DeprectionWarning=2C_point?= Message-ID: http://hg.python.org/cpython/rev/2bc374182ed4 changeset: 76009:2bc374182ed4 parent: 76007:ec99fd5b5e60 user: Andrew Svetlov date: Sat Mar 31 14:55:55 2012 +0300 summary: issue #3035: update PendingDeprecationWarning to DeprectionWarning, point deprecation in tkinter doc files: Doc/library/tkinter.rst | 21 +++++++++++++++------ Lib/tkinter/__init__.py | 20 ++++++++++---------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -735,22 +735,32 @@ displayed. You can use these :mod:`tkinter` functions to access these special points in text widgets: - AtEnd() +.. function:: AtEnd() refers to the last position in the text - AtInsert() + .. deprecated:: 3.3 + +.. function:: AtInsert() refers to the point where the text cursor is - AtSelFirst() + .. deprecated:: 3.3 + +.. function:: AtSelFirst() indicates the beginning point of the selected text - AtSelLast() + .. deprecated:: 3.3 + +.. function:: AtSelLast() denotes the last point of the selected text and finally - At(x[, y]) + .. deprecated:: 3.3 + +.. function:: At(x[, y]) refers to the character at pixel location *x*, *y* (with *y* not used in the case of a text entry widget, which contains a single line of text). + .. deprecated:: 3.3 + Text widget indexes The index notation for Text widgets is very rich and is best described in the Tk man pages. @@ -798,4 +808,3 @@ reference to the image. When the last Python reference to the image object is deleted, the image data is deleted as well, and Tk will display an empty box wherever the image was used. - diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2126,14 +2126,14 @@ # Indices: # XXX I don't like these -- take them away def AtEnd(): - warnings.warn("tkinter.AtEnd will be removed in 3.5", - PendingDeprecationWarning, stacklevel=2) + warnings.warn("tkinter.AtEnd will be removed in 3.4", + DeprecationWarning, stacklevel=2) return 'end' def AtInsert(*args): - warnings.warn("tkinter.AtInsert will be removed in 3.5", - PendingDeprecationWarning, stacklevel=2) + warnings.warn("tkinter.AtInsert will be removed in 3.4", + DeprecationWarning, stacklevel=2) s = 'insert' for a in args: if a: s = s + (' ' + a) @@ -2141,20 +2141,20 @@ def AtSelFirst(): - warnings.warn("tkinter.AtSelFirst will be removed in 3.5", - PendingDeprecationWarning, stacklevel=2) + warnings.warn("tkinter.AtSelFirst will be removed in 3.4", + DeprecationWarning, stacklevel=2) return 'sel.first' def AtSelLast(): - warnings.warn("tkinter.AtSelLast will be removed in 3.5", - PendingDeprecationWarning, stacklevel=2) + warnings.warn("tkinter.AtSelLast will be removed in 3.4", + DeprecationWarning, stacklevel=2) return 'sel.last' def At(x, y=None): - warnings.warn("tkinter.At will be removed in 3.5", - PendingDeprecationWarning, stacklevel=2) + warnings.warn("tkinter.At will be removed in 3.4", + DeprecationWarning, stacklevel=2) if y is None: return '@%r' % (x,) else: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 15:10:19 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Sat, 31 Mar 2012 15:10:19 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Issue_=2314435=3A_Add_Misc/?= =?utf8?q?NEWS_and_Misc/ACKS?= Message-ID: http://hg.python.org/cpython/rev/10fcaf5903e6 changeset: 76010:10fcaf5903e6 user: Kristj?n Valur J?nsson date: Sat Mar 31 13:08:11 2012 +0000 summary: Issue #14435: Add Misc/NEWS and Misc/ACKS files: Misc/ACKS | 1 + Misc/NEWS | 3 +++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -507,6 +507,7 @@ Richard Jones Irmen de Jong Lucas de Jonge +Kristj?n Valur J?nsson Jens B. Jorgensen John Jorgensen Sijin Joseph diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,9 @@ - Issue #14220: When a generator is delegating to another iterator with the yield from syntax, it needs to have its ``gi_running`` flag set to True. +- Issue #14435: Remove dedicated block allocator from floatobject.c and rely + on the PyObject_Malloc() api like all other objects. + Library ------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 15:35:32 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Sat, 31 Mar 2012 15:35:32 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_warning_when_compiling_?= =?utf8?q?socketmodule=2Ec_with_VS2010?= Message-ID: http://hg.python.org/cpython/rev/e46013f92013 changeset: 76011:e46013f92013 user: Kristj?n Valur J?nsson date: Sat Mar 31 13:35:00 2012 +0000 summary: Fix warning when compiling socketmodule.c with VS2010 VS2010 defineds the old errno constants in addition to the WSA* ones. files: Modules/socketmodule.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -390,6 +390,7 @@ #endif #ifdef MS_WIN32 +#undef EAFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #define snprintf _snprintf #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 17:46:37 2012 From: python-checkins at python.org (sandro.tosi) Date: Sat, 31 Mar 2012 17:46:37 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogYWRkICdzYWZhcmkn?= =?utf8?q?_to_webbrowser_browsers_table=3B_thanks_to_Jonathan_Eunice_from_?= =?utf8?q?docs=40?= Message-ID: http://hg.python.org/cpython/rev/9411b7268cf5 changeset: 76012:9411b7268cf5 branch: 2.7 parent: 76008:7c61fe5b4640 user: Sandro Tosi date: Sat Mar 31 17:22:47 2012 +0200 summary: add 'safari' to webbrowser browsers table; thanks to Jonathan Eunice from docs@ files: Doc/library/webbrowser.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst --- a/Doc/library/webbrowser.rst +++ b/Doc/library/webbrowser.rst @@ -142,6 +142,8 @@ +-----------------------+-----------------------------------------+-------+ | ``'macosx'`` | :class:`MacOSX('default')` | \(4) | +-----------------------+-----------------------------------------+-------+ +| ``'safari'`` | :class:`MacOSX('safari')` | \(4) | ++-----------------------+-----------------------------------------+-------+ Notes: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 17:46:37 2012 From: python-checkins at python.org (sandro.tosi) Date: Sat, 31 Mar 2012 17:46:37 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogYWRkICdzYWZhcmkn?= =?utf8?q?_to_webbrowser_browsers_table=3B_thanks_to_Jonathan_Eunice_from_?= =?utf8?q?docs=40?= Message-ID: http://hg.python.org/cpython/rev/722ce1be9eeb changeset: 76013:722ce1be9eeb branch: 3.2 parent: 76006:ba32b8c7f5be user: Sandro Tosi date: Sat Mar 31 17:23:10 2012 +0200 summary: add 'safari' to webbrowser browsers table; thanks to Jonathan Eunice from docs@ files: Doc/library/webbrowser.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst --- a/Doc/library/webbrowser.rst +++ b/Doc/library/webbrowser.rst @@ -137,6 +137,8 @@ +-----------------------+-----------------------------------------+-------+ | ``'macosx'`` | :class:`MacOSX('default')` | \(4) | +-----------------------+-----------------------------------------+-------+ +| ``'safari'`` | :class:`MacOSX('safari')` | \(4) | ++-----------------------+-----------------------------------------+-------+ Notes: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 17:46:38 2012 From: python-checkins at python.org (sandro.tosi) Date: Sat, 31 Mar 2012 17:46:38 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/a51764ed57a2 changeset: 76014:a51764ed57a2 parent: 76011:e46013f92013 parent: 76013:722ce1be9eeb user: Sandro Tosi date: Sat Mar 31 17:44:33 2012 +0200 summary: merge with 3.2 files: Doc/library/webbrowser.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst --- a/Doc/library/webbrowser.rst +++ b/Doc/library/webbrowser.rst @@ -137,6 +137,8 @@ +------------------------+-----------------------------------------+-------+ | ``'macosx'`` | :class:`MacOSX('default')` | \(4) | +------------------------+-----------------------------------------+-------+ +| ``'safari'`` | :class:`MacOSX('safari')` | \(4) | ++------------------------+-----------------------------------------+-------+ | ``'google-chrome'`` | :class:`Chrome('google-chrome')` | | +------------------------+-----------------------------------------+-------+ | ``'chrome'`` | :class:`Chrome('chrome')` | | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 18:11:16 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 31 Mar 2012 18:11:16 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogIzE0NDM0OiBtYWtl?= =?utf8?q?_tutorial_link_in_=27help=27_banner_version-specific?= Message-ID: http://hg.python.org/cpython/rev/d478c0a68bcb changeset: 76015:d478c0a68bcb branch: 3.2 parent: 76013:722ce1be9eeb user: R David Murray date: Sat Mar 31 12:06:35 2012 -0400 summary: #14434: make tutorial link in 'help' banner version-specific Without this fix, both 2.7 and 3.x would always point to the "current" docs...which means that before this fix python 3.2 'help' pointed to the 2.7 tutorial. files: Lib/pydoc.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1829,7 +1829,7 @@ Welcome to Python %s! This is the online help utility. If this is your first time using Python, you should definitely check out -the tutorial on the Internet at http://docs.python.org/tutorial/. +the tutorial on the Internet at http://docs.python.org/%s/tutorial/. Enter the name of any module, keyword, or topic to get help on writing Python programs and using Python modules. To quit this help utility and @@ -1839,7 +1839,7 @@ "keywords", or "topics". Each module also comes with a one-line summary of what it does; to list the modules whose summaries contain a given word such as "spam", type "modules spam". -''' % sys.version[:3]) +''' % tuple([sys.version[:3]]*2)) def list(self, items, columns=4, width=80): items = list(sorted(items)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 18:11:18 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 31 Mar 2012 18:11:18 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_=2314434=3A_make_tutorial_link_in_=27help=27_banner_ve?= =?utf8?q?rsion-specific?= Message-ID: http://hg.python.org/cpython/rev/ee9b6574b497 changeset: 76016:ee9b6574b497 parent: 76014:a51764ed57a2 parent: 76015:d478c0a68bcb user: R David Murray date: Sat Mar 31 12:08:59 2012 -0400 summary: Merge #14434: make tutorial link in 'help' banner version-specific Without this fix, both 2.7 and 3.x would always point to the "current" docs...which means that before this fix python 3.2 'help' pointed to the 2.7 tutorial. files: Lib/pydoc.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1826,7 +1826,7 @@ Welcome to Python %s! This is the online help utility. If this is your first time using Python, you should definitely check out -the tutorial on the Internet at http://docs.python.org/tutorial/. +the tutorial on the Internet at http://docs.python.org/%s/tutorial/. Enter the name of any module, keyword, or topic to get help on writing Python programs and using Python modules. To quit this help utility and @@ -1836,7 +1836,7 @@ "keywords", or "topics". Each module also comes with a one-line summary of what it does; to list the modules whose summaries contain a given word such as "spam", type "modules spam". -''' % sys.version[:3]) +''' % tuple([sys.version[:3]]*2)) def list(self, items, columns=4, width=80): items = list(sorted(items)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 18:11:19 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 31 Mar 2012 18:11:19 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogIzE0NDM0OiBtYWtl?= =?utf8?q?_tutorial_link_in_=27help=27_banner_version-specific?= Message-ID: http://hg.python.org/cpython/rev/b3a7b27953e0 changeset: 76017:b3a7b27953e0 branch: 2.7 parent: 76012:9411b7268cf5 user: R David Murray date: Sat Mar 31 12:10:48 2012 -0400 summary: #14434: make tutorial link in 'help' banner version-specific Without this fix, both 2.7 and 3.x would always point to the "current" docs...which means that before this fix python 3.2 'help' pointed to the 2.7 tutorial, and without this fix when we switch over to the 3.x docs being current, 2.7 would have pointed to the python3 tutorial. files: Lib/pydoc.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1799,7 +1799,7 @@ Welcome to Python %s! This is the online help utility. If this is your first time using Python, you should definitely check out -the tutorial on the Internet at http://docs.python.org/tutorial/. +the tutorial on the Internet at http://docs.python.org/%s/tutorial/. Enter the name of any module, keyword, or topic to get help on writing Python programs and using Python modules. To quit this help utility and @@ -1809,7 +1809,7 @@ "keywords", or "topics". Each module also comes with a one-line summary of what it does; to list the modules whose summaries contain a given word such as "spam", type "modules spam". -''' % sys.version[:3]) +''' % tuple([sys.version[:3]]*2)) def list(self, items, columns=4, width=80): items = items[:] -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Sat Mar 31 18:26:12 2012 From: ncoghlan at gmail.com (Nick Coghlan) Date: Sun, 1 Apr 2012 02:26:12 +1000 Subject: [Python-checkins] cpython (3.2): Issue #14409: IDLE doesn't not execute commands from shell with default In-Reply-To: References: Message-ID: On Sat, Mar 31, 2012 at 9:21 PM, Andrew Svetlov wrote: > Updated NEWS as Terry Reedy recommended. > Thank you, Terry. Thanks to you both :) Cheers, Nick. -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From python-checkins at python.org Sat Mar 31 18:37:14 2012 From: python-checkins at python.org (andrew.svetlov) Date: Sat, 31 Mar 2012 18:37:14 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_issue_=235136=3A_deprec?= =?utf8?q?ate_old_unused_functions_from_tkinter=2E?= Message-ID: http://hg.python.org/cpython/rev/6023d73c6f87 changeset: 76018:6023d73c6f87 parent: 76016:ee9b6574b497 user: Andrew Svetlov date: Sat Mar 31 19:36:39 2012 +0300 summary: fix issue #5136: deprecate old unused functions from tkinter. These functions are not documnted, so no documentation update. files: Misc/NEWS | 2 ++ Modules/_tkinter.c | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,8 @@ Library ------- +- Issue #5136: deprecated old, unused functions from tkinter. + - Issue #14409: IDLE now properly executes commands in the Shell window when it cannot read the normal config files on startup and has to use the built-in default key bindings. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1343,6 +1343,11 @@ char *cmd; PyObject *res = NULL; + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "globalcall is deprecated and will be removed in 3.4", + 1) < 0) + return 0; + CHECK_TCL_APPARTMENT; cmd = Merge(args); @@ -1392,6 +1397,11 @@ PyObject *res = NULL; int err; + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "globaleval is deprecated and will be removed in 3.4", + 1) < 0) + return 0; + if (!PyArg_ParseTuple(args, "s:globaleval", &script)) return NULL; @@ -1954,9 +1964,16 @@ static PyObject * Tkapp_Merge(PyObject *self, PyObject *args) { - char *s = Merge(args); + char *s; PyObject *res = NULL; + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "merge is deprecated and will be removed in 3.4", + 1) < 0) + return 0; + + s = Merge(args); + if (s) { res = PyUnicode_FromString(s); ckfree(s); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 18:44:25 2012 From: python-checkins at python.org (andrew.svetlov) Date: Sat, 31 Mar 2012 18:44:25 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_fix_typo?= Message-ID: http://hg.python.org/cpython/rev/d2b6d821934a changeset: 76019:d2b6d821934a user: Andrew Svetlov date: Sat Mar 31 19:44:18 2012 +0300 summary: fix typo files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,7 +37,7 @@ Library ------- -- Issue #5136: deprecated old, unused functions from tkinter. +- Issue #5136: deprecate old, unused functions from tkinter. - Issue #14409: IDLE now properly executes commands in the Shell window when it cannot read the normal config files on startup and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 18:49:09 2012 From: python-checkins at python.org (sandro.tosi) Date: Sat, 31 Mar 2012 18:49:09 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_use_unittest=2E?= =?utf8?q?skip=3B_thanks_to_Chang_Min_Jeon_from_docs=40?= Message-ID: http://hg.python.org/cpython/rev/3ca81a951c31 changeset: 76020:3ca81a951c31 branch: 2.7 parent: 76017:b3a7b27953e0 user: Sandro Tosi date: Sat Mar 31 18:34:42 2012 +0200 summary: use unittest.skip; thanks to Chang Min Jeon from docs@ files: Doc/library/unittest.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -616,7 +616,7 @@ Classes can be skipped just like methods: :: - @skip("showing class skipping") + @unittest.skip("showing class skipping") class MySkippedTestCase(unittest.TestCase): def test_not_run(self): pass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 18:49:09 2012 From: python-checkins at python.org (sandro.tosi) Date: Sat, 31 Mar 2012 18:49:09 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_use_unittest=2E?= =?utf8?q?skip=3B_thanks_to_Chang_Min_Jeon_from_docs=40?= Message-ID: http://hg.python.org/cpython/rev/6774a2285579 changeset: 76021:6774a2285579 branch: 3.2 parent: 76015:d478c0a68bcb user: Sandro Tosi date: Sat Mar 31 18:34:59 2012 +0200 summary: use unittest.skip; thanks to Chang Min Jeon from docs@ files: Doc/library/unittest.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -640,7 +640,7 @@ Classes can be skipped just like methods: :: - @skip("showing class skipping") + @unittest.skip("showing class skipping") class MySkippedTestCase(unittest.TestCase): def test_not_run(self): pass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 18:49:10 2012 From: python-checkins at python.org (sandro.tosi) Date: Sat, 31 Mar 2012 18:49:10 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_merge_with_3=2E2?= Message-ID: http://hg.python.org/cpython/rev/b926a8c386ad changeset: 76022:b926a8c386ad parent: 76016:ee9b6574b497 parent: 76021:6774a2285579 user: Sandro Tosi date: Sat Mar 31 18:35:16 2012 +0200 summary: merge with 3.2 files: Doc/library/unittest.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -640,7 +640,7 @@ Classes can be skipped just like methods: :: - @skip("showing class skipping") + @unittest.skip("showing class skipping") class MySkippedTestCase(unittest.TestCase): def test_not_run(self): pass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 18:49:11 2012 From: python-checkins at python.org (sandro.tosi) Date: Sat, 31 Mar 2012 18:49:11 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/40ed19ed0342 changeset: 76023:40ed19ed0342 parent: 76022:b926a8c386ad parent: 76018:6023d73c6f87 user: Sandro Tosi date: Sat Mar 31 18:44:18 2012 +0200 summary: merge heads files: Misc/NEWS | 2 ++ Modules/_tkinter.c | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,8 @@ Library ------- +- Issue #5136: deprecated old, unused functions from tkinter. + - Issue #14409: IDLE now properly executes commands in the Shell window when it cannot read the normal config files on startup and has to use the built-in default key bindings. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1343,6 +1343,11 @@ char *cmd; PyObject *res = NULL; + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "globalcall is deprecated and will be removed in 3.4", + 1) < 0) + return 0; + CHECK_TCL_APPARTMENT; cmd = Merge(args); @@ -1392,6 +1397,11 @@ PyObject *res = NULL; int err; + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "globaleval is deprecated and will be removed in 3.4", + 1) < 0) + return 0; + if (!PyArg_ParseTuple(args, "s:globaleval", &script)) return NULL; @@ -1954,9 +1964,16 @@ static PyObject * Tkapp_Merge(PyObject *self, PyObject *args) { - char *s = Merge(args); + char *s; PyObject *res = NULL; + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "merge is deprecated and will be removed in 3.4", + 1) < 0) + return 0; + + s = Merge(args); + if (s) { res = PyUnicode_FromString(s); ckfree(s); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 18:49:12 2012 From: python-checkins at python.org (sandro.tosi) Date: Sat, 31 Mar 2012 18:49:12 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_merge_heads?= Message-ID: http://hg.python.org/cpython/rev/4805f24ba269 changeset: 76024:4805f24ba269 parent: 76023:40ed19ed0342 parent: 76019:d2b6d821934a user: Sandro Tosi date: Sat Mar 31 18:46:45 2012 +0200 summary: merge heads files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,7 +37,7 @@ Library ------- -- Issue #5136: deprecated old, unused functions from tkinter. +- Issue #5136: deprecate old, unused functions from tkinter. - Issue #14409: IDLE now properly executes commands in the Shell window when it cannot read the normal config files on startup and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 20:30:50 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 31 Mar 2012 20:30:50 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314406=3A_Fix_a_race_condition_when_using?= Message-ID: http://hg.python.org/cpython/rev/2c1432552213 changeset: 76026:2c1432552213 parent: 76024:4805f24ba269 parent: 76025:0312db5265d0 user: Antoine Pitrou date: Sat Mar 31 20:25:22 2012 +0200 summary: Issue #14406: Fix a race condition when using `concurrent.futures.wait(return_when=ALL_COMPLETED)`. Patch by Matt Joiner. files: Lib/concurrent/futures/_base.py | 8 ++++-- Lib/test/test_concurrent_futures.py | 18 ++++++++++++++++- Misc/NEWS | 3 ++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -111,12 +111,14 @@ def __init__(self, num_pending_calls, stop_on_exception): self.num_pending_calls = num_pending_calls self.stop_on_exception = stop_on_exception + self.lock = threading.Lock() super().__init__() def _decrement_pending_calls(self): - self.num_pending_calls -= 1 - if not self.num_pending_calls: - self.event.set() + with self.lock: + self.num_pending_calls -= 1 + if not self.num_pending_calls: + self.event.set() def add_result(self, future): super().add_result(future) diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -183,7 +183,9 @@ for p in processes.values(): p.join() + class WaitTests(unittest.TestCase): + def test_first_completed(self): future1 = self.executor.submit(mul, 21, 2) future2 = self.executor.submit(time.sleep, 1.5) @@ -284,7 +286,21 @@ class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests): - pass + + def test_pending_calls_race(self): + # Issue #14406: multi-threaded race condition when waiting on all + # futures. + event = threading.Event() + def future_func(): + event.wait() + oldswitchinterval = sys.getswitchinterval() + sys.setswitchinterval(1e-6) + try: + fs = {self.executor.submit(future_func) for i in range(100)} + event.set() + futures.wait(fs, return_when=futures.ALL_COMPLETED) + finally: + sys.setswitchinterval(oldswitchinterval) class ProcessPoolWaitTests(ProcessPoolMixin, WaitTests): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,9 @@ Library ------- +- Issue #14406: Fix a race condition when using ``concurrent.futures.wait( + return_when=ALL_COMPLETED)``. Patch by Matt Joiner. + - Issue #5136: deprecate old, unused functions from tkinter. - Issue #14409: IDLE now properly executes commands in the Shell window -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 20:30:50 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 31 Mar 2012 20:30:50 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0NDA2?= =?utf8?q?=3A_Fix_a_race_condition_when_using?= Message-ID: http://hg.python.org/cpython/rev/0312db5265d0 changeset: 76025:0312db5265d0 branch: 3.2 parent: 76021:6774a2285579 user: Antoine Pitrou date: Sat Mar 31 20:23:30 2012 +0200 summary: Issue #14406: Fix a race condition when using `concurrent.futures.wait(return_when=ALL_COMPLETED)`. Patch by Matt Joiner. files: Lib/concurrent/futures/_base.py | 8 ++++-- Lib/test/test_concurrent_futures.py | 18 ++++++++++++++++- Misc/NEWS | 3 ++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -112,12 +112,14 @@ def __init__(self, num_pending_calls, stop_on_exception): self.num_pending_calls = num_pending_calls self.stop_on_exception = stop_on_exception + self.lock = threading.Lock() super().__init__() def _decrement_pending_calls(self): - self.num_pending_calls -= 1 - if not self.num_pending_calls: - self.event.set() + with self.lock: + self.num_pending_calls -= 1 + if not self.num_pending_calls: + self.event.set() def add_result(self, future): super().add_result(future) diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -183,7 +183,9 @@ for p in processes: p.join() + class WaitTests(unittest.TestCase): + def test_first_completed(self): future1 = self.executor.submit(mul, 21, 2) future2 = self.executor.submit(time.sleep, 1.5) @@ -284,7 +286,21 @@ class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests): - pass + + def test_pending_calls_race(self): + # Issue #14406: multi-threaded race condition when waiting on all + # futures. + event = threading.Event() + def future_func(): + event.wait() + oldswitchinterval = sys.getswitchinterval() + sys.setswitchinterval(1e-6) + try: + fs = {self.executor.submit(future_func) for i in range(100)} + event.set() + futures.wait(fs, return_when=futures.ALL_COMPLETED) + finally: + sys.setswitchinterval(oldswitchinterval) class ProcessPoolWaitTests(ProcessPoolMixin, WaitTests): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,9 @@ Library ------- +- Issue #14406: Fix a race condition when using ``concurrent.futures.wait( + return_when=ALL_COMPLETED)``. Patch by Matt Joiner. + - Issue #14409: IDLE now properly executes commands in the Shell window when it cannot read the normal config files on startup and has to use the built-in default key bindings. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 21:14:59 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 31 Mar 2012 21:14:59 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0NDU2?= =?utf8?q?=3A_improve_documentation_of_the_signal_module_w=2Er=2Et=2E_thre?= =?utf8?q?ads=2E?= Message-ID: http://hg.python.org/cpython/rev/52e32f3b933d changeset: 76027:52e32f3b933d branch: 3.2 parent: 76025:0312db5265d0 user: Antoine Pitrou date: Sat Mar 31 20:56:21 2012 +0200 summary: Issue #14456: improve documentation of the signal module w.r.t. threads. files: Doc/library/signal.rst | 78 +++++++++++++++++------------ 1 files changed, 45 insertions(+), 33 deletions(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -5,46 +5,58 @@ :synopsis: Set handlers for asynchronous events. -This module provides mechanisms to use signal handlers in Python. Some general -rules for working with signals and their handlers: +This module provides mechanisms to use signal handlers in Python. -* A handler for a particular signal, once set, remains installed until it is - explicitly reset (Python emulates the BSD style interface regardless of the - underlying implementation), with the exception of the handler for - :const:`SIGCHLD`, which follows the underlying implementation. -* There is no way to "block" signals temporarily from critical sections (since - this is not supported by all Unix flavors). +General rules +------------- -* Although Python signal handlers are called asynchronously as far as the Python - user is concerned, they can only occur between the "atomic" instructions of the - Python interpreter. This means that signals arriving during long calculations - implemented purely in C (such as regular expression matches on large bodies of - text) may be delayed for an arbitrary amount of time. +The :func:`signal.signal` function allows to define custom handlers to be +executed when a signal is received. A small number of default handlers are +installed: :const:`SIGPIPE` is ignored (so write errors on pipes and sockets +can be reported as ordinary Python exceptions) and :const:`SIGINT` is +translated into a :exc:`KeyboardInterrupt` exception. -* When a signal arrives during an I/O operation, it is possible that the I/O - operation raises an exception after the signal handler returns. This is - dependent on the underlying Unix system's semantics regarding interrupted system - calls. +A handler for a particular signal, once set, remains installed until it is +explicitly reset (Python emulates the BSD style interface regardless of the +underlying implementation), with the exception of the handler for +:const:`SIGCHLD`, which follows the underlying implementation. -* Because the C signal handler always returns, it makes little sense to catch - synchronous errors like :const:`SIGFPE` or :const:`SIGSEGV`. +There is no way to "block" signals temporarily from critical sections (since +this is not supported by all Unix flavors). -* Python installs a small number of signal handlers by default: :const:`SIGPIPE` - is ignored (so write errors on pipes and sockets can be reported as ordinary - Python exceptions) and :const:`SIGINT` is translated into a - :exc:`KeyboardInterrupt` exception. All of these can be overridden. -* Some care must be taken if both signals and threads are used in the same - program. The fundamental thing to remember in using signals and threads - simultaneously is: always perform :func:`signal` operations in the main thread - of execution. Any thread can perform an :func:`alarm`, :func:`getsignal`, - :func:`pause`, :func:`setitimer` or :func:`getitimer`; only the main thread - can set a new signal handler, and the main thread will be the only one to - receive signals (this is enforced by the Python :mod:`signal` module, even - if the underlying thread implementation supports sending signals to - individual threads). This means that signals can't be used as a means of - inter-thread communication. Use locks instead. +Execution of Python signal handlers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A Python signal handler does not get executed inside the low-level (C) signal +handler. Instead, the low-level signal handler sets a flag which tells the +:term:`virtual machine` to execute the corresponding Python signal handler +at a later point(for example at the next :term:`bytecode` instruction). +This has consequences: + +* It makes little sense to catch synchronous errors like :const:`SIGFPE` or + :const:`SIGSEGV`. + +* A long-running calculation implemented purely in C (such as regular + expression matching on a large body of text) may run uninterrupted for an + arbitrary amount of time, regardless of any signals received. The Python + signal handlers will be called when the calculation finishes. + + +Signals and threads +^^^^^^^^^^^^^^^^^^^ + +Python signal handlers are always executed in the main Python thread, +even if the signal was received in another thread. This means that signals +can't be used as a means of inter-thread communication. You can use +the synchronization primitives from the :mod:`threading` module instead. + +Besides, only the main thread is allowed to set a new signal handler. + + +Module contents +--------------- The variables defined in the :mod:`signal` module are: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 21:14:59 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 31 Mar 2012 21:14:59 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Issue_=2314456=3A_improve_documentation_of_the_signal_module?= =?utf8?q?_w=2Er=2Et=2E_threads=2E?= Message-ID: http://hg.python.org/cpython/rev/44d13f371811 changeset: 76028:44d13f371811 parent: 76026:2c1432552213 parent: 76027:52e32f3b933d user: Antoine Pitrou date: Sat Mar 31 21:09:00 2012 +0200 summary: Issue #14456: improve documentation of the signal module w.r.t. threads. files: Doc/library/signal.rst | 95 ++++++++++++++++++----------- 1 files changed, 59 insertions(+), 36 deletions(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -5,43 +5,61 @@ :synopsis: Set handlers for asynchronous events. -This module provides mechanisms to use signal handlers in Python. Some general -rules for working with signals and their handlers: +This module provides mechanisms to use signal handlers in Python. -* A handler for a particular signal, once set, remains installed until it is - explicitly reset (Python emulates the BSD style interface regardless of the - underlying implementation), with the exception of the handler for - :const:`SIGCHLD`, which follows the underlying implementation. -* Although Python signal handlers are called asynchronously as far as the Python - user is concerned, they can only occur between the "atomic" instructions of the - Python interpreter. This means that signals arriving during long calculations - implemented purely in C (such as regular expression matches on large bodies of - text) may be delayed for an arbitrary amount of time. +General rules +------------- -* When a signal arrives during an I/O operation, it is possible that the I/O - operation raises an exception after the signal handler returns. This is - dependent on the underlying Unix system's semantics regarding interrupted system - calls. +The :func:`signal.signal` function allows to define custom handlers to be +executed when a signal is received. A small number of default handlers are +installed: :const:`SIGPIPE` is ignored (so write errors on pipes and sockets +can be reported as ordinary Python exceptions) and :const:`SIGINT` is +translated into a :exc:`KeyboardInterrupt` exception. -* Because the C signal handler always returns, it makes little sense to catch - synchronous errors like :const:`SIGFPE` or :const:`SIGSEGV`. +A handler for a particular signal, once set, remains installed until it is +explicitly reset (Python emulates the BSD style interface regardless of the +underlying implementation), with the exception of the handler for +:const:`SIGCHLD`, which follows the underlying implementation. -* Python installs a small number of signal handlers by default: :const:`SIGPIPE` - is ignored (so write errors on pipes and sockets can be reported as ordinary - Python exceptions) and :const:`SIGINT` is translated into a - :exc:`KeyboardInterrupt` exception. All of these can be overridden. +There is no way to "block" signals temporarily from critical sections (since +this is not supported by all Unix flavors). -* Some care must be taken if both signals and threads are used in the same - program. The fundamental thing to remember in using signals and threads - simultaneously is: always perform :func:`signal` operations in the main thread - of execution. Any thread can perform an :func:`alarm`, :func:`getsignal`, - :func:`pause`, :func:`setitimer` or :func:`getitimer`; only the main thread - can set a new signal handler, and the main thread will be the only one to - receive signals (this is enforced by the Python :mod:`signal` module, even - if the underlying thread implementation supports sending signals to - individual threads). This means that signals can't be used as a means of - inter-thread communication. Use locks instead. + +Execution of Python signal handlers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A Python signal handler does not get executed inside the low-level (C) signal +handler. Instead, the low-level signal handler sets a flag which tells the +:term:`virtual machine` to execute the corresponding Python signal handler +at a later point(for example at the next :term:`bytecode` instruction). +This has consequences: + +* It makes little sense to catch synchronous errors like :const:`SIGFPE` or + :const:`SIGSEGV`. + +* A long-running calculation implemented purely in C (such as regular + expression matching on a large body of text) may run uninterrupted for an + arbitrary amount of time, regardless of any signals received. The Python + signal handlers will be called when the calculation finishes. + + +.. _signals-and-threads: + + +Signals and threads +^^^^^^^^^^^^^^^^^^^ + +Python signal handlers are always executed in the main Python thread, +even if the signal was received in another thread. This means that signals +can't be used as a means of inter-thread communication. You can use +the synchronization primitives from the :mod:`threading` module instead. + +Besides, only the main thread is allowed to set a new signal handler. + + +Module contents +--------------- The variables defined in the :mod:`signal` module are: @@ -189,15 +207,20 @@ .. function:: pthread_kill(thread_id, signum) - Send the signal *signum* to the thread *thread_id*, another thread in the same - process as the caller. The signal is asynchronously directed to thread. + Send the signal *signum* to the thread *thread_id*, another thread in the + same process as the caller. The target thread can be executing any code + (Python or not). However, if the target thread is executing the Python + interpreter, the Python signal handlers will be :ref:`executed by the main + thread `. Therefore, the only point of sending a signal to a particular + Python thread would be to force a running system call to fail with + :exc:`InterruptedError`. Use :func:`threading.get_ident()` or the :attr:`~threading.Thread.ident` - attribute of :attr:`threading.Thread` to get a 'thread identifier' for - *thread_id*. + attribute of :class:`threading.Thread` objects to get a suitable value + for *thread_id*. If *signum* is 0, then no signal is sent, but error checking is still - performed; this can be used to check if a thread is still running. + performed; this can be used to check if the target thread is still running. Availability: Unix (see the man page :manpage:`pthread_kill(3)` for further information). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 21:15:00 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 31 Mar 2012 21:15:00 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_formatting?= Message-ID: http://hg.python.org/cpython/rev/2f158dbebacf changeset: 76029:2f158dbebacf user: Antoine Pitrou date: Sat Mar 31 21:09:53 2012 +0200 summary: Fix formatting files: Doc/library/signal.rst | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@ -238,13 +238,13 @@ The behavior of the call is dependent on the value of *how*, as follows. - * :data:`SIG_BLOCK`: The set of blocked signals is the union of the current - set and the *mask* argument. - * :data:`SIG_UNBLOCK`: The signals in *mask* are removed from the current - set of blocked signals. It is permissible to attempt to unblock a - signal which is not blocked. - * :data:`SIG_SETMASK`: The set of blocked signals is set to the *mask* - argument. + * :data:`SIG_BLOCK`: The set of blocked signals is the union of the current + set and the *mask* argument. + * :data:`SIG_UNBLOCK`: The signals in *mask* are removed from the current + set of blocked signals. It is permissible to attempt to unblock a + signal which is not blocked. + * :data:`SIG_SETMASK`: The set of blocked signals is set to the *mask* + argument. *mask* is a set of signal numbers (e.g. {:const:`signal.SIGINT`, :const:`signal.SIGTERM`}). Use ``range(1, signal.NSIG)`` for a full mask -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 21:40:46 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2012 21:40:46 +0200 Subject: [Python-checkins] =?utf8?q?peps=3A_PEP_412=3A_add_missing_variabl?= =?utf8?q?es_footer_and_reformat=2E?= Message-ID: http://hg.python.org/peps/rev/0dd533ad5967 changeset: 4181:0dd533ad5967 user: Georg Brandl date: Sat Mar 31 21:40:52 2012 +0200 summary: PEP 412: add missing variables footer and reformat. files: pep-0412.txt | 185 +++++++++++++++++++++----------------- 1 files changed, 101 insertions(+), 84 deletions(-) diff --git a/pep-0412.txt b/pep-0412.txt --- a/pep-0412.txt +++ b/pep-0412.txt @@ -14,26 +14,28 @@ Abstract ======== -This PEP proposes a change in the implementation of the builtin dictionary -type ``dict``. The new implementation allows dictionaries which are used as -attribute dictionaries (the ``__dict__`` attribute of an object) to share -keys with other attribute dictionaries of instances of the same class. +This PEP proposes a change in the implementation of the builtin +dictionary type ``dict``. The new implementation allows dictionaries +which are used as attribute dictionaries (the ``__dict__`` attribute +of an object) to share keys with other attribute dictionaries of +instances of the same class. Motivation ========== -The current dictionary implementation uses more memory than is necessary -when used as a container for object attributes as the keys are -replicated for each instance rather than being shared across many instances -of the same class. -Despite this, the current dictionary implementation is finely tuned and -performs very well as a general-purpose mapping object. +The current dictionary implementation uses more memory than is +necessary when used as a container for object attributes as the keys +are replicated for each instance rather than being shared across many +instances of the same class. Despite this, the current dictionary +implementation is finely tuned and performs very well as a +general-purpose mapping object. -By separating the keys (and hashes) from the values it is possible to share -the keys between multiple dictionaries and improve memory use. -By ensuring that keys are separated from the values only when beneficial, -it is possible to retain the high-performance of the current dictionary -implementation when used as a general-purpose mapping object. +By separating the keys (and hashes) from the values it is possible to +share the keys between multiple dictionaries and improve memory use. +By ensuring that keys are separated from the values only when +beneficial, it is possible to retain the high-performance of the +current dictionary implementation when used as a general-purpose +mapping object. Behaviour ========= @@ -47,76 +49,80 @@ Memory Usage ------------ -Reduction in memory use is directly related to the number of dictionaries -with shared keys in existence at any time. These dictionaries are typically -half the size of the current dictionary implementation. +Reduction in memory use is directly related to the number of +dictionaries with shared keys in existence at any time. These +dictionaries are typically half the size of the current dictionary +implementation. Benchmarking shows that memory use is reduced by 10% to 20% for -object-oriented programs with no significant change in memory use -for other programs. +object-oriented programs with no significant change in memory use for +other programs. Speed ----- -The performance of the new implementation is dominated by memory locality -effects. When keys are not shared (for example in module dictionaries -and dictionary explicitly created by dict() or {} ) then performance is -unchanged (within a percent or two) from the current implementation. +The performance of the new implementation is dominated by memory +locality effects. When keys are not shared (for example in module +dictionaries and dictionary explicitly created by ``dict()`` or +``{}``) then performance is unchanged (within a percent or two) from +the current implementation. -For the shared keys case, the new implementation tends to separate keys -from values, but reduces total memory usage. This will improve performance -in many cases as the effects of reduced memory usage outweigh the loss of -locality, but some programs may show a small slow down. +For the shared keys case, the new implementation tends to separate +keys from values, but reduces total memory usage. This will improve +performance in many cases as the effects of reduced memory usage +outweigh the loss of locality, but some programs may show a small slow +down. Benchmarking shows no significant change of speed for most benchmarks. Object-oriented benchmarks show small speed ups when they create large -numbers of objects of the same class (the gcbench benchmark shows a 10% -speed up; this is likely to be an upper limit). +numbers of objects of the same class (the gcbench benchmark shows a +10% speed up; this is likely to be an upper limit). Implementation ============== -Both the old and new dictionaries consist of a fixed-sized dict struct and -a re-sizeable table. -In the new dictionary the table can be further split into a keys table and -values array. -The keys table holds the keys and hashes and (for non-split tables) the -values as well. It differs only from the original implementation in that it +Both the old and new dictionaries consist of a fixed-sized dict struct +and a re-sizeable table. In the new dictionary the table can be +further split into a keys table and values array. The keys table +holds the keys and hashes and (for non-split tables) the values as +well. It differs only from the original implementation in that it contains a number of fields that were previously in the dict struct. -If a table is split the values in the keys table are ignored, instead the -values are held in a separate array. +If a table is split the values in the keys table are ignored, instead +the values are held in a separate array. Split-Table dictionaries ------------------------ -When dictionaries are created to fill the __dict__ slot of an object, they are -created in split form. The keys table is cached in the type, potentially -allowing all attribute dictionaries of instances of one class to share keys. -In the event of the keys of these dictionaries starting to diverge, -individual dictionaries will lazily convert to the combined-table form. -This ensures good memory use in the common case, and correctness in all cases. +When dictionaries are created to fill the __dict__ slot of an object, +they are created in split form. The keys table is cached in the type, +potentially allowing all attribute dictionaries of instances of one +class to share keys. In the event of the keys of these dictionaries +starting to diverge, individual dictionaries will lazily convert to +the combined-table form. This ensures good memory use in the common +case, and correctness in all cases. When resizing a split dictionary it is converted to a combined table. -If resizing is as a result of storing an instance attribute, and there is -only instance of a class, then the dictionary will be re-split immediately. -Since most OO code will set attributes in the __init__ method, all attributes -will be set before a second instance is created and no more resizing will be -necessary as all further instance dictionaries will have the correct size. -For more complex use patterns, it is impossible to know what is the best -approach, so the implementation allows extra insertions up to the point -of a resize when it reverts to the combined table (non-shared keys). +If resizing is as a result of storing an instance attribute, and there +is only instance of a class, then the dictionary will be re-split +immediately. Since most OO code will set attributes in the __init__ +method, all attributes will be set before a second instance is created +and no more resizing will be necessary as all further instance +dictionaries will have the correct size. For more complex use +patterns, it is impossible to know what is the best approach, so the +implementation allows extra insertions up to the point of a resize +when it reverts to the combined table (non-shared keys). -A deletion from a split dictionary does not change the keys table, it simply -removes the value from the values array. +A deletion from a split dictionary does not change the keys table, it +simply removes the value from the values array. Combined-Table dictionaries --------------------------- -Explicit dictionaries (dict() or {}), module dictionaries and most other -dictionaries are created as combined-table dictionaries. -A combined-table dictionary never becomes a split-table dictionary. -Combined tables are laid out in much the same way as the tables in the old -dictionary, resulting in very similar performance. +Explicit dictionaries (``dict()`` or ``{}``), module dictionaries and +most other dictionaries are created as combined-table dictionaries. A +combined-table dictionary never becomes a split-table dictionary. +Combined tables are laid out in much the same way as the tables in the +old dictionary, resulting in very similar performance. Implementation ============== @@ -129,44 +135,45 @@ Pros ---- -Significant memory savings for object-oriented applications. -Small improvement to speed for programs which create lots of similar objects. +Significant memory savings for object-oriented applications. Small +improvement to speed for programs which create lots of similar +objects. Cons ---- -Change to data structures: -Third party modules which meddle with the internals of the dictionary -implementation will break. -Changes to repr() output and iteration order: -For most cases, this will be unchanged. -However for some split-table dictionaries the iteration order will -change. +Change to data structures: Third party modules which meddle with the +internals of the dictionary implementation will break. -Neither of these cons should be a problem. -Modules which meddle with the internals of the dictionary -implementation are already broken and should be fixed to use the API. -The iteration order of dictionaries was never defined and has always been -arbitrary; it is different for Jython and PyPy. +Changes to repr() output and iteration order: For most cases, this +will be unchanged. However for some split-table dictionaries the +iteration order will change. + +Neither of these cons should be a problem. Modules which meddle with +the internals of the dictionary implementation are already broken and +should be fixed to use the API. The iteration order of dictionaries +was never defined and has always been arbitrary; it is different for +Jython and PyPy. Alternative Implementation -------------------------- -An alternative implementation for split tables, which could save even more -memory, is to store an index in the value field of the keys table (instead -of ignoring the value field). This index would explicitly state where in the -value array to look. The value array would then only require 1 field for each -usable slot in the key table, rather than each slot in the key table. +An alternative implementation for split tables, which could save even +more memory, is to store an index in the value field of the keys table +(instead of ignoring the value field). This index would explicitly +state where in the value array to look. The value array would then +only require 1 field for each usable slot in the key table, rather +than each slot in the key table. This "indexed" version would reduce the size of value array by about -one third. The keys table would need an extra "values_size" field, increasing -the size of combined dicts by one word. -The extra indirection adds more complexity to the code, potentially reducing +one third. The keys table would need an extra "values_size" field, +increasing the size of combined dicts by one word. The extra +indirection adds more complexity to the code, potentially reducing performance a little. -The "indexed" version will not be included in this implementation, -but should be considered deferred rather than rejected, -pending further experimentation. +The "indexed" version will not be included in this implementation, but +should be considered deferred rather than rejected, pending further +experimentation. References ========== @@ -179,3 +186,13 @@ This document has been placed in the public domain. + + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Mar 31 23:58:15 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 31 Mar 2012 23:58:15 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0NDM3?= =?utf8?q?=3A_Fix_building_the_=5Fio_module_under_Cygwin=2E?= Message-ID: http://hg.python.org/cpython/rev/f96b603278cc changeset: 76030:f96b603278cc branch: 3.2 parent: 76027:52e32f3b933d user: Antoine Pitrou date: Sat Mar 31 23:50:31 2012 +0200 summary: Issue #14437: Fix building the _io module under Cygwin. files: Misc/NEWS | 2 ++ Modules/_io/_iomodule.h | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -105,6 +105,8 @@ Build ----- +- Issue #14437: Fix building the _io module under Cygwin. + - Issue #14387: Do not include accu.h from Python.h. - Issue #14359: Only use O_CLOEXEC in _posixmodule.c if it is defined. diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -67,7 +67,7 @@ PyObject *filename; /* Not used, but part of the IOError object */ Py_ssize_t written; } PyBlockingIOErrorObject; -PyAPI_DATA(PyObject *) PyExc_BlockingIOError; +extern PyObject *PyExc_BlockingIOError; /* * Offset type for positioning. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 23:58:16 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 31 Mar 2012 23:58:16 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Null_merge?= Message-ID: http://hg.python.org/cpython/rev/9a5ae3f37d06 changeset: 76031:9a5ae3f37d06 parent: 76029:2f158dbebacf parent: 76030:f96b603278cc user: Antoine Pitrou date: Sat Mar 31 23:51:25 2012 +0200 summary: Null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Mar 31 23:58:16 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 31 Mar 2012 23:58:16 +0200 Subject: [Python-checkins] =?utf8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0NDM3?= =?utf8?q?=3A_Fix_building_the_=5Fio_module_under_Cygwin=2E?= Message-ID: http://hg.python.org/cpython/rev/6f8dd543d80a changeset: 76032:6f8dd543d80a branch: 2.7 parent: 76020:3ca81a951c31 user: Antoine Pitrou date: Sat Mar 31 23:53:07 2012 +0200 summary: Issue #14437: Fix building the _io module under Cygwin. files: Misc/NEWS | 5 +++++ Modules/_io/_iomodule.h | 2 +- 2 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -78,6 +78,11 @@ - Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils on Windows. +Build +----- + +- Issue #14437: Fix building the _io module under Cygwin. + What's New in Python 2.7.3 release candidate 2? =============================================== diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -72,7 +72,7 @@ PyObject *filename; /* Not used, but part of the IOError object */ Py_ssize_t written; } PyBlockingIOErrorObject; -PyAPI_DATA(PyObject *) PyExc_BlockingIOError; +extern PyObject *PyExc_BlockingIOError; /* * Offset type for positioning. -- Repository URL: http://hg.python.org/cpython From amauryfa at gmail.com Mon Mar 5 07:58:47 2012 From: amauryfa at gmail.com (Amaury Forgeot d'Arc) Date: Mon, 05 Mar 2012 06:58:47 -0000 Subject: [Python-checkins] cpython: Issue #14168: Check for presence of _attrs before accessing it. Message-ID: Hi, > Library > ------- > > +- Issue #14168: Check for presence of _attrs before accessing it. > + This NEWS entry is a bit cryptic. Should the minidom package be mentioned somewhere? > - Issue #14195: An issue that caused weakref.WeakSet instances to incorrectly > return True for a WeakSet instance 'a' in both 'a < a' and 'a > a' has been > fixed. -- Amaury Forgeot d'Arc