2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/23278f23f092/ Changeset: 23278f23f092 User: hpk42 Date: 2013-09-27 12:28:34 Summary: fix some tests wrt to expecting output now that pytest does no introduce unwanted "buffering" on "-s" calls. Affected #: 4 files
diff -r 8f4c9f56a90fa62074cc2c52a4158f1f09adb084 -r 23278f23f0923076011f554bb875e332fde21125 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1623,7 +1623,7 @@ assert not name.startswith(self._argprefix) fixturedef = FixtureDef(self, nodeid, name, obj, marker.scope, marker.params, - marker.yieldctx, + yieldctx=marker.yieldctx, unittest=unittest) faclist = self._arg2fixturedefs.setdefault(name, []) if not fixturedef.has_location: diff -r 8f4c9f56a90fa62074cc2c52a4158f1f09adb084 -r 23278f23f0923076011f554bb875e332fde21125 testing/python/fixture.py --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -1993,12 +1993,12 @@ """) result = testdir.runpytest("-s") result.stdout.fnmatch_lines(""" - setup - test1 1 - teardown - setup - test2 1 - teardown + *setup* + *test1 1* + *teardown* + *setup* + *test2 1* + *teardown* """) def test_scoped(self, testdir): @@ -2016,10 +2016,10 @@ """) result = testdir.runpytest("-s") result.stdout.fnmatch_lines(""" - setup - test1 1 - test2 1 - teardown + *setup* + *test1 1* + *test2 1* + *teardown* """) def test_setup_exception(self, testdir): diff -r 8f4c9f56a90fa62074cc2c52a4158f1f09adb084 -r 23278f23f0923076011f554bb875e332fde21125 testing/test_fixture_finalizer.py --- a/testing/test_fixture_finalizer.py +++ b/testing/test_fixture_finalizer.py @@ -28,4 +28,4 @@ """)) reprec = testdir.runpytest("-s") for test in ['test_browser']: - reprec.stdout.fnmatch_lines('Finalized') + reprec.stdout.fnmatch_lines('*Finalized*') diff -r 8f4c9f56a90fa62074cc2c52a4158f1f09adb084 -r 23278f23f0923076011f554bb875e332fde21125 testing/test_terminal.py --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -672,7 +672,7 @@ stdout = k.pop() stdout.close() """) - result = testdir.runpytest("-s") + result = testdir.runpytest() result.stdout.fnmatch_lines([ "*2 passed*" ]) https://bitbucket.org/hpk42/pytest/commits/95a817c87a02/ Changeset: 95a817c87a02 User: hpk42 Date: 2013-09-27 12:33:06 Summary: merge monkeypatch.replace into monkeypatch.setattr, also support monkeypatch.delattr. Affected #: 4 files diff -r 23278f23f0923076011f554bb875e332fde21125 -r 95a817c87a020ef2c325244d6f596943eaf5d0ae CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -17,10 +17,10 @@ - PR27: correctly handle nose.SkipTest during collection. Thanks Antonio Cuni, Ronny Pfannschmidt. -- new monkeypatch.replace() to avoid imports and provide a shorter +- new monkeypatch.setattr() variant to provide a shorter invocation for patching out classes/functions from modules: - monkeypatch.replace("requests.get", myfunc + monkeypatch.setattr("requests.get", myfunc) will replace the "get" function of the "requests" module with ``myfunc``. diff -r 23278f23f0923076011f554bb875e332fde21125 -r 95a817c87a020ef2c325244d6f596943eaf5d0ae _pytest/monkeypatch.py --- a/_pytest/monkeypatch.py +++ b/_pytest/monkeypatch.py @@ -25,6 +25,39 @@ request.addfinalizer(mpatch.undo) return mpatch + + +def derive_importpath(import_path): + if not isinstance(import_path, str) or "." not in import_path: + raise TypeError("must be absolute import path string, not %r" % + (import_path,)) + rest = [] + target = import_path + while target: + try: + obj = __import__(target, None, None, "__doc__") + except ImportError: + if "." not in target: + __tracebackhide__ = True + pytest.fail("could not import any sub part: %s" % + import_path) + target, name = target.rsplit(".", 1) + rest.append(name) + else: + assert rest + try: + while len(rest) > 1: + attr = rest.pop() + obj = getattr(obj, attr) + attr = rest[0] + getattr(obj, attr) + except AttributeError: + __tracebackhide__ = True + pytest.fail("object %r has no attribute %r" % (obj, attr)) + return attr, obj + + + notset = object() class monkeypatch: @@ -34,70 +67,66 @@ self._setitem = [] self._cwd = None - def replace(self, import_path, value): - """ replace the object specified by a dotted ``import_path`` - with the given ``value``. + def setattr(self, target, name, value=notset, raising=True): + """ set attribute value on target, memorizing the old value. + By default raise AttributeError if the attribute did not exist. - For example ``replace("os.path.abspath", value)`` will - trigger an ``import os.path`` and a subsequent - setattr(os.path, "abspath", value). Or to prevent - the requests library from performing requests you can call - ``replace("requests.sessions.Session.request", None)`` - which will lead to an import of ``requests.sessions`` and a call - to ``setattr(requests.sessions.Session, "request", None)``. + For convenience you can specify a string as ``target`` which + will be interpreted as a dotted import path, with the last part + being the attribute name. Example: + ``monkeypatch.setattr("os.getcwd", lambda x: "/")`` + would set the ``getcwd`` function of the ``os`` module. + + The ``raising`` value determines if the setattr should fail + if the attribute is not already present (defaults to True + which means it will raise). """ - if not isinstance(import_path, str) or "." not in import_path: - raise TypeError("must be absolute import path string, not %r" % - (import_path,)) - rest = [] - target = import_path - while target: - try: - obj = __import__(target, None, None, "__doc__") - except ImportError: - if "." not in target: - __tracebackhide__ = True - pytest.fail("could not import any sub part: %s" % - import_path) - target, name = target.rsplit(".", 1) - rest.append(name) - else: - assert rest - try: - while len(rest) > 1: - attr = rest.pop() - obj = getattr(obj, attr) - attr = rest[0] - getattr(obj, attr) - except AttributeError: - __tracebackhide__ = True - pytest.fail("object %r has no attribute %r" % (obj, attr)) - return self.setattr(obj, attr, value) + __tracebackhide__ = True - def setattr(self, obj, name, value, raising=True): - """ set attribute ``name`` on ``obj`` to ``value``, by default - raise AttributeEror if the attribute did not exist. + if value is notset: + if not isinstance(target, str): + raise TypeError("use setattr(target, name, value) or " + "setattr(target, value) with target being a dotted " + "import string") + value = name + name, target = derive_importpath(target) - """ - oldval = getattr(obj, name, notset) + oldval = getattr(target, name, notset) if raising and oldval is notset: - raise AttributeError("%r has no attribute %r" %(obj, name)) + raise AttributeError("%r has no attribute %r" %(target, name)) # avoid class descriptors like staticmethod/classmethod - if inspect.isclass(obj): - oldval = obj.__dict__.get(name, notset) - self._setattr.insert(0, (obj, name, oldval)) - setattr(obj, name, value) + if inspect.isclass(target): + oldval = target.__dict__.get(name, notset) + self._setattr.insert(0, (target, name, oldval)) + setattr(target, name, value) - def delattr(self, obj, name, raising=True): - """ delete attribute ``name`` from ``obj``, by default raise - AttributeError it the attribute did not previously exist. """ - if not hasattr(obj, name): + def delattr(self, target, name=notset, raising=True): + """ delete attribute ``name`` from ``target``, by default raise + AttributeError it the attribute did not previously exist. + + If no ``name`` is specified and ``target`` is a string + it will be interpreted as a dotted import path with the + last part being the attribute name. + + If raising is set to false, the attribute is allowed to not + pre-exist. + """ + __tracebackhide__ = True + if name is notset: + if not isinstance(target, str): + raise TypeError("use delattr(target, name) or " + "delattr(target) with target being a dotted " + "import string") + name, target = derive_importpath(target) + + if not hasattr(target, name): if raising: raise AttributeError(name) else: - self._setattr.insert(0, (obj, name, getattr(obj, name, notset))) - delattr(obj, name) + self._setattr.insert(0, (target, name, + getattr(target, name, notset))) + delattr(target, name) def setitem(self, dic, name, value): """ set dictionary entry ``name`` to value. """ diff -r 23278f23f0923076011f554bb875e332fde21125 -r 95a817c87a020ef2c325244d6f596943eaf5d0ae doc/en/monkeypatch.txt --- a/doc/en/monkeypatch.txt +++ b/doc/en/monkeypatch.txt @@ -48,11 +48,28 @@ import pytest @pytest.fixture(autouse=True) def no_requests(monkeypatch): - monkeypatch.replace("requests.session.Session.request", None) + monkeypatch.delattr("requests.session.Session.request") -This autouse fixture will be executed for all test functions and it -will replace the method ``request.session.Session.request`` with the -value None so that any attempts to create http requests will fail. +This autouse fixture will be executed for each test function and it +will delete the method ``request.session.Session.request`` +so that any attempts within tests to create http requests will fail. + +example: setting an attribute on some class +------------------------------------------------------ + +If you need to patch out ``os.getcwd()`` to return an artifical +value:: + + def test_some_interaction(monkeypatch): + monkeypatch.setattr("os.getcwd", lambda: "/") + +which is equivalent to the long form:: + + def test_some_interaction(monkeypatch): + import os + monkeypatch.setattr(os, "getcwd", lambda: "/") + + Method reference of the monkeypatch function argument ----------------------------------------------------- diff -r 23278f23f0923076011f554bb875e332fde21125 -r 95a817c87a020ef2c325244d6f596943eaf5d0ae testing/test_monkeypatch.py --- a/testing/test_monkeypatch.py +++ b/testing/test_monkeypatch.py @@ -35,26 +35,32 @@ monkeypatch.undo() # double-undo makes no modification assert A.x == 5 -class TestReplace: +class TestSetattrWithImportPath: def test_string_expression(self, monkeypatch): - monkeypatch.replace("os.path.abspath", lambda x: "hello2") + monkeypatch.setattr("os.path.abspath", lambda x: "hello2") assert os.path.abspath("123") == "hello2" def test_string_expression_class(self, monkeypatch): - monkeypatch.replace("_pytest.config.Config", 42) + monkeypatch.setattr("_pytest.config.Config", 42) import _pytest assert _pytest.config.Config == 42 def test_wrong_target(self, monkeypatch): - pytest.raises(TypeError, lambda: monkeypatch.replace(None, None)) + pytest.raises(TypeError, lambda: monkeypatch.setattr(None, None)) def test_unknown_import(self, monkeypatch): pytest.raises(pytest.fail.Exception, - lambda: monkeypatch.replace("unkn123.classx", None)) + lambda: monkeypatch.setattr("unkn123.classx", None)) def test_unknown_attr(self, monkeypatch): pytest.raises(pytest.fail.Exception, - lambda: monkeypatch.replace("os.path.qweqwe", None)) + lambda: monkeypatch.setattr("os.path.qweqwe", None)) + + def test_delattr(self, monkeypatch): + monkeypatch.delattr("os.path.abspath") + assert not hasattr(os.path, "abspath") + monkeypatch.undo() + assert os.path.abspath def test_delattr(): class A: @@ -262,3 +268,5 @@ monkeypatch.undo() assert Sample.hello() + + 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