9 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/ce7494cefd35/ Changeset: ce7494cefd35 User: uweschmitt Date: 2014-08-07 16:13:12 Summary: fixed strange infinite recursion bug Affected #: 1 file
diff -r 737cf55acf3c5401b44f13239fa3d9e87031d8a3 -r ce7494cefd35ea88a35ed39562d0df4685645f7c _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -238,7 +238,8 @@ self.write(data) def __getattr__(self, name): - return getattr(self.buffer, name) + if name != "buffer": + return getattr(self.buffer, name) class MultiCapture(object): https://bitbucket.org/hpk42/pytest/commits/8a57dee643d7/ Changeset: 8a57dee643d7 User: uweschmitt Date: 2014-08-07 16:56:45 Summary: better fix as replacement for last commit Affected #: 1 file diff -r ce7494cefd35ea88a35ed39562d0df4685645f7c -r 8a57dee643d74783a9cb8fdb696d83eae6e9370d _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -238,8 +238,12 @@ self.write(data) def __getattr__(self, name): - if name != "buffer": - return getattr(self.buffer, name) + return getattr(self.buffer, name) + + def __setattr__(self, dd): + """default implementation for __setattr__ because unpickling causes infinite + recursion if only __getattr__ is overloaded and __setattr__ is missing""" + self.__dict__ = dd class MultiCapture(object): https://bitbucket.org/hpk42/pytest/commits/e52c087c5ef2/ Changeset: e52c087c5ef2 User: uweschmitt Date: 2014-08-07 17:17:05 Summary: even better fix as replacement for last commit which was wrong Affected #: 1 file diff -r 8a57dee643d74783a9cb8fdb696d83eae6e9370d -r e52c087c5ef2bb1de11b2e9eb119024af16bd425 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -240,9 +240,9 @@ def __getattr__(self, name): return getattr(self.buffer, name) - def __setattr__(self, dd): - """default implementation for __setattr__ because unpickling causes infinite - recursion if only __getattr__ is overloaded and __setattr__ is missing""" + def __setstate__(self, dd): + """default implementation for __setstate__ because unpickling causes infinite + recursion if only __getattr__ is overloaded and __setstate__ is missing""" self.__dict__ = dd https://bitbucket.org/hpk42/pytest/commits/d5df0a29b5e4/ Changeset: d5df0a29b5e4 User: uweschmitt Date: 2014-08-11 12:42:36 Summary: hopefully final fix for strange infinite recursion bug Affected #: 1 file diff -r e52c087c5ef2bb1de11b2e9eb119024af16bd425 -r d5df0a29b5e469f793b146b8d5c50ff5eb1da8f9 _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -238,12 +238,8 @@ self.write(data) def __getattr__(self, name): - return getattr(self.buffer, name) - - def __setstate__(self, dd): - """default implementation for __setstate__ because unpickling causes infinite - recursion if only __getattr__ is overloaded and __setstate__ is missing""" - self.__dict__ = dd + if hasattr(self, "buffer"): + return getattr(self.buffer, name) class MultiCapture(object): https://bitbucket.org/hpk42/pytest/commits/dc070608b6d1/ Changeset: dc070608b6d1 User: uweschmitt Date: 2014-08-11 12:57:47 Summary: hopefully final fix for strange infinite recursion bug Affected #: 2 files diff -r d5df0a29b5e469f793b146b8d5c50ff5eb1da8f9 -r dc070608b6d1a2d2269f7daaa3bde48d02a9a8bd _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -240,6 +240,8 @@ def __getattr__(self, name): if hasattr(self, "buffer"): return getattr(self.buffer, name) + else: + raise AttributeError("attribute buffer of %r not set" % self) class MultiCapture(object): diff -r d5df0a29b5e469f793b146b8d5c50ff5eb1da8f9 -r dc070608b6d1a2d2269f7daaa3bde48d02a9a8bd _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -159,6 +159,8 @@ self.config = config def __getattr__(self, name): + if not hasattr(self, "config"): + raise AttributeError("attribute config of %r not set" % self) hookmethod = getattr(self.config.hook, name) def call_matching_hooks(**kwargs): https://bitbucket.org/hpk42/pytest/commits/0a13140a9bf7/ Changeset: 0a13140a9bf7 User: uweschmitt Date: 2014-08-19 12:57:37 Summary: added smoke test for bug fixed in 3716:dc080608b6d1 Affected #: 1 file diff -r dc070608b6d1a2d2269f7daaa3bde48d02a9a8bd -r 0a13140a9bf7fdaddad3d067d9a6ba75b9d5758c testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1,6 +1,7 @@ # note: py.io capture tests where copied from # pylib 1.4.20.dev2 (rev 13d9af95547e) from __future__ import with_statement +import cPickle import os import sys import py @@ -1022,3 +1023,12 @@ """) reprec = testdir.inline_run() reprec.assertoutcome(passed=1) + + +def test_pickling_and_unpickling_enocded_file(): + # see + # https://bitbucket.org/hpk42/pytest/pull-request/194/fixed-strange-infinite-recursion-bug/diff + ef = capture.EncodedFile(None, None) + ef_as_str = cPickle.dumps(ef) + # this raises infinite recursion if EncodedFile.__getattr__ is not implemented properly: + cPickle.loads(ef_as_str) https://bitbucket.org/hpk42/pytest/commits/b87ba201ec47/ Changeset: b87ba201ec47 User: flub Date: 2014-09-06 00:55:14 Summary: Use py3k compatible .__getattr__() code >From the python-dev thread it seemed like using object.__getattribute__(self, 'name') is the cleanest way of implementing a class wich uses .__getattr__() and should be pickelable. That only works on new-style classes so this also turns HookProxy into a new-style class on py2. This also re-writes the test to not use cPickle so it runs on py3k. Affected #: 4 files diff -r 0a13140a9bf7fdaddad3d067d9a6ba75b9d5758c -r b87ba201ec47b0ba251ecf4f1a7e31f0cd99e29a _pytest/assertion/oldinterpret.py --- a/_pytest/assertion/oldinterpret.py +++ b/_pytest/assertion/oldinterpret.py @@ -57,7 +57,7 @@ def __getattr__(self, attr): # attributes not found in the normal hierarchy rooted on View # are looked up in the object's real class - return getattr(self.__obj__, attr) + return getattr(object.__getattribute__(self, '__obj__'), attr) def __viewkey__(self): return self.__obj__.__class__ diff -r 0a13140a9bf7fdaddad3d067d9a6ba75b9d5758c -r b87ba201ec47b0ba251ecf4f1a7e31f0cd99e29a _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -238,10 +238,7 @@ self.write(data) def __getattr__(self, name): - if hasattr(self, "buffer"): - return getattr(self.buffer, name) - else: - raise AttributeError("attribute buffer of %r not set" % self) + return getattr(object.__getattribute__(self, "buffer"), name) class MultiCapture(object): diff -r 0a13140a9bf7fdaddad3d067d9a6ba75b9d5758c -r b87ba201ec47b0ba251ecf4f1a7e31f0cd99e29a _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -153,15 +153,14 @@ ignore_paths.extend([py.path.local(x) for x in excludeopt]) return path in ignore_paths -class HookProxy: +class HookProxy(object): def __init__(self, fspath, config): self.fspath = fspath self.config = config def __getattr__(self, name): - if not hasattr(self, "config"): - raise AttributeError("attribute config of %r not set" % self) - hookmethod = getattr(self.config.hook, name) + config = object.__getattribute__(self, "config") + hookmethod = getattr(config.hook, name) def call_matching_hooks(**kwargs): plugins = self.config._getmatchingplugins(self.fspath) diff -r 0a13140a9bf7fdaddad3d067d9a6ba75b9d5758c -r b87ba201ec47b0ba251ecf4f1a7e31f0cd99e29a testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1,7 +1,7 @@ # note: py.io capture tests where copied from # pylib 1.4.20.dev2 (rev 13d9af95547e) from __future__ import with_statement -import cPickle +import pickle import os import sys import py @@ -1026,9 +1026,9 @@ def test_pickling_and_unpickling_enocded_file(): - # see - # https://bitbucket.org/hpk42/pytest/pull-request/194/fixed-strange-infinite-recursion-bug/diff + # See https://bitbucket.org/hpk42/pytest/pull-request/194 + # pickle.loads() raises infinite recursion if + # EncodedFile.__getattr__ is not implemented properly ef = capture.EncodedFile(None, None) - ef_as_str = cPickle.dumps(ef) - # this raises infinite recursion if EncodedFile.__getattr__ is not implemented properly: - cPickle.loads(ef_as_str) + ef_as_str = pickle.dumps(ef) + pickle.loads(ef_as_str) https://bitbucket.org/hpk42/pytest/commits/787f4b5a1fa1/ Changeset: 787f4b5a1fa1 User: flub Date: 2014-09-06 00:57:18 Summary: Merged in uweschmitt/pytest/default (pull request #194) Affected #: 4 files diff -r 2cf48d77a3764a1c3cf47ec3c63a972d35ad63d4 -r 787f4b5a1fa1c72fc513da39661f4dcc340844bd _pytest/assertion/oldinterpret.py --- a/_pytest/assertion/oldinterpret.py +++ b/_pytest/assertion/oldinterpret.py @@ -57,7 +57,7 @@ def __getattr__(self, attr): # attributes not found in the normal hierarchy rooted on View # are looked up in the object's real class - return getattr(self.__obj__, attr) + return getattr(object.__getattribute__(self, '__obj__'), attr) def __viewkey__(self): return self.__obj__.__class__ diff -r 2cf48d77a3764a1c3cf47ec3c63a972d35ad63d4 -r 787f4b5a1fa1c72fc513da39661f4dcc340844bd _pytest/capture.py --- a/_pytest/capture.py +++ b/_pytest/capture.py @@ -238,7 +238,7 @@ self.write(data) def __getattr__(self, name): - return getattr(self.buffer, name) + return getattr(object.__getattribute__(self, "buffer"), name) class MultiCapture(object): diff -r 2cf48d77a3764a1c3cf47ec3c63a972d35ad63d4 -r 787f4b5a1fa1c72fc513da39661f4dcc340844bd _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -153,13 +153,14 @@ ignore_paths.extend([py.path.local(x) for x in excludeopt]) return path in ignore_paths -class HookProxy: +class HookProxy(object): def __init__(self, fspath, config): self.fspath = fspath self.config = config def __getattr__(self, name): - hookmethod = getattr(self.config.hook, name) + config = object.__getattribute__(self, "config") + hookmethod = getattr(config.hook, name) def call_matching_hooks(**kwargs): plugins = self.config._getmatchingplugins(self.fspath) diff -r 2cf48d77a3764a1c3cf47ec3c63a972d35ad63d4 -r 787f4b5a1fa1c72fc513da39661f4dcc340844bd testing/test_capture.py --- a/testing/test_capture.py +++ b/testing/test_capture.py @@ -1,6 +1,7 @@ # note: py.io capture tests where copied from # pylib 1.4.20.dev2 (rev 13d9af95547e) from __future__ import with_statement +import pickle import os import sys import py @@ -1022,3 +1023,12 @@ """) reprec = testdir.inline_run() reprec.assertoutcome(passed=1) + + +def test_pickling_and_unpickling_enocded_file(): + # See https://bitbucket.org/hpk42/pytest/pull-request/194 + # pickle.loads() raises infinite recursion if + # EncodedFile.__getattr__ is not implemented properly + ef = capture.EncodedFile(None, None) + ef_as_str = pickle.dumps(ef) + pickle.loads(ef_as_str) https://bitbucket.org/hpk42/pytest/commits/faacab838caf/ Changeset: faacab838caf User: flub Date: 2014-09-06 01:00:43 Summary: Mention PR #194 in the changelog Affected #: 1 file diff -r 787f4b5a1fa1c72fc513da39661f4dcc340844bd -r faacab838caf54f0f67f7a05b4741516aa5306db CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,9 @@ - fix issue582: fix setuptools example, thanks Laszlo Papp and Ronny Pfannschmidt. +- Fix infinite recursion bug when pickling capture.EncodedFile, thanks + Uwe Schmitt. + 2.6.2 ----------- Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. _______________________________________________ pytest-commit mailing list pytest-commit@python.org https://mail.python.org/mailman/listinfo/pytest-commit