diff options
35 files changed, 401 insertions, 112 deletions
diff --git a/Doc/c-api/method.rst b/Doc/c-api/method.rst index 9d25571..9ee49ba 100644 --- a/Doc/c-api/method.rst +++ b/Doc/c-api/method.rst @@ -92,3 +92,9 @@ no longer available. .. cfunction:: PyObject* PyMethod_GET_SELF(PyObject *meth) Macro version of :cfunc:`PyMethod_Self` which avoids error checking. + + +.. cfunction:: int PyMethod_ClearFreeList(void) + + Clear the free list. Return the total number of freed items. + diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index 14d8eab..1560717 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -54,15 +54,11 @@ the constructor functions work with any iterable Python object. Return true if *p* is a :class:`set` object or an instance of a subtype. - .. versionadded:: 2.6 - .. cfunction:: int PyFrozenSet_Check(PyObject *p) Return true if *p* is a :class:`frozenset` object or an instance of a subtype. - .. versionadded:: 2.6 - .. cfunction:: int PyAnySet_Check(PyObject *p) Return true if *p* is a :class:`set` object, a :class:`frozenset` object, or an diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index eb661fb..c0e53fb 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -105,3 +105,7 @@ Tuple Objects this function. If the object referenced by ``*p`` is replaced, the original ``*p`` is destroyed. On failure, returns ``-1`` and sets ``*p`` to *NULL*, and raises :exc:`MemoryError` or :exc:`SystemError`. + +.. cfunction:: int PyMethod_ClearFreeList(void) + + Clear the free list. Return the total number of freed items. diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index d1d4e45..bc0eeef 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -37,8 +37,6 @@ Type Objects Clears the internal lookup cache. Return the current version tag. - .. versionadded:: 2.6 - .. cfunction:: int PyType_HasFeature(PyObject *o, int feature) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index 886ba65..448cf68 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -83,6 +83,11 @@ access internal read-only data of Unicode objects: Return a pointer to the internal buffer of the object. *o* has to be a :ctype:`PyUnicodeObject` (not checked). + +.. cfunction:: int PyUnicode_ClearFreeList(void) + + Clear the free list. Return the total number of freed items. + Unicode provides many different character properties. The most often needed ones are available through these macros which are mapped to C functions depending on the Python configuration. diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 3c305ed..b2d672f 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -2010,7 +2010,6 @@ Fundamental data types their methods and attributes. .. versionchanged:: 2.6 - ctypes data types that are not and do not contain pointers can now be pickled. diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index afba964..b0845e9 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -1352,19 +1352,15 @@ to work with the :class:`Decimal` class:: '<.02>' """ - q = Decimal((0, (1,), -places)) # 2 places --> '0.01' - sign, digits, exp = value.quantize(q).as_tuple() - assert exp == -places + q = Decimal(10) ** -places # 2 places --> '0.01' + sign, digits, exp = value.quantize(q).as_tuple() result = [] digits = map(str, digits) build, next = result.append, digits.pop if sign: build(trailneg) for i in range(places): - if digits: - build(next()) - else: - build('0') + build(next() if digits else '0') build(dp) i = 0 while digits: @@ -1374,12 +1370,8 @@ to work with the :class:`Decimal` class:: i = 0 build(sep) build(curr) - if sign: - build(neg) - else: - build(pos) - result.reverse() - return ''.join(result) + build(neg if sign else pos) + return ''.join(reversed(result)) def pi(): """Compute Pi to the current precision. @@ -1482,7 +1474,7 @@ Decimal FAQ Q. It is cumbersome to type ``decimal.Decimal('1234.5')``. Is there a way to minimize typing when using the interactive interpreter? -\A. Some users abbreviate the constructor to just a single letter:: +A. Some users abbreviate the constructor to just a single letter:: >>> D = decimal.Decimal >>> D('1.23') + D('3.45') @@ -1513,9 +1505,36 @@ the :const:`Inexact` trap is set, it is also useful for validation:: Q. Once I have valid two place inputs, how do I maintain that invariant throughout an application? -A. Some operations like addition and subtraction automatically preserve fixed -point. Others, like multiplication and division, change the number of decimal -places and need to be followed-up with a :meth:`quantize` step. +A. Some operations like addition, subtraction, and multiplication by an integer +will automatically preserve fixed point. Others operations, like division and +non-integer multiplication, will change the number of decimal places and need to +be followed-up with a :meth:`quantize` step:: + + >>> a = Decimal('102.72') # Initial fixed-point values + >>> b = Decimal('3.17') + >>> a + b # Addition preserves fixed-point + Decimal('105.89') + >>> a - b + Decimal('99.55') + >>> a * 42 # So does integer multiplication + Decimal('4314.24') + >>> (a * b).quantize(TWOPLACES) # Must quantize non-integer multiplication + Decimal('325.62') + >>> (b / a).quantize(TWOPLACES) # And quantize division + Decimal('0.03') + +In developing fixed-point applications, it is convenient to define functions +to handle the :meth:`quantize` step:: + + >>> def mul(x, y, fp=TWOPLACES): + ... return (x * y).quantize(fp) + >>> def div(x, y, fp=TWOPLACES): + ... return (x / y).quantize(fp) + + >>> mul(a, b) # Automatically preserve fixed-point + Decimal('325.62') + >>> div(b, a) + Decimal('0.03') Q. There are many ways to express the same value. The numbers :const:`200`, :const:`200.000`, :const:`2E2`, and :const:`.02E+4` all have the same value at @@ -1537,6 +1556,16 @@ of significant places in the coefficient. For example, expressing :const:`5.0E+3` as :const:`5000` keeps the value constant but cannot show the original's two-place significance. +If an application does not care about tracking significance, it is easy to +remove the exponent and trailing zeroes, losing signficance, but keeping the +value unchanged:: + + >>> def remove_exponent(d): + ... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize() + + >>> remove_exponent(Decimal('5E+3')) + Decimal('5000') + Q. Is there a way to convert a regular float to a :class:`Decimal`? A. Yes, all binary floating point numbers can be exactly expressed as a diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index d37c5ac..dae9b09 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -825,7 +825,7 @@ complete list of changes, or look through the CVS logs for all the details. int int >>> var._asdict() {'size': 4, 'type': 'int', 'id': 1, 'name': 'frequency'} - >>> v2 = var._replace('name', 'amplitude') + >>> v2 = var._replace(name='amplitude') >>> v2 variable(id=1, name='amplitude', type='int', size=4) diff --git a/Include/classobject.h b/Include/classobject.h index f6789d1..b7eebe5 100644 --- a/Include/classobject.h +++ b/Include/classobject.h @@ -31,6 +31,7 @@ PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *); #define PyMethod_GET_SELF(meth) \ (((PyMethodObject *)meth) -> im_self) +PyAPI_FUNC(int) PyMethod_ClearFreeList(void); typedef struct { PyObject_HEAD diff --git a/Include/frameobject.h b/Include/frameobject.h index 05877f9..d2afe8b 100644 --- a/Include/frameobject.h +++ b/Include/frameobject.h @@ -73,6 +73,8 @@ PyAPI_FUNC(PyObject **) PyFrame_ExtendStack(PyFrameObject *, int, int); PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int); PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); +PyAPI_FUNC(int) PyFrame_ClearFreeList(void); + #ifdef __cplusplus } #endif diff --git a/Include/methodobject.h b/Include/methodobject.h index 48e780e..cd1d265 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -85,6 +85,8 @@ typedef struct { PyObject *m_module; /* The __module__ attribute, can be anything */ } PyCFunctionObject; +PyAPI_FUNC(int) PyCFunction_ClearFreeList(void); + #ifdef __cplusplus } #endif diff --git a/Include/tupleobject.h b/Include/tupleobject.h index 018ef2f..7a887d1 100644 --- a/Include/tupleobject.h +++ b/Include/tupleobject.h @@ -53,6 +53,8 @@ PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...); /* Macro, *only* to be used to fill in brand new tuples */ #define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject *)(op))->ob_item[i] = v) +PyAPI_FUNC(int) PyTuple_ClearFreeList(void); + #ifdef __cplusplus } #endif diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h index 3954289..5e6c227 100644 --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -210,6 +210,7 @@ typedef PY_UNICODE_TYPE Py_UNICODE; # define _PyUnicode_AsDefaultEncodedString _PyUnicodeUCS2_AsDefaultEncodedString # define _PyUnicode_Fini _PyUnicodeUCS2_Fini # define _PyUnicode_Init _PyUnicodeUCS2_Init +# define PyUnicode_ClearFreeList PyUnicodeUCS2_ClearFreelist # define _PyUnicode_IsAlpha _PyUnicodeUCS2_IsAlpha # define _PyUnicode_IsDecimalDigit _PyUnicodeUCS2_IsDecimalDigit # define _PyUnicode_IsDigit _PyUnicodeUCS2_IsDigit @@ -303,6 +304,7 @@ typedef PY_UNICODE_TYPE Py_UNICODE; # define _PyUnicode_AsDefaultEncodedString _PyUnicodeUCS4_AsDefaultEncodedString # define _PyUnicode_Fini _PyUnicodeUCS4_Fini # define _PyUnicode_Init _PyUnicodeUCS4_Init +# define PyUnicode_ClearFreeList PyUnicodeUCS2_ClearFreelist # define _PyUnicode_IsAlpha _PyUnicodeUCS4_IsAlpha # define _PyUnicode_IsDecimalDigit _PyUnicodeUCS4_IsDecimalDigit # define _PyUnicode_IsDigit _PyUnicodeUCS4_IsDigit @@ -413,6 +415,8 @@ extern const unsigned char _Py_ascii_whitespace[]; extern "C" { #endif +PyAPI_FUNC(int) PyUnicode_ClearFreeList(void); + /* --- Unicode Type ------------------------------------------------------- */ typedef struct { diff --git a/Lib/SocketServer.py b/Lib/SocketServer.py index f62b7df..9c5d4c2 100644 --- a/Lib/SocketServer.py +++ b/Lib/SocketServer.py @@ -452,7 +452,11 @@ class ForkingMixIn: except os.error: pid = None if not pid: break - self.active_children.remove(pid) + try: + self.active_children.remove(pid) + except ValueError as e: + raise ValueError('%s. x=%d and list=%r' % (e.message, pid, + self.active_children)) def handle_timeout(self): """Wait for zombies after self.timeout seconds of inactivity. diff --git a/Lib/UserString.py b/Lib/UserString.py index 27b2b53..704ea59 100755 --- a/Lib/UserString.py +++ b/Lib/UserString.py @@ -162,8 +162,6 @@ class UserString(collections.Sequence): def upper(self): return self.__class__(self.data.upper()) def zfill(self, width): return self.__class__(self.data.zfill(width)) -collections.Sequence.register(UserString) - class MutableString(UserString, collections.MutableSequence): """mutable string objects diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py index 0cd668a..e1d9ba3 100644 --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -109,16 +109,6 @@ class EditorWindow(object): self.width = idleConf.GetOption('main','EditorWindow','width') self.text = text = MultiCallCreator(Text)( text_frame, name='text', padx=5, wrap='none', - foreground=idleConf.GetHighlight(currentTheme, - 'normal',fgBg='fg'), - background=idleConf.GetHighlight(currentTheme, - 'normal',fgBg='bg'), - highlightcolor=idleConf.GetHighlight(currentTheme, - 'hilite',fgBg='fg'), - highlightbackground=idleConf.GetHighlight(currentTheme, - 'hilite',fgBg='bg'), - insertbackground=idleConf.GetHighlight(currentTheme, - 'cursor',fgBg='fg'), width=self.width, height=idleConf.GetOption('main','EditorWindow','height') ) self.top.focused_widget = self.text @@ -225,7 +215,6 @@ class EditorWindow(object): # Making the initial values larger slows things down more often. self.num_context_lines = 50, 500, 5000000 self.per = per = self.Percolator(text) - self.color = None self.undo = undo = self.UndoDelegator() per.insertfilter(undo) text.undo_block_start = undo.undo_block_start @@ -236,6 +225,7 @@ class EditorWindow(object): io.set_filename_change_hook(self.filename_change_hook) self.good_load = False self.set_indentation_params(False) + self.color = None # initialized below in self.ResetColorizer if filename: if os.path.exists(filename) and not os.path.isdir(filename): if io.loadfile(filename): @@ -247,6 +237,7 @@ class EditorWindow(object): per.insertfilter(color) else: io.set_filename(filename) + self.ResetColorizer() self.saved_change_hook() self.update_recent_files_list() self.load_extensions() @@ -561,36 +552,42 @@ class EditorWindow(object): self.flist.filename_changed_edit(self) self.saved_change_hook() self.top.update_windowlist_registry(self) - if self.ispythonsource(self.io.filename): - self.addcolorizer() - else: - self.rmcolorizer() + self.ResetColorizer() - def addcolorizer(self): + def _addcolorizer(self): if self.color: return - self.per.removefilter(self.undo) - self.color = self.ColorDelegator() - self.per.insertfilter(self.color) - self.per.insertfilter(self.undo) + if self.ispythonsource(self.io.filename): + self.color = self.ColorDelegator() + # can add more colorizers here... + if self.color: + self.per.removefilter(self.undo) + self.per.insertfilter(self.color) + self.per.insertfilter(self.undo) - def rmcolorizer(self): + def _rmcolorizer(self): if not self.color: return self.color.removecolors() - self.per.removefilter(self.undo) self.per.removefilter(self.color) self.color = None - self.per.insertfilter(self.undo) def ResetColorizer(self): - "Update the colour theme if it is changed" - # Called from configDialog.py - if self.color: - self.color = self.ColorDelegator() - self.per.insertfilter(self.color) + "Update the colour theme" + # Called from self.filename_change_hook and from configDialog.py + self._rmcolorizer() + self._addcolorizer() theme = idleConf.GetOption('main','Theme','name') - self.text.config(idleConf.GetHighlight(theme, "normal")) + normal_colors = idleConf.GetHighlight(theme, 'normal') + cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg') + select_colors = idleConf.GetHighlight(theme, 'hilite') + self.text.config( + foreground=normal_colors['foreground'], + background=normal_colors['background'], + insertbackground=cursor_color, + selectforeground=select_colors['foreground'], + selectbackground=select_colors['background'], + ) IDENTCHARS = string.ascii_letters + string.digits + "_" diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index cd8565c..1885421 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -45,6 +45,12 @@ What's New in IDLE 2.6a1? *Release date: XX-XXX-200X* UNRELEASED, but merged into 3.0 +- Configured selection highlighting colors were ignored; updating highlighting + in the config dialog would cause non-Python files to be colored as if they + were Python source; improve use of ColorDelagator. Patch 1334. Tal Einat. + +- ScriptBinding event handlers weren't returning 'break'. Patch 2050, Tal Einat. + - There was an error on exit if no sys.exitfunc was defined. Issue 1647. - Could not open files in .idlerc directory if latter was hidden on Windows. diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py index ae530e5..226c66c 100644 --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -55,11 +55,11 @@ class ScriptBinding: def check_module_event(self, event): filename = self.getfilename() if not filename: - return + return 'break' if not self.checksyntax(filename): - return + return 'break' if not self.tabnanny(filename): - return + return 'break' def tabnanny(self, filename): f = open(filename, 'r') @@ -120,12 +120,12 @@ class ScriptBinding: """ filename = self.getfilename() if not filename: - return + return 'break' code = self.checksyntax(filename) if not code: - return + return 'break' if not self.tabnanny(filename): - return + return 'break' shell = self.shell interp = shell.interp if PyShell.use_subprocess: @@ -148,6 +148,7 @@ class ScriptBinding: # go to __stderr__. With subprocess, they go to the shell. # Need to change streams in PyShell.ModifiedInterpreter. interp.runcode(code) + return 'break' def getfilename(self): """Get source filename. If not saved, offer to save (or create) file diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py index d0e4066..b750dcd 100644 --- a/Lib/idlelib/configDialog.py +++ b/Lib/idlelib/configDialog.py @@ -1114,15 +1114,12 @@ class ConfigDialog(Toplevel): def ActivateConfigChanges(self): "Dynamically apply configuration changes" winInstances = self.parent.instance_dict.keys() - theme = idleConf.CurrentTheme() - cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg') for instance in winInstances: instance.ResetColorizer() instance.ResetFont() instance.set_notabs_indentwidth() instance.ApplyKeybindings() instance.reset_help_menu_entries() - instance.text.configure(insertbackground=cursor_color) def Cancel(self): self.destroy() diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index 42dc3cf..fbed4f2 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -4,6 +4,8 @@ from test import test_support from random import random from math import atan2 +INF = float("inf") +NAN = float("nan") # These tests ensure that complex math does the right thing class ComplexTest(unittest.TestCase): @@ -316,6 +318,18 @@ class ComplexTest(unittest.TestCase): self.assertEqual(-6j,complex(repr(-6j))) self.assertEqual(6j,complex(repr(6j))) + self.assertEqual(repr(complex(1., INF)), "(1+inf*j)") + self.assertEqual(repr(complex(1., -INF)), "(1-inf*j)") + self.assertEqual(repr(complex(INF, 1)), "(inf+1j)") + self.assertEqual(repr(complex(-INF, INF)), "(-inf+inf*j)") + self.assertEqual(repr(complex(NAN, 1)), "(nan+1j)") + self.assertEqual(repr(complex(1, NAN)), "(1+nan*j)") + self.assertEqual(repr(complex(NAN, NAN)), "(nan+nan*j)") + + self.assertEqual(repr(complex(0, INF)), "inf*j") + self.assertEqual(repr(complex(0, -INF)), "-inf*j") + self.assertEqual(repr(complex(0, NAN)), "nan*j") + def test_neg(self): self.assertEqual(-(1+6j), -1-6j) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index d28a84a..288afd4 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1067,6 +1067,23 @@ order (MRO) for bases """ a.foo = 42 self.assertEqual(a.__dict__, {"foo": 42}) + def test_slots_descriptor(self): + # Issue2115: slot descriptors did not correctly check + # the type of the given object + import abc + class MyABC(metaclass=abc.ABCMeta): + __slots__ = "a" + + class Unrelated(object): + pass + MyABC.register(Unrelated) + + u = Unrelated() + self.assert_(isinstance(u, MyABC)) + + # This used to crash + self.assertRaises(TypeError, MyABC.a.__set__, u, 3) + def test_dynamics(self): # Testing class attribute propagation... class D(object): diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index bae0038..9d5e0ea 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -236,21 +236,33 @@ class GCTests(unittest.TestCase): gc.disable() gc.set_threshold(*thresholds) + # The following two tests are fragile: + # They precisely count the number of allocations, + # which is highly implementation-dependent. + # For example: + # - disposed tuples are not freed, but reused + # - the call to assertEqual somehow avoids building its args tuple def test_get_count(self): + # Avoid future allocation of method object + assertEqual = self.assertEqual gc.collect() - self.assertEqual(gc.get_count(), (0, 0, 0)) + assertEqual(gc.get_count(), (0, 0, 0)) a = dict() - self.assertEqual(gc.get_count(), (1, 0, 0)) + # since gc.collect(), we created two objects: + # the dict, and the tuple returned by get_count() + assertEqual(gc.get_count(), (2, 0, 0)) def test_collect_generations(self): + # Avoid future allocation of method object + assertEqual = self.assertEqual gc.collect() a = dict() gc.collect(0) - self.assertEqual(gc.get_count(), (0, 1, 0)) + assertEqual(gc.get_count(), (0, 1, 0)) gc.collect(1) - self.assertEqual(gc.get_count(), (0, 0, 1)) + assertEqual(gc.get_count(), (0, 0, 1)) gc.collect(2) - self.assertEqual(gc.get_count(), (0, 0, 0)) + assertEqual(gc.get_count(), (0, 0, 0)) def test_trashcan(self): class Ouch: diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index f6ee371..c3f7dbb 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -425,6 +425,13 @@ class MmapTests(unittest.TestCase): return mmap.mmap.__new__(klass, -1, *args, **kwargs) anon_mmap(PAGESIZE) + def test_prot_readonly(self): + mapsize = 10 + open(TESTFN, "wb").write(b"a"*mapsize) + f = open(TESTFN, "rb") + m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ) + self.assertRaises(TypeError, m.write, "foo") + def test_main(): run_unittest(MmapTests) @@ -12,6 +12,39 @@ What's New in Python 3.0a3? Core and Builtins ----------------- +<<<<<<< .working +======= +- Issue #2115: Important speedup in setting __slot__ attributes. Also + prevent a possible crash: an Abstract Base Class would try to access a slot + on a registered virtual subclass. + +- Fixed repr() and str() of complex numbers with infinity or nan as real or + imaginary part. + +- Clear all free list during a gc.collect() of the highest generation in order + to allow pymalloc to free more arenas. Python may give back memory to the + OS earlier. + +- Issue #2045: Fix an infinite recursion triggered when printing a subclass of + collections.defaultdict, if its default_factory is set to a bound method. + +- Fixed a minor memory leak in dictobject.c. The content of the free + list was not freed on interpreter shutdown. + +- Limit free list of method and builtin function objects to 256 entries + each. + +- Patch #1953: Added ``sys._compact_freelists()`` and the C API functions + ``PyInt_CompactFreeList`` and ``PyFloat_CompactFreeList`` + to compact the internal free lists of pre-allocted ints and floats. + +- Bug #1983: Fixed return type of fork(), fork1() and forkpty() calls. + Python expected the return type int but the fork familie returns pi_t. + +- Issue #1678380: Fix a bug that identifies 0j and -0j when they appear + in the same code unit. + +>>>>>>> .merge-right.r60845 - Issue #2025 : Add tuple.count() and tuple.index() methods to comply with the collections.Sequence API. @@ -67,7 +100,13 @@ Core and Builtins Extension Modules ----------------- +<<<<<<< .working - Issue #1762972: Readded the reload() function as imp.reload() +======= +- Bug #2111: mmap segfaults when trying to write a block opened with PROT_READ + +- #2063: correct order of utime and stime in os.times() result on Windows. +>>>>>>> .merge-right.r60845 Library diff --git a/Misc/build.sh b/Misc/build.sh index 91a8cbc..70034c4 100755 --- a/Misc/build.sh +++ b/Misc/build.sh @@ -92,6 +92,24 @@ update_status() { echo "<li><a href=\"$2\">$1</a> <font size=\"-1\">($time seconds)</font></li>" >> $RESULT_FILE } +place_summary_first() { + testf=$1 + sed -n '/^[0-9][0-9]* tests OK\./,$p' < $testf \ + | egrep -v '\[[0-9]+ refs\]' > $testf.tmp + echo "" >> $testf.tmp + cat $testf >> $testf.tmp + mv $testf.tmp $testf +} + +count_failures () { + testf=$1 + n=`grep -ic " failed:" $testf` + if [ $n -eq 1 ] ; then + n=`grep " failed:" $testf | sed -e 's/ .*//'` + fi + echo $n +} + mail_on_failure() { if [ "$NUM_FAILURES" != "0" ]; then dest=$FAILURE_MAILTO @@ -187,14 +205,16 @@ if [ $err = 0 -a "$BUILD_DISABLED" != "yes" ]; then F=make-test.out start=`current_time` $PYTHON $REGRTEST_ARGS $ALWAYS_SKIP >& build/$F - NUM_FAILURES=`grep -ic " failed:" build/$F` + NUM_FAILURES=`count_failures build/$F` + place_summary_first build/$F update_status "Testing basics ($NUM_FAILURES failures)" "$F" $start mail_on_failure "basics" build/$F F=make-test-opt.out start=`current_time` $PYTHON -O $REGRTEST_ARGS $ALWAYS_SKIP >& build/$F - NUM_FAILURES=`grep -ic " failed:" build/$F` + NUM_FAILURES=`count_failures build/$F` + place_summary_first build/$F update_status "Testing opt ($NUM_FAILURES failures)" "$F" $start mail_on_failure "opt" build/$F @@ -206,6 +226,7 @@ if [ $err = 0 -a "$BUILD_DISABLED" != "yes" ]; then $PYTHON $REGRTEST_ARGS -R 4:3:$REFLOG -u network $LEAKY_SKIPS >& build/$F LEAK_PAT="($LEAKY_TESTS|sum=0)" NUM_FAILURES=`egrep -vc "$LEAK_PAT" $REFLOG` + place_summary_first build/$F update_status "Testing refleaks ($NUM_FAILURES failures)" "$F" $start mail_on_failure "refleak" $REFLOG "$LEAK_PAT" @@ -215,7 +236,8 @@ if [ $err = 0 -a "$BUILD_DISABLED" != "yes" ]; then ## skip curses when running from cron since there's no terminal ## skip sound since it's not setup on the PSF box (/dev/dsp) $PYTHON $REGRTEST_ARGS -uall -x test_curses test_linuxaudiodev test_ossaudiodev $_ALWAYS_SKIP >& build/$F - NUM_FAILURES=`grep -ic " failed:" build/$F` + NUM_FAILURES=`count_failures build/$F` + place_summary_first build/$F update_status "Testing all except curses and sound ($NUM_FAILURES failures)" "$F" $start mail_on_failure "all" build/$F fi diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index d449a2b..f332231 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -19,6 +19,7 @@ */ #include "Python.h" +#include "frameobject.h" /* for PyFrame_ClearFreeList */ /* Get an object's GC head */ #define AS_GC(o) ((PyGC_Head *)(o)-1) @@ -687,6 +688,21 @@ delete_garbage(PyGC_Head *collectable, PyGC_Head *old) } } +/* Clear all free lists + * All free lists are cleared during the collection of the highest generation. + * Allocated items in the free list may keep a pymalloc arena occupied. + * Clearing the free lists may give back memory to the OS earlier. + */ +static void +clear_freelists(void) +{ + (void)PyMethod_ClearFreeList(); + (void)PyFrame_ClearFreeList(); + (void)PyCFunction_ClearFreeList(); + (void)PyTuple_ClearFreeList(); + (void)PyUnicode_ClearFreeList(); +} + /* This is the main function. Read this to understand how the * collection process works. */ static Py_ssize_t @@ -839,6 +855,12 @@ collect(int generation) */ (void)handle_finalizers(&finalizers, old); + /* Clear free list only during the collection of the higest + * generation */ + if (generation == NUM_GENERATIONS-1) { + clear_freelists(); + } + if (PyErr_Occurred()) { if (gc_str == NULL) gc_str = PyUnicode_FromString("garbage collection"); diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index c83af0d..b77dda5 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1043,6 +1043,10 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) "mmap invalid access parameter."); } + if (prot == PROT_READ) { + access = ACCESS_READ; + } + #ifdef HAVE_FSTAT # ifdef __VMS /* on OpenVMS we must ensure that all bytes are written to the file */ diff --git a/Objects/abstract.c b/Objects/abstract.c index b50b43e..bb6c301 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1405,13 +1405,19 @@ PyNumber_Float(PyObject *o) PyObject * PyNumber_ToBase(PyObject *n, int base) { - PyObject *res; + PyObject *res = NULL; PyObject *index = PyNumber_Index(n); if (!index) return NULL; - assert(PyLong_Check(index)); - res = _PyLong_Format(index, base); + if (PyLong_Check(index)) + res = _PyLong_Format(index, base); + else + /* It should not be possible to get here, as + PyNumber_Index already has a check for the same + condition */ + PyErr_SetString(PyExc_ValueError, "PyNumber_ToBase: index not " + "int or long"); Py_DECREF(index); return res; } @@ -2540,10 +2546,17 @@ recursive_isinstance(PyObject *inst, PyObject *cls, int recursion_depth) int PyObject_IsInstance(PyObject *inst, PyObject *cls) { + static PyObject *name = NULL; PyObject *t, *v, *tb; PyObject *checker; PyErr_Fetch(&t, &v, &tb); - checker = PyObject_GetAttrString(cls, "__instancecheck__"); + + if (name == NULL) { + name = PyUnicode_InternFromString("__instancecheck__"); + if (name == NULL) + return -1; + } + checker = PyObject_GetAttr(cls, name); PyErr_Restore(t, v, tb); if (checker != NULL) { PyObject *res; @@ -2611,10 +2624,17 @@ recursive_issubclass(PyObject *derived, PyObject *cls, int recursion_depth) int PyObject_IsSubclass(PyObject *derived, PyObject *cls) { + static PyObject *name = NULL; PyObject *t, *v, *tb; PyObject *checker; PyErr_Fetch(&t, &v, &tb); - checker = PyObject_GetAttrString(cls, "__subclasscheck__"); + + if (name == NULL) { + name = PyUnicode_InternFromString("__subclasscheck__"); + if (name == NULL) + return -1; + } + checker = PyObject_GetAttr(cls, name); PyErr_Restore(t, v, tb); if (checker != NULL) { PyObject *res; diff --git a/Objects/classobject.c b/Objects/classobject.c index be7ba2d..0e131eb 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -382,9 +382,11 @@ PyTypeObject PyMethod_Type = { /* Clear out the free list */ -void -PyMethod_Fini(void) +int +PyMethod_ClearFreeList(void) { + int freelist_size = numfree; + while (free_list) { PyMethodObject *im = free_list; free_list = (PyMethodObject *)(im->im_self); @@ -392,6 +394,13 @@ PyMethod_Fini(void) numfree--; } assert(numfree == 0); + return freelist_size; +} + +void +PyMethod_Fini(void) +{ + (void)PyMethod_ClearFreeList(); } /* ------------------------------------------------------------------------ diff --git a/Objects/complexobject.c b/Objects/complexobject.c index a08253e..a47cd54 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -314,16 +314,49 @@ complex_to_buf(char *buf, int bufsz, PyComplexObject *v, int precision) { char format[32]; if (v->cval.real == 0.) { - PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); - PyOS_ascii_formatd(buf, bufsz - 1, format, v->cval.imag); - strncat(buf, "j", 1); + if (!Py_IS_FINITE(v->cval.imag)) { + if (Py_IS_NAN(v->cval.imag)) + strncpy(buf, "nan*j", 6); + /* else if (copysign(1, v->cval.imag) == 1) */ + else if (v->cval.imag > 0) + strncpy(buf, "inf*j", 6); + else + strncpy(buf, "-inf*j", 7); + } + else { + PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); + PyOS_ascii_formatd(buf, bufsz - 1, format, v->cval.imag); + strncat(buf, "j", 1); + } } else { char re[64], im[64]; /* Format imaginary part with sign, real part without */ - PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); - PyOS_ascii_formatd(re, sizeof(re), format, v->cval.real); - PyOS_snprintf(format, sizeof(format), "%%+.%ig", precision); - PyOS_ascii_formatd(im, sizeof(im), format, v->cval.imag); + if (!Py_IS_FINITE(v->cval.real)) { + if (Py_IS_NAN(v->cval.real)) + strncpy(re, "nan", 4); + /* else if (copysign(1, v->cval.real) == 1) */ + else if (v->cval.real > 0) + strncpy(re, "inf", 4); + else + strncpy(re, "-inf", 5); + } + else { + PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); + PyOS_ascii_formatd(re, sizeof(re), format, v->cval.real); + } + if (!Py_IS_FINITE(v->cval.imag)) { + if (Py_IS_NAN(v->cval.imag)) + strncpy(im, "+nan*", 6); + /* else if (copysign(1, v->cval.imag) == 1) */ + else if (v->cval.imag > 0) + strncpy(im, "+inf*", 6); + else + strncpy(im, "-inf*", 6); + } + else { + PyOS_snprintf(format, sizeof(format), "%%+.%ig", precision); + PyOS_ascii_formatd(im, sizeof(im), format, v->cval.imag); + } PyOS_snprintf(buf, bufsz, "(%s%sj)", re, im); } } diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 0926817..17bdf5c 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -168,7 +168,7 @@ descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value, int *pres) { assert(obj != NULL); - if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) { + if (!PyObject_TypeCheck(obj, descr->d_type)) { PyErr_Format(PyExc_TypeError, "descriptor '%V' for '%.100s' objects " "doesn't apply to '%.100s' object", diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 658ce1d..7815f92 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -897,10 +897,11 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) } /* Clear out the free list */ - -void -PyFrame_Fini(void) +int +PyFrame_ClearFreeList(void) { + int freelist_size = numfree; + while (free_list != NULL) { PyFrameObject *f = free_list; free_list = free_list->f_back; @@ -908,6 +909,13 @@ PyFrame_Fini(void) --numfree; } assert(numfree == 0); + return freelist_size; +} + +void +PyFrame_Fini(void) +{ + (void)PyFrame_ClearFreeList(); Py_XDECREF(builtin_object); builtin_object = NULL; } diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 7a82d89..2c1db73 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -319,9 +319,11 @@ Py_FindMethod(PyMethodDef *methods, PyObject *self, const char *name) /* Clear out the free list */ -void -PyCFunction_Fini(void) +int +PyCFunction_ClearFreeList(void) { + int freelist_size = numfree; + while (free_list) { PyCFunctionObject *v = free_list; free_list = (PyCFunctionObject *)(v->m_self); @@ -329,6 +331,13 @@ PyCFunction_Fini(void) numfree--; } assert(numfree == 0); + return freelist_size; +} + +void +PyCFunction_Fini(void) +{ + (void)PyCFunction_ClearFreeList(); } /* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(), diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index df69db9..9a53cfa 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -807,19 +807,18 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) return 0; } -void -PyTuple_Fini(void) +int +PyTuple_ClearFreeList(void) { + int freelist_size = 0; #if PyTuple_MAXSAVESIZE > 0 int i; - - Py_XDECREF(free_list[0]); - free_list[0] = NULL; - for (i = 1; i < PyTuple_MAXSAVESIZE; i++) { PyTupleObject *p, *q; p = free_list[i]; + freelist_size += numfree[i]; free_list[i] = NULL; + numfree[i] = 0; while (p) { q = p; p = (PyTupleObject *)(p->ob_item[0]); @@ -827,6 +826,20 @@ PyTuple_Fini(void) } } #endif + return freelist_size; +} + +void +PyTuple_Fini(void) +{ +#if PyTuple_MAXSAVESIZE > 0 + /* empty tuples are used all over the place and applications may + * rely on the fact that an empty tuple is a singleton. */ + Py_XDECREF(free_list[0]); + free_list[0] = NULL; + + (void)PyTuple_ClearFreeList(); +#endif } /*********************** Tuple Iterator **************************/ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 4f0de1e..86d8b54 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9111,10 +9111,29 @@ void _PyUnicode_Init(void) /* Finalize the Unicode implementation */ +int +PyUnicode_ClearFreeList(void) +{ + int freelist_size = numfree; + PyUnicodeObject *u; + + for (u = free_list; u != NULL;) { + PyUnicodeObject *v = u; + u = *(PyUnicodeObject **)u; + if (v->str) + PyMem_DEL(v->str); + Py_XDECREF(v->defenc); + PyObject_Del(v); + numfree--; + } + free_list = NULL; + assert(numfree == 0); + return freelist_size; +} + void _PyUnicode_Fini(void) { - PyUnicodeObject *u; int i; Py_XDECREF(unicode_empty); @@ -9126,17 +9145,7 @@ _PyUnicode_Fini(void) unicode_latin1[i] = NULL; } } - - for (u = free_list; u != NULL;) { - PyUnicodeObject *v = u; - u = *(PyUnicodeObject **)u; - if (v->str) - PyMem_DEL(v->str); - Py_XDECREF(v->defenc); - PyObject_Del(v); - } - free_list = NULL; - numfree = 0; + (void)PyUnicode_ClearFreeList(); } void |