Closed night199uk closed 5 years ago
Yes, you are correct, but the fix you propose is not really helping. You can not use partial in this context (At least not with positional arguments)
import functools
from lark import Lark
from lark.visitors import Transformer, v_args
def test(self, x):
print(self, x)
@v_args(inline=True)
class T(Transformer):
start = functools.partial(test, "test")
parser = Lark(r"""
start: "test"
""", parser="lalr", transformer=T())
if __name__ == '__main__':
sample_conf = """test"""
r = parser.parse(sample_conf)
With this code, the following outputs for changes in utils.py occur:
return create_decorator(f.func, True)
TypeError: test() missing 1 required positional argument: 'x'
Makes sense. We now completely discard the partial and only use the underlying function.
return create_decorator(f, True)
test <__main__.T object at 0x00000181841E6940>
The seems promising! But wait... if you remember what we are printing:
print(self, x)
you can see that x
contains the reference to the Transformer object. Also makes sense: partial puts all arguments in front of all arguments passed afterwards. The only thing I found that works coorectly is if partial only uses keyword arguments:
@v_args(inline=True)
class T(Transformer):
start = functools.partial(test, x="test")
This prints the expected output (with the last change in utils.py
):
<__main__.T object at 0x0000020A6C246908> test
I am not sure what the best course of action is. One could:
self
is passed as the first argument (or provided own implementation)My solution was to simply manually removed the self
argument, as it doesn't make sense in partials
The following test works now:
tree = Tree("start", [Tree("a", ["test1"]), Tree("b", ["test2"])])
def test(prefix, s, postfix):
return prefix + s.upper() + postfix
@v_args(inline=True)
class T(Transformer):
a = functools.partial(test, "@", postfix="!")
b = functools.partial(lambda s: s + "!")
res = T().transform(tree)
assert res.children == ["@TEST1!", "test2!"]
lgtm!
The simple test case below generates this for me:
From what I can see partial objects have no func in Py2 or Py3? Should it be f.func?