view tests/test-extensions-wrapfunction.py @ 43874:bc7d8f45c3b6

rust-dirs: handle forgotten `Result`s In 1fe2e574616e I introduced a temporary bugfix to align Rust code with a new behavior from C/Python and forgot about a few `Result`s (cargo's compiler cache does not re-emit warnings on cached modules). This fixes it. For the record, I am still unsure that this behavior change is a good idea. Note: I was already quite unhappy with the setters and getters for the `DirstateMap` and, indirectly, `Dirs`, and this only further reinforces my feelings. I hope we can one day fix that situation at the type level; Georges Racinet and I were just talking about devising a POC for using the builder pattern in the context of FFI with Python, we'll see what comes out of it. Differential Revision: https://phab.mercurial-scm.org/D7609
author Raphaël Gomès <rgomes@octobus.net>
date Thu, 12 Dec 2019 15:55:25 +0100
parents 2372284d9457
children 6000f5b25c9b
line wrap: on
line source

from __future__ import absolute_import, print_function

from mercurial import extensions


def genwrapper(x):
    def f(orig, *args, **kwds):
        return [x] + orig(*args, **kwds)

    f.x = x
    return f


def getid(wrapper):
    return getattr(wrapper, 'x', '-')


wrappers = [genwrapper(i) for i in range(5)]


class dummyclass(object):
    def getstack(self):
        return ['orig']


dummy = dummyclass()


def batchwrap(wrappers):
    for w in wrappers:
        extensions.wrapfunction(dummy, 'getstack', w)
        print('wrap %d: %s' % (getid(w), dummy.getstack()))


def batchunwrap(wrappers):
    for w in wrappers:
        result = None
        try:
            result = extensions.unwrapfunction(dummy, 'getstack', w)
            msg = str(dummy.getstack())
        except (ValueError, IndexError) as e:
            msg = e.__class__.__name__
        print('unwrap %s: %s: %s' % (getid(w), getid(result), msg))


batchwrap(wrappers + [wrappers[0]])
batchunwrap(
    [
        (wrappers[i] if i is not None and i >= 0 else None)
        for i in [3, None, 0, 4, 0, 2, 1, None]
    ]
)

wrap0 = extensions.wrappedfunction(dummy, 'getstack', wrappers[0])
wrap1 = extensions.wrappedfunction(dummy, 'getstack', wrappers[1])

# Use them in a different order from how they were created to check that
# the wrapping happens in __enter__, not in __init__
print('context manager', dummy.getstack())
with wrap1:
    print('context manager', dummy.getstack())
    with wrap0:
        print('context manager', dummy.getstack())
        # Bad programmer forgets to unwrap the function, but the context
        # managers still unwrap their wrappings.
        extensions.wrapfunction(dummy, 'getstack', wrappers[2])
        print('context manager', dummy.getstack())
    print('context manager', dummy.getstack())
print('context manager', dummy.getstack())

# Wrap callable object which has no __name__
class callableobj(object):
    def __call__(self):
        return ['orig']


dummy.cobj = callableobj()
extensions.wrapfunction(dummy, 'cobj', wrappers[0])
print('wrap callable object', dummy.cobj())