[Python-checkins] r55977 - in python/branches/cpy_merge: Lib/_abcoll.py Lib/abc.py Lib/test/test_abc.py Lib/test/test_super.py Lib/test/test_urllib2_localnet.py Tools/buildbot/build-amd64.bat Tools/buildbot/clean-amd64.bat Tools/buildbot/external-amd64.bat Tools/buildbot/test-amd64.bat
alexandre.vassalotti
python-checkins at python.org
Thu Jun 14 23:10:26 CEST 2007
Author: alexandre.vassalotti
Date: Thu Jun 14 23:10:12 2007
New Revision: 55977
Added:
python/branches/cpy_merge/Lib/_abcoll.py
python/branches/cpy_merge/Lib/abc.py
python/branches/cpy_merge/Lib/test/test_abc.py
python/branches/cpy_merge/Lib/test/test_super.py
python/branches/cpy_merge/Lib/test/test_urllib2_localnet.py
python/branches/cpy_merge/Tools/buildbot/build-amd64.bat
python/branches/cpy_merge/Tools/buildbot/clean-amd64.bat
python/branches/cpy_merge/Tools/buildbot/external-amd64.bat
python/branches/cpy_merge/Tools/buildbot/test-amd64.bat
Log:
Add new files from the merge in r55972.
Added: python/branches/cpy_merge/Lib/_abcoll.py
==============================================================================
--- (empty file)
+++ python/branches/cpy_merge/Lib/_abcoll.py Thu Jun 14 23:10:12 2007
@@ -0,0 +1,535 @@
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Abstract Base Classes (ABCs) for collections, according to PEP 3119.
+
+DON'T USE THIS MODULE DIRECTLY! The classes here should be imported
+via collections; they are defined here only to alleviate ceratin
+bootstrapping issues. Unit tests are in test_collections.
+"""
+
+from abc import ABCMeta, abstractmethod
+
+__all__ = ["Hashable", "Iterable", "Iterator",
+ "Sized", "Container", "Callable",
+ "Set", "MutableSet",
+ "Mapping", "MutableMapping",
+ "MappingView", "KeysView", "ItemsView", "ValuesView",
+ "Sequence", "MutableSequence",
+ ]
+
+### ONE-TRICK PONIES ###
+
+class Hashable(metaclass=ABCMeta):
+
+ @abstractmethod
+ def __hash__(self):
+ return 0
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Hashable:
+ for B in C.__mro__:
+ if "__hash__" in B.__dict__:
+ if B.__dict__["__hash__"]:
+ return True
+ break
+ return NotImplemented
+
+
+class Iterable(metaclass=ABCMeta):
+
+ @abstractmethod
+ def __iter__(self):
+ while False:
+ yield None
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Iterable:
+ if any("__iter__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
+
+Iterable.register(bytes)
+
+
+class Iterator(metaclass=ABCMeta):
+
+ @abstractmethod
+ def __next__(self):
+ raise StopIteration
+
+ def __iter__(self):
+ return self
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Iterator:
+ if any("__next__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
+
+
+class Sized(metaclass=ABCMeta):
+
+ @abstractmethod
+ def __len__(self):
+ return 0
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Sized:
+ if any("__len__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
+
+
+class Container(metaclass=ABCMeta):
+
+ @abstractmethod
+ def __contains__(self, x):
+ return False
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Container:
+ if any("__contains__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
+
+
+class Callable(metaclass=ABCMeta):
+
+ @abstractmethod
+ def __contains__(self, x):
+ return False
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Callable:
+ if any("__call__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
+
+
+### SETS ###
+
+
+class Set(metaclass=ABCMeta):
+
+ """A set is a finite, iterable container.
+
+ This class provides concrete generic implementations of all
+ methods except for __contains__, __iter__ and __len__.
+
+ To override the comparisons (presumably for speed, as the
+ semantics are fixed), all you have to do is redefine __le__ and
+ then the other operations will automatically follow suit.
+ """
+
+ @abstractmethod
+ def __contains__(self, value):
+ return False
+
+ @abstractmethod
+ def __iter__(self):
+ while False:
+ yield None
+
+ @abstractmethod
+ def __len__(self):
+ return 0
+
+ def __le__(self, other):
+ if not isinstance(other, Set):
+ return NotImplemented
+ if len(self) > len(other):
+ return False
+ for elem in self:
+ if elem not in other:
+ return False
+ return True
+
+ def __lt__(self, other):
+ if not isinstance(other, Set):
+ return NotImplemented
+ return len(self) < len(other) and self.__le__(other)
+
+ def __eq__(self, other):
+ if not isinstance(other, Set):
+ return NotImplemented
+ return len(self) == len(other) and self.__le__(other)
+
+ @classmethod
+ def _from_iterable(cls, it):
+ return frozenset(it)
+
+ def __and__(self, other):
+ if not isinstance(other, Iterable):
+ return NotImplemented
+ return self._from_iterable(value for value in other if value in self)
+
+ def __or__(self, other):
+ if not isinstance(other, Iterable):
+ return NotImplemented
+ return self._from_iterable(itertools.chain(self, other))
+
+ def __sub__(self, other):
+ if not isinstance(other, Set):
+ if not isinstance(other, Iterable):
+ return NotImplemented
+ other = self._from_iterable(other)
+ return self._from_iterable(value for value in self
+ if value not in other)
+
+ def __xor__(self, other):
+ if not isinstance(other, Set):
+ if not isinstance(other, Iterable):
+ return NotImplemented
+ other = self._from_iterable(other)
+ return (self - other) | (other - self)
+
+ def _hash(self):
+ """Compute the hash value of a set.
+
+ Note that we don't define __hash__: not all sets are hashable.
+ But if you define a hashable set type, its __hash__ should
+ call this function.
+
+ This must be compatible __eq__.
+
+ All sets ought to compare equal if they contain the same
+ elements, regardless of how they are implemented, and
+ regardless of the order of the elements; so there's not much
+ freedom for __eq__ or __hash__. We match the algorithm used
+ by the built-in frozenset type.
+ """
+ MAX = sys.maxint
+ MASK = 2 * MAX + 1
+ n = len(self)
+ h = 1927868237 * (n + 1)
+ h &= MASK
+ for x in self:
+ hx = hash(x)
+ h ^= (hx ^ (hx << 16) ^ 89869747) * 3644798167
+ h &= MASK
+ h = h * 69069 + 907133923
+ h &= MASK
+ if h > MAX:
+ h -= MASK + 1
+ if h == -1:
+ h = 590923713
+ return h
+
+Set.register(frozenset)
+
+
+class MutableSet(Set):
+
+ @abstractmethod
+ def add(self, value):
+ """Return True if it was added, False if already there."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def discard(self, value):
+ """Return True if it was deleted, False if not there."""
+ raise NotImplementedError
+
+ def pop(self):
+ """Return the popped value. Raise KeyError if empty."""
+ it = iter(self)
+ try:
+ value = it.__next__()
+ except StopIteration:
+ raise KeyError
+ self.discard(value)
+ return value
+
+ def toggle(self, value):
+ """Return True if it was added, False if deleted."""
+ # XXX This implementation is not thread-safe
+ if value in self:
+ self.discard(value)
+ return False
+ else:
+ self.add(value)
+ return True
+
+ def clear(self):
+ """This is slow (creates N new iterators!) but effective."""
+ try:
+ while True:
+ self.pop()
+ except KeyError:
+ pass
+
+ def __ior__(self, it: Iterable):
+ for value in it:
+ self.add(value)
+ return self
+
+ def __iand__(self, c: Container):
+ for value in self:
+ if value not in c:
+ self.discard(value)
+ return self
+
+ def __ixor__(self, it: Iterable):
+ # This calls toggle(), so if that is overridded, we call the override
+ for value in it:
+ self.toggle(it)
+ return self
+
+ def __isub__(self, it: Iterable):
+ for value in it:
+ self.discard(value)
+ return self
+
+MutableSet.register(set)
+
+
+### MAPPINGS ###
+
+
+class Mapping(metaclass=ABCMeta):
+
+ @abstractmethod
+ def __getitem__(self, key):
+ raise KeyError
+
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ def __contains__(self, key):
+ try:
+ self[key]
+ except KeyError:
+ return False
+ else:
+ return True
+
+ @abstractmethod
+ def __len__(self):
+ return 0
+
+ @abstractmethod
+ def __iter__(self):
+ while False:
+ yield None
+
+ def keys(self):
+ return KeysView(self)
+
+ def items(self):
+ return ItemsView(self)
+
+ def values(self):
+ return ValuesView(self)
+
+
+class MappingView(metaclass=ABCMeta):
+
+ def __init__(self, mapping):
+ self._mapping = mapping
+
+ def __len__(self):
+ return len(self._mapping)
+
+
+class KeysView(MappingView, Set):
+
+ def __contains__(self, key):
+ return key in self._mapping
+
+ def __iter__(self):
+ for key in self._mapping:
+ yield key
+
+KeysView.register(type({}.keys()))
+
+
+class ItemsView(MappingView, Set):
+
+ def __contains__(self, item):
+ key, value = item
+ try:
+ v = self._mapping[key]
+ except KeyError:
+ return False
+ else:
+ return v == value
+
+ def __iter__(self):
+ for key in self._mapping:
+ yield (key, self._mapping[key])
+
+ItemsView.register(type({}.items()))
+
+
+class ValuesView(MappingView):
+
+ def __contains__(self, value):
+ for key in self._mapping:
+ if value == self._mapping[key]:
+ return True
+ return False
+
+ def __iter__(self):
+ for key in self._mapping:
+ yield self._mapping[key]
+
+ValuesView.register(type({}.values()))
+
+
+class MutableMapping(Mapping):
+
+ @abstractmethod
+ def __setitem__(self, key, value):
+ raise KeyError
+
+ @abstractmethod
+ def __delitem__(self, key):
+ raise KeyError
+
+ __marker = object()
+
+ def pop(self, key, default=__marker):
+ try:
+ value = self[key]
+ except KeyError:
+ if default is self.__marker:
+ raise
+ return default
+ else:
+ del self[key]
+ return value
+
+ def popitem(self):
+ try:
+ key = next(iter(self))
+ except StopIteration:
+ raise KeyError
+ value = self[key]
+ del self[key]
+ return key, value
+
+ def clear(self):
+ try:
+ while True:
+ self.popitem()
+ except KeyError:
+ pass
+
+ def update(self, other=(), **kwds):
+ if isinstance(other, Mapping):
+ for key in other:
+ self[key] = other[key]
+ elif hasattr(other, "keys"):
+ for key in other.keys():
+ self[key] = other[key]
+ else:
+ for key, value in other:
+ self[key] = value
+ for key, value in kwds.items():
+ self[key] = value
+
+MutableMapping.register(dict)
+
+
+### SEQUENCES ###
+
+
+class Sequence(metaclass=ABCMeta):
+
+ """All the operations on a read-only sequence.
+
+ Concrete subclasses must override __new__ or __init__,
+ __getitem__, and __len__.
+ """
+
+ @abstractmethod
+ def __getitem__(self, index):
+ raise IndexError
+
+ @abstractmethod
+ def __len__(self):
+ return 0
+
+ def __iter__(self):
+ i = 0
+ while True:
+ try:
+ v = self[i]
+ except IndexError:
+ break
+ yield v
+ i += 1
+
+ def __contains__(self, value):
+ for v in self:
+ if v == value:
+ return True
+ return False
+
+ def __reversed__(self):
+ for i in reversed(range(len(self))):
+ yield self[i]
+
+ def index(self, value):
+ for i, v in enumerate(self):
+ if v == value:
+ return i
+ raise ValueError
+
+ def count(self, value):
+ return sum(1 for v in self if v == value)
+
+Sequence.register(tuple)
+Sequence.register(basestring)
+Sequence.register(buffer)
+
+
+class MutableSequence(Sequence):
+
+ @abstractmethod
+ def __setitem__(self, index, value):
+ raise IndexError
+
+ @abstractmethod
+ def __delitem__(self, index):
+ raise IndexError
+
+ @abstractmethod
+ def insert(self, index, value):
+ raise IndexError
+
+ def append(self, value):
+ self.insert(len(self), value)
+
+ def reverse(self):
+ n = len(self)
+ for i in range(n//2):
+ self[i], self[n-i-1] = self[n-i-1], self[i]
+
+ def extend(self, values):
+ for v in values:
+ self.append(v)
+
+ def pop(self, index=-1):
+ v = self[index]
+ del self[index]
+ return v
+
+ def remove(self, value):
+ del self[self.index(value)]
+
+ def __iadd__(self, values):
+ self.extend(values)
+
+MutableSequence.register(list)
+MutableSequence.register(bytes)
Added: python/branches/cpy_merge/Lib/abc.py
==============================================================================
--- (empty file)
+++ python/branches/cpy_merge/Lib/abc.py Thu Jun 14 23:10:12 2007
@@ -0,0 +1,179 @@
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Abstract Base Classes (ABCs) according to PEP 3119."""
+
+
+def abstractmethod(funcobj):
+ """A decorator indicating abstract methods.
+
+ 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 methods are overridden.
+ The abstract methods can be called using any of the the normal
+ 'super' call mechanisms.
+
+ Usage:
+
+ class C(metaclass=ABCMeta):
+ @abstractmethod
+ def my_abstract_method(self, ...):
+ ...
+ """
+ funcobj.__isabstractmethod__ = True
+ return funcobj
+
+
+class _Abstract(object):
+
+ """Helper class inserted into the bases by ABCMeta (using _fix_bases()).
+
+ You should never need to explicitly subclass this class.
+
+ There should never be a base class between _Abstract and object.
+ """
+
+ def __new__(cls, *args, **kwds):
+ am = cls.__dict__.get("__abstractmethods__")
+ if am:
+ raise TypeError("Can't instantiate abstract class %s "
+ "with abstract methods %s" %
+ (cls.__name__, ", ".join(sorted(am))))
+ if (args or kwds) and cls.__init__ is object.__init__:
+ raise TypeError("Can't pass arguments to __new__ "
+ "without overriding __init__")
+ return object.__new__(cls)
+
+ @classmethod
+ def __subclasshook__(cls, subclass):
+ """Abstract classes can override this to customize issubclass().
+
+ This is invoked early on by __subclasscheck__() below. It
+ should return True, False or NotImplemented. If it returns
+ NotImplemented, the normal algorithm is used. Otherwise, it
+ overrides the normal algorithm (and the outcome is cached).
+ """
+ return NotImplemented
+
+
+def _fix_bases(bases):
+ """Helper method that inserts _Abstract in the bases if needed."""
+ for base in bases:
+ if issubclass(base, _Abstract):
+ # _Abstract is already a base (maybe indirectly)
+ return bases
+ if object in bases:
+ # Replace object with _Abstract
+ return tuple([_Abstract if base is object else base
+ for base in bases])
+ # Append _Abstract to the end
+ return bases + (_Abstract,)
+
+
+class ABCMeta(type):
+
+ """Metaclass for defining Abstract Base Classes (ABCs).
+
+ Use this metaclass to create an ABC. An ABC can be subclassed
+ directly, and then acts as a mix-in class. You can also register
+ unrelated concrete classes (even built-in classes) and unrelated
+ ABCs as 'virtual subclasses' -- these and their descendants will
+ be considered subclasses of the registering ABC by the built-in
+ issubclass() function, but the registering ABC won't show up in
+ their MRO (Method Resolution Order) nor will method
+ implementations defined by the registering ABC be callable (not
+ even via super()).
+
+ """
+
+ # A global counter that is incremented each time a class is
+ # registered as a virtual subclass of anything. It forces the
+ # negative cache to be cleared before its next use.
+ __invalidation_counter = 0
+
+ def __new__(mcls, name, bases, namespace):
+ bases = _fix_bases(bases)
+ cls = super().__new__(mcls, name, bases, namespace)
+ # Compute set of abstract method names
+ abstracts = {name
+ for name, value in namespace.items()
+ if getattr(value, "__isabstractmethod__", False)}
+ for base in bases:
+ for name in getattr(base, "__abstractmethods__", set()):
+ value = getattr(cls, name, None)
+ if getattr(value, "__isabstractmethod__", False):
+ abstracts.add(name)
+ cls.__abstractmethods__ = abstracts
+ # Set up inheritance registry
+ cls.__registry = set()
+ cls.__cache = set()
+ cls.__negative_cache = set()
+ cls.__negative_cache_version = ABCMeta.__invalidation_counter
+ return cls
+
+ def register(cls, subclass):
+ """Register a virtual subclass of an ABC."""
+ if not isinstance(cls, type):
+ raise TypeError("Can only register classes")
+ if issubclass(subclass, cls):
+ return # Already a subclass
+ # Subtle: test for cycles *after* testing for "already a subclass";
+ # this means we allow X.register(X) and interpret it as a no-op.
+ if issubclass(cls, subclass):
+ # This would create a cycle, which is bad for the algorithm below
+ raise RuntimeError("Refusing to create an inheritance cycle")
+ cls.__registry.add(subclass)
+ ABCMeta.__invalidation_counter += 1 # Invalidate negative cache
+
+ def _dump_registry(cls, file=None):
+ """Debug helper to print the ABC registry."""
+ print("Class: %s.%s" % (cls.__module__, cls.__name__), file=file)
+ print("Inv.counter: %s" % ABCMeta.__invalidation_counter, file=file)
+ for name in sorted(cls.__dict__.keys()):
+ if name.startswith("__abc_"):
+ value = getattr(cls, name)
+ print("%s: %r" % (name, value), file=file)
+
+ def __instancecheck__(cls, instance):
+ """Override for isinstance(instance, cls)."""
+ return any(cls.__subclasscheck__(c)
+ for c in {instance.__class__, type(instance)})
+
+ def __subclasscheck__(cls, subclass):
+ """Override for issubclass(subclass, cls)."""
+ # Check cache
+ if subclass in cls.__cache:
+ return True
+ # Check negative cache; may have to invalidate
+ if cls.__negative_cache_version < ABCMeta.__invalidation_counter:
+ # Invalidate the negative cache
+ cls.__negative_cache_version = ABCMeta.__invalidation_counter
+ cls.__negative_cache = set()
+ elif subclass in cls.__negative_cache:
+ return False
+ # Check the subclass hook
+ ok = cls.__subclasshook__(subclass)
+ if ok is not NotImplemented:
+ assert isinstance(ok, bool)
+ if ok:
+ cls.__cache.add(subclass)
+ else:
+ cls.__negative_cache.add(subclass)
+ return ok
+ # Check if it's a direct subclass
+ if cls in subclass.__mro__:
+ cls.__cache.add(subclass)
+ return True
+ # Check if it's a subclass of a registered class (recursive)
+ for rcls in cls.__registry:
+ if issubclass(subclass, rcls):
+ cls.__registry.add(subclass)
+ return True
+ # Check if it's a subclass of a subclass (recursive)
+ for scls in cls.__subclasses__():
+ if issubclass(subclass, scls):
+ cls.__registry.add(subclass)
+ return True
+ # No dice; update negative cache
+ cls.__negative_cache.add(subclass)
+ return False
Added: python/branches/cpy_merge/Lib/test/test_abc.py
==============================================================================
--- (empty file)
+++ python/branches/cpy_merge/Lib/test/test_abc.py Thu Jun 14 23:10:12 2007
@@ -0,0 +1,123 @@
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Unit tests for abc.py."""
+
+import sys
+import unittest
+from test import test_support
+
+import abc
+
+
+class TestABC(unittest.TestCase):
+
+ def test_abstractmethod_basics(self):
+ @abc.abstractmethod
+ def foo(self): pass
+ self.assertEqual(foo.__isabstractmethod__, True)
+ def bar(self): pass
+ self.assertEqual(hasattr(bar, "__isabstractmethod__"), False)
+
+ def test_abstractmethod_integration(self):
+ 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
+ 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
+
+ def test_registration_basics(self):
+ class A(metaclass=abc.ABCMeta):
+ pass
+ class B:
+ pass
+ b = B()
+ self.assertEqual(issubclass(B, A), False)
+ self.assertEqual(isinstance(b, A), False)
+ A.register(B)
+ self.assertEqual(issubclass(B, A), True)
+ self.assertEqual(isinstance(b, A), True)
+ class C(B):
+ pass
+ c = C()
+ self.assertEqual(issubclass(C, A), True)
+ self.assertEqual(isinstance(c, A), True)
+
+ def test_registration_builtins(self):
+ class A(metaclass=abc.ABCMeta):
+ pass
+ A.register(int)
+ self.assertEqual(isinstance(42, A), True)
+ self.assertEqual(issubclass(int, A), True)
+ class B(A):
+ pass
+ B.register(basestring)
+ self.assertEqual(isinstance("", A), True)
+ self.assertEqual(issubclass(str, A), True)
+
+ def test_registration_edge_cases(self):
+ class A(metaclass=abc.ABCMeta):
+ pass
+ A.register(A) # should pass silently
+ class A1(A):
+ pass
+ self.assertRaises(RuntimeError, A1.register, A) # cycles not allowed
+ class B:
+ pass
+ A1.register(B) # ok
+ A1.register(B) # should pass silently
+ class C(A):
+ pass
+ A.register(C) # should pass silently
+ self.assertRaises(RuntimeError, C.register, A) # cycles not allowed
+ C.register(B) # ok
+
+ def test_registration_transitiveness(self):
+ class A(metaclass=abc.ABCMeta):
+ pass
+ self.failUnless(issubclass(A, A))
+ class B(metaclass=abc.ABCMeta):
+ pass
+ self.failIf(issubclass(A, B))
+ self.failIf(issubclass(B, A))
+ class C(metaclass=abc.ABCMeta):
+ pass
+ A.register(B)
+ class B1(B):
+ pass
+ self.failUnless(issubclass(B1, A))
+ class C1(C):
+ pass
+ B1.register(C1)
+ self.failIf(issubclass(C, B))
+ self.failIf(issubclass(C, B1))
+ self.failUnless(issubclass(C1, A))
+ self.failUnless(issubclass(C1, B))
+ self.failUnless(issubclass(C1, B1))
+ C1.register(int)
+ class MyInt(int):
+ pass
+ self.failUnless(issubclass(MyInt, A))
+ self.failUnless(isinstance(42, A))
+
+
+def test_main():
+ test_support.run_unittest(TestABC)
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: python/branches/cpy_merge/Lib/test/test_super.py
==============================================================================
--- (empty file)
+++ python/branches/cpy_merge/Lib/test/test_super.py Thu Jun 14 23:10:12 2007
@@ -0,0 +1,79 @@
+"""Unit tests for new super() implementation."""
+
+import sys
+import unittest
+from test import test_support
+
+
+class A:
+ def f(self):
+ return 'A'
+ @classmethod
+ def cm(cls):
+ return (cls, 'A')
+
+class B(A):
+ def f(self):
+ return super().f() + 'B'
+ @classmethod
+ def cm(cls):
+ return (cls, super().cm(), 'B')
+
+class C(A):
+ def f(self):
+ return super().f() + 'C'
+ @classmethod
+ def cm(cls):
+ return (cls, super().cm(), 'C')
+
+class D(C, B):
+ def f(self):
+ return super().f() + 'D'
+ def cm(cls):
+ return (cls, super().cm(), 'D')
+
+class E(D):
+ pass
+
+class F(E):
+ f = E.f
+
+class G(A):
+ pass
+
+
+class TestSuper(unittest.TestCase):
+
+ def testBasicsWorking(self):
+ self.assertEqual(D().f(), 'ABCD')
+
+ def testClassGetattrWorking(self):
+ self.assertEqual(D.f(D()), 'ABCD')
+
+ def testSubclassNoOverrideWorking(self):
+ self.assertEqual(E().f(), 'ABCD')
+ self.assertEqual(E.f(E()), 'ABCD')
+
+ def testUnboundMethodTransferWorking(self):
+ self.assertEqual(F().f(), 'ABCD')
+ self.assertEqual(F.f(F()), 'ABCD')
+
+ def testClassMethodsStillWorking(self):
+ self.assertEqual(A.cm(), (A, 'A'))
+ self.assertEqual(A().cm(), (A, 'A'))
+ self.assertEqual(G.cm(), (G, 'A'))
+ self.assertEqual(G().cm(), (G, 'A'))
+
+ def testSuperInClassMethodsWorking(self):
+ d = D()
+ self.assertEqual(d.cm(), (d, (D, (D, (D, 'A'), 'B'), 'C'), 'D'))
+ e = E()
+ self.assertEqual(e.cm(), (e, (E, (E, (E, 'A'), 'B'), 'C'), 'D'))
+
+
+def test_main():
+ test_support.run_unittest(TestSuper)
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: python/branches/cpy_merge/Lib/test/test_urllib2_localnet.py
==============================================================================
--- (empty file)
+++ python/branches/cpy_merge/Lib/test/test_urllib2_localnet.py Thu Jun 14 23:10:12 2007
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+
+import sys
+import threading
+import urlparse
+import urllib2
+import BaseHTTPServer
+import unittest
+import hashlib
+from test import test_support
+
+# Loopback http server infrastructure
+
+class LoopbackHttpServer(BaseHTTPServer.HTTPServer):
+ """HTTP server w/ a few modifications that make it useful for
+ loopback testing purposes.
+ """
+
+ def __init__(self, server_address, RequestHandlerClass):
+ BaseHTTPServer.HTTPServer.__init__(self,
+ server_address,
+ RequestHandlerClass)
+
+ # Set the timeout of our listening socket really low so
+ # that we can stop the server easily.
+ self.socket.settimeout(1.0)
+
+ def get_request(self):
+ """BaseHTTPServer method, overridden."""
+
+ request, client_address = self.socket.accept()
+
+ # It's a loopback connection, so setting the timeout
+ # really low shouldn't affect anything, but should make
+ # deadlocks less likely to occur.
+ request.settimeout(10.0)
+
+ return (request, client_address)
+
+class LoopbackHttpServerThread(threading.Thread):
+ """Stoppable thread that runs a loopback http server."""
+
+ def __init__(self, port, RequestHandlerClass):
+ threading.Thread.__init__(self)
+ self._RequestHandlerClass = RequestHandlerClass
+ self._stop = False
+ self._port = port
+ self._server_address = ('127.0.0.1', self._port)
+ self.ready = threading.Event()
+ self.error = None
+
+ def stop(self):
+ """Stops the webserver if it's currently running."""
+
+ # Set the stop flag.
+ self._stop = True
+
+ self.join()
+
+ def run(self):
+ protocol = "HTTP/1.0"
+
+ try:
+ self._RequestHandlerClass.protocol_version = protocol
+ httpd = LoopbackHttpServer(self._server_address,
+ self._RequestHandlerClass)
+
+ sa = httpd.socket.getsockname()
+ #print "Serving HTTP on", sa[0], "port", sa[1], "..."
+ except:
+ # Fail "gracefully" if we are unable to start.
+ self.ready.set()
+ self.error = sys.exc_info()[1]
+ raise
+
+ self.ready.set()
+ while not self._stop:
+ httpd.handle_request()
+
+# Authentication infrastructure
+
+class DigestAuthHandler:
+ """Handler for performing digest authentication."""
+
+ def __init__(self):
+ self._request_num = 0
+ self._nonces = []
+ self._users = {}
+ self._realm_name = "Test Realm"
+ self._qop = "auth"
+
+ def set_qop(self, qop):
+ self._qop = qop
+
+ def set_users(self, users):
+ assert isinstance(users, dict)
+ self._users = users
+
+ def set_realm(self, realm):
+ self._realm_name = realm
+
+ def _generate_nonce(self):
+ self._request_num += 1
+ nonce = hashlib.md5(str(self._request_num)).hexdigest()
+ self._nonces.append(nonce)
+ return nonce
+
+ def _create_auth_dict(self, auth_str):
+ first_space_index = auth_str.find(" ")
+ auth_str = auth_str[first_space_index+1:]
+
+ parts = auth_str.split(",")
+
+ auth_dict = {}
+ for part in parts:
+ name, value = part.split("=")
+ name = name.strip()
+ if value[0] == '"' and value[-1] == '"':
+ value = value[1:-1]
+ else:
+ value = value.strip()
+ auth_dict[name] = value
+ return auth_dict
+
+ def _validate_auth(self, auth_dict, password, method, uri):
+ final_dict = {}
+ final_dict.update(auth_dict)
+ final_dict["password"] = password
+ final_dict["method"] = method
+ final_dict["uri"] = uri
+ HA1_str = "%(username)s:%(realm)s:%(password)s" % final_dict
+ HA1 = hashlib.md5(HA1_str).hexdigest()
+ HA2_str = "%(method)s:%(uri)s" % final_dict
+ HA2 = hashlib.md5(HA2_str).hexdigest()
+ final_dict["HA1"] = HA1
+ final_dict["HA2"] = HA2
+ response_str = "%(HA1)s:%(nonce)s:%(nc)s:" \
+ "%(cnonce)s:%(qop)s:%(HA2)s" % final_dict
+ response = hashlib.md5(response_str).hexdigest()
+
+ return response == auth_dict["response"]
+
+ def _return_auth_challenge(self, request_handler):
+ request_handler.send_response(407, "Proxy Authentication Required")
+ request_handler.send_header("Content-Type", "text/html")
+ request_handler.send_header(
+ 'Proxy-Authenticate', 'Digest realm="%s", '
+ 'qop="%s",'
+ 'nonce="%s", ' % \
+ (self._realm_name, self._qop, self._generate_nonce()))
+ # XXX: Not sure if we're supposed to add this next header or
+ # not.
+ #request_handler.send_header('Connection', 'close')
+ request_handler.end_headers()
+ request_handler.wfile.write("Proxy Authentication Required.")
+ return False
+
+ def handle_request(self, request_handler):
+ """Performs digest authentication on the given HTTP request
+ handler. Returns True if authentication was successful, False
+ otherwise.
+
+ If no users have been set, then digest auth is effectively
+ disabled and this method will always return True.
+ """
+
+ if len(self._users) == 0:
+ return True
+
+ if 'Proxy-Authorization' not in request_handler.headers:
+ return self._return_auth_challenge(request_handler)
+ else:
+ auth_dict = self._create_auth_dict(
+ request_handler.headers['Proxy-Authorization']
+ )
+ if auth_dict["username"] in self._users:
+ password = self._users[ auth_dict["username"] ]
+ else:
+ return self._return_auth_challenge(request_handler)
+ if not auth_dict.get("nonce") in self._nonces:
+ return self._return_auth_challenge(request_handler)
+ else:
+ self._nonces.remove(auth_dict["nonce"])
+
+ auth_validated = False
+
+ # MSIE uses short_path in its validation, but Python's
+ # urllib2 uses the full path, so we're going to see if
+ # either of them works here.
+
+ for path in [request_handler.path, request_handler.short_path]:
+ if self._validate_auth(auth_dict,
+ password,
+ request_handler.command,
+ path):
+ auth_validated = True
+
+ if not auth_validated:
+ return self._return_auth_challenge(request_handler)
+ return True
+
+# Proxy test infrastructure
+
+class FakeProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ """This is a 'fake proxy' that makes it look like the entire
+ internet has gone down due to a sudden zombie invasion. It main
+ utility is in providing us with authentication support for
+ testing.
+ """
+
+ digest_auth_handler = DigestAuthHandler()
+
+ def log_message(self, format, *args):
+ # Uncomment the next line for debugging.
+ #sys.stderr.write(format % args)
+ pass
+
+ def do_GET(self):
+ (scm, netloc, path, params, query, fragment) = urlparse.urlparse(
+ self.path, 'http')
+ self.short_path = path
+ if self.digest_auth_handler.handle_request(self):
+ self.send_response(200, "OK")
+ self.send_header("Content-Type", "text/html")
+ self.end_headers()
+ self.wfile.write("You've reached %s!<BR>" % self.path)
+ self.wfile.write("Our apologies, but our server is down due to "
+ "a sudden zombie invasion.")
+
+# Test cases
+
+class ProxyAuthTests(unittest.TestCase):
+ URL = "http://www.foo.com"
+
+ PORT = 8080
+ USER = "tester"
+ PASSWD = "test123"
+ REALM = "TestRealm"
+
+ PROXY_URL = "http://127.0.0.1:%d" % PORT
+
+ def setUp(self):
+ FakeProxyHandler.digest_auth_handler.set_users({
+ self.USER : self.PASSWD
+ })
+ FakeProxyHandler.digest_auth_handler.set_realm(self.REALM)
+
+ self.server = LoopbackHttpServerThread(self.PORT, FakeProxyHandler)
+ self.server.start()
+ self.server.ready.wait()
+ if self.server.error:
+ raise self.server.error
+
+ handler = urllib2.ProxyHandler({"http" : self.PROXY_URL})
+ self._digest_auth_handler = urllib2.ProxyDigestAuthHandler()
+ self.opener = urllib2.build_opener(handler, self._digest_auth_handler)
+
+ def tearDown(self):
+ self.server.stop()
+
+ def test_proxy_with_bad_password_raises_httperror(self):
+ self._digest_auth_handler.add_password(self.REALM, self.URL,
+ self.USER, self.PASSWD+"bad")
+ FakeProxyHandler.digest_auth_handler.set_qop("auth")
+ self.assertRaises(urllib2.HTTPError,
+ self.opener.open,
+ self.URL)
+
+ def test_proxy_with_no_password_raises_httperror(self):
+ FakeProxyHandler.digest_auth_handler.set_qop("auth")
+ self.assertRaises(urllib2.HTTPError,
+ self.opener.open,
+ self.URL)
+
+ def test_proxy_qop_auth_works(self):
+ self._digest_auth_handler.add_password(self.REALM, self.URL,
+ self.USER, self.PASSWD)
+ FakeProxyHandler.digest_auth_handler.set_qop("auth")
+ result = self.opener.open(self.URL)
+ while result.read():
+ pass
+ result.close()
+
+ def test_proxy_qop_auth_int_works_or_throws_urlerror(self):
+ self._digest_auth_handler.add_password(self.REALM, self.URL,
+ self.USER, self.PASSWD)
+ FakeProxyHandler.digest_auth_handler.set_qop("auth-int")
+ try:
+ result = self.opener.open(self.URL)
+ except urllib2.URLError:
+ # It's okay if we don't support auth-int, but we certainly
+ # shouldn't receive any kind of exception here other than
+ # a URLError.
+ result = None
+ if result:
+ while result.read():
+ pass
+ result.close()
+
+def test_main():
+ # We will NOT depend on the network resource flag
+ # (Lib/test/regrtest.py -u network) since all tests here are only
+ # localhost. However, if this is a bad rationale, then uncomment
+ # the next line.
+ #test_support.requires("network")
+
+ test_support.run_unittest(ProxyAuthTests)
+
+if __name__ == "__main__":
+ test_main()
Added: python/branches/cpy_merge/Tools/buildbot/build-amd64.bat
==============================================================================
--- (empty file)
+++ python/branches/cpy_merge/Tools/buildbot/build-amd64.bat Thu Jun 14 23:10:12 2007
@@ -0,0 +1,6 @@
+ at rem Used by the buildbot "compile" step.
+setlocal
+cmd /c Tools\buildbot\external-amd64.bat
+call "%VS71COMNTOOLS%vsvars32.bat"
+REM cmd /q/c Tools\buildbot\kill_python.bat
+devenv.com /build ReleaseAMD64 PCbuild\pcbuild.sln
Added: python/branches/cpy_merge/Tools/buildbot/clean-amd64.bat
==============================================================================
--- (empty file)
+++ python/branches/cpy_merge/Tools/buildbot/clean-amd64.bat Thu Jun 14 23:10:12 2007
@@ -0,0 +1,6 @@
+ at rem Used by the buildbot "clean" step.
+call "%VS71COMNTOOLS%vsvars32.bat"
+cd PCbuild
+ at echo Deleting .pyc/.pyo files ...
+python.exe rmpyc.py
+devenv.com /clean ReleaseAMD64 pcbuild.sln
Added: python/branches/cpy_merge/Tools/buildbot/external-amd64.bat
==============================================================================
--- (empty file)
+++ python/branches/cpy_merge/Tools/buildbot/external-amd64.bat Thu Jun 14 23:10:12 2007
@@ -0,0 +1,44 @@
+ at rem Fetches (and builds if necessary) external dependencies
+setlocal
+
+ at rem need this so that 'devenv' is found
+call "%VS71COMNTOOLS%vsvars32.bat"
+ at rem set the build environment
+call "%MSSdk%\SetEnv" /XP64 /RETAIL
+
+ at rem Assume we start inside the Python source directory
+cd ..
+
+ at rem sqlite
+if not exist sqlite-source-3.3.4 (
+ svn export http://svn.python.org/projects/external/sqlite-source-3.3.4
+ if exist build\PCbuild\sqlite3.dll del build\PCbuild\sqlite3.dll
+)
+if not exist build\PCbuild\sqlite3.dll (
+ cd sqlite-source-3.3.4\amd64
+ cl ..\*.c
+ link /def:..\sqlite3.def /dll *.obj /out:sqlite3.dll bufferoverflowU.lib
+ cd ..\..
+ copy sqlite-source-3.3.4\amd64\sqlite3.dll build\PCbuild
+)
+
+ at rem bzip
+if not exist bzip2-1.0.3 svn export http://svn.python.org/projects/external/bzip2-1.0.3
+
+ at rem Sleepycat db
+if not exist db-4.4.20 svn export http://svn.python.org/projects/external/db-4.4.20
+if not exist "db-4.4.20\build_win32\Release_AMD64\libdb44s.lib" (
+ cd db-4.4.20\build_win32
+ devenv Berkeley_DB.sln /build "Release AMD64" /project db_static /useenv
+ cd ..\..
+)
+
+ at rem OpenSSL
+if not exist openssl-0.9.8a svn export http://svn.python.org/projects/external/openssl-0.9.8a
+
+ at rem tcltk
+if not exist tcl8.4.12 (
+ if exist tcltk rd /s/q tcltk
+ svn export http://svn.python.org/projects/external/tcl8.4.12
+ svn export http://svn.python.org/projects/external/tk8.4.12
+)
Added: python/branches/cpy_merge/Tools/buildbot/test-amd64.bat
==============================================================================
--- (empty file)
+++ python/branches/cpy_merge/Tools/buildbot/test-amd64.bat Thu Jun 14 23:10:12 2007
@@ -0,0 +1,3 @@
+ at rem Used by the buildbot "test" step.
+cd PCbuild
+call rt.bat -q -uall -rw
More information about the Python-checkins
mailing list