diff -r 7c717d423160 Lib/hmac.py --- a/Lib/hmac.py Wed Dec 19 15:28:46 2012 -0600 +++ b/Lib/hmac.py Thu Dec 20 18:26:25 2012 -0600 @@ -4,7 +4,7 @@ """ import warnings as _warnings -from operator import _compare_digest as compare_digest +from _operator import _compare_digest as compare_digest trans_5C = bytes((x ^ 0x5C) for x in range(256)) trans_36 = bytes((x ^ 0x36) for x in range(256)) diff -r 7c717d423160 Lib/operator.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/operator.py Thu Dec 20 18:26:25 2012 -0600 @@ -0,0 +1,395 @@ +#!/usr/bin/env python3 +""" +Operator Interface + +This module exports a set of functions corresponding to the intrinsic +operators of Python. For example, operator.add(x, y) is equivalent +to the expression x+y. The function names are those used for special +methods; variants without leading and trailing '__' are also provided +for convenience. + +This is the pure Python implementation of the module. +""" + +__all__ = ['__abs__', '__add__', '__and__', '__concat__', '__contains__', + '__delitem__', '__eq__', '__floordiv__', '__ge__', '__getitem__', + '__gt__', '__iadd__', '__iand__', '__iconcat__', '__ifloordiv__', + '__ilshift__', '__imod__', '__imul__', '__index__', '__inv__', + '__invert__', '__ior__', '__ipow__', '__irshift__', '__isub__', + '__itruediv__', '__ixor__', '__le__', '__loader__', '__lshift__', + '__lt__', '__mod__', '__mul__', '__name__', '__ne__', '__neg__', + '__not__', '__or__', '__pos__', '__pow__', '__rshift__', + '__setitem__', '__sub__', '__truediv__', '__xor__', + 'abs', 'add', 'and_', 'attrgetter', 'concat', 'contains', 'countOf', + 'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd', 'iand', + 'iconcat', 'ifloordiv', 'ilshift', 'imod', 'imul', 'index', + 'indexOf', 'inv', 'invert', 'ior', 'ipow', 'irshift', 'is_', + 'is_not', 'isub', 'itemgetter', 'itruediv', 'ixor', 'le', + 'length_hint', 'lshift', 'lt', 'methodcaller', 'mod', 'mul', 'ne', + 'neg', 'not_', 'or_', 'pos', 'pow', 'rshift', 'setitem', 'sub', + 'truediv', 'truth', 'xor'] + +from builtins import abs as _abs + +def lt(a, b): + "Same as a < b." + return a < b +__lt__ = lt + +def le(a, b): + "Same as a <= b." + return a <= b +__le__ = le + +def eq(a, b): + "Same as a == b." + return a == b +__eq__ = eq + +def ne(a, b): + "Same as a != b." + return a != b +__ne__ = ne + +def ge(a, b): + "Same as a >= b." + return a >= b +__ge__ = ge + +def gt(a, b): + "Same as a > b." + return a > b +__gt__ = gt + +def not_(a): + "Same as not a." + return not a +__not__ = not_ + +def truth(a): + "Return True if a is true, False otherwise." + return True if a else False + +def is_(a, b): + "Same as a is b." + return a is b + +def is_not(a, b): + "Same as a is not b." + return a is not b + +def abs(a): + "Same as abs(a)." + return _abs(a) +__abs__ = abs + +def add(a, b): + "Same as a + b." + return a + b +__add__ = add + +def and_(a, b): + "Same as a & b." + return a & b +__and__ = and_ + +def floordiv(a, b): + "Same as a // b." + return a // b +__floordiv__ = floordiv + +def index(a): + "Same as a.__index__()." + return a.__index__() +__index__ = index + +def inv(a): + "Same as ~a." + return ~a +invert = __inv__ = __invert__ = inv + +def lshift(a, b): + "Same as a << b." + return a << b +__lshift__ = lshift + +def mod(a, b): + "Same as a % b." + return a % b +__mod__ = mod + +def mul(a, b): + "Same as a * b." + return a * b +__mul__ = mul + +def neg(a): + "Same as -a." + return -a +__neg__ = neg + +def or_(a, b): + "Same as a | b." + return a | b +__or__ = or_ + +def pos(a): + "Same as +a." + return +a +__pos__ = pos + +def pow(a, b): + "Same as a ** b." + return a ** b +__pow__ = pow + +def rshift(a, b): + "Same as a >> b." + return a >> b +__rshift__ = rshift + +def sub(a, b): + "Same as a - b." + return a - b +__sub__ = sub + +def truediv(a, b): + "Same as a / b." + return a / b +__truediv__ = truediv + +def xor(a, b): + "Same as a ^ b." + return a ^ b +__xor__ = xor + +def concat(a, b): + "Same as a + b, for a and b sequences." + if not (hasattr(a, '__getitem__') and hasattr(b, '__getitem__')): + msg = "'%s' object can't be concatenated" % type(a).__name__ + raise TypeError(msg) + return a + b +__concat__ = concat + +def contains(a, b): + "Same as b in a (note reversed operands)." + return b in a +__contains__ = contains + +def countOf(a, b): + "Return the number of times b occurs in a." + count = 0 + for i in a: + if i == b: + count += 1 + return count + +def delitem(a, b): + "Same as del a[b]." + del a[b] +__delitem__ = delitem + +def getitem(a, b): + "Same as a[b]." + return a[b] +__getitem__ = getitem + +def indexOf(a, b): + "Return the first index of b in a." + for i, j in enumerate(a): + if j == b: + return i + else: + raise ValueError('sequence.index(x): x not in sequence') + +def setitem(a, b, c): + "Same as a[b] = c." + a[b] = c +__setitem__ = setitem + +class attrgetter: + """ + Return a callable object that fetches the given attribute(s) from its operand. + After f=attrgetter('name'), the call f(r) returns r.name. + After g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date). + After h=attrgetter('name.first', 'name.last'), the call h(r) returns + (r.name.first, r.name.last). + """ + def __init__(self, attr, *attrs): + if not attrs: + if not isinstance(attr, str): + raise TypeError('attribute name must be a string') + names = attr.split('.') + def func(obj): + for name in names: + obj = getattr(obj, name) + return obj + self._call = func + else: + getters = tuple(map(attrgetter, (attr,) + attrs)) + def func(obj): + return tuple(getter(obj) for getter in getters) + self._call = func + + def __call__(self, obj): + return self._call(obj) + +class itemgetter: + """ + Return a callable object that fetches the given item(s) from its operand. + After f=itemgetter(2), the call f(r) returns r[2]. + After g=itemgetter(2,5,3), the call g(r) returns (r[2], r[5], r[3]) + """ + def __init__(self, item, *items): + if not items: + def func(obj): + return obj.__getitem__(item) + self._call = func + else: + getters = tuple(map(itemgetter, (item,) + items)) + def func(obj): + return tuple(getter(obj) for getter in getters) + self._call = func + + def __call__(self, obj): + return self._call(obj) + +class methodcaller: + """ + Return a callable object that calls the given method on its operand. + After f = methodcaller('name'), the call f(r) returns r.name(). + After g = methodcaller('name', 'date', foo=1), the call g(r) returns + r.name('date', foo=1). + """ + + def __init__(self, name, *args, **kwargs): + self._name = name + self._args = args + self._kwargs = kwargs + + def __call__(self, obj): + return getattr(obj, self._name)(*self._args, **self._kwargs) + +def iadd(a, b): + "Same as a += b." + a += b + return a +__iadd__ = iadd + +def iand(a, b): + "Same as a &= b." + a &= b + return a +__iand__ = iand + +def iconcat(a, b): + "Same as a += b, for a and b sequences." + if not (hasattr(a, '__getitem__') and hasattr(b, '__getitem__')): + msg = "'%s' object can't be concatenated" % type(a).__name__ + raise TypeError(msg) + a += b + return a +__iconcat__ = iconcat + +def ifloordiv(a, b): + "Same as a //= b." + a //= b + return a +__ifloordiv__ = ifloordiv + +def ilshift(a, b): + "Same as a <<= b." + a <<= b + return a +__ilshift__ = ilshift + +def imod(a, b): + "Same as a %= b." + a %= b + return a +__imod__ = imod + +def imul(a, b): + "Same as a *= b." + a *= b + return a +__imul__ = imul + +def ior(a, b): + "Same as a |= b." + a |= b + return a +__ior__ = ior + +def ipow(a, b): + "Same as a **= b." + a **=b + return a +__ipow__ = ipow + +def irshift(a, b): + "Same as a >>= b." + a >>= b + return a +__irshift__ = irshift + +def isub(a, b): + "Same as a -= b." + a -= b + return a +__isub__ = isub + +def itruediv(a, b): + "Same as a /= b." + a /= b + return a +__itruediv__ = itruediv + +def ixor(a, b): + "Same as a ^= b." + a ^= b + return a +__ixor__ = ixor + +def length_hint(obj, default=0): + """ + Return an estimate of the number of items in obj. + This is useful for presizing containers when building from an iterable. + + If the object supports len(), the result will be exact. Otherwise, it may + over- or under-estimate by an arbitrary amount. The result will be an + integer >= 0. + """ + if not isinstance(default, int): + msg = ("'%s' object cannot be interpreted as an integer" % + type(default).__name__) + raise TypeError(msg) + + try: + return len(obj) + except TypeError: + pass + + if getattr(type(obj), '__length_hint__', False): + try: + val = obj.__length_hint__() + except TypeError: + return default + if val is NotImplemented: + return default + if not isinstance(val, int): + msg = ('__length_hint__ must be integer, not %s' % + type(val).__name__) + raise TypeError(msg) + if val < 0: + msg = '__length_hint__() should return >= 0' + raise ValueError(msg) + return val + else: + return default + + +try: + from _operator import * +except ImportError: + pass diff -r 7c717d423160 Lib/test/test_operator.py --- a/Lib/test/test_operator.py Wed Dec 19 15:28:46 2012 -0600 +++ b/Lib/test/test_operator.py Thu Dec 20 18:26:25 2012 -0600 @@ -1,8 +1,10 @@ -import operator import unittest from test import support +py_operator = support.import_fresh_module('operator', blocked=['_operator']) +c_operator = support.import_fresh_module('operator', fresh=['_operator']) + class Seq1: def __init__(self, lst): self.lst = lst @@ -33,338 +35,340 @@ class OperatorTestCase(unittest.TestCase): + module = None + def test_lt(self): - self.assertRaises(TypeError, operator.lt) - self.assertRaises(TypeError, operator.lt, 1j, 2j) - self.assertFalse(operator.lt(1, 0)) - self.assertFalse(operator.lt(1, 0.0)) - self.assertFalse(operator.lt(1, 1)) - self.assertFalse(operator.lt(1, 1.0)) - self.assertTrue(operator.lt(1, 2)) - self.assertTrue(operator.lt(1, 2.0)) + self.assertRaises(TypeError, self.module.lt) + self.assertRaises(TypeError, self.module.lt, 1j, 2j) + self.assertFalse(self.module.lt(1, 0)) + self.assertFalse(self.module.lt(1, 0.0)) + self.assertFalse(self.module.lt(1, 1)) + self.assertFalse(self.module.lt(1, 1.0)) + self.assertTrue(self.module.lt(1, 2)) + self.assertTrue(self.module.lt(1, 2.0)) def test_le(self): - self.assertRaises(TypeError, operator.le) - self.assertRaises(TypeError, operator.le, 1j, 2j) - self.assertFalse(operator.le(1, 0)) - self.assertFalse(operator.le(1, 0.0)) - self.assertTrue(operator.le(1, 1)) - self.assertTrue(operator.le(1, 1.0)) - self.assertTrue(operator.le(1, 2)) - self.assertTrue(operator.le(1, 2.0)) + self.assertRaises(TypeError, self.module.le) + self.assertRaises(TypeError, self.module.le, 1j, 2j) + self.assertFalse(self.module.le(1, 0)) + self.assertFalse(self.module.le(1, 0.0)) + self.assertTrue(self.module.le(1, 1)) + self.assertTrue(self.module.le(1, 1.0)) + self.assertTrue(self.module.le(1, 2)) + self.assertTrue(self.module.le(1, 2.0)) def test_eq(self): class C(object): def __eq__(self, other): raise SyntaxError - self.assertRaises(TypeError, operator.eq) - self.assertRaises(SyntaxError, operator.eq, C(), C()) - self.assertFalse(operator.eq(1, 0)) - self.assertFalse(operator.eq(1, 0.0)) - self.assertTrue(operator.eq(1, 1)) - self.assertTrue(operator.eq(1, 1.0)) - self.assertFalse(operator.eq(1, 2)) - self.assertFalse(operator.eq(1, 2.0)) + self.assertRaises(TypeError, self.module.eq) + self.assertRaises(SyntaxError, self.module.eq, C(), C()) + self.assertFalse(self.module.eq(1, 0)) + self.assertFalse(self.module.eq(1, 0.0)) + self.assertTrue(self.module.eq(1, 1)) + self.assertTrue(self.module.eq(1, 1.0)) + self.assertFalse(self.module.eq(1, 2)) + self.assertFalse(self.module.eq(1, 2.0)) def test_ne(self): class C(object): def __ne__(self, other): raise SyntaxError - self.assertRaises(TypeError, operator.ne) - self.assertRaises(SyntaxError, operator.ne, C(), C()) - self.assertTrue(operator.ne(1, 0)) - self.assertTrue(operator.ne(1, 0.0)) - self.assertFalse(operator.ne(1, 1)) - self.assertFalse(operator.ne(1, 1.0)) - self.assertTrue(operator.ne(1, 2)) - self.assertTrue(operator.ne(1, 2.0)) + self.assertRaises(TypeError, self.module.ne) + self.assertRaises(SyntaxError, self.module.ne, C(), C()) + self.assertTrue(self.module.ne(1, 0)) + self.assertTrue(self.module.ne(1, 0.0)) + self.assertFalse(self.module.ne(1, 1)) + self.assertFalse(self.module.ne(1, 1.0)) + self.assertTrue(self.module.ne(1, 2)) + self.assertTrue(self.module.ne(1, 2.0)) def test_ge(self): - self.assertRaises(TypeError, operator.ge) - self.assertRaises(TypeError, operator.ge, 1j, 2j) - self.assertTrue(operator.ge(1, 0)) - self.assertTrue(operator.ge(1, 0.0)) - self.assertTrue(operator.ge(1, 1)) - self.assertTrue(operator.ge(1, 1.0)) - self.assertFalse(operator.ge(1, 2)) - self.assertFalse(operator.ge(1, 2.0)) + self.assertRaises(TypeError, self.module.ge) + self.assertRaises(TypeError, self.module.ge, 1j, 2j) + self.assertTrue(self.module.ge(1, 0)) + self.assertTrue(self.module.ge(1, 0.0)) + self.assertTrue(self.module.ge(1, 1)) + self.assertTrue(self.module.ge(1, 1.0)) + self.assertFalse(self.module.ge(1, 2)) + self.assertFalse(self.module.ge(1, 2.0)) def test_gt(self): - self.assertRaises(TypeError, operator.gt) - self.assertRaises(TypeError, operator.gt, 1j, 2j) - self.assertTrue(operator.gt(1, 0)) - self.assertTrue(operator.gt(1, 0.0)) - self.assertFalse(operator.gt(1, 1)) - self.assertFalse(operator.gt(1, 1.0)) - self.assertFalse(operator.gt(1, 2)) - self.assertFalse(operator.gt(1, 2.0)) + self.assertRaises(TypeError, self.module.gt) + self.assertRaises(TypeError, self.module.gt, 1j, 2j) + self.assertTrue(self.module.gt(1, 0)) + self.assertTrue(self.module.gt(1, 0.0)) + self.assertFalse(self.module.gt(1, 1)) + self.assertFalse(self.module.gt(1, 1.0)) + self.assertFalse(self.module.gt(1, 2)) + self.assertFalse(self.module.gt(1, 2.0)) def test_abs(self): - self.assertRaises(TypeError, operator.abs) - self.assertRaises(TypeError, operator.abs, None) - self.assertEqual(operator.abs(-1), 1) - self.assertEqual(operator.abs(1), 1) + self.assertRaises(TypeError, self.module.abs) + self.assertRaises(TypeError, self.module.abs, None) + self.assertEqual(self.module.abs(-1), 1) + self.assertEqual(self.module.abs(1), 1) def test_add(self): - self.assertRaises(TypeError, operator.add) - self.assertRaises(TypeError, operator.add, None, None) - self.assertTrue(operator.add(3, 4) == 7) + self.assertRaises(TypeError, self.module.add) + self.assertRaises(TypeError, self.module.add, None, None) + self.assertTrue(self.module.add(3, 4) == 7) def test_bitwise_and(self): - self.assertRaises(TypeError, operator.and_) - self.assertRaises(TypeError, operator.and_, None, None) - self.assertTrue(operator.and_(0xf, 0xa) == 0xa) + self.assertRaises(TypeError, self.module.and_) + self.assertRaises(TypeError, self.module.and_, None, None) + self.assertTrue(self.module.and_(0xf, 0xa) == 0xa) def test_concat(self): - self.assertRaises(TypeError, operator.concat) - self.assertRaises(TypeError, operator.concat, None, None) - self.assertTrue(operator.concat('py', 'thon') == 'python') - self.assertTrue(operator.concat([1, 2], [3, 4]) == [1, 2, 3, 4]) - self.assertTrue(operator.concat(Seq1([5, 6]), Seq1([7])) == [5, 6, 7]) - self.assertTrue(operator.concat(Seq2([5, 6]), Seq2([7])) == [5, 6, 7]) - self.assertRaises(TypeError, operator.concat, 13, 29) + self.assertRaises(TypeError, self.module.concat) + self.assertRaises(TypeError, self.module.concat, None, None) + self.assertTrue(self.module.concat('py', 'thon') == 'python') + self.assertTrue(self.module.concat([1, 2], [3, 4]) == [1, 2, 3, 4]) + self.assertTrue(self.module.concat(Seq1([5, 6]), Seq1([7])) == [5, 6, 7]) + self.assertTrue(self.module.concat(Seq2([5, 6]), Seq2([7])) == [5, 6, 7]) + self.assertRaises(TypeError, self.module.concat, 13, 29) def test_countOf(self): - self.assertRaises(TypeError, operator.countOf) - self.assertRaises(TypeError, operator.countOf, None, None) - self.assertTrue(operator.countOf([1, 2, 1, 3, 1, 4], 3) == 1) - self.assertTrue(operator.countOf([1, 2, 1, 3, 1, 4], 5) == 0) + self.assertRaises(TypeError, self.module.countOf) + self.assertRaises(TypeError, self.module.countOf, None, None) + self.assertTrue(self.module.countOf([1, 2, 1, 3, 1, 4], 3) == 1) + self.assertTrue(self.module.countOf([1, 2, 1, 3, 1, 4], 5) == 0) def test_delitem(self): a = [4, 3, 2, 1] - self.assertRaises(TypeError, operator.delitem, a) - self.assertRaises(TypeError, operator.delitem, a, None) - self.assertTrue(operator.delitem(a, 1) is None) + self.assertRaises(TypeError, self.module.delitem, a) + self.assertRaises(TypeError, self.module.delitem, a, None) + self.assertTrue(self.module.delitem(a, 1) is None) self.assertTrue(a == [4, 2, 1]) def test_floordiv(self): - self.assertRaises(TypeError, operator.floordiv, 5) - self.assertRaises(TypeError, operator.floordiv, None, None) - self.assertTrue(operator.floordiv(5, 2) == 2) + self.assertRaises(TypeError, self.module.floordiv, 5) + self.assertRaises(TypeError, self.module.floordiv, None, None) + self.assertTrue(self.module.floordiv(5, 2) == 2) def test_truediv(self): - self.assertRaises(TypeError, operator.truediv, 5) - self.assertRaises(TypeError, operator.truediv, None, None) - self.assertTrue(operator.truediv(5, 2) == 2.5) + self.assertRaises(TypeError, self.module.truediv, 5) + self.assertRaises(TypeError, self.module.truediv, None, None) + self.assertTrue(self.module.truediv(5, 2) == 2.5) def test_getitem(self): a = range(10) - self.assertRaises(TypeError, operator.getitem) - self.assertRaises(TypeError, operator.getitem, a, None) - self.assertTrue(operator.getitem(a, 2) == 2) + self.assertRaises(TypeError, self.module.getitem) + self.assertRaises(TypeError, self.module.getitem, a, None) + self.assertTrue(self.module.getitem(a, 2) == 2) def test_indexOf(self): - self.assertRaises(TypeError, operator.indexOf) - self.assertRaises(TypeError, operator.indexOf, None, None) - self.assertTrue(operator.indexOf([4, 3, 2, 1], 3) == 1) - self.assertRaises(ValueError, operator.indexOf, [4, 3, 2, 1], 0) + self.assertRaises(TypeError, self.module.indexOf) + self.assertRaises(TypeError, self.module.indexOf, None, None) + self.assertTrue(self.module.indexOf([4, 3, 2, 1], 3) == 1) + self.assertRaises(ValueError, self.module.indexOf, [4, 3, 2, 1], 0) def test_invert(self): - self.assertRaises(TypeError, operator.invert) - self.assertRaises(TypeError, operator.invert, None) - self.assertEqual(operator.inv(4), -5) + self.assertRaises(TypeError, self.module.invert) + self.assertRaises(TypeError, self.module.invert, None) + self.assertEqual(self.module.inv(4), -5) def test_lshift(self): - self.assertRaises(TypeError, operator.lshift) - self.assertRaises(TypeError, operator.lshift, None, 42) - self.assertTrue(operator.lshift(5, 1) == 10) - self.assertTrue(operator.lshift(5, 0) == 5) - self.assertRaises(ValueError, operator.lshift, 2, -1) + self.assertRaises(TypeError, self.module.lshift) + self.assertRaises(TypeError, self.module.lshift, None, 42) + self.assertTrue(self.module.lshift(5, 1) == 10) + self.assertTrue(self.module.lshift(5, 0) == 5) + self.assertRaises(ValueError, self.module.lshift, 2, -1) def test_mod(self): - self.assertRaises(TypeError, operator.mod) - self.assertRaises(TypeError, operator.mod, None, 42) - self.assertTrue(operator.mod(5, 2) == 1) + self.assertRaises(TypeError, self.module.mod) + self.assertRaises(TypeError, self.module.mod, None, 42) + self.assertTrue(self.module.mod(5, 2) == 1) def test_mul(self): - self.assertRaises(TypeError, operator.mul) - self.assertRaises(TypeError, operator.mul, None, None) - self.assertTrue(operator.mul(5, 2) == 10) + self.assertRaises(TypeError, self.module.mul) + self.assertRaises(TypeError, self.module.mul, None, None) + self.assertTrue(self.module.mul(5, 2) == 10) def test_neg(self): - self.assertRaises(TypeError, operator.neg) - self.assertRaises(TypeError, operator.neg, None) - self.assertEqual(operator.neg(5), -5) - self.assertEqual(operator.neg(-5), 5) - self.assertEqual(operator.neg(0), 0) - self.assertEqual(operator.neg(-0), 0) + self.assertRaises(TypeError, self.module.neg) + self.assertRaises(TypeError, self.module.neg, None) + self.assertEqual(self.module.neg(5), -5) + self.assertEqual(self.module.neg(-5), 5) + self.assertEqual(self.module.neg(0), 0) + self.assertEqual(self.module.neg(-0), 0) def test_bitwise_or(self): - self.assertRaises(TypeError, operator.or_) - self.assertRaises(TypeError, operator.or_, None, None) - self.assertTrue(operator.or_(0xa, 0x5) == 0xf) + self.assertRaises(TypeError, self.module.or_) + self.assertRaises(TypeError, self.module.or_, None, None) + self.assertTrue(self.module.or_(0xa, 0x5) == 0xf) def test_pos(self): - self.assertRaises(TypeError, operator.pos) - self.assertRaises(TypeError, operator.pos, None) - self.assertEqual(operator.pos(5), 5) - self.assertEqual(operator.pos(-5), -5) - self.assertEqual(operator.pos(0), 0) - self.assertEqual(operator.pos(-0), 0) + self.assertRaises(TypeError, self.module.pos) + self.assertRaises(TypeError, self.module.pos, None) + self.assertEqual(self.module.pos(5), 5) + self.assertEqual(self.module.pos(-5), -5) + self.assertEqual(self.module.pos(0), 0) + self.assertEqual(self.module.pos(-0), 0) def test_pow(self): - self.assertRaises(TypeError, operator.pow) - self.assertRaises(TypeError, operator.pow, None, None) - self.assertEqual(operator.pow(3,5), 3**5) - self.assertEqual(operator.__pow__(3,5), 3**5) - self.assertRaises(TypeError, operator.pow, 1) - self.assertRaises(TypeError, operator.pow, 1, 2, 3) + self.assertRaises(TypeError, self.module.pow) + self.assertRaises(TypeError, self.module.pow, None, None) + self.assertEqual(self.module.pow(3,5), 3**5) + self.assertEqual(self.module.__pow__(3,5), 3**5) + self.assertRaises(TypeError, self.module.pow, 1) + self.assertRaises(TypeError, self.module.pow, 1, 2, 3) def test_rshift(self): - self.assertRaises(TypeError, operator.rshift) - self.assertRaises(TypeError, operator.rshift, None, 42) - self.assertTrue(operator.rshift(5, 1) == 2) - self.assertTrue(operator.rshift(5, 0) == 5) - self.assertRaises(ValueError, operator.rshift, 2, -1) + self.assertRaises(TypeError, self.module.rshift) + self.assertRaises(TypeError, self.module.rshift, None, 42) + self.assertTrue(self.module.rshift(5, 1) == 2) + self.assertTrue(self.module.rshift(5, 0) == 5) + self.assertRaises(ValueError, self.module.rshift, 2, -1) def test_contains(self): - self.assertRaises(TypeError, operator.contains) - self.assertRaises(TypeError, operator.contains, None, None) - self.assertTrue(operator.contains(range(4), 2)) - self.assertFalse(operator.contains(range(4), 5)) + self.assertRaises(TypeError, self.module.contains) + self.assertRaises(TypeError, self.module.contains, None, None) + self.assertTrue(self.module.contains(range(4), 2)) + self.assertFalse(self.module.contains(range(4), 5)) def test_setitem(self): a = list(range(3)) - self.assertRaises(TypeError, operator.setitem, a) - self.assertRaises(TypeError, operator.setitem, a, None, None) - self.assertTrue(operator.setitem(a, 0, 2) is None) + self.assertRaises(TypeError, self.module.setitem, a) + self.assertRaises(TypeError, self.module.setitem, a, None, None) + self.assertTrue(self.module.setitem(a, 0, 2) is None) self.assertTrue(a == [2, 1, 2]) - self.assertRaises(IndexError, operator.setitem, a, 4, 2) + self.assertRaises(IndexError, self.module.setitem, a, 4, 2) def test_sub(self): - self.assertRaises(TypeError, operator.sub) - self.assertRaises(TypeError, operator.sub, None, None) - self.assertTrue(operator.sub(5, 2) == 3) + self.assertRaises(TypeError, self.module.sub) + self.assertRaises(TypeError, self.module.sub, None, None) + self.assertTrue(self.module.sub(5, 2) == 3) def test_truth(self): class C(object): def __bool__(self): raise SyntaxError - self.assertRaises(TypeError, operator.truth) - self.assertRaises(SyntaxError, operator.truth, C()) - self.assertTrue(operator.truth(5)) - self.assertTrue(operator.truth([0])) - self.assertFalse(operator.truth(0)) - self.assertFalse(operator.truth([])) + self.assertRaises(TypeError, self.module.truth) + self.assertRaises(SyntaxError, self.module.truth, C()) + self.assertTrue(self.module.truth(5)) + self.assertTrue(self.module.truth([0])) + self.assertFalse(self.module.truth(0)) + self.assertFalse(self.module.truth([])) def test_bitwise_xor(self): - self.assertRaises(TypeError, operator.xor) - self.assertRaises(TypeError, operator.xor, None, None) - self.assertTrue(operator.xor(0xb, 0xc) == 0x7) + self.assertRaises(TypeError, self.module.xor) + self.assertRaises(TypeError, self.module.xor, None, None) + self.assertTrue(self.module.xor(0xb, 0xc) == 0x7) def test_is(self): a = b = 'xyzpdq' c = a[:3] + b[3:] - self.assertRaises(TypeError, operator.is_) - self.assertTrue(operator.is_(a, b)) - self.assertFalse(operator.is_(a,c)) + self.assertRaises(TypeError, self.module.is_) + self.assertTrue(self.module.is_(a, b)) + self.assertFalse(self.module.is_(a,c)) def test_is_not(self): a = b = 'xyzpdq' c = a[:3] + b[3:] - self.assertRaises(TypeError, operator.is_not) - self.assertFalse(operator.is_not(a, b)) - self.assertTrue(operator.is_not(a,c)) + self.assertRaises(TypeError, self.module.is_not) + self.assertFalse(self.module.is_not(a, b)) + self.assertTrue(self.module.is_not(a,c)) def test_attrgetter(self): class A: pass a = A() a.name = 'arthur' - f = operator.attrgetter('name') + f = self.module.attrgetter('name') self.assertEqual(f(a), 'arthur') - f = operator.attrgetter('rank') + f = self.module.attrgetter('rank') self.assertRaises(AttributeError, f, a) - self.assertRaises(TypeError, operator.attrgetter, 2) - self.assertRaises(TypeError, operator.attrgetter) + self.assertRaises(TypeError, self.module.attrgetter, 2) + self.assertRaises(TypeError, self.module.attrgetter) # multiple gets record = A() record.x = 'X' record.y = 'Y' record.z = 'Z' - self.assertEqual(operator.attrgetter('x','z','y')(record), ('X', 'Z', 'Y')) - self.assertRaises(TypeError, operator.attrgetter, ('x', (), 'y')) + self.assertEqual(self.module.attrgetter('x','z','y')(record), ('X', 'Z', 'Y')) + self.assertRaises(TypeError, self.module.attrgetter, ('x', (), 'y')) class C(object): def __getattr__(self, name): raise SyntaxError - self.assertRaises(SyntaxError, operator.attrgetter('foo'), C()) + self.assertRaises(SyntaxError, self.module.attrgetter('foo'), C()) # recursive gets a = A() a.name = 'arthur' a.child = A() a.child.name = 'thomas' - f = operator.attrgetter('child.name') + f = self.module.attrgetter('child.name') self.assertEqual(f(a), 'thomas') self.assertRaises(AttributeError, f, a.child) - f = operator.attrgetter('name', 'child.name') + f = self.module.attrgetter('name', 'child.name') self.assertEqual(f(a), ('arthur', 'thomas')) - f = operator.attrgetter('name', 'child.name', 'child.child.name') + f = self.module.attrgetter('name', 'child.name', 'child.child.name') self.assertRaises(AttributeError, f, a) - f = operator.attrgetter('child.') + f = self.module.attrgetter('child.') self.assertRaises(AttributeError, f, a) - f = operator.attrgetter('.child') + f = self.module.attrgetter('.child') self.assertRaises(AttributeError, f, a) a.child.child = A() a.child.child.name = 'johnson' - f = operator.attrgetter('child.child.name') + f = self.module.attrgetter('child.child.name') self.assertEqual(f(a), 'johnson') - f = operator.attrgetter('name', 'child.name', 'child.child.name') + f = self.module.attrgetter('name', 'child.name', 'child.child.name') self.assertEqual(f(a), ('arthur', 'thomas', 'johnson')) def test_itemgetter(self): a = 'ABCDE' - f = operator.itemgetter(2) + f = self.module.itemgetter(2) self.assertEqual(f(a), 'C') - f = operator.itemgetter(10) + f = self.module.itemgetter(10) self.assertRaises(IndexError, f, a) class C(object): def __getitem__(self, name): raise SyntaxError - self.assertRaises(SyntaxError, operator.itemgetter(42), C()) + self.assertRaises(SyntaxError, self.module.itemgetter(42), C()) - f = operator.itemgetter('name') + f = self.module.itemgetter('name') self.assertRaises(TypeError, f, a) - self.assertRaises(TypeError, operator.itemgetter) + self.assertRaises(TypeError, self.module.itemgetter) d = dict(key='val') - f = operator.itemgetter('key') + f = self.module.itemgetter('key') self.assertEqual(f(d), 'val') - f = operator.itemgetter('nonkey') + f = self.module.itemgetter('nonkey') self.assertRaises(KeyError, f, d) # example used in the docs inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)] - getcount = operator.itemgetter(1) + getcount = self.module.itemgetter(1) self.assertEqual(list(map(getcount, inventory)), [3, 2, 5, 1]) self.assertEqual(sorted(inventory, key=getcount), [('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)]) # multiple gets data = list(map(str, range(20))) - self.assertEqual(operator.itemgetter(2,10,5)(data), ('2', '10', '5')) - self.assertRaises(TypeError, operator.itemgetter(2, 'x', 5), data) + self.assertEqual(self.module.itemgetter(2,10,5)(data), ('2', '10', '5')) + self.assertRaises(TypeError, self.module.itemgetter(2, 'x', 5), data) def test_methodcaller(self): - self.assertRaises(TypeError, operator.methodcaller) + self.assertRaises(TypeError, self.module.methodcaller) class A: def foo(self, *args, **kwds): return args[0] + args[1] def bar(self, f=42): return f a = A() - f = operator.methodcaller('foo') + f = self.module.methodcaller('foo') self.assertRaises(IndexError, f, a) - f = operator.methodcaller('foo', 1, 2) + f = self.module.methodcaller('foo', 1, 2) self.assertEqual(f(a), 3) - f = operator.methodcaller('bar') + f = self.module.methodcaller('bar') self.assertEqual(f(a), 42) self.assertRaises(TypeError, f, a, a) - f = operator.methodcaller('bar', f=5) + f = self.module.methodcaller('bar', f=5) self.assertEqual(f(a), 5) def test_inplace(self): @@ -383,32 +387,32 @@ def __ixor__ (self, other): return "ixor" def __getitem__(self, other): return 5 # so that C is a sequence c = C() - self.assertEqual(operator.iadd (c, 5), "iadd") - self.assertEqual(operator.iand (c, 5), "iand") - self.assertEqual(operator.ifloordiv(c, 5), "ifloordiv") - self.assertEqual(operator.ilshift (c, 5), "ilshift") - self.assertEqual(operator.imod (c, 5), "imod") - self.assertEqual(operator.imul (c, 5), "imul") - self.assertEqual(operator.ior (c, 5), "ior") - self.assertEqual(operator.ipow (c, 5), "ipow") - self.assertEqual(operator.irshift (c, 5), "irshift") - self.assertEqual(operator.isub (c, 5), "isub") - self.assertEqual(operator.itruediv (c, 5), "itruediv") - self.assertEqual(operator.ixor (c, 5), "ixor") - self.assertEqual(operator.iconcat (c, c), "iadd") - self.assertEqual(operator.__iadd__ (c, 5), "iadd") - self.assertEqual(operator.__iand__ (c, 5), "iand") - self.assertEqual(operator.__ifloordiv__(c, 5), "ifloordiv") - self.assertEqual(operator.__ilshift__ (c, 5), "ilshift") - self.assertEqual(operator.__imod__ (c, 5), "imod") - self.assertEqual(operator.__imul__ (c, 5), "imul") - self.assertEqual(operator.__ior__ (c, 5), "ior") - self.assertEqual(operator.__ipow__ (c, 5), "ipow") - self.assertEqual(operator.__irshift__ (c, 5), "irshift") - self.assertEqual(operator.__isub__ (c, 5), "isub") - self.assertEqual(operator.__itruediv__ (c, 5), "itruediv") - self.assertEqual(operator.__ixor__ (c, 5), "ixor") - self.assertEqual(operator.__iconcat__ (c, c), "iadd") + self.assertEqual(self.module.iadd (c, 5), "iadd") + self.assertEqual(self.module.iand (c, 5), "iand") + self.assertEqual(self.module.ifloordiv(c, 5), "ifloordiv") + self.assertEqual(self.module.ilshift (c, 5), "ilshift") + self.assertEqual(self.module.imod (c, 5), "imod") + self.assertEqual(self.module.imul (c, 5), "imul") + self.assertEqual(self.module.ior (c, 5), "ior") + self.assertEqual(self.module.ipow (c, 5), "ipow") + self.assertEqual(self.module.irshift (c, 5), "irshift") + self.assertEqual(self.module.isub (c, 5), "isub") + self.assertEqual(self.module.itruediv (c, 5), "itruediv") + self.assertEqual(self.module.ixor (c, 5), "ixor") + self.assertEqual(self.module.iconcat (c, c), "iadd") + self.assertEqual(self.module.__iadd__ (c, 5), "iadd") + self.assertEqual(self.module.__iand__ (c, 5), "iand") + self.assertEqual(self.module.__ifloordiv__(c, 5), "ifloordiv") + self.assertEqual(self.module.__ilshift__ (c, 5), "ilshift") + self.assertEqual(self.module.__imod__ (c, 5), "imod") + self.assertEqual(self.module.__imul__ (c, 5), "imul") + self.assertEqual(self.module.__ior__ (c, 5), "ior") + self.assertEqual(self.module.__ipow__ (c, 5), "ipow") + self.assertEqual(self.module.__irshift__ (c, 5), "irshift") + self.assertEqual(self.module.__isub__ (c, 5), "isub") + self.assertEqual(self.module.__itruediv__ (c, 5), "itruediv") + self.assertEqual(self.module.__ixor__ (c, 5), "ixor") + self.assertEqual(self.module.__iconcat__ (c, c), "iadd") def test_length_hint(self): class X(object): @@ -421,24 +425,31 @@ else: return self.value - self.assertEqual(operator.length_hint([], 2), 0) - self.assertEqual(operator.length_hint(iter([1, 2, 3])), 3) + self.assertEqual(self.module.length_hint([], 2), 0) + self.assertEqual(self.module.length_hint(iter([1, 2, 3])), 3) - self.assertEqual(operator.length_hint(X(2)), 2) - self.assertEqual(operator.length_hint(X(NotImplemented), 4), 4) - self.assertEqual(operator.length_hint(X(TypeError), 12), 12) + self.assertEqual(self.module.length_hint(X(2)), 2) + self.assertEqual(self.module.length_hint(X(NotImplemented), 4), 4) + self.assertEqual(self.module.length_hint(X(TypeError), 12), 12) with self.assertRaises(TypeError): - operator.length_hint(X("abc")) + self.module.length_hint(X("abc")) with self.assertRaises(ValueError): - operator.length_hint(X(-2)) + self.module.length_hint(X(-2)) with self.assertRaises(LookupError): - operator.length_hint(X(LookupError)) + self.module.length_hint(X(LookupError)) +class PyOperatorTestCase(OperatorTestCase): + module = py_operator + +@unittest.skipUnless(c_operator, 'requires _operator') +class COperatorTestCase(OperatorTestCase): + module = c_operator def test_main(verbose=None): import sys test_classes = ( - OperatorTestCase, + PyOperatorTestCase, + COperatorTestCase ) support.run_unittest(*test_classes) diff -r 7c717d423160 Modules/Setup.dist --- a/Modules/Setup.dist Wed Dec 19 15:28:46 2012 -0600 +++ b/Modules/Setup.dist Thu Dec 20 18:26:25 2012 -0600 @@ -113,7 +113,7 @@ _codecs _codecsmodule.c # access to the builtin codecs and codec registry _weakref _weakref.c # weak references _functools _functoolsmodule.c # Tools for working with functions and callable objects -operator operator.c # operator.add() and similar goodies +_operator _operator.c # operator.add() and similar goodies _collections _collectionsmodule.c # Container types itertools itertoolsmodule.c # Functions creating iterators for efficient looping diff -r 7c717d423160 Modules/_operator.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Modules/_operator.c Thu Dec 20 18:26:25 2012 -0600 @@ -0,0 +1,962 @@ + +#include "Python.h" + +PyDoc_STRVAR(operator_doc, +"Operator interface.\n\ +\n\ +This module exports a set of functions implemented in C corresponding\n\ +to the intrinsic operators of Python. For example, operator.add(x, y)\n\ +is equivalent to the expression x+y. The function names are those\n\ +used for special methods; variants without leading and trailing\n\ +'__' are also provided for convenience."); + +#define spam1(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a1) { \ + return AOP(a1); } + +#define spam2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + return AOP(a1,a2); } + +#define spamoi(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1; int a2; \ + if(! PyArg_ParseTuple(a,"Oi:" #OP,&a1,&a2)) return NULL; \ + return AOP(a1,a2); } + +#define spam2n(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + if(-1 == AOP(a1,a2)) return NULL; \ + Py_INCREF(Py_None); \ + return Py_None; } + +#define spam3n(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2, *a3; \ + if(! PyArg_UnpackTuple(a,#OP,3,3,&a1,&a2,&a3)) return NULL; \ + if(-1 == AOP(a1,a2,a3)) return NULL; \ + Py_INCREF(Py_None); \ + return Py_None; } + +#define spami(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a1) { \ + long r; \ + if(-1 == (r=AOP(a1))) return NULL; \ + return PyBool_FromLong(r); } + +#define spami2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; long r; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + if(-1 == (r=AOP(a1,a2))) return NULL; \ + return PyLong_FromLong(r); } + +#define spamn2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; Py_ssize_t r; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + if(-1 == (r=AOP(a1,a2))) return NULL; \ + return PyLong_FromSsize_t(r); } + +#define spami2b(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; long r; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + if(-1 == (r=AOP(a1,a2))) return NULL; \ + return PyBool_FromLong(r); } + +#define spamrc(OP,A) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + return PyObject_RichCompare(a1,a2,A); } + +spami(truth , PyObject_IsTrue) +spam2(op_add , PyNumber_Add) +spam2(op_sub , PyNumber_Subtract) +spam2(op_mul , PyNumber_Multiply) +spam2(op_floordiv , PyNumber_FloorDivide) +spam2(op_truediv , PyNumber_TrueDivide) +spam2(op_mod , PyNumber_Remainder) +spam1(op_neg , PyNumber_Negative) +spam1(op_pos , PyNumber_Positive) +spam1(op_abs , PyNumber_Absolute) +spam1(op_inv , PyNumber_Invert) +spam1(op_invert , PyNumber_Invert) +spam2(op_lshift , PyNumber_Lshift) +spam2(op_rshift , PyNumber_Rshift) +spami(op_not_ , PyObject_Not) +spam2(op_and_ , PyNumber_And) +spam2(op_xor , PyNumber_Xor) +spam2(op_or_ , PyNumber_Or) +spam2(op_iadd , PyNumber_InPlaceAdd) +spam2(op_isub , PyNumber_InPlaceSubtract) +spam2(op_imul , PyNumber_InPlaceMultiply) +spam2(op_ifloordiv , PyNumber_InPlaceFloorDivide) +spam2(op_itruediv , PyNumber_InPlaceTrueDivide) +spam2(op_imod , PyNumber_InPlaceRemainder) +spam2(op_ilshift , PyNumber_InPlaceLshift) +spam2(op_irshift , PyNumber_InPlaceRshift) +spam2(op_iand , PyNumber_InPlaceAnd) +spam2(op_ixor , PyNumber_InPlaceXor) +spam2(op_ior , PyNumber_InPlaceOr) +spam2(op_concat , PySequence_Concat) +spam2(op_iconcat , PySequence_InPlaceConcat) +spami2b(op_contains , PySequence_Contains) +spamn2(indexOf , PySequence_Index) +spamn2(countOf , PySequence_Count) +spam2(op_getitem , PyObject_GetItem) +spam2n(op_delitem , PyObject_DelItem) +spam3n(op_setitem , PyObject_SetItem) +spamrc(op_lt , Py_LT) +spamrc(op_le , Py_LE) +spamrc(op_eq , Py_EQ) +spamrc(op_ne , Py_NE) +spamrc(op_gt , Py_GT) +spamrc(op_ge , Py_GE) + +static PyObject* +op_pow(PyObject *s, PyObject *a) +{ + PyObject *a1, *a2; + if (PyArg_UnpackTuple(a,"pow", 2, 2, &a1, &a2)) + return PyNumber_Power(a1, a2, Py_None); + return NULL; +} + +static PyObject* +op_ipow(PyObject *s, PyObject *a) +{ + PyObject *a1, *a2; + if (PyArg_UnpackTuple(a,"ipow", 2, 2, &a1, &a2)) + return PyNumber_InPlacePower(a1, a2, Py_None); + return NULL; +} + +static PyObject * +op_index(PyObject *s, PyObject *a) +{ + return PyNumber_Index(a); +} + +static PyObject* +is_(PyObject *s, PyObject *a) +{ + PyObject *a1, *a2, *result = NULL; + if (PyArg_UnpackTuple(a,"is_", 2, 2, &a1, &a2)) { + result = (a1 == a2) ? Py_True : Py_False; + Py_INCREF(result); + } + return result; +} + +static PyObject* +is_not(PyObject *s, PyObject *a) +{ + PyObject *a1, *a2, *result = NULL; + if (PyArg_UnpackTuple(a,"is_not", 2, 2, &a1, &a2)) { + result = (a1 != a2) ? Py_True : Py_False; + Py_INCREF(result); + } + return result; +} + +#undef spam1 +#undef spam2 +#undef spam1o +#undef spam1o + +/* compare_digest **********************************************************/ + +/* + * timing safe compare + * + * Returns 1 of the strings are equal. + * In case of len(a) != len(b) the function tries to keep the timing + * dependent on the length of b. CPU cache locally may still alter timing + * a bit. + */ +static int +_tscmp(const unsigned char *a, const unsigned char *b, + Py_ssize_t len_a, Py_ssize_t len_b) +{ + /* The volatile type declarations make sure that the compiler has no + * chance to optimize and fold the code in any way that may change + * the timing. + */ + volatile Py_ssize_t length; + volatile const unsigned char *left; + volatile const unsigned char *right; + Py_ssize_t i; + unsigned char result; + + /* loop count depends on length of b */ + length = len_b; + left = NULL; + right = b; + + /* don't use else here to keep the amount of CPU instructions constant, + * volatile forces re-evaluation + * */ + if (len_a == length) { + left = *((volatile const unsigned char**)&a); + result = 0; + } + if (len_a != length) { + left = b; + result = 1; + } + + for (i=0; i < length; i++) { + result |= *left++ ^ *right++; + } + + return (result == 0); +} + +PyDoc_STRVAR(length_hint__doc__, +"length_hint(obj, default=0) -> int\n" +"Return an estimate of the number of items in obj.\n" +"This is useful for presizing containers when building from an\n" +"iterable.\n" +"\n" +"If the object supports len(), the result will be\n" +"exact. Otherwise, it may over- or under-estimate by an\n" +"arbitrary amount. The result will be an integer >= 0."); + +static PyObject *length_hint(PyObject *self, PyObject *args) +{ + PyObject *obj; + Py_ssize_t defaultvalue = 0, res; + if (!PyArg_ParseTuple(args, "O|n:length_hint", &obj, &defaultvalue)) { + return NULL; + } + res = PyObject_LengthHint(obj, defaultvalue); + if (res == -1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromSsize_t(res); +} + + +PyDoc_STRVAR(compare_digest__doc__, +"compare_digest(a, b) -> bool\n" +"\n" +"Return 'a == b'. This function uses an approach designed to prevent\n" +"timing analysis, making it appropriate for cryptography.\n" +"a and b must both be of the same type: either str (ASCII only),\n" +"or any type that supports the buffer protocol (e.g. bytes).\n" +"\n" +"Note: If a and b are of different lengths, or if an error occurs,\n" +"a timing attack could theoretically reveal information about the\n" +"types and lengths of a and b--but not their values.\n"); + +static PyObject* +compare_digest(PyObject *self, PyObject *args) +{ + PyObject *a, *b; + int rc; + + if (!PyArg_ParseTuple(args, "OO:compare_digest", &a, &b)) { + return NULL; + } + + /* ASCII unicode string */ + if(PyUnicode_Check(a) && PyUnicode_Check(b)) { + if (PyUnicode_READY(a) == -1 || PyUnicode_READY(b) == -1) { + return NULL; + } + if (!PyUnicode_IS_ASCII(a) || !PyUnicode_IS_ASCII(b)) { + PyErr_SetString(PyExc_TypeError, + "comparing strings with non-ASCII characters is " + "not supported"); + return NULL; + } + + rc = _tscmp(PyUnicode_DATA(a), + PyUnicode_DATA(b), + PyUnicode_GET_LENGTH(a), + PyUnicode_GET_LENGTH(b)); + } + /* fallback to buffer interface for bytes, bytesarray and other */ + else { + Py_buffer view_a; + Py_buffer view_b; + + if ((PyObject_CheckBuffer(a) == 0) & (PyObject_CheckBuffer(b) == 0)) { + PyErr_Format(PyExc_TypeError, + "unsupported operand types(s) or combination of types: " + "'%.100s' and '%.100s'", + Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name); + return NULL; + } + + if (PyObject_GetBuffer(a, &view_a, PyBUF_SIMPLE) == -1) { + return NULL; + } + if (view_a.ndim > 1) { + PyErr_SetString(PyExc_BufferError, + "Buffer must be single dimension"); + PyBuffer_Release(&view_a); + return NULL; + } + + if (PyObject_GetBuffer(b, &view_b, PyBUF_SIMPLE) == -1) { + PyBuffer_Release(&view_a); + return NULL; + } + if (view_b.ndim > 1) { + PyErr_SetString(PyExc_BufferError, + "Buffer must be single dimension"); + PyBuffer_Release(&view_a); + PyBuffer_Release(&view_b); + return NULL; + } + + rc = _tscmp((const unsigned char*)view_a.buf, + (const unsigned char*)view_b.buf, + view_a.len, + view_b.len); + + PyBuffer_Release(&view_a); + PyBuffer_Release(&view_b); + } + + return PyBool_FromLong(rc); +} + +/* operator methods **********************************************************/ + +#define spam1(OP,DOC) {#OP, OP, METH_VARARGS, PyDoc_STR(DOC)}, +#define spam2(OP,ALTOP,DOC) {#OP, op_##OP, METH_VARARGS, PyDoc_STR(DOC)}, \ + {#ALTOP, op_##OP, METH_VARARGS, PyDoc_STR(DOC)}, +#define spam1o(OP,DOC) {#OP, OP, METH_O, PyDoc_STR(DOC)}, +#define spam2o(OP,ALTOP,DOC) {#OP, op_##OP, METH_O, PyDoc_STR(DOC)}, \ + {#ALTOP, op_##OP, METH_O, PyDoc_STR(DOC)}, + +static struct PyMethodDef operator_methods[] = { + +spam1o(truth, + "truth(a) -- Return True if a is true, False otherwise.") +spam2(contains,__contains__, + "contains(a, b) -- Same as b in a (note reversed operands).") +spam1(indexOf, + "indexOf(a, b) -- Return the first index of b in a.") +spam1(countOf, + "countOf(a, b) -- Return the number of times b occurs in a.") + +spam1(is_, "is_(a, b) -- Same as a is b.") +spam1(is_not, "is_not(a, b) -- Same as a is not b.") +spam2o(index, __index__, "index(a) -- Same as a.__index__()") +spam2(add,__add__, "add(a, b) -- Same as a + b.") +spam2(sub,__sub__, "sub(a, b) -- Same as a - b.") +spam2(mul,__mul__, "mul(a, b) -- Same as a * b.") +spam2(floordiv,__floordiv__, "floordiv(a, b) -- Same as a // b.") +spam2(truediv,__truediv__, "truediv(a, b) -- Same as a / b.") +spam2(mod,__mod__, "mod(a, b) -- Same as a % b.") +spam2o(neg,__neg__, "neg(a) -- Same as -a.") +spam2o(pos,__pos__, "pos(a) -- Same as +a.") +spam2o(abs,__abs__, "abs(a) -- Same as abs(a).") +spam2o(inv,__inv__, "inv(a) -- Same as ~a.") +spam2o(invert,__invert__, "invert(a) -- Same as ~a.") +spam2(lshift,__lshift__, "lshift(a, b) -- Same as a << b.") +spam2(rshift,__rshift__, "rshift(a, b) -- Same as a >> b.") +spam2o(not_,__not__, "not_(a) -- Same as not a.") +spam2(and_,__and__, "and_(a, b) -- Same as a & b.") +spam2(xor,__xor__, "xor(a, b) -- Same as a ^ b.") +spam2(or_,__or__, "or_(a, b) -- Same as a | b.") +spam2(iadd,__iadd__, "a = iadd(a, b) -- Same as a += b.") +spam2(isub,__isub__, "a = isub(a, b) -- Same as a -= b.") +spam2(imul,__imul__, "a = imul(a, b) -- Same as a *= b.") +spam2(ifloordiv,__ifloordiv__, "a = ifloordiv(a, b) -- Same as a //= b.") +spam2(itruediv,__itruediv__, "a = itruediv(a, b) -- Same as a /= b") +spam2(imod,__imod__, "a = imod(a, b) -- Same as a %= b.") +spam2(ilshift,__ilshift__, "a = ilshift(a, b) -- Same as a <<= b.") +spam2(irshift,__irshift__, "a = irshift(a, b) -- Same as a >>= b.") +spam2(iand,__iand__, "a = iand(a, b) -- Same as a &= b.") +spam2(ixor,__ixor__, "a = ixor(a, b) -- Same as a ^= b.") +spam2(ior,__ior__, "a = ior(a, b) -- Same as a |= b.") +spam2(concat,__concat__, + "concat(a, b) -- Same as a + b, for a and b sequences.") +spam2(iconcat,__iconcat__, + "a = iconcat(a, b) -- Same as a += b, for a and b sequences.") +spam2(getitem,__getitem__, + "getitem(a, b) -- Same as a[b].") +spam2(setitem,__setitem__, + "setitem(a, b, c) -- Same as a[b] = c.") +spam2(delitem,__delitem__, + "delitem(a, b) -- Same as del a[b].") +spam2(pow,__pow__, "pow(a, b) -- Same as a ** b.") +spam2(ipow,__ipow__, "a = ipow(a, b) -- Same as a **= b.") +spam2(lt,__lt__, "lt(a, b) -- Same as ab.") +spam2(ge,__ge__, "ge(a, b) -- Same as a>=b.") + + {"_compare_digest", (PyCFunction)compare_digest, METH_VARARGS, + compare_digest__doc__}, + {"length_hint", (PyCFunction)length_hint, METH_VARARGS, + length_hint__doc__}, + {NULL, NULL} /* sentinel */ + +}; + +/* itemgetter object **********************************************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t nitems; + PyObject *item; +} itemgetterobject; + +static PyTypeObject itemgetter_type; + +static PyObject * +itemgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + itemgetterobject *ig; + PyObject *item; + Py_ssize_t nitems; + + if (!_PyArg_NoKeywords("itemgetter()", kwds)) + return NULL; + + nitems = PyTuple_GET_SIZE(args); + if (nitems <= 1) { + if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &item)) + return NULL; + } else + item = args; + + /* create itemgetterobject structure */ + ig = PyObject_GC_New(itemgetterobject, &itemgetter_type); + if (ig == NULL) + return NULL; + + Py_INCREF(item); + ig->item = item; + ig->nitems = nitems; + + PyObject_GC_Track(ig); + return (PyObject *)ig; +} + +static void +itemgetter_dealloc(itemgetterobject *ig) +{ + PyObject_GC_UnTrack(ig); + Py_XDECREF(ig->item); + PyObject_GC_Del(ig); +} + +static int +itemgetter_traverse(itemgetterobject *ig, visitproc visit, void *arg) +{ + Py_VISIT(ig->item); + return 0; +} + +static PyObject * +itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw) +{ + PyObject *obj, *result; + Py_ssize_t i, nitems=ig->nitems; + + if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &obj)) + return NULL; + if (nitems == 1) + return PyObject_GetItem(obj, ig->item); + + assert(PyTuple_Check(ig->item)); + assert(PyTuple_GET_SIZE(ig->item) == nitems); + + result = PyTuple_New(nitems); + if (result == NULL) + return NULL; + + for (i=0 ; i < nitems ; i++) { + PyObject *item, *val; + item = PyTuple_GET_ITEM(ig->item, i); + val = PyObject_GetItem(obj, item); + if (val == NULL) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, val); + } + return result; +} + +PyDoc_STRVAR(itemgetter_doc, +"itemgetter(item, ...) --> itemgetter object\n\ +\n\ +Return a callable object that fetches the given item(s) from its operand.\n\ +After f=itemgetter(2), the call f(r) returns r[2].\n\ +After g=itemgetter(2,5,3), the call g(r) returns (r[2], r[5], r[3])"); + +static PyTypeObject itemgetter_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "operator.itemgetter", /* tp_name */ + sizeof(itemgetterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)itemgetter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)itemgetter_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + itemgetter_doc, /* tp_doc */ + (traverseproc)itemgetter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + itemgetter_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/* attrgetter object **********************************************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t nattrs; + PyObject *attr; +} attrgetterobject; + +static PyTypeObject attrgetter_type; + +static PyObject * +attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + attrgetterobject *ag; + PyObject *attr; + Py_ssize_t nattrs, idx, char_idx; + + if (!_PyArg_NoKeywords("attrgetter()", kwds)) + return NULL; + + nattrs = PyTuple_GET_SIZE(args); + if (nattrs <= 1) { + if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &attr)) + return NULL; + } + + attr = PyTuple_New(nattrs); + if (attr == NULL) + return NULL; + + /* prepare attr while checking args */ + for (idx = 0; idx < nattrs; ++idx) { + PyObject *item = PyTuple_GET_ITEM(args, idx); + Py_ssize_t item_len; + void *data; + unsigned int kind; + int dot_count; + + if (!PyUnicode_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "attribute name must be a string"); + Py_DECREF(attr); + return NULL; + } + if (PyUnicode_READY(item)) { + Py_DECREF(attr); + return NULL; + } + item_len = PyUnicode_GET_LENGTH(item); + kind = PyUnicode_KIND(item); + data = PyUnicode_DATA(item); + + /* check whethere the string is dotted */ + dot_count = 0; + for (char_idx = 0; char_idx < item_len; ++char_idx) { + if (PyUnicode_READ(kind, data, char_idx) == '.') + ++dot_count; + } + + if (dot_count == 0) { + Py_INCREF(item); + PyUnicode_InternInPlace(&item); + PyTuple_SET_ITEM(attr, idx, item); + } else { /* make it a tuple of non-dotted attrnames */ + PyObject *attr_chain = PyTuple_New(dot_count + 1); + PyObject *attr_chain_item; + Py_ssize_t unibuff_from = 0; + Py_ssize_t unibuff_till = 0; + Py_ssize_t attr_chain_idx = 0; + + if (attr_chain == NULL) { + Py_DECREF(attr); + return NULL; + } + + for (; dot_count > 0; --dot_count) { + while (PyUnicode_READ(kind, data, unibuff_till) != '.') { + ++unibuff_till; + } + attr_chain_item = PyUnicode_Substring(item, + unibuff_from, + unibuff_till); + if (attr_chain_item == NULL) { + Py_DECREF(attr_chain); + Py_DECREF(attr); + return NULL; + } + PyUnicode_InternInPlace(&attr_chain_item); + PyTuple_SET_ITEM(attr_chain, attr_chain_idx, attr_chain_item); + ++attr_chain_idx; + unibuff_till = unibuff_from = unibuff_till + 1; + } + + /* now add the last dotless name */ + attr_chain_item = PyUnicode_Substring(item, + unibuff_from, item_len); + if (attr_chain_item == NULL) { + Py_DECREF(attr_chain); + Py_DECREF(attr); + return NULL; + } + PyUnicode_InternInPlace(&attr_chain_item); + PyTuple_SET_ITEM(attr_chain, attr_chain_idx, attr_chain_item); + + PyTuple_SET_ITEM(attr, idx, attr_chain); + } + } + + /* create attrgetterobject structure */ + ag = PyObject_GC_New(attrgetterobject, &attrgetter_type); + if (ag == NULL) { + Py_DECREF(attr); + return NULL; + } + + ag->attr = attr; + ag->nattrs = nattrs; + + PyObject_GC_Track(ag); + return (PyObject *)ag; +} + +static void +attrgetter_dealloc(attrgetterobject *ag) +{ + PyObject_GC_UnTrack(ag); + Py_XDECREF(ag->attr); + PyObject_GC_Del(ag); +} + +static int +attrgetter_traverse(attrgetterobject *ag, visitproc visit, void *arg) +{ + Py_VISIT(ag->attr); + return 0; +} + +static PyObject * +dotted_getattr(PyObject *obj, PyObject *attr) +{ + PyObject *newobj; + + /* attr is either a tuple or instance of str. + Ensured by the setup code of attrgetter_new */ + if (PyTuple_CheckExact(attr)) { /* chained getattr */ + Py_ssize_t name_idx = 0, name_count; + PyObject *attr_name; + + name_count = PyTuple_GET_SIZE(attr); + Py_INCREF(obj); + for (name_idx = 0; name_idx < name_count; ++name_idx) { + attr_name = PyTuple_GET_ITEM(attr, name_idx); + newobj = PyObject_GetAttr(obj, attr_name); + Py_DECREF(obj); + if (newobj == NULL) { + return NULL; + } + /* here */ + obj = newobj; + } + } else { /* single getattr */ + newobj = PyObject_GetAttr(obj, attr); + if (newobj == NULL) + return NULL; + obj = newobj; + } + + return obj; +} + +static PyObject * +attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw) +{ + PyObject *obj, *result; + Py_ssize_t i, nattrs=ag->nattrs; + + if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &obj)) + return NULL; + if (ag->nattrs == 1) /* ag->attr is always a tuple */ + return dotted_getattr(obj, PyTuple_GET_ITEM(ag->attr, 0)); + + assert(PyTuple_Check(ag->attr)); + assert(PyTuple_GET_SIZE(ag->attr) == nattrs); + + result = PyTuple_New(nattrs); + if (result == NULL) + return NULL; + + for (i=0 ; i < nattrs ; i++) { + PyObject *attr, *val; + attr = PyTuple_GET_ITEM(ag->attr, i); + val = dotted_getattr(obj, attr); + if (val == NULL) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, val); + } + return result; +} + +PyDoc_STRVAR(attrgetter_doc, +"attrgetter(attr, ...) --> attrgetter object\n\ +\n\ +Return a callable object that fetches the given attribute(s) from its operand.\n\ +After f=attrgetter('name'), the call f(r) returns r.name.\n\ +After g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\ +After h=attrgetter('name.first', 'name.last'), the call h(r) returns\n\ +(r.name.first, r.name.last)."); + +static PyTypeObject attrgetter_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "operator.attrgetter", /* tp_name */ + sizeof(attrgetterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)attrgetter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)attrgetter_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + attrgetter_doc, /* tp_doc */ + (traverseproc)attrgetter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + attrgetter_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/* methodcaller object **********************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *name; + PyObject *args; + PyObject *kwds; +} methodcallerobject; + +static PyTypeObject methodcaller_type; + +static PyObject * +methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + methodcallerobject *mc; + PyObject *name, *newargs; + + if (PyTuple_GET_SIZE(args) < 1) { + PyErr_SetString(PyExc_TypeError, "methodcaller needs at least " + "one argument, the method name"); + return NULL; + } + + /* create methodcallerobject structure */ + mc = PyObject_GC_New(methodcallerobject, &methodcaller_type); + if (mc == NULL) + return NULL; + + newargs = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); + if (newargs == NULL) { + Py_DECREF(mc); + return NULL; + } + mc->args = newargs; + + name = PyTuple_GET_ITEM(args, 0); + Py_INCREF(name); + mc->name = name; + + Py_XINCREF(kwds); + mc->kwds = kwds; + + PyObject_GC_Track(mc); + return (PyObject *)mc; +} + +static void +methodcaller_dealloc(methodcallerobject *mc) +{ + PyObject_GC_UnTrack(mc); + Py_XDECREF(mc->name); + Py_XDECREF(mc->args); + Py_XDECREF(mc->kwds); + PyObject_GC_Del(mc); +} + +static int +methodcaller_traverse(methodcallerobject *mc, visitproc visit, void *arg) +{ + Py_VISIT(mc->args); + Py_VISIT(mc->kwds); + return 0; +} + +static PyObject * +methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw) +{ + PyObject *method, *obj, *result; + + if (!PyArg_UnpackTuple(args, "methodcaller", 1, 1, &obj)) + return NULL; + method = PyObject_GetAttr(obj, mc->name); + if (method == NULL) + return NULL; + result = PyObject_Call(method, mc->args, mc->kwds); + Py_DECREF(method); + return result; +} + +PyDoc_STRVAR(methodcaller_doc, +"methodcaller(name, ...) --> methodcaller object\n\ +\n\ +Return a callable object that calls the given method on its operand.\n\ +After f = methodcaller('name'), the call f(r) returns r.name().\n\ +After g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\ +r.name('date', foo=1)."); + +static PyTypeObject methodcaller_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "operator.methodcaller", /* tp_name */ + sizeof(methodcallerobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)methodcaller_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)methodcaller_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + methodcaller_doc, /* tp_doc */ + (traverseproc)methodcaller_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + methodcaller_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/* Initialization function for the module (*must* be called PyInit__operator) */ + + +static struct PyModuleDef operatormodule = { + PyModuleDef_HEAD_INIT, + "_operator", + operator_doc, + -1, + operator_methods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC +PyInit__operator(void) +{ + PyObject *m; + + /* Create the module and add the functions */ + m = PyModule_Create(&operatormodule); + if (m == NULL) + return NULL; + + if (PyType_Ready(&itemgetter_type) < 0) + return NULL; + Py_INCREF(&itemgetter_type); + PyModule_AddObject(m, "itemgetter", (PyObject *)&itemgetter_type); + + if (PyType_Ready(&attrgetter_type) < 0) + return NULL; + Py_INCREF(&attrgetter_type); + PyModule_AddObject(m, "attrgetter", (PyObject *)&attrgetter_type); + + if (PyType_Ready(&methodcaller_type) < 0) + return NULL; + Py_INCREF(&methodcaller_type); + PyModule_AddObject(m, "methodcaller", (PyObject *)&methodcaller_type); + return m; +} diff -r 7c717d423160 Modules/operator.c --- a/Modules/operator.c Wed Dec 19 15:28:46 2012 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,962 +0,0 @@ - -#include "Python.h" - -PyDoc_STRVAR(operator_doc, -"Operator interface.\n\ -\n\ -This module exports a set of functions implemented in C corresponding\n\ -to the intrinsic operators of Python. For example, operator.add(x, y)\n\ -is equivalent to the expression x+y. The function names are those\n\ -used for special methods; variants without leading and trailing\n\ -'__' are also provided for convenience."); - -#define spam1(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a1) { \ - return AOP(a1); } - -#define spam2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ - PyObject *a1, *a2; \ - if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ - return AOP(a1,a2); } - -#define spamoi(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ - PyObject *a1; int a2; \ - if(! PyArg_ParseTuple(a,"Oi:" #OP,&a1,&a2)) return NULL; \ - return AOP(a1,a2); } - -#define spam2n(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ - PyObject *a1, *a2; \ - if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ - if(-1 == AOP(a1,a2)) return NULL; \ - Py_INCREF(Py_None); \ - return Py_None; } - -#define spam3n(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ - PyObject *a1, *a2, *a3; \ - if(! PyArg_UnpackTuple(a,#OP,3,3,&a1,&a2,&a3)) return NULL; \ - if(-1 == AOP(a1,a2,a3)) return NULL; \ - Py_INCREF(Py_None); \ - return Py_None; } - -#define spami(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a1) { \ - long r; \ - if(-1 == (r=AOP(a1))) return NULL; \ - return PyBool_FromLong(r); } - -#define spami2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ - PyObject *a1, *a2; long r; \ - if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ - if(-1 == (r=AOP(a1,a2))) return NULL; \ - return PyLong_FromLong(r); } - -#define spamn2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ - PyObject *a1, *a2; Py_ssize_t r; \ - if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ - if(-1 == (r=AOP(a1,a2))) return NULL; \ - return PyLong_FromSsize_t(r); } - -#define spami2b(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ - PyObject *a1, *a2; long r; \ - if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ - if(-1 == (r=AOP(a1,a2))) return NULL; \ - return PyBool_FromLong(r); } - -#define spamrc(OP,A) static PyObject *OP(PyObject *s, PyObject *a) { \ - PyObject *a1, *a2; \ - if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ - return PyObject_RichCompare(a1,a2,A); } - -spami(truth , PyObject_IsTrue) -spam2(op_add , PyNumber_Add) -spam2(op_sub , PyNumber_Subtract) -spam2(op_mul , PyNumber_Multiply) -spam2(op_floordiv , PyNumber_FloorDivide) -spam2(op_truediv , PyNumber_TrueDivide) -spam2(op_mod , PyNumber_Remainder) -spam1(op_neg , PyNumber_Negative) -spam1(op_pos , PyNumber_Positive) -spam1(op_abs , PyNumber_Absolute) -spam1(op_inv , PyNumber_Invert) -spam1(op_invert , PyNumber_Invert) -spam2(op_lshift , PyNumber_Lshift) -spam2(op_rshift , PyNumber_Rshift) -spami(op_not_ , PyObject_Not) -spam2(op_and_ , PyNumber_And) -spam2(op_xor , PyNumber_Xor) -spam2(op_or_ , PyNumber_Or) -spam2(op_iadd , PyNumber_InPlaceAdd) -spam2(op_isub , PyNumber_InPlaceSubtract) -spam2(op_imul , PyNumber_InPlaceMultiply) -spam2(op_ifloordiv , PyNumber_InPlaceFloorDivide) -spam2(op_itruediv , PyNumber_InPlaceTrueDivide) -spam2(op_imod , PyNumber_InPlaceRemainder) -spam2(op_ilshift , PyNumber_InPlaceLshift) -spam2(op_irshift , PyNumber_InPlaceRshift) -spam2(op_iand , PyNumber_InPlaceAnd) -spam2(op_ixor , PyNumber_InPlaceXor) -spam2(op_ior , PyNumber_InPlaceOr) -spam2(op_concat , PySequence_Concat) -spam2(op_iconcat , PySequence_InPlaceConcat) -spami2b(op_contains , PySequence_Contains) -spamn2(indexOf , PySequence_Index) -spamn2(countOf , PySequence_Count) -spam2(op_getitem , PyObject_GetItem) -spam2n(op_delitem , PyObject_DelItem) -spam3n(op_setitem , PyObject_SetItem) -spamrc(op_lt , Py_LT) -spamrc(op_le , Py_LE) -spamrc(op_eq , Py_EQ) -spamrc(op_ne , Py_NE) -spamrc(op_gt , Py_GT) -spamrc(op_ge , Py_GE) - -static PyObject* -op_pow(PyObject *s, PyObject *a) -{ - PyObject *a1, *a2; - if (PyArg_UnpackTuple(a,"pow", 2, 2, &a1, &a2)) - return PyNumber_Power(a1, a2, Py_None); - return NULL; -} - -static PyObject* -op_ipow(PyObject *s, PyObject *a) -{ - PyObject *a1, *a2; - if (PyArg_UnpackTuple(a,"ipow", 2, 2, &a1, &a2)) - return PyNumber_InPlacePower(a1, a2, Py_None); - return NULL; -} - -static PyObject * -op_index(PyObject *s, PyObject *a) -{ - return PyNumber_Index(a); -} - -static PyObject* -is_(PyObject *s, PyObject *a) -{ - PyObject *a1, *a2, *result = NULL; - if (PyArg_UnpackTuple(a,"is_", 2, 2, &a1, &a2)) { - result = (a1 == a2) ? Py_True : Py_False; - Py_INCREF(result); - } - return result; -} - -static PyObject* -is_not(PyObject *s, PyObject *a) -{ - PyObject *a1, *a2, *result = NULL; - if (PyArg_UnpackTuple(a,"is_not", 2, 2, &a1, &a2)) { - result = (a1 != a2) ? Py_True : Py_False; - Py_INCREF(result); - } - return result; -} - -#undef spam1 -#undef spam2 -#undef spam1o -#undef spam1o - -/* compare_digest **********************************************************/ - -/* - * timing safe compare - * - * Returns 1 of the strings are equal. - * In case of len(a) != len(b) the function tries to keep the timing - * dependent on the length of b. CPU cache locally may still alter timing - * a bit. - */ -static int -_tscmp(const unsigned char *a, const unsigned char *b, - Py_ssize_t len_a, Py_ssize_t len_b) -{ - /* The volatile type declarations make sure that the compiler has no - * chance to optimize and fold the code in any way that may change - * the timing. - */ - volatile Py_ssize_t length; - volatile const unsigned char *left; - volatile const unsigned char *right; - Py_ssize_t i; - unsigned char result; - - /* loop count depends on length of b */ - length = len_b; - left = NULL; - right = b; - - /* don't use else here to keep the amount of CPU instructions constant, - * volatile forces re-evaluation - * */ - if (len_a == length) { - left = *((volatile const unsigned char**)&a); - result = 0; - } - if (len_a != length) { - left = b; - result = 1; - } - - for (i=0; i < length; i++) { - result |= *left++ ^ *right++; - } - - return (result == 0); -} - -PyDoc_STRVAR(length_hint__doc__, -"length_hint(obj, default=0) -> int\n" -"Return an estimate of the number of items in obj.\n" -"This is useful for presizing containers when building from an\n" -"iterable.\n" -"\n" -"If the object supports len(), the result will be\n" -"exact. Otherwise, it may over- or under-estimate by an\n" -"arbitrary amount. The result will be an integer >= 0."); - -static PyObject *length_hint(PyObject *self, PyObject *args) -{ - PyObject *obj; - Py_ssize_t defaultvalue = 0, res; - if (!PyArg_ParseTuple(args, "O|n:length_hint", &obj, &defaultvalue)) { - return NULL; - } - res = PyObject_LengthHint(obj, defaultvalue); - if (res == -1 && PyErr_Occurred()) { - return NULL; - } - return PyLong_FromSsize_t(res); -} - - -PyDoc_STRVAR(compare_digest__doc__, -"compare_digest(a, b) -> bool\n" -"\n" -"Return 'a == b'. This function uses an approach designed to prevent\n" -"timing analysis, making it appropriate for cryptography.\n" -"a and b must both be of the same type: either str (ASCII only),\n" -"or any type that supports the buffer protocol (e.g. bytes).\n" -"\n" -"Note: If a and b are of different lengths, or if an error occurs,\n" -"a timing attack could theoretically reveal information about the\n" -"types and lengths of a and b--but not their values.\n"); - -static PyObject* -compare_digest(PyObject *self, PyObject *args) -{ - PyObject *a, *b; - int rc; - - if (!PyArg_ParseTuple(args, "OO:compare_digest", &a, &b)) { - return NULL; - } - - /* ASCII unicode string */ - if(PyUnicode_Check(a) && PyUnicode_Check(b)) { - if (PyUnicode_READY(a) == -1 || PyUnicode_READY(b) == -1) { - return NULL; - } - if (!PyUnicode_IS_ASCII(a) || !PyUnicode_IS_ASCII(b)) { - PyErr_SetString(PyExc_TypeError, - "comparing strings with non-ASCII characters is " - "not supported"); - return NULL; - } - - rc = _tscmp(PyUnicode_DATA(a), - PyUnicode_DATA(b), - PyUnicode_GET_LENGTH(a), - PyUnicode_GET_LENGTH(b)); - } - /* fallback to buffer interface for bytes, bytesarray and other */ - else { - Py_buffer view_a; - Py_buffer view_b; - - if ((PyObject_CheckBuffer(a) == 0) & (PyObject_CheckBuffer(b) == 0)) { - PyErr_Format(PyExc_TypeError, - "unsupported operand types(s) or combination of types: " - "'%.100s' and '%.100s'", - Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name); - return NULL; - } - - if (PyObject_GetBuffer(a, &view_a, PyBUF_SIMPLE) == -1) { - return NULL; - } - if (view_a.ndim > 1) { - PyErr_SetString(PyExc_BufferError, - "Buffer must be single dimension"); - PyBuffer_Release(&view_a); - return NULL; - } - - if (PyObject_GetBuffer(b, &view_b, PyBUF_SIMPLE) == -1) { - PyBuffer_Release(&view_a); - return NULL; - } - if (view_b.ndim > 1) { - PyErr_SetString(PyExc_BufferError, - "Buffer must be single dimension"); - PyBuffer_Release(&view_a); - PyBuffer_Release(&view_b); - return NULL; - } - - rc = _tscmp((const unsigned char*)view_a.buf, - (const unsigned char*)view_b.buf, - view_a.len, - view_b.len); - - PyBuffer_Release(&view_a); - PyBuffer_Release(&view_b); - } - - return PyBool_FromLong(rc); -} - -/* operator methods **********************************************************/ - -#define spam1(OP,DOC) {#OP, OP, METH_VARARGS, PyDoc_STR(DOC)}, -#define spam2(OP,ALTOP,DOC) {#OP, op_##OP, METH_VARARGS, PyDoc_STR(DOC)}, \ - {#ALTOP, op_##OP, METH_VARARGS, PyDoc_STR(DOC)}, -#define spam1o(OP,DOC) {#OP, OP, METH_O, PyDoc_STR(DOC)}, -#define spam2o(OP,ALTOP,DOC) {#OP, op_##OP, METH_O, PyDoc_STR(DOC)}, \ - {#ALTOP, op_##OP, METH_O, PyDoc_STR(DOC)}, - -static struct PyMethodDef operator_methods[] = { - -spam1o(truth, - "truth(a) -- Return True if a is true, False otherwise.") -spam2(contains,__contains__, - "contains(a, b) -- Same as b in a (note reversed operands).") -spam1(indexOf, - "indexOf(a, b) -- Return the first index of b in a.") -spam1(countOf, - "countOf(a, b) -- Return the number of times b occurs in a.") - -spam1(is_, "is_(a, b) -- Same as a is b.") -spam1(is_not, "is_not(a, b) -- Same as a is not b.") -spam2o(index, __index__, "index(a) -- Same as a.__index__()") -spam2(add,__add__, "add(a, b) -- Same as a + b.") -spam2(sub,__sub__, "sub(a, b) -- Same as a - b.") -spam2(mul,__mul__, "mul(a, b) -- Same as a * b.") -spam2(floordiv,__floordiv__, "floordiv(a, b) -- Same as a // b.") -spam2(truediv,__truediv__, "truediv(a, b) -- Same as a / b.") -spam2(mod,__mod__, "mod(a, b) -- Same as a % b.") -spam2o(neg,__neg__, "neg(a) -- Same as -a.") -spam2o(pos,__pos__, "pos(a) -- Same as +a.") -spam2o(abs,__abs__, "abs(a) -- Same as abs(a).") -spam2o(inv,__inv__, "inv(a) -- Same as ~a.") -spam2o(invert,__invert__, "invert(a) -- Same as ~a.") -spam2(lshift,__lshift__, "lshift(a, b) -- Same as a << b.") -spam2(rshift,__rshift__, "rshift(a, b) -- Same as a >> b.") -spam2o(not_,__not__, "not_(a) -- Same as not a.") -spam2(and_,__and__, "and_(a, b) -- Same as a & b.") -spam2(xor,__xor__, "xor(a, b) -- Same as a ^ b.") -spam2(or_,__or__, "or_(a, b) -- Same as a | b.") -spam2(iadd,__iadd__, "a = iadd(a, b) -- Same as a += b.") -spam2(isub,__isub__, "a = isub(a, b) -- Same as a -= b.") -spam2(imul,__imul__, "a = imul(a, b) -- Same as a *= b.") -spam2(ifloordiv,__ifloordiv__, "a = ifloordiv(a, b) -- Same as a //= b.") -spam2(itruediv,__itruediv__, "a = itruediv(a, b) -- Same as a /= b") -spam2(imod,__imod__, "a = imod(a, b) -- Same as a %= b.") -spam2(ilshift,__ilshift__, "a = ilshift(a, b) -- Same as a <<= b.") -spam2(irshift,__irshift__, "a = irshift(a, b) -- Same as a >>= b.") -spam2(iand,__iand__, "a = iand(a, b) -- Same as a &= b.") -spam2(ixor,__ixor__, "a = ixor(a, b) -- Same as a ^= b.") -spam2(ior,__ior__, "a = ior(a, b) -- Same as a |= b.") -spam2(concat,__concat__, - "concat(a, b) -- Same as a + b, for a and b sequences.") -spam2(iconcat,__iconcat__, - "a = iconcat(a, b) -- Same as a += b, for a and b sequences.") -spam2(getitem,__getitem__, - "getitem(a, b) -- Same as a[b].") -spam2(setitem,__setitem__, - "setitem(a, b, c) -- Same as a[b] = c.") -spam2(delitem,__delitem__, - "delitem(a, b) -- Same as del a[b].") -spam2(pow,__pow__, "pow(a, b) -- Same as a ** b.") -spam2(ipow,__ipow__, "a = ipow(a, b) -- Same as a **= b.") -spam2(lt,__lt__, "lt(a, b) -- Same as ab.") -spam2(ge,__ge__, "ge(a, b) -- Same as a>=b.") - - {"_compare_digest", (PyCFunction)compare_digest, METH_VARARGS, - compare_digest__doc__}, - {"length_hint", (PyCFunction)length_hint, METH_VARARGS, - length_hint__doc__}, - {NULL, NULL} /* sentinel */ - -}; - -/* itemgetter object **********************************************************/ - -typedef struct { - PyObject_HEAD - Py_ssize_t nitems; - PyObject *item; -} itemgetterobject; - -static PyTypeObject itemgetter_type; - -static PyObject * -itemgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - itemgetterobject *ig; - PyObject *item; - Py_ssize_t nitems; - - if (!_PyArg_NoKeywords("itemgetter()", kwds)) - return NULL; - - nitems = PyTuple_GET_SIZE(args); - if (nitems <= 1) { - if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &item)) - return NULL; - } else - item = args; - - /* create itemgetterobject structure */ - ig = PyObject_GC_New(itemgetterobject, &itemgetter_type); - if (ig == NULL) - return NULL; - - Py_INCREF(item); - ig->item = item; - ig->nitems = nitems; - - PyObject_GC_Track(ig); - return (PyObject *)ig; -} - -static void -itemgetter_dealloc(itemgetterobject *ig) -{ - PyObject_GC_UnTrack(ig); - Py_XDECREF(ig->item); - PyObject_GC_Del(ig); -} - -static int -itemgetter_traverse(itemgetterobject *ig, visitproc visit, void *arg) -{ - Py_VISIT(ig->item); - return 0; -} - -static PyObject * -itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw) -{ - PyObject *obj, *result; - Py_ssize_t i, nitems=ig->nitems; - - if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &obj)) - return NULL; - if (nitems == 1) - return PyObject_GetItem(obj, ig->item); - - assert(PyTuple_Check(ig->item)); - assert(PyTuple_GET_SIZE(ig->item) == nitems); - - result = PyTuple_New(nitems); - if (result == NULL) - return NULL; - - for (i=0 ; i < nitems ; i++) { - PyObject *item, *val; - item = PyTuple_GET_ITEM(ig->item, i); - val = PyObject_GetItem(obj, item); - if (val == NULL) { - Py_DECREF(result); - return NULL; - } - PyTuple_SET_ITEM(result, i, val); - } - return result; -} - -PyDoc_STRVAR(itemgetter_doc, -"itemgetter(item, ...) --> itemgetter object\n\ -\n\ -Return a callable object that fetches the given item(s) from its operand.\n\ -After, f=itemgetter(2), the call f(r) returns r[2].\n\ -After, g=itemgetter(2,5,3), the call g(r) returns (r[2], r[5], r[3])"); - -static PyTypeObject itemgetter_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "operator.itemgetter", /* tp_name */ - sizeof(itemgetterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)itemgetter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)itemgetter_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - itemgetter_doc, /* tp_doc */ - (traverseproc)itemgetter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - itemgetter_new, /* tp_new */ - 0, /* tp_free */ -}; - - -/* attrgetter object **********************************************************/ - -typedef struct { - PyObject_HEAD - Py_ssize_t nattrs; - PyObject *attr; -} attrgetterobject; - -static PyTypeObject attrgetter_type; - -static PyObject * -attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - attrgetterobject *ag; - PyObject *attr; - Py_ssize_t nattrs, idx, char_idx; - - if (!_PyArg_NoKeywords("attrgetter()", kwds)) - return NULL; - - nattrs = PyTuple_GET_SIZE(args); - if (nattrs <= 1) { - if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &attr)) - return NULL; - } - - attr = PyTuple_New(nattrs); - if (attr == NULL) - return NULL; - - /* prepare attr while checking args */ - for (idx = 0; idx < nattrs; ++idx) { - PyObject *item = PyTuple_GET_ITEM(args, idx); - Py_ssize_t item_len; - void *data; - unsigned int kind; - int dot_count; - - if (!PyUnicode_Check(item)) { - PyErr_SetString(PyExc_TypeError, - "attribute name must be a string"); - Py_DECREF(attr); - return NULL; - } - if (PyUnicode_READY(item)) { - Py_DECREF(attr); - return NULL; - } - item_len = PyUnicode_GET_LENGTH(item); - kind = PyUnicode_KIND(item); - data = PyUnicode_DATA(item); - - /* check whethere the string is dotted */ - dot_count = 0; - for (char_idx = 0; char_idx < item_len; ++char_idx) { - if (PyUnicode_READ(kind, data, char_idx) == '.') - ++dot_count; - } - - if (dot_count == 0) { - Py_INCREF(item); - PyUnicode_InternInPlace(&item); - PyTuple_SET_ITEM(attr, idx, item); - } else { /* make it a tuple of non-dotted attrnames */ - PyObject *attr_chain = PyTuple_New(dot_count + 1); - PyObject *attr_chain_item; - Py_ssize_t unibuff_from = 0; - Py_ssize_t unibuff_till = 0; - Py_ssize_t attr_chain_idx = 0; - - if (attr_chain == NULL) { - Py_DECREF(attr); - return NULL; - } - - for (; dot_count > 0; --dot_count) { - while (PyUnicode_READ(kind, data, unibuff_till) != '.') { - ++unibuff_till; - } - attr_chain_item = PyUnicode_Substring(item, - unibuff_from, - unibuff_till); - if (attr_chain_item == NULL) { - Py_DECREF(attr_chain); - Py_DECREF(attr); - return NULL; - } - PyUnicode_InternInPlace(&attr_chain_item); - PyTuple_SET_ITEM(attr_chain, attr_chain_idx, attr_chain_item); - ++attr_chain_idx; - unibuff_till = unibuff_from = unibuff_till + 1; - } - - /* now add the last dotless name */ - attr_chain_item = PyUnicode_Substring(item, - unibuff_from, item_len); - if (attr_chain_item == NULL) { - Py_DECREF(attr_chain); - Py_DECREF(attr); - return NULL; - } - PyUnicode_InternInPlace(&attr_chain_item); - PyTuple_SET_ITEM(attr_chain, attr_chain_idx, attr_chain_item); - - PyTuple_SET_ITEM(attr, idx, attr_chain); - } - } - - /* create attrgetterobject structure */ - ag = PyObject_GC_New(attrgetterobject, &attrgetter_type); - if (ag == NULL) { - Py_DECREF(attr); - return NULL; - } - - ag->attr = attr; - ag->nattrs = nattrs; - - PyObject_GC_Track(ag); - return (PyObject *)ag; -} - -static void -attrgetter_dealloc(attrgetterobject *ag) -{ - PyObject_GC_UnTrack(ag); - Py_XDECREF(ag->attr); - PyObject_GC_Del(ag); -} - -static int -attrgetter_traverse(attrgetterobject *ag, visitproc visit, void *arg) -{ - Py_VISIT(ag->attr); - return 0; -} - -static PyObject * -dotted_getattr(PyObject *obj, PyObject *attr) -{ - PyObject *newobj; - - /* attr is either a tuple or instance of str. - Ensured by the setup code of attrgetter_new */ - if (PyTuple_CheckExact(attr)) { /* chained getattr */ - Py_ssize_t name_idx = 0, name_count; - PyObject *attr_name; - - name_count = PyTuple_GET_SIZE(attr); - Py_INCREF(obj); - for (name_idx = 0; name_idx < name_count; ++name_idx) { - attr_name = PyTuple_GET_ITEM(attr, name_idx); - newobj = PyObject_GetAttr(obj, attr_name); - Py_DECREF(obj); - if (newobj == NULL) { - return NULL; - } - /* here */ - obj = newobj; - } - } else { /* single getattr */ - newobj = PyObject_GetAttr(obj, attr); - if (newobj == NULL) - return NULL; - obj = newobj; - } - - return obj; -} - -static PyObject * -attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw) -{ - PyObject *obj, *result; - Py_ssize_t i, nattrs=ag->nattrs; - - if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &obj)) - return NULL; - if (ag->nattrs == 1) /* ag->attr is always a tuple */ - return dotted_getattr(obj, PyTuple_GET_ITEM(ag->attr, 0)); - - assert(PyTuple_Check(ag->attr)); - assert(PyTuple_GET_SIZE(ag->attr) == nattrs); - - result = PyTuple_New(nattrs); - if (result == NULL) - return NULL; - - for (i=0 ; i < nattrs ; i++) { - PyObject *attr, *val; - attr = PyTuple_GET_ITEM(ag->attr, i); - val = dotted_getattr(obj, attr); - if (val == NULL) { - Py_DECREF(result); - return NULL; - } - PyTuple_SET_ITEM(result, i, val); - } - return result; -} - -PyDoc_STRVAR(attrgetter_doc, -"attrgetter(attr, ...) --> attrgetter object\n\ -\n\ -Return a callable object that fetches the given attribute(s) from its operand.\n\ -After, f=attrgetter('name'), the call f(r) returns r.name.\n\ -After, g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\ -After, h=attrgetter('name.first', 'name.last'), the call h(r) returns\n\ -(r.name.first, r.name.last)."); - -static PyTypeObject attrgetter_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "operator.attrgetter", /* tp_name */ - sizeof(attrgetterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)attrgetter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)attrgetter_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - attrgetter_doc, /* tp_doc */ - (traverseproc)attrgetter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - attrgetter_new, /* tp_new */ - 0, /* tp_free */ -}; - - -/* methodcaller object **********************************************************/ - -typedef struct { - PyObject_HEAD - PyObject *name; - PyObject *args; - PyObject *kwds; -} methodcallerobject; - -static PyTypeObject methodcaller_type; - -static PyObject * -methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - methodcallerobject *mc; - PyObject *name, *newargs; - - if (PyTuple_GET_SIZE(args) < 1) { - PyErr_SetString(PyExc_TypeError, "methodcaller needs at least " - "one argument, the method name"); - return NULL; - } - - /* create methodcallerobject structure */ - mc = PyObject_GC_New(methodcallerobject, &methodcaller_type); - if (mc == NULL) - return NULL; - - newargs = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); - if (newargs == NULL) { - Py_DECREF(mc); - return NULL; - } - mc->args = newargs; - - name = PyTuple_GET_ITEM(args, 0); - Py_INCREF(name); - mc->name = name; - - Py_XINCREF(kwds); - mc->kwds = kwds; - - PyObject_GC_Track(mc); - return (PyObject *)mc; -} - -static void -methodcaller_dealloc(methodcallerobject *mc) -{ - PyObject_GC_UnTrack(mc); - Py_XDECREF(mc->name); - Py_XDECREF(mc->args); - Py_XDECREF(mc->kwds); - PyObject_GC_Del(mc); -} - -static int -methodcaller_traverse(methodcallerobject *mc, visitproc visit, void *arg) -{ - Py_VISIT(mc->args); - Py_VISIT(mc->kwds); - return 0; -} - -static PyObject * -methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw) -{ - PyObject *method, *obj, *result; - - if (!PyArg_UnpackTuple(args, "methodcaller", 1, 1, &obj)) - return NULL; - method = PyObject_GetAttr(obj, mc->name); - if (method == NULL) - return NULL; - result = PyObject_Call(method, mc->args, mc->kwds); - Py_DECREF(method); - return result; -} - -PyDoc_STRVAR(methodcaller_doc, -"methodcaller(name, ...) --> methodcaller object\n\ -\n\ -Return a callable object that calls the given method on its operand.\n\ -After, f = methodcaller('name'), the call f(r) returns r.name().\n\ -After, g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\ -r.name('date', foo=1)."); - -static PyTypeObject methodcaller_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "operator.methodcaller", /* tp_name */ - sizeof(methodcallerobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)methodcaller_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)methodcaller_call, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - methodcaller_doc, /* tp_doc */ - (traverseproc)methodcaller_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - methodcaller_new, /* tp_new */ - 0, /* tp_free */ -}; - - -/* Initialization function for the module (*must* be called PyInit_operator) */ - - -static struct PyModuleDef operatormodule = { - PyModuleDef_HEAD_INIT, - "operator", - operator_doc, - -1, - operator_methods, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC -PyInit_operator(void) -{ - PyObject *m; - - /* Create the module and add the functions */ - m = PyModule_Create(&operatormodule); - if (m == NULL) - return NULL; - - if (PyType_Ready(&itemgetter_type) < 0) - return NULL; - Py_INCREF(&itemgetter_type); - PyModule_AddObject(m, "itemgetter", (PyObject *)&itemgetter_type); - - if (PyType_Ready(&attrgetter_type) < 0) - return NULL; - Py_INCREF(&attrgetter_type); - PyModule_AddObject(m, "attrgetter", (PyObject *)&attrgetter_type); - - if (PyType_Ready(&methodcaller_type) < 0) - return NULL; - Py_INCREF(&methodcaller_type); - PyModule_AddObject(m, "methodcaller", (PyObject *)&methodcaller_type); - return m; -} diff -r 7c717d423160 PC/VC6/pythoncore.dsp --- a/PC/VC6/pythoncore.dsp Wed Dec 19 15:28:46 2012 -0600 +++ b/PC/VC6/pythoncore.dsp Thu Dec 20 18:26:25 2012 -0600 @@ -582,7 +582,7 @@ # End Source File # Begin Source File -SOURCE=..\..\Modules\operator.c +SOURCE=..\..\Modules\_operator.c # End Source File # Begin Source File diff -r 7c717d423160 PC/VS7.1/pythoncore.vcproj --- a/PC/VS7.1/pythoncore.vcproj Wed Dec 19 15:28:46 2012 -0600 +++ b/PC/VS7.1/pythoncore.vcproj Thu Dec 20 18:26:25 2012 -0600 @@ -688,7 +688,7 @@ RelativePath="..\..\Objects\obmalloc.c"> + RelativePath="..\..\Modules\_operator.c"> diff -r 7c717d423160 PC/VS8.0/pythoncore.vcproj --- a/PC/VS8.0/pythoncore.vcproj Wed Dec 19 15:28:46 2012 -0600 +++ b/PC/VS8.0/pythoncore.vcproj Thu Dec 20 18:26:25 2012 -0600 @@ -1115,7 +1115,7 @@ > - + diff -r 7c717d423160 PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters Wed Dec 19 15:28:46 2012 -0600 +++ b/PCbuild/pythoncore.vcxproj.filters Thu Dec 20 18:26:25 2012 -0600 @@ -498,7 +498,7 @@ Modules - + Modules