summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/concrete.rst14
-rw-r--r--Doc/c-api/utilities.rst8
-rw-r--r--Doc/library/collections.rst4
-rw-r--r--Doc/library/curses.rst13
-rw-r--r--Doc/library/logging.rst112
-rw-r--r--Doc/library/rational.rst14
-rw-r--r--Lib/email/mime/multipart.py6
-rw-r--r--Lib/email/test/test_email.py3
-rwxr-xr-xLib/rational.py76
-rw-r--r--Lib/test/crashers/weakref_in_del.py17
-rw-r--r--Lib/test/test_rational.py69
-rw-r--r--Lib/test/test_threading_local.py44
-rw-r--r--Modules/_sre.c3
-rw-r--r--Objects/complexobject.c68
14 files changed, 312 insertions, 139 deletions
diff --git a/Doc/c-api/concrete.rst b/Doc/c-api/concrete.rst
index cc5c9d5..343223c 100644
--- a/Doc/c-api/concrete.rst
+++ b/Doc/c-api/concrete.rst
@@ -1259,7 +1259,7 @@ These are the UTF-8 codec APIs:
.. cfunction:: PyObject* PyUnicode_AsUTF8String(PyObject *unicode)
- Encode a Unicode objects using UTF-8 and return the result as Python string
+ Encode a Unicode object using UTF-8 and return the result as Python string
object. Error handling is "strict". Return *NULL* if an exception was raised
by the codec.
@@ -1411,7 +1411,7 @@ These are the "Unicode Escape" codec APIs:
.. cfunction:: PyObject* PyUnicode_AsUnicodeEscapeString(PyObject *unicode)
- Encode a Unicode objects using Unicode-Escape and return the result as Python
+ Encode a Unicode object using Unicode-Escape and return the result as Python
string object. Error handling is "strict". Return *NULL* if an exception was
raised by the codec.
@@ -1435,7 +1435,7 @@ These are the "Raw Unicode Escape" codec APIs:
.. cfunction:: PyObject* PyUnicode_AsRawUnicodeEscapeString(PyObject *unicode)
- Encode a Unicode objects using Raw-Unicode-Escape and return the result as
+ Encode a Unicode object using Raw-Unicode-Escape and return the result as
Python string object. Error handling is "strict". Return *NULL* if an exception
was raised by the codec.
@@ -1459,7 +1459,7 @@ ordinals and only these are accepted by the codecs during encoding.
.. cfunction:: PyObject* PyUnicode_AsLatin1String(PyObject *unicode)
- Encode a Unicode objects using Latin-1 and return the result as Python string
+ Encode a Unicode object using Latin-1 and return the result as Python string
object. Error handling is "strict". Return *NULL* if an exception was raised
by the codec.
@@ -1483,7 +1483,7 @@ codes generate errors.
.. cfunction:: PyObject* PyUnicode_AsASCIIString(PyObject *unicode)
- Encode a Unicode objects using ASCII and return the result as Python string
+ Encode a Unicode object using ASCII and return the result as Python string
object. Error handling is "strict". Return *NULL* if an exception was raised
by the codec.
@@ -1532,7 +1532,7 @@ characters to different code points.
.. cfunction:: PyObject* PyUnicode_AsCharmapString(PyObject *unicode, PyObject *mapping)
- Encode a Unicode objects using the given *mapping* object and return the result
+ Encode a Unicode object using the given *mapping* object and return the result
as Python string object. Error handling is "strict". Return *NULL* if an
exception was raised by the codec.
@@ -1582,7 +1582,7 @@ the user settings on the machine running the codec.
.. cfunction:: PyObject* PyUnicode_AsMBCSString(PyObject *unicode)
- Encode a Unicode objects using MBCS and return the result as Python string
+ Encode a Unicode object using MBCS and return the result as Python string
object. Error handling is "strict". Return *NULL* if an exception was raised
by the codec.
diff --git a/Doc/c-api/utilities.rst b/Doc/c-api/utilities.rst
index c30a62a..6138c63 100644
--- a/Doc/c-api/utilities.rst
+++ b/Doc/c-api/utilities.rst
@@ -201,12 +201,12 @@ Importing Modules
.. cfunction:: PyObject* PyImport_ImportModuleNoBlock(const char *name)
This version of :cfunc:`PyImport_ImportModule` does not block. It's intended
- to be used in C function which import other modules to execute a function.
+ to be used in C functions that import other modules to execute a function.
The import may block if another thread holds the import lock. The function
- :cfunc:`PyImport_ImportModuleNoBlock` doesn't block. It first tries to fetch
+ :cfunc:`PyImport_ImportModuleNoBlock` never blocks. It first tries to fetch
the module from sys.modules and falls back to :cfunc:`PyImport_ImportModule`
- unless the the lock is hold. In the latter case the function raises an
- ImportError.
+ unless the lock is held, in which case the function will raise an
+ :exc:`ImportError`.
.. cfunction:: PyObject* PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist)
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index cbc9c6b..d138d23 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -579,8 +579,8 @@ Default values can be implemented by using :meth:`_replace` to
customize a prototype instance::
>>> Account = namedtuple('Account', 'owner balance transaction_count')
- >>> model_account = Account('<owner name>', 0.0, 0)
- >>> johns_account = model_account._replace(owner='John')
+ >>> default_account = Account('<owner name>', 0.0, 0)
+ >>> johns_account = default_account._replace(owner='John')
.. rubric:: Footnotes
diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst
index 07ccc55..7f82bca 100644
--- a/Doc/library/curses.rst
+++ b/Doc/library/curses.rst
@@ -16,6 +16,19 @@ for DOS, OS/2, and possibly other systems as well. This extension module is
designed to match the API of ncurses, an open-source curses library hosted on
Linux and the BSD variants of Unix.
+.. note::
+
+ Since version 5.4, the ncurses library decides how to interpret non-ASCII data
+ using the ``nl_langinfo`` function. That means that you have to call
+ :func:`locale.setlocale` in the application and encode Unicode strings
+ using one of the system's available encodings. This example uses the
+ system's default encoding::
+
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+ code = locale.getpreferredencoding()
+
+ Then use *code* as the encoding for :meth:`str.encode` calls.
.. seealso::
diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst
index 258bb0a..923d9f2 100644
--- a/Doc/library/logging.rst
+++ b/Doc/library/logging.rst
@@ -1179,65 +1179,65 @@ to do what you need. Here's an example script which uses this class, which
also illustrates what dict-like behaviour is needed from an arbitrary
"dict-like" object for use in the constructor::
-import logging
-
-class ConnInfo:
- """
- An example class which shows how an arbitrary class can be used as
- the 'extra' context information repository passed to a LoggerAdapter.
- """
-
- def __getitem__(self, name):
- """
- To allow this instance to look like a dict.
- """
- from random import choice
- if name == "ip":
- result = choice(["127.0.0.1", "192.168.0.1"])
- elif name == "user":
- result = choice(["jim", "fred", "sheila"])
- else:
- result = self.__dict__.get(name, "?")
- return result
-
- def __iter__(self):
- """
- To allow iteration over keys, which will be merged into
- the LogRecord dict before formatting and output.
- """
- keys = ["ip", "user"]
- keys.extend(self.__dict__.keys())
- return keys.__iter__()
-
-if __name__ == "__main__":
- from random import choice
- levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
- a1 = logging.LoggerAdapter(logging.getLogger("a.b.c"),
- { "ip" : "123.231.231.123", "user" : "sheila" })
- logging.basicConfig(level=logging.DEBUG,
- format="%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s")
- a1.debug("A debug message")
- a1.info("An info message with %s", "some parameters")
- a2 = logging.LoggerAdapter(logging.getLogger("d.e.f"), ConnInfo())
- for x in range(10):
- lvl = choice(levels)
- lvlname = logging.getLevelName(lvl)
- a2.log(lvl, "A message at %s level with %d %s", lvlname, 2, "parameters")
+ import logging
+
+ class ConnInfo:
+ """
+ An example class which shows how an arbitrary class can be used as
+ the 'extra' context information repository passed to a LoggerAdapter.
+ """
+
+ def __getitem__(self, name):
+ """
+ To allow this instance to look like a dict.
+ """
+ from random import choice
+ if name == "ip":
+ result = choice(["127.0.0.1", "192.168.0.1"])
+ elif name == "user":
+ result = choice(["jim", "fred", "sheila"])
+ else:
+ result = self.__dict__.get(name, "?")
+ return result
+
+ def __iter__(self):
+ """
+ To allow iteration over keys, which will be merged into
+ the LogRecord dict before formatting and output.
+ """
+ keys = ["ip", "user"]
+ keys.extend(self.__dict__.keys())
+ return keys.__iter__()
+
+ if __name__ == "__main__":
+ from random import choice
+ levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
+ a1 = logging.LoggerAdapter(logging.getLogger("a.b.c"),
+ { "ip" : "123.231.231.123", "user" : "sheila" })
+ logging.basicConfig(level=logging.DEBUG,
+ format="%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s")
+ a1.debug("A debug message")
+ a1.info("An info message with %s", "some parameters")
+ a2 = logging.LoggerAdapter(logging.getLogger("d.e.f"), ConnInfo())
+ for x in range(10):
+ lvl = choice(levels)
+ lvlname = logging.getLevelName(lvl)
+ a2.log(lvl, "A message at %s level with %d %s", lvlname, 2, "parameters")
When this script is run, the output should look something like this::
-2008-01-18 14:49:54,023 a.b.c DEBUG IP: 123.231.231.123 User: sheila A debug message
-2008-01-18 14:49:54,023 a.b.c INFO IP: 123.231.231.123 User: sheila An info message with some parameters
-2008-01-18 14:49:54,023 d.e.f CRITICAL IP: 192.168.0.1 User: jim A message at CRITICAL level with 2 parameters
-2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: jim A message at INFO level with 2 parameters
-2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters
-2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: fred A message at ERROR level with 2 parameters
-2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: sheila A message at ERROR level with 2 parameters
-2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters
-2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: jim A message at WARNING level with 2 parameters
-2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: fred A message at INFO level with 2 parameters
-2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters
-2008-01-18 14:49:54,033 d.e.f WARNING IP: 127.0.0.1 User: jim A message at WARNING level with 2 parameters
+ 2008-01-18 14:49:54,023 a.b.c DEBUG IP: 123.231.231.123 User: sheila A debug message
+ 2008-01-18 14:49:54,023 a.b.c INFO IP: 123.231.231.123 User: sheila An info message with some parameters
+ 2008-01-18 14:49:54,023 d.e.f CRITICAL IP: 192.168.0.1 User: jim A message at CRITICAL level with 2 parameters
+ 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: jim A message at INFO level with 2 parameters
+ 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters
+ 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: fred A message at ERROR level with 2 parameters
+ 2008-01-18 14:49:54,033 d.e.f ERROR IP: 127.0.0.1 User: sheila A message at ERROR level with 2 parameters
+ 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters
+ 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: jim A message at WARNING level with 2 parameters
+ 2008-01-18 14:49:54,033 d.e.f INFO IP: 192.168.0.1 User: fred A message at INFO level with 2 parameters
+ 2008-01-18 14:49:54,033 d.e.f WARNING IP: 192.168.0.1 User: sheila A message at WARNING level with 2 parameters
+ 2008-01-18 14:49:54,033 d.e.f WARNING IP: 127.0.0.1 User: jim A message at WARNING level with 2 parameters
.. versionadded:: 2.6
diff --git a/Doc/library/rational.rst b/Doc/library/rational.rst
index dd18305..8ed702f 100644
--- a/Doc/library/rational.rst
+++ b/Doc/library/rational.rst
@@ -15,6 +15,7 @@ Rational number class.
.. class:: Rational(numerator=0, denominator=1)
Rational(other_rational)
+ Rational(string)
The first version requires that *numerator* and *denominator* are
instances of :class:`numbers.Integral` and returns a new
@@ -22,10 +23,12 @@ Rational number class.
*denominator* is :const:`0`, raises a :exc:`ZeroDivisionError`. The
second version requires that *other_rational* is an instance of
:class:`numbers.Rational` and returns an instance of
- :class:`Rational` with the same value.
+ :class:`Rational` with the same value. The third version expects a
+ string of the form ``[-+]?[0-9]+(/[0-9]+)?``, optionally surrounded
+ by spaces.
Implements all of the methods and operations from
- :class:`numbers.Rational` and is hashable.
+ :class:`numbers.Rational` and is immutable and hashable.
.. method:: Rational.from_float(flt)
@@ -36,6 +39,13 @@ Rational number class.
10)``
+.. method:: Rational.from_decimal(dec)
+
+ This classmethod constructs a :class:`Rational` representing the
+ exact value of *dec*, which must be a
+ :class:`decimal.Decimal`.
+
+
.. method:: Rational.__floor__()
Returns the greatest :class:`int` ``<= self``. Will be accessible
diff --git a/Lib/email/mime/multipart.py b/Lib/email/mime/multipart.py
index 5c8c9db..9661865 100644
--- a/Lib/email/mime/multipart.py
+++ b/Lib/email/mime/multipart.py
@@ -34,6 +34,12 @@ class MIMEMultipart(MIMEBase):
keyword arguments (or passed into the _params argument).
"""
MIMEBase.__init__(self, 'multipart', _subtype, **_params)
+
+ # Initialise _payload to an empty list as the Message superclass's
+ # implementation of is_multipart assumes that _payload is a list for
+ # multipart messages.
+ self._payload = []
+
if _subparts:
for p in _subparts:
self.attach(p)
diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py
index c544004..1ca41e9 100644
--- a/Lib/email/test/test_email.py
+++ b/Lib/email/test/test_email.py
@@ -1892,6 +1892,9 @@ message 2
eq(msg.get_payload(0), text1)
eq(msg.get_payload(1), text2)
+ def test_default_multipart_constructor(self):
+ msg = MIMEMultipart()
+ self.assertTrue(msg.is_multipart())
# A general test of parser->model->generator idempotency. IOW, read a message
diff --git a/Lib/rational.py b/Lib/rational.py
index c913ec7..71ffff7 100755
--- a/Lib/rational.py
+++ b/Lib/rational.py
@@ -6,6 +6,7 @@
import math
import numbers
import operator
+import re
__all__ = ["Rational"]
@@ -75,6 +76,10 @@ def _binary_float_to_ratio(x):
return (top, 2 ** -e)
+_RATIONAL_FORMAT = re.compile(
+ r'^\s*(?P<sign>[-+]?)(?P<num>\d+)(?:/(?P<denom>\d+))?\s*$')
+
+
class Rational(RationalAbc):
"""This class implements rational numbers.
@@ -83,18 +88,41 @@ class Rational(RationalAbc):
and the denominator defaults to 1 so that Rational(3) == 3 and
Rational() == 0.
+ Rationals can also be constructed from strings of the form
+ '[-+]?[0-9]+(/[0-9]+)?', optionally surrounded by spaces.
+
"""
__slots__ = ('_numerator', '_denominator')
- def __init__(self, numerator=0, denominator=1):
- if (not isinstance(numerator, numbers.Integral) and
- isinstance(numerator, RationalAbc) and
- denominator == 1):
- # Handle copies from other rationals.
- other_rational = numerator
- numerator = other_rational.numerator
- denominator = other_rational.denominator
+ # We're immutable, so use __new__ not __init__
+ def __new__(cls, numerator=0, denominator=1):
+ """Constructs a Rational.
+
+ Takes a string, another Rational, or a numerator/denominator pair.
+
+ """
+ self = super(Rational, cls).__new__(cls)
+
+ if denominator == 1:
+ if isinstance(numerator, str):
+ # Handle construction from strings.
+ input = numerator
+ m = _RATIONAL_FORMAT.match(input)
+ if m is None:
+ raise ValueError('Invalid literal for Rational: ' + input)
+ numerator = int(m.group('num'))
+ # Default denominator to 1. That's the only optional group.
+ denominator = int(m.group('denom') or 1)
+ if m.group('sign') == '-':
+ numerator = -numerator
+
+ elif (not isinstance(numerator, numbers.Integral) and
+ isinstance(numerator, RationalAbc)):
+ # Handle copies from other rationals.
+ other_rational = numerator
+ numerator = other_rational.numerator
+ denominator = other_rational.denominator
if (not isinstance(numerator, numbers.Integral) or
not isinstance(denominator, numbers.Integral)):
@@ -107,10 +135,15 @@ class Rational(RationalAbc):
g = _gcd(numerator, denominator)
self._numerator = int(numerator // g)
self._denominator = int(denominator // g)
+ return self
@classmethod
def from_float(cls, f):
- """Converts a float to a rational number, exactly."""
+ """Converts a finite float to a rational number, exactly.
+
+ Beware that Rational.from_float(0.3) != Rational(3, 10).
+
+ """
if not isinstance(f, float):
raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
(cls.__name__, f, type(f).__name__))
@@ -118,6 +151,26 @@ class Rational(RationalAbc):
raise TypeError("Cannot convert %r to %s." % (f, cls.__name__))
return cls(*_binary_float_to_ratio(f))
+ @classmethod
+ def from_decimal(cls, dec):
+ """Converts a finite Decimal instance to a rational number, exactly."""
+ from decimal import Decimal
+ if not isinstance(dec, Decimal):
+ raise TypeError(
+ "%s.from_decimal() only takes Decimals, not %r (%s)" %
+ (cls.__name__, dec, type(dec).__name__))
+ if not dec.is_finite():
+ # Catches infinities and nans.
+ raise TypeError("Cannot convert %s to %s." % (dec, cls.__name__))
+ sign, digits, exp = dec.as_tuple()
+ digits = int(''.join(map(str, digits)))
+ if sign:
+ digits = -digits
+ if exp >= 0:
+ return cls(digits * 10 ** exp)
+ else:
+ return cls(digits, 10 ** -exp)
+
@property
def numerator(a):
return a._numerator
@@ -128,15 +181,14 @@ class Rational(RationalAbc):
def __repr__(self):
"""repr(self)"""
- return ('rational.Rational(%r,%r)' %
- (self.numerator, self.denominator))
+ return ('Rational(%r,%r)' % (self.numerator, self.denominator))
def __str__(self):
"""str(self)"""
if self.denominator == 1:
return str(self.numerator)
else:
- return '(%s/%s)' % (self.numerator, self.denominator)
+ return '%s/%s' % (self.numerator, self.denominator)
def _operator_fallbacks(monomorphic_operator, fallback_operator):
"""Generates forward and reverse operators given a purely-rational
diff --git a/Lib/test/crashers/weakref_in_del.py b/Lib/test/crashers/weakref_in_del.py
deleted file mode 100644
index 2e9b186..0000000
--- a/Lib/test/crashers/weakref_in_del.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import weakref
-
-# http://python.org/sf/1377858
-# Fixed for new-style classes in 2.5c1.
-
-ref = None
-
-def test_weakref_in_del():
- class Target():
- def __del__(self):
- global ref
- ref = weakref.ref(self)
-
- w = Target()
-
-if __name__ == '__main__':
- test_weakref_in_del()
diff --git a/Lib/test/test_rational.py b/Lib/test/test_rational.py
index 952a97f..e57adce 100644
--- a/Lib/test/test_rational.py
+++ b/Lib/test/test_rational.py
@@ -45,6 +45,44 @@ class RationalTest(unittest.TestCase):
self.assertRaises(TypeError, R, 1.5)
self.assertRaises(TypeError, R, 1.5 + 3j)
+ self.assertRaises(TypeError, R, R(1, 2), 3)
+ self.assertRaises(TypeError, R, "3/2", 3)
+
+ def testFromString(self):
+ self.assertEquals((5, 1), _components(R("5")))
+ self.assertEquals((3, 2), _components(R("3/2")))
+ self.assertEquals((3, 2), _components(R(" \n +3/2")))
+ self.assertEquals((-3, 2), _components(R("-3/2 ")))
+ self.assertEquals((3, 2), _components(R(" 03/02 \n ")))
+ self.assertEquals((3, 2), _components(R(" 03/02 \n ")))
+
+ self.assertRaisesMessage(
+ ZeroDivisionError, "Rational(3, 0)",
+ R, "3/0")
+ self.assertRaisesMessage(
+ ValueError, "Invalid literal for Rational: 3/",
+ R, "3/")
+ self.assertRaisesMessage(
+ ValueError, "Invalid literal for Rational: 3 /2",
+ R, "3 /2")
+ self.assertRaisesMessage(
+ # Denominators don't need a sign.
+ ValueError, "Invalid literal for Rational: 3/+2",
+ R, "3/+2")
+ self.assertRaisesMessage(
+ # Imitate float's parsing.
+ ValueError, "Invalid literal for Rational: + 3/2",
+ R, "+ 3/2")
+ self.assertRaisesMessage(
+ # Only parse fractions, not decimals.
+ ValueError, "Invalid literal for Rational: 3.2",
+ R, "3.2")
+
+ def testImmutable(self):
+ r = R(7, 3)
+ r.__init__(2, 15)
+ self.assertEquals((7, 3), _components(r))
+
def testFromFloat(self):
self.assertRaisesMessage(
TypeError, "Rational.from_float() only takes floats, not 3 (int)",
@@ -72,6 +110,31 @@ class RationalTest(unittest.TestCase):
TypeError, "Cannot convert nan to Rational.",
R.from_float, nan)
+ def testFromDecimal(self):
+ self.assertRaisesMessage(
+ TypeError,
+ "Rational.from_decimal() only takes Decimals, not 3 (int)",
+ R.from_decimal, 3)
+ self.assertEquals(R(0), R.from_decimal(Decimal("-0")))
+ self.assertEquals(R(5, 10), R.from_decimal(Decimal("0.5")))
+ self.assertEquals(R(5, 1000), R.from_decimal(Decimal("5e-3")))
+ self.assertEquals(R(5000), R.from_decimal(Decimal("5e3")))
+ self.assertEquals(1 - R(1, 10**30),
+ R.from_decimal(Decimal("0." + "9" * 30)))
+
+ self.assertRaisesMessage(
+ TypeError, "Cannot convert Infinity to Rational.",
+ R.from_decimal, Decimal("inf"))
+ self.assertRaisesMessage(
+ TypeError, "Cannot convert -Infinity to Rational.",
+ R.from_decimal, Decimal("-inf"))
+ self.assertRaisesMessage(
+ TypeError, "Cannot convert NaN to Rational.",
+ R.from_decimal, Decimal("nan"))
+ self.assertRaisesMessage(
+ TypeError, "Cannot convert sNaN to Rational.",
+ R.from_decimal, Decimal("snan"))
+
def testConversions(self):
self.assertTypedEquals(-1, trunc(R(-11, 10)))
self.assertTypedEquals(-2, math.floor(R(-11, 10)))
@@ -175,7 +238,7 @@ class RationalTest(unittest.TestCase):
self.assertTypedEquals(1.0 + 0j, (1.0 + 0j) ** R(1, 10))
def testMixingWithDecimal(self):
- """Decimal refuses mixed comparisons."""
+ # Decimal refuses mixed comparisons.
self.assertRaisesMessage(
TypeError,
"unsupported operand type(s) for +: 'Rational' and 'Decimal'",
@@ -238,8 +301,8 @@ class RationalTest(unittest.TestCase):
self.assertFalse(R(5, 2) == 2)
def testStringification(self):
- self.assertEquals("rational.Rational(7,3)", repr(R(7, 3)))
- self.assertEquals("(7/3)", str(R(7, 3)))
+ self.assertEquals("Rational(7,3)", repr(R(7, 3)))
+ self.assertEquals("7/3", str(R(7, 3)))
self.assertEquals("7", str(R(7, 1)))
def testHash(self):
diff --git a/Lib/test/test_threading_local.py b/Lib/test/test_threading_local.py
index 0aaedbc..b7dd538 100644
--- a/Lib/test/test_threading_local.py
+++ b/Lib/test/test_threading_local.py
@@ -1,9 +1,51 @@
import unittest
from doctest import DocTestSuite
from test import test_support
+import threading
+import weakref
+import gc
+
+class Weak(object):
+ pass
+
+def target(local, weaklist):
+ weak = Weak()
+ local.weak = weak
+ weaklist.append(weakref.ref(weak))
+
+class ThreadingLocalTest(unittest.TestCase):
+
+ def test_local_refs(self):
+ self._local_refs(20)
+ self._local_refs(50)
+ self._local_refs(100)
+
+ def _local_refs(self, n):
+ local = threading.local()
+ weaklist = []
+ for i in range(n):
+ t = threading.Thread(target=target, args=(local, weaklist))
+ t.start()
+ t.join()
+ del t
+
+ gc.collect()
+ self.assertEqual(len(weaklist), n)
+
+ # XXX threading.local keeps the local of the last stopped thread alive.
+ deadlist = [weak for weak in weaklist if weak() is None]
+ self.assertEqual(len(deadlist), n-1)
+
+ # Assignment to the same thread local frees it sometimes (!)
+ local.someothervar = None
+ gc.collect()
+ deadlist = [weak for weak in weaklist if weak() is None]
+ self.assert_(len(deadlist) in (n-1, n), (n, len(deadlist)))
def test_main():
- suite = DocTestSuite('_threading_local')
+ suite = unittest.TestSuite()
+ suite.addTest(DocTestSuite('_threading_local'))
+ suite.addTest(unittest.makeSuite(ThreadingLocalTest))
try:
from thread import _local
diff --git a/Modules/_sre.c b/Modules/_sre.c
index b81a8e2..bfe4ae9 100644
--- a/Modules/_sre.c
+++ b/Modules/_sre.c
@@ -2677,7 +2677,7 @@ _compile(PyObject* self_, PyObject* args)
return NULL;
n = PyList_GET_SIZE(code);
-
+ /* coverity[ampersand_in_size] */
self = PyObject_NEW_VAR(PatternObject, &Pattern_Type, n);
if (!self)
return NULL;
@@ -3187,6 +3187,7 @@ pattern_new_match(PatternObject* pattern, SRE_STATE* state, int status)
if (status > 0) {
/* create match object (with room for extra group marks) */
+ /* coverity[ampersand_in_size] */
match = PyObject_NEW_VAR(MatchObject, &Match_Type,
2*(pattern->groups+1));
if (!match)
diff --git a/Objects/complexobject.c b/Objects/complexobject.c
index de4641c..a7bf342 100644
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -375,24 +375,24 @@ complex_hash(PyComplexObject *v)
static int
to_complex(PyObject **pobj, Py_complex *pc)
{
- PyObject *obj = *pobj;
-
- pc->real = pc->imag = 0.0;
- if (PyLong_Check(obj)) {
- pc->real = PyLong_AsDouble(obj);
- if (pc->real == -1.0 && PyErr_Occurred()) {
- *pobj = NULL;
- return -1;
- }
- return 0;
- }
- if (PyFloat_Check(obj)) {
- pc->real = PyFloat_AsDouble(obj);
- return 0;
- }
- Py_INCREF(Py_NotImplemented);
- *pobj = Py_NotImplemented;
- return -1;
+ PyObject *obj = *pobj;
+
+ pc->real = pc->imag = 0.0;
+ if (PyLong_Check(obj)) {
+ pc->real = PyLong_AsDouble(obj);
+ if (pc->real == -1.0 && PyErr_Occurred()) {
+ *pobj = NULL;
+ return -1;
+ }
+ return 0;
+ }
+ if (PyFloat_Check(obj)) {
+ pc->real = PyFloat_AsDouble(obj);
+ return 0;
+ }
+ Py_INCREF(Py_NotImplemented);
+ *pobj = Py_NotImplemented;
+ return -1;
}
@@ -401,8 +401,8 @@ complex_add(PyObject *v, PyObject *w)
{
Py_complex result;
Py_complex a, b;
- TO_COMPLEX(v, a);
- TO_COMPLEX(w, b);
+ TO_COMPLEX(v, a);
+ TO_COMPLEX(w, b);
PyFPE_START_PROTECT("complex_add", return 0)
result = c_sum(a, b);
PyFPE_END_PROTECT(result)
@@ -414,8 +414,8 @@ complex_sub(PyObject *v, PyObject *w)
{
Py_complex result;
Py_complex a, b;
- TO_COMPLEX(v, a);
- TO_COMPLEX(w, b);
+ TO_COMPLEX(v, a);
+ TO_COMPLEX(w, b);
PyFPE_START_PROTECT("complex_sub", return 0)
result = c_diff(a, b);
PyFPE_END_PROTECT(result)
@@ -427,8 +427,8 @@ complex_mul(PyObject *v, PyObject *w)
{
Py_complex result;
Py_complex a, b;
- TO_COMPLEX(v, a);
- TO_COMPLEX(w, b);
+ TO_COMPLEX(v, a);
+ TO_COMPLEX(w, b);
PyFPE_START_PROTECT("complex_mul", return 0)
result = c_prod(a, b);
PyFPE_END_PROTECT(result)
@@ -440,8 +440,8 @@ complex_div(PyObject *v, PyObject *w)
{
Py_complex quot;
Py_complex a, b;
- TO_COMPLEX(v, a);
- TO_COMPLEX(w, b);
+ TO_COMPLEX(v, a);
+ TO_COMPLEX(w, b);
PyFPE_START_PROTECT("complex_div", return 0)
errno = 0;
quot = c_quot(a, b);
@@ -477,8 +477,8 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
Py_complex exponent;
long int_exponent;
Py_complex a, b;
- TO_COMPLEX(v, a);
- TO_COMPLEX(w, b);
+ TO_COMPLEX(v, a);
+ TO_COMPLEX(w, b);
if (z != Py_None) {
PyErr_SetString(PyExc_ValueError, "complex modulo");
@@ -557,8 +557,8 @@ complex_richcompare(PyObject *v, PyObject *w, int op)
{
PyObject *res;
Py_complex i, j;
- TO_COMPLEX(v, i);
- TO_COMPLEX(w, j);
+ TO_COMPLEX(v, i);
+ TO_COMPLEX(w, j);
if (op != Py_EQ && op != Py_NE) {
/* XXX Should eventually return NotImplemented */
@@ -673,11 +673,11 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v)
start = s;
while (*s && isspace(Py_CHARMASK(*s)))
s++;
- if (s[0] == '\0') {
+ if (s[0] == '\0') {
PyErr_SetString(PyExc_ValueError,
"complex() arg is an empty string");
return NULL;
- }
+ }
if (s[0] == '(') {
/* Skip over possible bracket from repr(). */
got_bracket = 1;
@@ -837,7 +837,7 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
"complex() can't take second arg"
" if first is a string");
return NULL;
- }
+ }
return complex_subtype_from_string(type, r);
}
if (i != NULL && PyUnicode_Check(i)) {
@@ -915,7 +915,7 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
cr.real = PyFloat_AsDouble(tmp);
- cr.imag = 0.0; /* Shut up compiler warning */
+ cr.imag = 0.0; /* Shut up compiler warning */
Py_DECREF(tmp);
}
if (i == NULL) {