Known bugs in Python 2.2

Real bugs

These are actual bugs, and we will make fixes available as soon as we have them. (There may be other bugs that aren't generally worth knowing about; search the SourceForge bug tracker; you can also use that to report new bugs you find, of course.)

  • The ftplib module's FTP class was supposed to default to passive mode. Unfortunately it doesn't. This means that urllib.urlopen() doesn't work from inside most firewalls. If you have this problem, delete or comment out line 117, "self.passiveserver = 0", from file ftplib.py.

  • The -Qnew option is implemented incompletely: it turns / into true division, but unfortunately not /=. See SourceForge bug report #496549.

  • Attempting to pickle the result of time.localtime() causes infinite recursion. See SourceForge bug report #496873.

  • In Python 2.1, the StringIO module (though not cStringIO) supported Unicode. This capability is accidentally not present in Python 2.2.

  • A deep copy (using copy.deepcopy()) of a recursive data structure built out of new-style classes would cause infinite recursion. See SourceForge bug report #497426.

  • The Demo/extend subdirectory should not have been shipped; it contains an obsolete example. To build extensions, you should use distutils, which is documented extensively in the standard documentation bundle ("Distributing Python Modules").

Incompatibilities between Python 2.1[.1] and Python 2.2

The following visible differences between Python 2.2 and previous versions are intentional.

  • Not everything is listed here; for the full list see the Misc/NEWS file in the distribution.

  • Not listed here are various deprecated modules and features that may issue warnings: the warnings shouldn't affect the correct execution of your program, and they can be disabled with a command line option or programmatically; see the documentation for the warnings module.

  • Also not listed are new constructs that used to be an error (e.g. "key in dict" is now a valid test where formerly it would always raise an exception).

  • The dir() function behaves differently than in Python 2.1 and before. Generally, dir() returns more information than it used to do in 2.1. For example, dir([]) also reports the special methods that overload various operators ('__add__', '__getitem__', '__len__', etc.) as well as '__class__'. For classes (classic as well as new-style), it returns the attributes of the class as well as of the base classes.

  • The special attributes __members__ and __methods__ are no longer supported (for most built-in types). Use the new and improved dir() function instead.

  • type("").__name__ == "str" # was "string"

  • type(0L).__name__ == "long" # was "long int"

  • Overflowing int operations return the corresponding long value rather than raising the OverflowError exception.

  • Conversion of long to float now raises OverflowError if the long is too big to represent as a C double. This used to return an "infinity" value on most platforms.

  • The 3-argument builtin pow() no longer allows a third non-None argument if either of the first two arguments is a float, or if both are of integer types and the second argument is negative (in which latter case the arguments are converted to float, so this is really the same restriction).

  • An old tokenizer bug allowed floating point literals with an incomplete exponent, such as 1e and 3.1e-. Such literals now raise SyntaxError.

  • Nested scopes are standard in 2.2 (they were enabled per module through "from __future__ import nested_scopes" in 2.1[.1]). This may change the meaning of code like the following:
        def f(str):
            def g(x): return str(x)
            return g
    
    In this example, the use of str inside the inner function g() now refers to the argument str in the outer function f(); previously (without nested scopes), it would refer to the built-in function str.

  • Unbound method objects have their im_class field set differently. In previous versions, the im_class field was set to the class that defined the method. Now it is set to the class that was used to create the method object. For example:
        class A:
            def meth(self): ...
        class B(A):
            ... # doesn't define meth
        class C(A):
            def meth(self):
                B.meth(self) # error, C doesn't inherit from B
    
    This code accidentally worked before, even though B is not a base class of C, because B.meth.im_class was set to A, and A is a base class of C! Presumably long ago the inheritance tree was different and C did inherit from B; when that was changed the upcall wasn't fixed. C will break when the unrelated class B gets a new definition of meth(). Also, previously, B().meth.im_class would return A; now it returns B (because it's a method bound to an instance of B).

  • The C API to the GC module has changed incompatibly. Extensions written to support the 2.1 version of the GC module will still compile, but the GC feature will be disabled.

  • The contents of gc.garbage is different; it used to contain all uncollectible cycles; now it contains only objects in uncollectible cycles with a __del__ method.

  • The hash order of dict items is different than in previous versions. (No code should rely on this order, but it's easy to forget this.)

  • Assignment to __debug__ raises SyntaxError at compile-time.

  • The UTF-16 codec was modified to be more RFC compliant. It will now only remove BOM characters at the start of the string and then only if running in native mode (UTF-16-LE and -BE won't remove a leading BMO character).

  • Many error messages are different; in some cases an error condition raises a different exception (most common are cases where TypeError and AttributeError are swapped).

Differences between classic classes and new-style classes

The following differences between classic and new-style classes may require attention when you are converting a classic class to a new-style class. Since previous versions of Python don't support new-style classes, these can't be considered to be real bugs, but since we've tried very hard to make the behavior of new-style classes backwards compatible, it's important to note these differences. (There are of course many more differences that become relevant if you are writing a new-style class from scratch; this list only lists changes in behavior relevant for the conversion of classic classes.)

  • The method resolution order is different; see the tutorial.

  • New-style classes that overload binary operators (__add__ and so on) cannot rely on the __coerce__ method to coerce the arguments; the other argument will be whatever was present originally. Thus, if x is a new-style class instance defining an __add__ method, x+1 causes a call to x.__add__(1). The method implementation will have to analyze the other argument's type in order to be able to implement the operation correctly. If the method implementation decides that it doesn't know how to implement the operation for this particular combination of argument types, it should return the special singleton value NotImplemented. (This behavior is the same as for classic classes lacking a __coerce__ method; the difference is that the __coerce__ method is ignored by the new-style binary operators.)

  • New-style class instances allow assignment to their __class__ attribute only if the C-level structure layout of the old and new class are the same. This prevents disasters like taking a list and changing its __class__ to make it a dict.

  • New-style class objects don't support assignment to their __bases__ attribute.

  • (I'm sure there are more differences that are relevant to the conversion of classic classes to new-style classes), but I can't think of then right now.)

To report a bug not listed above, always use the SourceForge Bug Tracker. If you have a patch, please use the SourceForge Patch Manager. Please mention that you are reporting a bug in 2.2!