diff options
35 files changed, 401 insertions, 112 deletions
diff --git a/Doc/c-api/method.rst b/Doc/c-api/method.rst index 9d25571f14..9ee49ba64d 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 14d8eab914..1560717c74 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 eb661fb829..c0e53fb7b5 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 d1d4e45623..bc0eeef2d5 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 886ba65209..448cf6895c 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 3c305ed39a..b2d672ff38 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 afba9645fe..b0845e94f3 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 d37c5ac304..dae9b0923f 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 f6789d1a72..b7eebe5e95 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 05877f9768..d2afe8b6d5 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 48e780e478..cd1d265564 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 018ef2f981..7a887d1d2e 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 39542893d7..5e6c227897 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 f62b7df169..9c5d4c2b71 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 27b2b53d5a..704ea59b32 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 0cd668abf8..e1d9ba3256 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 cd8565ce16..1885421d57 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 ae530e5fa8..226c66ce34 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 d0e4066b29..b750dcd576 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 42dc3cfc75..fbed4f285c 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 d28a84aa6e..288afd48c1 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 bae00381df..9d5e0ea6d0 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 f6ee371750..c3f7dbb5de 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 91a8cbc93d..70034c461c 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 d449a2b9fe..f332231f4d 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 c83af0d5db..b77dda506a 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 b50b43e7e6..bb6c301074 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 be7ba2dbeb..0e131eb1c1 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 a08253e0dc..a47cd549c5 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 0926817b78..17bdf5cdb7 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 658ce1da52..7815f928a4 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 7a82d8942a..2c1db739b6 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 df69db929a..9a53cfa32f 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 4f0de1e24a..86d8b547bf 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  | 
