Index: Objects/complexobject.c =================================================================== --- Objects/complexobject.c (revision 56658) +++ Objects/complexobject.c (working copy) @@ -466,57 +466,18 @@ static PyObject * complex_remainder(PyObject *v, PyObject *w) { - Py_complex div, mod; - Py_complex a, b; - TO_COMPLEX(v, a); - TO_COMPLEX(w, b); - - if (PyErr_Warn(PyExc_DeprecationWarning, - "complex divmod(), // and % are deprecated") < 0) - return NULL; - - errno = 0; - div = c_quot(a, b); /* The raw divisor value. */ - if (errno == EDOM) { - PyErr_SetString(PyExc_ZeroDivisionError, "complex remainder"); - return NULL; - } - div.real = floor(div.real); /* Use the floor of the real part. */ - div.imag = 0.0; - mod = c_diff(a, c_prod(b, div)); - - return PyComplex_FromCComplex(mod); + PyErr_SetString(PyExc_TypeError, + "can't mod complex numbers."); + return NULL; } static PyObject * complex_divmod(PyObject *v, PyObject *w) { - Py_complex div, mod; - PyObject *d, *m, *z; - Py_complex a, b; - TO_COMPLEX(v, a); - TO_COMPLEX(w, b); - - if (PyErr_Warn(PyExc_DeprecationWarning, - "complex divmod(), // and % are deprecated") < 0) - return NULL; - - errno = 0; - div = c_quot(a, b); /* The raw divisor value. */ - if (errno == EDOM) { - PyErr_SetString(PyExc_ZeroDivisionError, "complex divmod()"); - return NULL; - } - div.real = floor(div.real); /* Use the floor of the real part. */ - div.imag = 0.0; - mod = c_diff(a, c_prod(b, div)); - d = PyComplex_FromCComplex(div); - m = PyComplex_FromCComplex(mod); - z = PyTuple_Pack(2, d, m); - Py_XDECREF(d); - Py_XDECREF(m); - return z; + PyErr_SetString(PyExc_TypeError, + "can't take floor or mod of complex number."); + return NULL; } static PyObject * @@ -560,15 +521,8 @@ static PyObject * complex_int_div(PyObject *v, PyObject *w) { - PyObject *t, *r; - - t = complex_divmod(v, w); - if (t != NULL) { - r = PyTuple_GET_ITEM(t, 0); - Py_INCREF(r); - Py_DECREF(t); - return r; - } + PyErr_SetString(PyExc_TypeError, + "can't take floor of complex number."); return NULL; } @@ -665,6 +619,11 @@ return PyComplex_FromCComplex(c); } +PyDoc_STRVAR(complex_conjugate_doc, +"complex.conjugate() -> complex\n" +"\n" +"Returns the complex conjugate of its argument. (3-4j).conjugate() == 3+4j."); + static PyObject * complex_getnewargs(PyComplexObject *v) { @@ -672,7 +631,8 @@ } static PyMethodDef complex_methods[] = { - {"conjugate", (PyCFunction)complex_conjugate, METH_NOARGS}, + {"conjugate", (PyCFunction)complex_conjugate, METH_NOARGS, + complex_conjugate_doc}, {"__getnewargs__", (PyCFunction)complex_getnewargs, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; Index: Objects/longobject.c =================================================================== --- Objects/longobject.c (revision 56658) +++ Objects/longobject.c (working copy) @@ -1985,7 +1985,7 @@ /* forward */ static PyLongObject *x_divrem (PyLongObject *, PyLongObject *, PyLongObject **); -static PyObject *long_pos(PyLongObject *); +static PyObject *long_long(PyObject *v); static int long_divrem(PyLongObject *, PyLongObject *, PyLongObject **, PyLongObject **); @@ -3181,17 +3181,6 @@ } static PyObject * -long_pos(PyLongObject *v) -{ - if (PyLong_CheckExact(v)) { - Py_INCREF(v); - return (PyObject *)v; - } - else - return _PyLong_Copy(v); -} - -static PyObject * long_neg(PyLongObject *v) { PyLongObject *z; @@ -3209,7 +3198,7 @@ if (Py_Size(v) < 0) return long_neg(v); else - return long_pos(v); + return long_long((PyObject *)v); } static int @@ -3496,12 +3485,6 @@ } static PyObject * -long_int(PyObject *v) -{ - return long_long(v); -} - -static PyObject * long_float(PyObject *v) { double result; @@ -3600,11 +3583,38 @@ return Py_BuildValue("(N)", _PyLong_Copy(v)); } +static PyObject * +long_getN(PyLongObject *v, void *context) { + return PyLong_FromLong((intptr_t)context); +} + static PyMethodDef long_methods[] = { + {"conjugate", (PyCFunction)long_long, METH_NOARGS, + "Returns self, the complex conjugate of any int."}, {"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; +static PyGetSetDef long_getseters[] = { + {"real", + (getter)long_long, (setter)NULL, + "the real part of a complex number", + NULL}, + {"imag", + (getter)long_getN, (setter)NULL, + "the imaginary part of a complex number", + (void*)0}, + {"numerator", + (getter)long_long, (setter)NULL, + "the numerator of a rational number in lowest terms", + NULL}, + {"denominator", + (getter)long_getN, (setter)NULL, + "the denominator of a rational number in lowest terms", + (void*)1}, + {NULL} /* Sentinel */ +}; + PyDoc_STRVAR(long_doc, "int(x[, base]) -> integer\n\ \n\ @@ -3622,7 +3632,7 @@ long_divmod, /*nb_divmod*/ long_pow, /*nb_power*/ (unaryfunc) long_neg, /*nb_negative*/ - (unaryfunc) long_pos, /*tp_positive*/ + (unaryfunc) long_long, /*tp_positive*/ (unaryfunc) long_abs, /*tp_absolute*/ (inquiry) long_bool, /*tp_bool*/ (unaryfunc) long_invert, /*nb_invert*/ @@ -3632,7 +3642,7 @@ long_xor, /*nb_xor*/ long_or, /*nb_or*/ 0, /*nb_coerce*/ - long_int, /*nb_int*/ + long_long, /*nb_int*/ long_long, /*nb_long*/ long_float, /*nb_float*/ 0, /*nb_oct*/ /* not used */ @@ -3687,7 +3697,7 @@ 0, /* tp_iternext */ long_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + long_getseters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ Index: Objects/floatobject.c =================================================================== --- Objects/floatobject.c (revision 56658) +++ Objects/floatobject.c (working copy) @@ -694,9 +694,7 @@ * bugs so we have to figure it out ourselves. */ if (iw != floor(iw)) { - PyErr_SetString(PyExc_ValueError, "negative number " - "cannot be raised to a fractional power"); - return NULL; + return PyComplex_Type.tp_as_number->nb_power(v, w, z); } /* iw is an exact integer, albeit perhaps a very large one. * -1 raised to an exact integer should never be exceptional. @@ -743,17 +741,6 @@ } static PyObject * -float_pos(PyFloatObject *v) -{ - if (PyFloat_CheckExact(v)) { - Py_INCREF(v); - return (PyObject *)v; - } - else - return PyFloat_FromDouble(v->ob_fval); -} - -static PyObject * float_abs(PyFloatObject *v) { return PyFloat_FromDouble(fabs(v->ob_fval)); @@ -985,7 +972,15 @@ "Overrides the automatic determination of C-level floating point type.\n" "This affects how floats are converted to and from binary strings."); +static PyObject * +float_getzero(PyObject *v, void *closure) +{ + return PyFloat_FromDouble(0.0); +} + static PyMethodDef float_methods[] = { + {"conjugate", (PyCFunction)float_float, METH_NOARGS, + "Returns self, the complex conjugate of any float."}, {"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS}, {"__getformat__", (PyCFunction)float_getformat, METH_O|METH_CLASS, float_getformat_doc}, @@ -994,6 +989,18 @@ {NULL, NULL} /* sentinel */ }; +static PyGetSetDef float_getseters[] = { + {"real", + (getter)float_float, (setter)NULL, + "the real part of a complex number", + NULL}, + {"imag", + (getter)float_getzero, (setter)NULL, + "the imaginary part of a complex number", + NULL}, + {NULL} /* Sentinel */ +}; + PyDoc_STRVAR(float_doc, "float(x) -> floating point number\n\ \n\ @@ -1008,7 +1015,7 @@ float_divmod, /*nb_divmod*/ float_pow, /*nb_power*/ (unaryfunc)float_neg, /*nb_negative*/ - (unaryfunc)float_pos, /*nb_positive*/ + (unaryfunc)float_float, /*nb_positive*/ (unaryfunc)float_abs, /*nb_absolute*/ (inquiry)float_bool, /*nb_bool*/ 0, /*nb_invert*/ @@ -1069,7 +1076,7 @@ 0, /* tp_iternext */ float_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + float_getseters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ Index: Lib/numbers.py =================================================================== --- Lib/numbers.py (revision 0) +++ Lib/numbers.py (revision 0) @@ -0,0 +1,368 @@ +# Copyright 2007 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141. + +TODO: Fill out more detailed documentation on the operators.""" + +from abc import ABCMeta, abstractmethod, abstractproperty + +__all__ = ["Number", "Exact", "Inexact", + "Complex", "Real", "Rational", "Integral", + ] + + +class Number(metaclass=ABCMeta): + """All numbers inherit from this class. + + If you just want to check if an argument x is a number, without + caring what kind, use isinstance(x, Number). + """ + + +class Exact(Number): + """Operations on instances of this type are exact. + + As long as the result of a homogenous operation is of the same + type, you can assume that it was computed exactly, and there are + no round-off errors. Laws like commutativity and associativity + hold. + """ + +Exact.register(int) + + +class Inexact(Number): + """Operations on instances of this type are inexact. + + Given X, an instance of Inexact, it is possible that (X + -X) + 3 + == 3, but X + (-X + 3) == 0. The exact form this error takes will + vary by type, but it's generally unsafe to compare this type for + equality. + """ + +Inexact.register(complex) +Inexact.register(float) + + +class Complex(Number): + """Complex defines the operations that work on the builtin complex type. + + In short, those are: a conversion to complex, .real, .imag, +, -, + *, /, abs(), .conjugate, ==, and !=. + + If it is given heterogenous arguments, and doesn't have special + knowledge about them, it should fall back to the builtin complex + type as described below. + """ + + @abstractmethod + def __complex__(self): + """Return a builtin complex instance. Called for complex(self).""" + + def __bool__(self): + """True if self != 0. Called for bool(self).""" + return self != 0 + + @abstractproperty + def real(self): + """Retrieve the real component of this number. + + This should subclass Real. + """ + raise NotImplementedError + + @abstractproperty + def imag(self): + """Retrieve the real component of this number. + + This should subclass Real. + """ + raise NotImplementedError + + @abstractmethod + def __add__(self, other): + """self + other""" + raise NotImplementedError + + @abstractmethod + def __radd__(self, other): + """other + self""" + raise NotImplementedError + + @abstractmethod + def __neg__(self): + """-self""" + raise NotImplementedError + + def __pos__(self): + """+self""" + return self + + def __sub__(self, other): + """self - other""" + return self + -other + + def __rsub__(self, other): + """other - self""" + return -self + other + + @abstractmethod + def __mul__(self, other): + """self * other""" + raise NotImplementedError + + @abstractmethod + def __rmul__(self, other): + """other * self""" + raise NotImplementedError + + @abstractmethod + def __div__(self, other): + """self / other""" + raise NotImplementedError + + @abstractmethod + def __rdiv__(self, other): + """other / self""" + raise NotImplementedError + + @abstractmethod + def __pow__(self, exponent): + """Like division, self**exponent should promote to complex when necessary.""" + raise NotImplementedError + + @abstractmethod + def __rpow__(self, base): + """base ** self""" + raise NotImplementedError + + @abstractmethod + def __abs__(self): + """Returns the Real distance from 0. Called for abs(self).""" + raise NotImplementedError + + @abstractmethod + def conjugate(self): + """(x+y*i).conjugate() returns (x-y*i).""" + raise NotImplementedError + + @abstractmethod + def __eq__(self, other): + """self == other""" + raise NotImplementedError + + def __ne__(self, other): + """self != other""" + return not (self == other) + +Complex.register(complex) + + +class Real(Complex): + """To Complex, Real adds the operations that work on real numbers. + + In short, those are: a conversion to float, trunc(), divmod, + %, <, <=, >, and >=. + + Real also provides defaults for the derived operations. + """ + + @abstractmethod + def __float__(self): + """Any Real can be converted to a native float object. + + Called for float(self).""" + raise NotImplementedError + + @abstractmethod + def __trunc__(self): + """trunc(self): Truncates self to an Integral. + + Returns an Integral i such that: + * i>0 iff self>0 + * abs(i) <= abs(self). + """ + raise NotImplementedError + + def __divmod__(self, other): + """divmod(self, other): The pair (self // other, self % other). + + Sometimes this can be computed faster than the pair of + operations. + """ + return (self // other, self % other) + + def __rdivmod__(self, other): + """divmod(other, self): The pair (self // other, self % other). + + Sometimes this can be computed faster than the pair of + operations. + """ + return (other // self, other % self) + + @abstractmethod + def __floordiv__(self, other): + """self // other: The floor() of self/other.""" + raise NotImplementedError + + @abstractmethod + def __rfloordiv__(self, other): + """other // self: The floor() of other/self.""" + raise NotImplementedError + + @abstractmethod + def __mod__(self, other): + """self % other""" + raise NotImplementedError + + @abstractmethod + def __rmod__(self, other): + """other % self""" + raise NotImplementedError + + @abstractmethod + def __lt__(self, other): + """self < other + + < on Reals defines a total ordering, except perhaps for NaN.""" + raise NotImplementedError + + @abstractmethod + def __le__(self, other): + """self <= other""" + raise NotImplementedError + + # Concrete implementations of Complex abstract methods. + def __complex__(self): + """complex(self) == complex(float(self), 0)""" + return complex(float(self)) + + @property + def real(self): + """Real numbers are their real component.""" + return self + + @property + def imag(self): + """Real numbers have no imaginary component.""" + return 0 + + def conjugate(self): + """Conjugate is a no-op for Reals.""" + return self + +Real.register(float) + + +class Rational(Real, Exact): + """.numerator and .denominator should be in lowest terms.""" + + @abstractproperty + def numerator(self): + raise NotImplementedError + + @abstractproperty + def denominator(self): + raise NotImplementedError + + # Concrete implementation of Real's conversion to float. + def __float__(self): + """float(self) = self.numerator / self.denominator""" + return self.numerator / self.denominator + + +class Integral(Rational): + """Integral adds a conversion to int and the bit-string operations.""" + + @abstractmethod + def __int__(self): + """int(self)""" + raise NotImplementedError + + def __index__(self): + """index(self)""" + return int(self) + + @abstractmethod + def __pow__(self, exponent, modulus=None): + """self ** exponent % modulus, but maybe faster. + + Accept the modulus argument if you want to support the + 3-argument version of pow(). Raise a TypeError if exponent < 0 + or any argument isn't Integral. Otherwise, just implement the + 2-argument version described in Complex. + """ + raise NotImplementedError + + @abstractmethod + def __lshift__(self, other): + """self << other""" + raise NotImplementedError + + @abstractmethod + def __rlshift__(self, other): + """other << self""" + raise NotImplementedError + + @abstractmethod + def __rshift__(self, other): + """self >> other""" + raise NotImplementedError + + @abstractmethod + def __rrshift__(self, other): + """other >> self""" + raise NotImplementedError + + @abstractmethod + def __and__(self, other): + """self & other""" + raise NotImplementedError + + @abstractmethod + def __rand__(self, other): + """other & self""" + raise NotImplementedError + + @abstractmethod + def __xor__(self, other): + """self ^ other""" + raise NotImplementedError + + @abstractmethod + def __rxor__(self, other): + """other ^ self""" + raise NotImplementedError + + @abstractmethod + def __or__(self, other): + """self | other""" + raise NotImplementedError + + @abstractmethod + def __ror__(self, other): + """other | self""" + raise NotImplementedError + + @abstractmethod + def __invert__(self): + """~self""" + raise NotImplementedError + + # Concrete implementations of Rational and Real abstract methods. + def __float__(self): + """float(self) == float(int(self))""" + return float(int(self)) + + @property + def numerator(self): + """Integers are their own numerators.""" + return self + + @property + def denominator(self): + """Integers have a denominator of 1.""" + return 1 + +Integral.register(int) Index: Lib/abc.py =================================================================== --- Lib/abc.py (revision 56658) +++ Lib/abc.py (working copy) @@ -24,6 +24,25 @@ return funcobj +class abstractproperty(property): + """A decorator indicating abstract properties. + + Requires that the metaclass is ABCMeta or derived from it. A + class that has a metaclass derived from ABCMeta cannot be + instantiated unless all of its abstract properties are overridden. + The abstract properties can be called using any of the the normal + 'super' call mechanisms. + + Usage: + + class C(metaclass=ABCMeta): + @abstractproperty + def my_abstract_property(self): + ... + """ + __isabstractmethod__ = True + + class _Abstract(object): """Helper class inserted into the bases by ABCMeta (using _fix_bases()). Index: Lib/unittest.py =================================================================== --- Lib/unittest.py (revision 56658) +++ Lib/unittest.py (working copy) @@ -339,7 +339,7 @@ Note that decimal places (from zero) are usually not the same as significant digits (measured from the most signficant digit). """ - if round(second-first, places) != 0: + if round(abs(second-first), places) != 0: raise self.failureException, \ (msg or '%r != %r within %r places' % (first, second, places)) @@ -351,7 +351,7 @@ Note that decimal places (from zero) are usually not the same as significant digits (measured from the most signficant digit). """ - if round(second-first, places) == 0: + if round(abs(second-first), places) == 0: raise self.failureException, \ (msg or '%r == %r within %r places' % (first, second, places)) Index: Lib/test/test_descr.py =================================================================== --- Lib/test/test_descr.py (revision 56658) +++ Lib/test/test_descr.py (working copy) @@ -2,13 +2,8 @@ from test.test_support import verify, vereq, verbose, TestFailed, TESTFN, get_original_stdout from copy import deepcopy -import warnings import types -warnings.filterwarnings("ignore", - r'complex divmod\(\), // and % are deprecated$', - DeprecationWarning, r'(|%s)$' % __name__) - def veris(a, b): if a is not b: raise TestFailed, "%r is %r" % (a, b) @@ -441,7 +436,8 @@ def complexes(): if verbose: print("Testing complex operations...") - numops(100.0j, 3.0j, skip=['lt', 'le', 'gt', 'ge', 'int', 'long', 'float']) + numops(100.0j, 3.0j, skip=['lt', 'le', 'gt', 'ge', 'int', 'long', 'float', + 'divmod', 'mod']) class Number(complex): __slots__ = ['prec'] def __new__(cls, *args, **kwds): Index: Lib/test/test_complex.py =================================================================== --- Lib/test/test_complex.py (revision 56658) +++ Lib/test/test_complex.py (working copy) @@ -1,13 +1,6 @@ import unittest, os from test import test_support -import warnings -warnings.filterwarnings( - "ignore", - category=DeprecationWarning, - message=".*complex divmod.*are deprecated" -) - from random import random # These tests ensure that complex math does the right thing @@ -89,8 +82,7 @@ self.assertRaises(ZeroDivisionError, complex.__truediv__, 1+1j, 0+0j) def test_floordiv(self): - self.assertAlmostEqual(complex.__floordiv__(3+0j, 1.5+0j), 2) - self.assertRaises(ZeroDivisionError, complex.__floordiv__, 3+0j, 0+0j) + self.assertRaises(TypeError, complex.__floordiv__, 3+0j, 1.5+0j) def test_richcompare(self): self.assertRaises(OverflowError, complex.__eq__, 1+1j, 1<<10000) @@ -105,18 +97,10 @@ self.assertRaises(TypeError, complex.__ge__, 1+1j, 2+2j) def test_mod(self): - self.assertRaises(ZeroDivisionError, (1+1j).__mod__, 0+0j) + self.assertRaises(TypeError, (1+1j).__mod__, 4.3j) - a = 3.33+4.43j - try: - a % 0 - except ZeroDivisionError: - pass - else: - self.fail("modulo parama can't be 0") - def test_divmod(self): - self.assertRaises(ZeroDivisionError, divmod, 1+1j, 0+0j) + self.assertRaises(TypeError, divmod, 1+1j, 1+1j) def test_pow(self): self.assertAlmostEqual(pow(1+1j, 0+0j), 1.0) Index: Lib/test/test_abstract_numbers.py =================================================================== --- Lib/test/test_abstract_numbers.py (revision 0) +++ Lib/test/test_abstract_numbers.py (revision 0) @@ -0,0 +1,52 @@ +"""Unit tests for numbers.py.""" + +import unittest +from test import test_support +from numbers import Number, Exact, Inexact +from numbers import Complex, Real, Rational, Integral +import operator + +class TestNumbers(unittest.TestCase): + def test_int(self): + self.failUnless(issubclass(int, Integral)) + self.failUnless(issubclass(int, Complex)) + self.failUnless(issubclass(int, Exact)) + self.failIf(issubclass(int, Inexact)) + + self.assertEqual(7, int(7).real) + self.assertEqual(0, int(7).imag) + self.assertEqual(7, int(7).conjugate()) + self.assertEqual(7, int(7).numerator) + self.assertEqual(1, int(7).denominator) + + def test_float(self): + self.failIf(issubclass(float, Rational)) + self.failUnless(issubclass(float, Real)) + self.failIf(issubclass(float, Exact)) + self.failUnless(issubclass(float, Inexact)) + + self.assertEqual(7.3, float(7.3).real) + self.assertEqual(0, float(7.3).imag) + self.assertEqual(7.3, float(7.3).conjugate()) + + def test_complex(self): + self.failIf(issubclass(complex, Real)) + self.failUnless(issubclass(complex, Complex)) + self.failIf(issubclass(complex, Exact)) + self.failUnless(issubclass(complex, Inexact)) + + c1, c2 = complex(3, 2), complex(4,1) + # TODO: Uncomment this test when trunc() exists. + #self.assertRaises(None, trunc, c1) + self.assertRaises(TypeError, operator.mod, c1, c2) + self.assertRaises(TypeError, divmod, c1, c2) + self.assertRaises(TypeError, operator.floordiv, c1, c2) + self.assertRaises(TypeError, float, c1) + self.assertRaises(TypeError, int, c1) + +def test_main(): + test_support.run_unittest(TestNumbers) + + +if __name__ == "__main__": + unittest.main() Index: Lib/test/test_abc.py =================================================================== --- Lib/test/test_abc.py (revision 56658) +++ Lib/test/test_abc.py (working copy) @@ -19,27 +19,43 @@ def bar(self): pass self.assertEqual(hasattr(bar, "__isabstractmethod__"), False) - def test_abstractmethod_integration(self): + def test_abstractproperty_basics(self): + @abc.abstractproperty + def foo(self): pass + self.assertEqual(foo.__isabstractmethod__, True) + def bar(self): pass + self.assertEqual(hasattr(bar, "__isabstractmethod__"), False) + class C(metaclass=abc.ABCMeta): - @abc.abstractmethod - def foo(self): pass # abstract - def bar(self): pass # concrete - self.assertEqual(C.__abstractmethods__, {"foo"}) - self.assertRaises(TypeError, C) # because foo is abstract + @abc.abstractproperty + def foo(self): return 3 class D(C): - def bar(self): pass # concrete override of concrete - self.assertEqual(D.__abstractmethods__, {"foo"}) - self.assertRaises(TypeError, D) # because foo is still abstract - class E(D): - def foo(self): pass - self.assertEqual(E.__abstractmethods__, set()) - E() # now foo is concrete, too - class F(E): - @abc.abstractmethod - def bar(self): pass # abstract override of concrete - self.assertEqual(F.__abstractmethods__, {"bar"}) - self.assertRaises(TypeError, F) # because bar is abstract now + @property + def foo(self): return super().foo + self.assertEqual(D().foo, 3) + def test_abstractmethod_integration(self): + for abstractthing in [abc.abstractmethod, abc.abstractproperty]: + class C(metaclass=abc.ABCMeta): + @abstractthing + def foo(self): pass # abstract + def bar(self): pass # concrete + self.assertEqual(C.__abstractmethods__, {"foo"}) + self.assertRaises(TypeError, C) # because foo is abstract + class D(C): + def bar(self): pass # concrete override of concrete + self.assertEqual(D.__abstractmethods__, {"foo"}) + self.assertRaises(TypeError, D) # because foo is still abstract + class E(D): + def foo(self): pass + self.assertEqual(E.__abstractmethods__, set()) + E() # now foo is concrete, too + class F(E): + @abstractthing + def bar(self): pass # abstract override of concrete + self.assertEqual(F.__abstractmethods__, {"bar"}) + self.assertRaises(TypeError, F) # because bar is abstract now + def test_registration_basics(self): class A(metaclass=abc.ABCMeta): pass Index: Lib/test/test_builtin.py =================================================================== --- Lib/test/test_builtin.py (revision 56658) +++ Lib/test/test_builtin.py (working copy) @@ -1383,11 +1383,13 @@ else: self.assertAlmostEqual(pow(x, y, z), 24.0) + self.assertAlmostEqual(pow(-1, 0.5), 1j) + self.assertAlmostEqual(pow(-1, 1/3), 0.5 + 0.8660254037844386j) + self.assertRaises(TypeError, pow, -1, -2, 3) self.assertRaises(ValueError, pow, 1, 2, 0) self.assertRaises(TypeError, pow, -1, -2, 3) self.assertRaises(ValueError, pow, 1, 2, 0) - self.assertRaises(ValueError, pow, -342.43, 0.234) self.assertRaises(TypeError, pow)