summaryrefslogtreecommitdiff
path: root/lib/Crypto/Util
diff options
context:
space:
mode:
authorLegrandin <gooksankoo@hoiptorrow.mailexpire.com>2011-10-18 23:20:26 +0200
committerLegrandin <gooksankoo@hoiptorrow.mailexpire.com>2011-10-18 23:20:26 +0200
commitc22fa18c0dedb43a8b19dcb9b29512ba59e1764b (patch)
treee7864a848ed2c37d4a2c0d65bcae0f0cbdc6ea27 /lib/Crypto/Util
parent897b75983c31a9e2630af92161e6206c2480685e (diff)
parentb9658a26003ebfcfce1804a2363a29354799b47e (diff)
downloadpycrypto-c22fa18c0dedb43a8b19dcb9b29512ba59e1764b.tar.gz
Merged from upstream (py3k support) and modified so that all unit tests pass.
Diffstat (limited to 'lib/Crypto/Util')
-rw-r--r--lib/Crypto/Util/Counter.py18
-rw-r--r--lib/Crypto/Util/RFC1751.py20
-rw-r--r--lib/Crypto/Util/_number_new.py4
-rw-r--r--lib/Crypto/Util/asn1.py61
-rw-r--r--lib/Crypto/Util/number.py56
-rw-r--r--lib/Crypto/Util/py21compat.py (renamed from lib/Crypto/Util/python_compat.py)4
-rw-r--r--lib/Crypto/Util/py3compat.py70
-rw-r--r--lib/Crypto/Util/wrapper.py41
8 files changed, 192 insertions, 82 deletions
diff --git a/lib/Crypto/Util/Counter.py b/lib/Crypto/Util/Counter.py
index 42dab42..f00099b 100644
--- a/lib/Crypto/Util/Counter.py
+++ b/lib/Crypto/Util/Counter.py
@@ -22,13 +22,16 @@
# SOFTWARE.
# ===================================================================
-from Crypto.Util.python_compat import *
+import sys
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
+from Crypto.Util.py3compat import *
from Crypto.Util import _counter
import struct
# Factory function
-def new(nbits, prefix="", suffix="", initial_value=1, overflow=0, little_endian=False, allow_wraparound=False, disable_shortcut=False):
+def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_endian=False, allow_wraparound=False, disable_shortcut=False):
# TODO: Document this
# Sanity-check the message size
@@ -42,20 +45,21 @@ def new(nbits, prefix="", suffix="", initial_value=1, overflow=0, little_endian=
raise ValueError("nbits too large")
initval = _encode(initial_value, nbytes, little_endian)
+
if little_endian:
- return _counter._newLE(str(prefix), str(suffix), initval, allow_wraparound=allow_wraparound, disable_shortcut=disable_shortcut)
+ return _counter._newLE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound, disable_shortcut=disable_shortcut)
else:
- return _counter._newBE(str(prefix), str(suffix), initval, allow_wraparound=allow_wraparound, disable_shortcut=disable_shortcut)
+ return _counter._newBE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound, disable_shortcut=disable_shortcut)
def _encode(n, nbytes, little_endian=False):
retval = []
n = long(n)
for i in range(nbytes):
if little_endian:
- retval.append(chr(n & 0xff))
+ retval.append(bchr(n & 0xff))
else:
- retval.insert(0, chr(n & 0xff))
+ retval.insert(0, bchr(n & 0xff))
n >>= 8
- return "".join(retval)
+ return b("").join(retval)
# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/Util/RFC1751.py b/lib/Crypto/Util/RFC1751.py
index 85e0e99..9786e6f 100644
--- a/lib/Crypto/Util/RFC1751.py
+++ b/lib/Crypto/Util/RFC1751.py
@@ -1,4 +1,3 @@
-#!/usr/local/bin/python
# rfc1751.py : Converts between 128-bit strings and a human-readable
# sequence of words, as defined in RFC1751: "A Convention for
# Human-Readable 128-bit Keys", by Daniel L. McDonald.
@@ -28,7 +27,8 @@
__revision__ = "$Id$"
-import string, binascii
+import binascii
+from Crypto.Util.py3compat import *
binary={0:'0000', 1:'0001', 2:'0010', 3:'0011', 4:'0100', 5:'0101',
6:'0110', 7:'0111', 8:'1000', 9:'1001', 10:'1010', 11:'1011',
@@ -36,18 +36,18 @@ binary={0:'0000', 1:'0001', 2:'0010', 3:'0011', 4:'0100', 5:'0101',
def _key2bin(s):
"Convert a key into a string of binary digits"
- kl=map(lambda x: ord(x), s)
+ kl=map(lambda x: bord(x), s)
kl=map(lambda x: binary[x>>4]+binary[x&15], kl)
return ''.join(kl)
def _extract(key, start, length):
- """Extract a bitstring from a string of binary digits, and return its
+ """Extract a bitstring(2.x)/bytestring(2.x) from a string of binary digits, and return its
numeric value."""
k=key[start:start+length]
return reduce(lambda x,y: x*2+ord(y)-48, k, 0)
def key_to_english (key):
- """key_to_english(key:string) : string
+ """key_to_english(key:string(2.x)/bytes(3.x)) : string
Transform an arbitrary key into a string containing English words.
The key length must be a multiple of 8.
"""
@@ -58,20 +58,20 @@ def key_to_english (key):
skbin=_key2bin(subkey) ; p=0
for i in range(0, 64, 2): p=p+_extract(skbin, i, 2)
# Append parity bits to the subkey
- skbin=_key2bin(subkey+chr((p<<6) & 255))
+ skbin=_key2bin(subkey+bchr((p<<6) & 255))
for i in range(0, 64, 11):
english=english+wordlist[_extract(skbin, i, 11)]+' '
return english[:-1] # Remove the trailing space
-def english_to_key (str):
- """english_to_key(string):string
+def english_to_key (s):
+ """english_to_key(string):string(2.x)/bytes(2.x)
Transform a string into a corresponding key.
The string must contain words separated by whitespace; the number
of words must be a multiple of 6.
"""
- L=string.split(string.upper(str)) ; key=''
+ L=s.upper().split() ; key=b('')
for index in range(0, len(L), 6):
sublist=L[index:index+6] ; char=9*[0] ; bits=0
for i in sublist:
@@ -88,7 +88,7 @@ def english_to_key (str):
char[(bits>>3)+1] = char[(bits>>3)+1] | cr
else: char[bits>>3] = char[bits>>3] | cr
bits=bits+11
- subkey=reduce(lambda x,y:x+chr(y), char, '')
+ subkey=reduce(lambda x,y:x+bchr(y), char, b(''))
# Check the parity of the resulting key
skbin=_key2bin(subkey)
diff --git a/lib/Crypto/Util/_number_new.py b/lib/Crypto/Util/_number_new.py
index 2640392..b040025 100644
--- a/lib/Crypto/Util/_number_new.py
+++ b/lib/Crypto/Util/_number_new.py
@@ -27,7 +27,9 @@
__revision__ = "$Id$"
__all__ = ['ceil_shift', 'ceil_div', 'floor_div', 'exact_log2', 'exact_div']
-from Crypto.Util.python_compat import *
+import sys
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
def ceil_shift(n, b):
"""Return ceil(n / 2**b) without performing any floating-point or division operations.
diff --git a/lib/Crypto/Util/asn1.py b/lib/Crypto/Util/asn1.py
index f7658b4..e09b3ff 100644
--- a/lib/Crypto/Util/asn1.py
+++ b/lib/Crypto/Util/asn1.py
@@ -21,8 +21,10 @@
# ===================================================================
from Crypto.Util.number import long_to_bytes, bytes_to_long
+import sys
+from Crypto.Util.py3compat import *
-__all__ = [ 'DerObject', 'DerInteger', 'DerOctetString', 'DerNull', 'DerSequence' ]
+__all__ = [ 'DerObject', 'DerInteger', 'DerOctetString', 'DerNull', 'DerSequence', 'DerObjectId' ]
class DerObject:
"""Base class for defining a single DER object.
@@ -31,35 +33,41 @@ class DerObject:
"""
# Known TAG types
- typeTags = { 'SEQUENCE':'\x30', 'BIT STRING':'\x03', 'INTEGER':'\x02',
- 'OCTET STRING':'\x04', 'NULL':'\x05', 'OBJECT IDENTIFIER':'\x06'}
+ typeTags = { 'SEQUENCE': 0x30, 'BIT STRING': 0x03, 'INTEGER': 0x02,
+ 'OCTET STRING': 0x04, 'NULL': 0x05, 'OBJECT IDENTIFIER': 0x06 }
- def __init__(self, ASN1Type=None, payload=''):
+ def __init__(self, ASN1Type=None, payload=b('')):
"""Initialize the DER object according to a specific type.
The ASN.1 type is either specified as the ASN.1 string (e.g.
'SEQUENCE'), directly with its numerical tag or with no tag
- atl all (None)."""
- self.typeTag = self.typeTags.get(ASN1Type, ASN1Type)
+ at all (None)."""
+ if isInt(ASN1Type) or ASN1Type is None:
+ self.typeTag = ASN1Type
+ else:
+ if len(ASN1Type)==1:
+ self.typeTag = ord(ASN1Type)
+ else:
+ self.typeTag = self.typeTags.get(ASN1Type)
self.payload = payload
def isType(self, ASN1Type):
return self.typeTags[ASN1Type]==self.typeTag
def _lengthOctets(self, payloadLen):
- """Return a string that encodes the given payload length (in
+ """Return a byte string that encodes the given payload length (in
bytes) in a format suitable for a DER length tag (L).
"""
if payloadLen>127:
encoding = long_to_bytes(payloadLen)
- return chr(len(encoding)+128) + encoding
- return chr(payloadLen)
+ return bchr(len(encoding)+128) + encoding
+ return bchr(payloadLen)
def encode(self):
"""Return a complete DER element, fully encoded as a TLV."""
- return self.typeTag + self._lengthOctets(len(self.payload)) + self.payload
+ return bchr(self.typeTag) + self._lengthOctets(len(self.payload)) + self.payload
- def _decodeLen(self, idx, str):
+ def _decodeLen(self, idx, der):
"""Given a (part of a) DER element, and an index to the first byte of
a DER length tag (L), return a tuple with the payload size,
and the index of the first byte of the such payload (V).
@@ -67,10 +75,10 @@ class DerObject:
Raises a ValueError exception if the DER length is invalid.
Raises an IndexError exception if the DER element is too short.
"""
- length = ord(str[idx])
+ length = bord(der[idx])
if length<=127:
return (length,idx+1)
- payloadLength = bytes_to_long(str[idx+1:idx+1+(length & 0x7F)])
+ payloadLength = bytes_to_long(der[idx+1:idx+1+(length & 0x7F)])
if payloadLength<=127:
raise ValueError("Not a DER length tag.")
return (payloadLength, idx+1+(length & 0x7F))
@@ -90,8 +98,8 @@ class DerObject:
Raises an IndexError exception if the DER element is too short.
"""
try:
- self.typeTag = derEle[0]
- if (ord(self.typeTag) & 0x1F)==0x1F:
+ self.typeTag = bord(derEle[0])
+ if (self.typeTag & 0x1F)==0x1F:
raise ValueError("Unsupported DER tag")
(length,idx) = self._decodeLen(1, derEle)
if noLeftOvers and len(derEle) != (idx+length):
@@ -113,8 +121,8 @@ class DerInteger(DerObject):
def encode(self):
"""Return a complete INTEGER DER element, fully encoded as a TLV."""
self.payload = long_to_bytes(self.value)
- if ord(self.payload[0])>127:
- self.payload = '\x00' + self.payload
+ if bord(self.payload[0])>127:
+ self.payload = bchr(0x00) + self.payload
return DerObject.encode(self)
def decode(self, derEle, noLeftOvers=0):
@@ -135,7 +143,7 @@ class DerInteger(DerObject):
tlvLength = DerObject.decode(self, derEle, noLeftOvers)
if self.typeTag!=self.typeTags['INTEGER']:
raise ValueError ("Not a DER INTEGER.")
- if ord(self.payload[0])>127:
+ if bord(self.payload[0])>127:
raise ValueError ("Negative INTEGER.")
self.value = bytes_to_long(self.payload)
return tlvLength
@@ -179,13 +187,6 @@ class DerSequence(DerObject):
def hasInts(self):
"""Return the number of items in this sequence that are numbers."""
- def isInt(x):
- test = 0
- try:
- test += x
- except TypeError:
- return 0
- return 1
return len(filter(isInt, self._seq))
def hasOnlyInts(self):
@@ -199,7 +200,7 @@ class DerSequence(DerObject):
Limitation: Raises a ValueError exception if it some elements
in the sequence are neither Python integers nor complete DER INTEGERs.
"""
- self.payload = ''
+ self.payload = b('')
for item in self._seq:
try:
self.payload += item
@@ -275,3 +276,11 @@ class DerObjectId(DerObject):
raise ValueError("Not a valid OBJECT IDENTIFIER.")
return p
+def isInt(x):
+ test = 0
+ try:
+ test += x
+ except TypeError:
+ return 0
+ return 1
+
diff --git a/lib/Crypto/Util/number.py b/lib/Crypto/Util/number.py
index 7be595b..2b5beb6 100644
--- a/lib/Crypto/Util/number.py
+++ b/lib/Crypto/Util/number.py
@@ -26,15 +26,36 @@
__revision__ = "$Id$"
-from Crypto.pct_warnings import GetRandomNumber_DeprecationWarning
+from Crypto.pct_warnings import GetRandomNumber_DeprecationWarning, PowmInsecureWarning
+from warnings import warn as _warn
import math
+import sys
+from Crypto.Util.py3compat import *
bignum = long
try:
from Crypto.PublicKey import _fastmath
except ImportError:
+ # For production, we are going to let import issues due to gmp/mpir shared
+ # libraries not loading slide silently and use slowmath. If you'd rather
+ # see an exception raised if _fastmath exists but cannot be imported,
+ # uncomment the below
+ #
+ # from distutils.sysconfig import get_config_var
+ # import inspect, os
+ # _fm_path = os.path.normpath(os.path.dirname(os.path.abspath(
+ # inspect.getfile(inspect.currentframe())))
+ # +"/../../PublicKey/_fastmath"+get_config_var("SO"))
+ # if os.path.exists(_fm_path):
+ # raise ImportError("While the _fastmath module exists, importing "+
+ # "it failed. This may point to the gmp or mpir shared library "+
+ # "not being in the path. _fastmath was found at "+_fm_path)
_fastmath = None
+# You need libgmp v5 or later to get mpz_powm_sec. Warn if it's not available.
+if _fastmath is not None and not _fastmath.HAVE_DECL_MPZ_POWM_SEC:
+ _warn("Not using mpz_powm_sec. You should rebuild using libgmp >= 5 to avoid timing attack vulnerability.", PowmInsecureWarning)
+
# New functions
from _number_new import *
@@ -62,7 +83,8 @@ def size (N):
def getRandomNumber(N, randfunc=None):
"""Deprecated. Use getRandomInteger or getRandomNBitInteger instead."""
- warnings.warn("Crypto.Util.number.getRandomNumber has confusing semantics and has been deprecated. Use getRandomInteger or getRandomNBitInteger instead.",
+ warnings.warn("Crypto.Util.number.getRandomNumber has confusing semantics"+
+ "and has been deprecated. Use getRandomInteger or getRandomNBitInteger instead.",
GetRandomNumber_DeprecationWarning)
return getRandomNBitInteger(N, randfunc)
@@ -83,7 +105,7 @@ def getRandomInteger(N, randfunc=None):
odd_bits = N % 8
if odd_bits != 0:
char = ord(randfunc(1)) >> (8-odd_bits)
- S = chr(char) + S
+ S = bchr(char) + S
value = bytes_to_long(S)
return value
@@ -221,7 +243,7 @@ def getStrongPrime(N, e=0, false_positive_prob=1e-6, randfunc=None):
The optional false_positive_prob is the statistical probability
that true is returned even though it is not (pseudo-prime).
It defaults to 1e-6 (less than 1:1000000).
- Note that the real probability of a false-positiv is far less. This is
+ Note that the real probability of a false-positive is far less. This is
just the mathematically provable limit.
randfunc should take a single int parameter and return that
@@ -239,7 +261,8 @@ def getStrongPrime(N, e=0, false_positive_prob=1e-6, randfunc=None):
# Use the accelerator if available
if _fastmath is not None:
- return _fastmath.getStrongPrime(long(N), long(e), false_positive_prob, randfunc)
+ return _fastmath.getStrongPrime(long(N), long(e), false_positive_prob,
+ randfunc)
if (N < 512) or ((N % 128) != 0):
raise ValueError ("bits must be multiple of 128 and > 512")
@@ -263,7 +286,6 @@ def getStrongPrime(N, e=0, false_positive_prob=1e-6, randfunc=None):
for i in (0, 1):
# randomly choose 101-bit y
y = getRandomNBitInteger (101, randfunc)
-
# initialize the field for sieving
field = [0] * 5 * len (sieve_base)
# sieve the field
@@ -300,13 +322,13 @@ def getStrongPrime(N, e=0, false_positive_prob=1e-6, randfunc=None):
X = X + (R - (X % increment))
while 1:
is_possible_prime = 1
- # first check canidate against sieve_base
+ # first check candidate against sieve_base
for prime in sieve_base:
if (X % prime) == 0:
is_possible_prime = 0
break
# if e is given make sure that e and X-1 are coprime
- # this is not necessarily a strong prime criterion but usefull when
+ # this is not necessarily a strong prime criterion but useful when
# creating them for RSA where the p-1 and q-1 should be coprime to
# the public exponent e
if e and is_possible_prime:
@@ -314,8 +336,9 @@ def getStrongPrime(N, e=0, false_positive_prob=1e-6, randfunc=None):
if GCD (e, X-1) != 1:
is_possible_prime = 0
else:
- if GCD (e, (X-1)/2) != 1:
+ if GCD (e, divmod((X-1),2)[0]) != 1:
is_possible_prime = 0
+
# do some Rabin-Miller-Tests
if is_possible_prime:
result = _rabinMillerTest (X, rabin_miller_rounds)
@@ -336,7 +359,7 @@ def isPrime(N, false_positive_prob=1e-6, randfunc=None):
The optional false_positive_prob is the statistical probability
that true is returned even though it is not (pseudo-prime).
It defaults to 1e-6 (less than 1:1000000).
- Note that the real probability of a false-positiv is far less. This is
+ Note that the real probability of a false-positive is far less. This is
just the mathematically provable limit.
If randfunc is omitted, then Random.new().read is used.
@@ -370,7 +393,7 @@ def long_to_bytes(n, blocksize=0):
blocksize.
"""
# after much testing, this algorithm was deemed to be the fastest
- s = ''
+ s = b('')
n = long(n)
pack = struct.pack
while n > 0:
@@ -378,17 +401,17 @@ def long_to_bytes(n, blocksize=0):
n = n >> 32
# strip off leading zeros
for i in range(len(s)):
- if s[i] != '\000':
+ if s[i] != b('\000')[0]:
break
else:
# only happens when n == 0
- s = '\000'
+ s = b('\000')
i = 0
s = s[i:]
# add back some pad bytes. this could be done more efficiently w.r.t. the
# de-padding being done above, but sigh...
if blocksize > 0 and len(s) % blocksize:
- s = (blocksize - len(s) % blocksize) * '\000' + s
+ s = (blocksize - len(s) % blocksize) * b('\000') + s
return s
def bytes_to_long(s):
@@ -402,7 +425,7 @@ def bytes_to_long(s):
length = len(s)
if length % 4:
extra = (4 - length % 4)
- s = '\000' * extra + s
+ s = b('\000') * extra + s
length = length + extra
for i in range(0, length, 4):
acc = (acc << 32) + unpack('>I', s[i:i+4])[0]
@@ -418,7 +441,8 @@ def str2long(s):
return bytes_to_long(s)
def _import_Random():
- # This is called in a function instead of at the module level in order to avoid problems with recursive imports
+ # This is called in a function instead of at the module level in order to
+ # avoid problems with recursive imports
global Random, StrongRandom
from Crypto import Random
from Crypto.Random.random import StrongRandom
diff --git a/lib/Crypto/Util/python_compat.py b/lib/Crypto/Util/py21compat.py
index 7eb2803..624408b 100644
--- a/lib/Crypto/Util/python_compat.py
+++ b/lib/Crypto/Util/py21compat.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Util/python_compat.py : Compatibility code for old versions of Python
+# Util/py21compat.py : Compatibility code for Python 2.1
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
@@ -22,7 +22,7 @@
# SOFTWARE.
# ===================================================================
-"""Compatibility code for old versions of Python
+"""Compatibility code for Python 2.1
Currently, this just defines:
- True and False
diff --git a/lib/Crypto/Util/py3compat.py b/lib/Crypto/Util/py3compat.py
new file mode 100644
index 0000000..76d168b
--- /dev/null
+++ b/lib/Crypto/Util/py3compat.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+#
+# Util/py3compat.py : Compatibility code for handling Py3k / Python 2.x
+#
+# Written in 2010 by Thorsten Behrens
+#
+# ===================================================================
+# The contents of this file are dedicated to the public domain. To
+# the extent that dedication to the public domain is not available,
+# everyone is granted a worldwide, perpetual, royalty-free,
+# non-exclusive license to exercise all rights associated with the
+# contents of this file for any purpose whatsoever.
+# No rights are reserved.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# ===================================================================
+
+"""Compatibility code for handling string/bytes changes from Python 2.x to Py3k
+"""
+
+__revision__ = "$Id$"
+
+import sys
+
+if sys.version_info[0] == 2:
+ def b(s):
+ return s
+ def bchr(s):
+ return chr(s)
+ def bstr(s):
+ return str(s)
+ def bord(s):
+ return ord(s)
+ def tobytes(s):
+ if isinstance(s,str):
+ return s
+ else:
+ if isinstance(s, unicode):
+ return s.encode("latin-1")
+ else:
+ ''.join(s)
+else:
+ def b(s):
+ return s.encode("latin-1") # utf-8 would cause some side-effects we don't want
+ def bchr(s):
+ return bytes([s])
+ def bstr(s):
+ if isinstance(s,str):
+ return bytes(s,"latin-1")
+ else:
+ return bytes(s)
+ def bord(s):
+ return s
+ def tobytes(s):
+ if isinstance(s,bytes):
+ return s
+ else:
+ if isinstance(s,str):
+ return s.encode("latin-1")
+ else:
+ return bytes(s)
+
+# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/Util/wrapper.py b/lib/Crypto/Util/wrapper.py
index 479ae26..1090fc7 100644
--- a/lib/Crypto/Util/wrapper.py
+++ b/lib/Crypto/Util/wrapper.py
@@ -1,6 +1,6 @@
#
# wrapper.py: Small class to wrap an object, instantiated from a class
-# or generated by a module.
+# or generated by a module.
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
@@ -24,23 +24,24 @@
__all__ = [ 'Wrapper' ]
class Wrapper:
- '''
- Wrapper for an object, instantiated from a class
- or from a call to a new() function in a module.
- '''
- def __init__(self, wrapped, *args):
- """
- wrapped is either a class or a module with a new() function.
- """
- if hasattr(wrapped, 'new'):
- self._wrapped = wrapped.new(*args)
- else:
- self._wrapped = wrapped(*args)
- def __getattr__(self, name):
- try:
- return getattr(getattr(self,'_wrapped'),name)
- except AttributeError:
- if hasattr(self, name):
- return getattr(self,name)
- raise
+ '''
+ Wrapper for an object, instantiated from a class
+ or from a call to a new() function in a module.
+ '''
+ def __init__(self, wrapped, *args):
+ """
+ wrapped is either a class or a module with a new() function.
+ """
+ if hasattr(wrapped, 'new'):
+ self._wrapped = wrapped.new(*args)
+ else:
+ self._wrapped = wrapped(*args)
+
+ def __getattr__(self, name):
+ try:
+ return getattr(getattr(self,'_wrapped'),name)
+ except AttributeError:
+ if hasattr(self, name):
+ return getattr(self,name)
+ raise