view tests/test-extensions-wrapfunction.py @ 48011:8655a77dce94

parser: force a `ValueError` to bytes before passing to `error.ParseError` I'm not sure what changed before pytype 09-09-2021 (from 04-15-2021), but this started getting flagged. I think there's a pytype bug here, because I don't see how `.lower()` can be getting called on a `ValueError` after it is forced to a byte string. That's suppressed for now to make progress. This fixes: File "/mnt/c/Users/Matt/hg/mercurial/parser.py", line 219, in unescapestr: Function bytestr.__init__ was called with the wrong arguments [wrong-arg-types] Expected: (self, ints: Iterable[int]) Actually passed: (self, ints: ValueError) Attributes of protocol Iterable[int] are not implemented on ValueError: __iter__ File "/mnt/c/Users/Matt/hg/mercurial/parser.py", line 219, in unescapestr: No attribute 'lower' on ValueError [attribute-error] In Union[ValueError, mercurial.pycompat.bytestr] Differential Revision: https://phab.mercurial-scm.org/D11471
author Matt Harbison <matt_harbison@yahoo.com>
date Mon, 20 Sep 2021 10:59:26 -0400
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())