]> granicus.if.org Git - python/commitdiff
Merged revisions 60481,60485,60489-60492,60494-60496,60498-60499,60501-60503,60505...
authorChristian Heimes <christian@cheimes.de>
Sat, 16 Feb 2008 07:38:31 +0000 (07:38 +0000)
committerChristian Heimes <christian@cheimes.de>
Sat, 16 Feb 2008 07:38:31 +0000 (07:38 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r60790 | raymond.hettinger | 2008-02-14 10:32:45 +0100 (Thu, 14 Feb 2008) | 4 lines

  Add diagnostic message to help figure-out why SocketServer tests occasionally crash
  when trying to remove a pid that in not in the activechildren list.
........
  r60791 | raymond.hettinger | 2008-02-14 11:46:57 +0100 (Thu, 14 Feb 2008) | 1 line

  Add fixed-point examples to the decimal FAQ
........
  r60792 | raymond.hettinger | 2008-02-14 12:01:10 +0100 (Thu, 14 Feb 2008) | 1 line

  Improve rst markup
........
  r60794 | raymond.hettinger | 2008-02-14 12:57:25 +0100 (Thu, 14 Feb 2008) | 1 line

  Show how to remove exponents.
........
  r60795 | raymond.hettinger | 2008-02-14 13:05:42 +0100 (Thu, 14 Feb 2008) | 1 line

  Fix markup.
........
  r60797 | christian.heimes | 2008-02-14 13:47:33 +0100 (Thu, 14 Feb 2008) | 1 line

  Implemented Martin's suggestion to clear the free lists during the garbage collection of the highest generation.
........
  r60798 | raymond.hettinger | 2008-02-14 13:49:37 +0100 (Thu, 14 Feb 2008) | 1 line

  Simplify moneyfmt() recipe.
........
  r60810 | raymond.hettinger | 2008-02-14 20:02:39 +0100 (Thu, 14 Feb 2008) | 1 line

  Fix markup
........
  r60811 | raymond.hettinger | 2008-02-14 20:30:30 +0100 (Thu, 14 Feb 2008) | 1 line

  No need to register subclass of ABCs.
........
  r60814 | thomas.heller | 2008-02-14 22:00:28 +0100 (Thu, 14 Feb 2008) | 1 line

  Try to correct a markup error that does hide the following paragraph.
........
  r60822 | christian.heimes | 2008-02-14 23:40:11 +0100 (Thu, 14 Feb 2008) | 1 line

  Use a static and interned string for __subclasscheck__ and __instancecheck__ as suggested by Thomas Heller in #2115
........
  r60827 | christian.heimes | 2008-02-15 07:57:08 +0100 (Fri, 15 Feb 2008) | 1 line

  Fixed repr() and str() of complex numbers. Complex suffered from the same problem as floats but I forgot to test and fix them.
........
  r60830 | christian.heimes | 2008-02-15 09:20:11 +0100 (Fri, 15 Feb 2008) | 2 lines

  Bug #2111: mmap segfaults when trying to write a block opened with PROT_READ
  Thanks to Thomas Herve for the fix.
........
  r60835 | eric.smith | 2008-02-15 13:14:32 +0100 (Fri, 15 Feb 2008) | 1 line

  In PyNumber_ToBase, changed from an assert to returning an error when PyObject_Index() returns something other than an int or long.  It should never be possible to trigger this, as PyObject_Index checks to make sure it returns an int or long.
........
  r60837 | skip.montanaro | 2008-02-15 20:03:59 +0100 (Fri, 15 Feb 2008) | 8 lines

  Two new functions:

    * place_summary_first copies the regrtest summary to the front of the file
      making it easier to scan quickly for problems.

    * count_failures gets the actual count of the number of failing tests, not
      just a 1 (some failures) or 0 (no failures).
........
  r60840 | raymond.hettinger | 2008-02-15 22:21:25 +0100 (Fri, 15 Feb 2008) | 1 line

  Update example to match the current syntax.
........
  r60841 | amaury.forgeotdarc | 2008-02-15 22:22:45 +0100 (Fri, 15 Feb 2008) | 8 lines

  Issue #2115: __slot__ attributes setting was 10x slower.
  Also correct a possible crash using ABCs.

  This change is exactly the same as an optimisation
  done 5 years ago, but on slot *access*:
  http://svn.python.org/view?view=rev&rev=28297
........
  r60842 | amaury.forgeotdarc | 2008-02-15 22:27:44 +0100 (Fri, 15 Feb 2008) | 2 lines

  Temporarily let these tests pass
........
  r60843 | kurt.kaiser | 2008-02-15 22:56:36 +0100 (Fri, 15 Feb 2008) | 2 lines

  ScriptBinding event handlers weren't returning 'break'. Patch 2050, Tal Einat.
........
  r60844 | kurt.kaiser | 2008-02-15 23:25:09 +0100 (Fri, 15 Feb 2008) | 4 lines

  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.
........
  r60845 | amaury.forgeotdarc | 2008-02-15 23:44:20 +0100 (Fri, 15 Feb 2008) | 9 lines

  Re-enable tests, they were failing since gc.collect() clears the various freelists.
  They still remain fragile.

  For example, a call to assertEqual currently does not make any allocation
  (which surprised me at first).
  But this can change when gc.collect also deletes the numerous "zombie frames"
  attached to each function.
........

35 files changed:
Doc/c-api/method.rst
Doc/c-api/set.rst
Doc/c-api/tuple.rst
Doc/c-api/type.rst
Doc/c-api/unicode.rst
Doc/library/ctypes.rst
Doc/library/decimal.rst
Doc/whatsnew/2.6.rst
Include/classobject.h
Include/frameobject.h
Include/methodobject.h
Include/tupleobject.h
Include/unicodeobject.h
Lib/SocketServer.py
Lib/UserString.py
Lib/idlelib/EditorWindow.py
Lib/idlelib/NEWS.txt
Lib/idlelib/ScriptBinding.py
Lib/idlelib/configDialog.py
Lib/test/test_complex.py
Lib/test/test_descr.py
Lib/test/test_gc.py
Lib/test/test_mmap.py
Misc/NEWS
Misc/build.sh
Modules/gcmodule.c
Modules/mmapmodule.c
Objects/abstract.c
Objects/classobject.c
Objects/complexobject.c
Objects/descrobject.c
Objects/frameobject.c
Objects/methodobject.c
Objects/tupleobject.c
Objects/unicodeobject.c

index 9d25571f1444515eb427af7a27c119f9de943d05..9ee49ba64d33a5ea4db26c0b2c1d67f565a60422 100644 (file)
@@ -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.
+
index 14d8eab914b2c66f73f1bfa91387ed924b628243..1560717c7469eb369cfb995493fdba0a4c4e6522 100644 (file)
@@ -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
index eb661fb82926fbff14592af480b95bec9d937c3e..c0e53fb7b5be56c1663b8f954d525b2912efc212 100644 (file)
@@ -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.
index d1d4e456231ade1cd0c0caed75f6833ef9cc00a1..bc0eeef2d5754c95c4c75ea6674a35bac45102ef 100644 (file)
@@ -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)
 
