diff --exclude=.svn --exclude=.hg -I '$Id:.*$' -r -u Python-3.2.orig/Lib/asyncore.py Python-3.2/Lib/asyncore.py --- Python-3.2.orig/Lib/asyncore.py 2011-02-11 15:01:46.000000000 +0100 +++ Python-3.2/Lib/asyncore.py 2011-10-05 12:50:23.000000000 +0200 @@ -406,6 +406,11 @@ # cheap inheritance, used to pass all other attribute # references to the underlying socket object. def __getattr__(self, attr): + # Avoid infinite recursion. The 'socket' attribute may be missing + # when doing a copy of, or when unpickling, a dispatcher instance. + if attr == 'socket': + raise AttributeError("%s instance has no attribute 'socket'" + % self.__class__.__name__) try: retattr = getattr(self.socket, attr) except AttributeError: diff --exclude=.svn --exclude=.hg -I '$Id:.*$' -r -u Python-3.2.orig/Lib/test/test_asyncore.py Python-3.2/Lib/test/test_asyncore.py --- Python-3.2.orig/Lib/test/test_asyncore.py 2010-12-01 03:32:32.000000000 +0100 +++ Python-3.2/Lib/test/test_asyncore.py 2011-10-05 12:54:05.000000000 +0200 @@ -7,6 +7,7 @@ import time import warnings import errno +import copy from test import support from test.support import TESTFN, run_unittest, unlink @@ -331,6 +332,18 @@ err = asyncore._strerror(-1) self.assertIn("unknown error", err.lower()) + def test_issue_13103 (self): + # Check that a 'copy' of a dispatcher instance, does not cause + # infinite recursion. + try: + d = copy.copy(asyncore.dispatcher()) + except RuntimeError: + # Trap RuntimeError to avoid cluttering the screen with + # error messages. + self.assertTrue(False) + else: + self.assertEqual(repr(d), '' % id(d)) + class dispatcherwithsend_noread(asyncore.dispatcher_with_send): def readable(self):