Monkey patch python with instruction

I am using py.test for my python module testing. Consider the following code:

def mytest():
    "Test method"
    print "Before with statement"
    with TestClass('file.zip', 'r') as test_obj:
        print "This shouldn't print after patching."
        # some operation on object.
    print "After with statement."

      

Is it possible to execute the monkeypatch command so TestClass

that the code in the block with

becomes noop

?

For example, the output after the fix should be:

Before with statement
After with statement

      

I know I can fix the feature mytest

, but this is for better testing coverage.

I tried, something along the following lines but couldn't get it to work.

class MockTestClass(object):
    def __init__(self, *args):
        print "__init__ called."

    def __enter__(self):
        print "__enter__ called."
        raise TestException("Yeah done with it! Get lost now.")

    def __exit__(self, type, value, traceback):
        print "__exit__ called."

module_name.setattr('TestClass',  MockTestClass)

      

+3


source to share


2 answers


I think what you are trying to do is prohibited by the Python language specification.

As you can see in PEP-343, the definition of the "with" statement will prevent you from trying to exit the context earlier:



mgr = (EXPR)
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
    try:
        VAR = value  # Only if "as VAR" is present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
        # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)

      

It was suggested to change this to a feature of the function you would need ( PEP-377 ), but this was rejected.

+1


source


It is clear from @ Peter's answer that we cannot make the whole block like noop

. I ended up doing the following for my use.



# Module foo.py
class Foo(object):
    def __init__(self):
        print "class inited"

    def __enter__(self):
        print "entered class"
        return None

    def foo(self):
        raise Exception("Not implemented")

    def __exit__(self, type, value, traceback):
        print "exited class"
        return True

----------------------------
# Module FooTest
import foo

class FooTest(object):
    def __init__(self):
        print "class inited"

    def __enter__(self):
        print "entered class"
        return None

    def __exit__(self, type, value, traceback):
        print "exited class"
        return True

try:
    foo.Foo()
    print "It shouldn't print"
except:
    print "Expected exception"
setattr(foo, 'Foo', FooTest)
print "Patched"
with foo.Foo() as a:
    a.foo()
    print "It shouldn't print"
print 'Test passed!'

      

0


source







All Articles