index 886ba65209c5bf951657e33f70a4142dbe52bb6b..448cf6895cc8e8ea063da0aefad82443729a6376 100644 (file)
@@ -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.
index 3c305ed39a77138ee3b9f304ba3dff7d25d0feae..b2d672ff38098fa6353b9510331f2b5e91339b94 100644 (file)
@@ -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.
 
index afba9645fef069afae5f37ccfae6c87679c9a655..b0845e94f36cbe38179d8ab8e1e93f2f6b4beff1 100644 (file)
@@ -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
index d37c5ac3042a2784417050216914fb9bd206e482..dae9b0923f32cf768230adab543bb672a555f5a4 100644 (file)
@@ -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)
 
index f6789d1a729e16baf6153c6b23d238e54351d669..b7eebe5e952e125504e8df0ac47e3448b280fcb9 100644 (file)
@@ -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
index 05877f976848138262d9136f8439dbb885d21fa3..d2afe8b6d5bf99d65a2ce9e7381dd2627cdf2b8d 100644 (file)
@@ -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
index 48e780e47823877f1fac72197de13a47e09f8418..cd1d2655640fdb7922aa859b0e5149ead648af4d 100644 (file)
@@ -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
index 018ef2f981103ea9ffb651be358183918066bc25..7a887d1d2eb17f1287de608c3172404780d502c5 100644 (file)
@@ -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
index 39542893d7a09c28dfd65c58974d253a49884e17..5e6c22789738e924d90a8a2dc96331d977f28f76 100644 (file)
@@ -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 {
index f62b7df1696e7e2b7706e930de98a62e0ef4d0ff..9c5d4c2b7162d72b23aeac45ed5e09a9a7ed9a40 100644 (file)
@@ -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.
index 27b2b53d5a66ea50a0192d7003926cd977deab2a..704ea59b32a3b5c5bd2d92465fa21760196be026 100755 (executable)
@@ -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
 
index 0cd668abf8a1e1428d51d2980ceebbb5ebc2eceb..e1d9ba3256f8be8237c0950ace4c97411e1856f4 100644 (file)
@@ -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 + "_"
 
index cd8565ce1674e60ac95bd949662a4198488caf01..1885421d57609240c91fd6cd224d311b5d2844c4 100644 (file)
@@ -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.
index ae530e5fa851700cf9df4a8df56f65d3f9d09a56..226c66ce34af215a5948ccd9b50bb96181f3e109 100644 (file)
@@ -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
index d0e4066b295cc45d4fc6dd6707b3ae5e5176915c..b750dcd5767c68c52d6fc98f19300d1356a7625f 100644 (file)
@@ -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()
index 42dc3cfc75d06abd1d3359e45c3cb1a941acc84b..fbed4f285c6c94fa9fc14ec2459ce26d5c7ef28e 100644 (file)
@@ -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)
 
index d28a84aa6e949c71e8dde7ac3796a06d2196068c..288afd48c1026df949c0b77ca145d5333cd72694 100644 (file)
@@ -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):
index bae00381dfc7c18131641ca656e2fee8f120912d..9d5e0ea6d082459bfb73a9f4c8adedb62f9fcf21 100644 (file)
@@ -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:
index f6ee3717504d4ef9dd4be9d3c20cfcf7b0ce4ed1..c3f7dbb5de48f5cbd41e14f3002556d15ff5c41d 100644 (file)
@@ -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)
index 9ef34070fef484e1f2b809e3c125fd69fe08749a..9025aa4e41f5ffd7d7f27e3d065647d9f1b624fd 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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
index 91a8cbc93dccaa6df371ab7142d82a49bad9bf39..70034c461c7aeada669a2b62ef1ab6fffd9a5c34 100755 (executable)
@@ -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
index d449a2b9fef2403ce23f2997c86fe055e72d2ecd..f332231f4d1368cf64e8793eeffe32a0f0430e44 100644 (file)
@@ -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");
index c83af0d5db235a5a15cd660b4269119b65615769..b77dda506a351e2e136fdfae3b8c6e83142e20de 100644 (file)
@@ -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 */
index b50b43e7e6934c627c24d54612d1a3c685b3d9f3..bb6c301074f6e07b856524235a0ec7baace9fc6d 100644 (file)
@@ -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;
index be7ba2dbeb697448b5729b7de5cb68ba749bb006..0e131eb1c1bf6c34bc539a4df6a2f830d49d07c2 100644 (file)
@@ -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();
 }
 
 /* ------------------------------------------------------------------------
index a08253e0dc5a52f808739e636156f5ec318585ac..a47cd549c558ae06d16cdd82409658e9e89749ba 100644 (file)
@@ -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);
        }
 }
index 0926817b78a756138325950532f55d7f1ee8af82..17bdf5cdb74ced379ddd7b2b7f3379752d474c76 100644 (file)
@@ -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",
index 658ce1da52402f9c286538b7326fb63e99162b4e..7815f928a42773e83cc809280686618b694103ac 100644 (file)
@@ -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;
 }
index 7a82d8942af7862419e9e681b94678bc4a344642..2c1db739b6a799905042eb953108f62aa881908c 100644 (file)
@@ -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(),
index df69db929a0431b23142b67ba5bc78c53aebaadc..9a53cfa32f9a0912d7eddb2ad1e504e761de7a6a 100644 (file)
@@ -807,25 +807,38 @@ _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]);
                        PyObject_GC_Del(q);
                }
        }
+#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
 }
 
index 4f0de1e24a46dd45295f959b2a9225e785bacefa..86d8b547bfd225c8448c55f3f4ca71a967e369f9 100644 (file)
@@ -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