From c1085fbe2649fdfe194a2d7a02953d1bd18764c2 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Thu, 10 Dec 2020 00:31:41 -0600 Subject: [PATCH 01/10] add support for parsing dotted names into tags --- pytools/tag.py | 149 ++++++++++++++++++++++++++++++++++++++++++++++ test/test_tags.py | 32 ++++++++++ test/testlib.py | 26 ++++++++ 3 files changed, 207 insertions(+) create mode 100644 test/test_tags.py create mode 100644 test/testlib.py diff --git a/pytools/tag.py b/pytools/tag.py index e9a4cc6..7c1c176 100644 --- a/pytools/tag.py +++ b/pytools/tag.py @@ -1,5 +1,8 @@ from dataclasses import dataclass from typing import Tuple, Any, FrozenSet +import importlib +from lark import Lark, Transformer +from mako.template import Template __copyright__ = """ Copyright (C) 2020 Andreas Kloeckner @@ -36,6 +39,8 @@ Tag Interface .. autoclass:: Tag .. autoclass:: UniqueTag +.. autoclass:: ToPythonObjectMapper +.. autofunction:: parse_tag Supporting Functionality ------------------------ @@ -130,4 +135,148 @@ TagsType = FrozenSet[Tag] # }}} + +# {{{ parse + +def build_tag_grammar(shortcuts): + tag_grammar_tmplt = """ + tag: tag_class "(" params ")" -> map_tag + % if shortcuts: + | SHORTCUT -> map_shortcut + % endif + + params: -> map_empty_args_params + | args -> map_args_only_params + | kwargs -> map_kwargs_only_params + | args "," kwargs -> map_args_kwargs_params + + ?kwargs: kwarg + | kwargs "," kwarg -> map_kwargs + + args: arg -> map_singleton_args + | args "," arg -> map_args + + kwarg: name "=" arg -> map_kwarg + + ?arg: tag + | INT -> map_int + | ESCAPED_STRING -> map_string + + tag_class: module "." name -> map_tag_class + + module: name -> map_top_level_module + | module "." name -> map_nested_module + + name: CNAME -> map_name + + % if shortcuts: + SHORTCUT: (${" | ".join('"' + name + '"' for name in shortcuts)}) + % endif + + %%import common.INT + %%import common.ESCAPED_STRING + %%import common.CNAME + %%import common.WS + %%ignore WS + """ + return Template(tag_grammar_tmplt).render(shortcuts=shortcuts).replace("%%", "%") + + +class CallParams: + """ + Intermediate data structure for :class:`ToPythonObjectMapper`. + """ + def __init__(self, args, kwargs): + self.args = args + self.kwargs = kwargs + + +class ToPythonObjectMapper(Transformer): + """ + Map a parsed tree to pythonic objects. + """ + def __init__(self, shortcuts): + super().__init__() + self.shortcuts = shortcuts + + def _call_userfunc(self, tree, new_children=None): + # Assumes tree is already transformed + children = new_children if new_children is not None else tree.children + try: + f = getattr(self, tree.data) + except AttributeError: + return self.__default__(tree.data, children, tree.meta) + else: + # flatten the args + return f(*children) + + def map_tag(self, cls, params): + return cls(*params.args, **params.kwargs) + + def map_empty_args_params(self): + return CallParams((), {}) + + def map_args_only_params(self, args): + return CallParams(args, {}) + + def map_kwargs_only_params(self, kwargs): + return CallParams((), kwargs) + + def map_args_kwargs_params(self, args, kwargs): + return CallParams(args, kwargs) + + def map_name(self, tok): + return tok.value + + def map_top_level_module(self, modulename): + return importlib.import_module(modulename) + + def map_nested_module(self, module, child): + return getattr(module, child) + + def map_tag_class(self, module, classname): + return getattr(module, classname) + + def map_string(self, text): + return str(text) + + def map_int(self, text): + return int(text) + + def map_singleton_args(self, arg): + return (arg,) + + def map_args(self, args, arg): + return args + (arg,) + + def map_kwarg(self, name, arg): + return {name: arg} + + def map_kwargs(self, kwargs, kwarg): + assert len(kwarg) == 1 + (key, val), = kwarg.items() + if key in kwargs: + # FIXME: This should probably be GrammarError + raise ValueError("keyword argument '{key}' repeated") + + updated_kwargs = kwargs.copy() + updated_kwargs[key] = val + return updated_kwargs + + def map_shortcut(self, name): + return self.shortcuts[name.value] + + +def parse_tag(tag_text, shortcuts={}): + """ + Parses a :class:`Tag` from a provided dotted name. + """ + tag_grammar = build_tag_grammar(shortcuts) + parser = Lark(tag_grammar, start="tag") + tag = ToPythonObjectMapper(shortcuts).transform(parser.parse(tag_text)) + + return tag + +# }}} + # vim: foldmethod=marker diff --git a/test/test_tags.py b/test/test_tags.py new file mode 100644 index 0000000..cfb065a --- /dev/null +++ b/test/test_tags.py @@ -0,0 +1,32 @@ +import sys +import testlib # noqa + + +def test_parse_tags(): + from pytools.tag import parse_tag + + def assert_same_as_python(tag_text): + assert parse_tag(tag_text) == eval(tag_text) + + assert_same_as_python("testlib.FruitNameTag(testlib.MangoTag())") + assert_same_as_python("testlib.LocalAxisTag(0)") + assert_same_as_python('testlib.ColorTag("blue")') + assert_same_as_python('testlib.ColorTag(color="blue")') + assert_same_as_python("testlib.LocalAxisTag(axis=0)") + + assert (parse_tag("testlib.FruitNameTag(mango)", + shortcuts={"mango": testlib.MangoTag(), + "apple": testlib.AppleTag()}) + == testlib.FruitNameTag(testlib.MangoTag())) + + assert (parse_tag("l.0", + shortcuts={"l.0": testlib.LocalAxisTag(0)}) + == testlib.LocalAxisTag(axis=0)) + + +if __name__ == "__main__": + if len(sys.argv) > 1: + exec(sys.argv[1]) + else: + from pytest import main + main([__file__]) diff --git a/test/testlib.py b/test/testlib.py new file mode 100644 index 0000000..5bec114 --- /dev/null +++ b/test/testlib.py @@ -0,0 +1,26 @@ +from pytools.tag import Tag, UniqueTag + + +class FruitNameTag(UniqueTag): + def __init__(self, tag): + self.tag = tag + + +class MangoTag(Tag): + def __str__(self): + return "mango" + + +class AppleTag(Tag): + def __str__(self): + return "apple" + + +class ColorTag(Tag): + def __init__(self, color): + self.color = color + + +class LocalAxisTag(Tag): + def __init__(self, axis): + self.axis = axis -- GitLab From 016d50b3fc2e8ac7f1dd061201f570b106a507a8 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Thu, 10 Dec 2020 00:35:07 -0600 Subject: [PATCH 02/10] add mako, lark to dependencies --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ed73fd6..8f2a0ad 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,9 @@ setup(name="pytools", "decorator>=3.2.0", "appdirs>=1.4.0", "numpy>=1.6.0", - "dataclasses>=0.7;python_version<='3.6'" + "dataclasses>=0.7;python_version<='3.6'", + "Mako", + "lark-parser", ], package_data={"pytools": ["py.typed"]}, -- GitLab From e3196efec4642f8a9bccf06143b3a2dda8e06b3b Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Thu, 10 Dec 2020 00:40:09 -0600 Subject: [PATCH 03/10] typo fix --- pytools/tag.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytools/tag.py b/pytools/tag.py index 7c1c176..8de1a95 100644 --- a/pytools/tag.py +++ b/pytools/tag.py @@ -257,7 +257,7 @@ class ToPythonObjectMapper(Transformer): (key, val), = kwarg.items() if key in kwargs: # FIXME: This should probably be GrammarError - raise ValueError("keyword argument '{key}' repeated") + raise ValueError(f"keyword argument '{key}' repeated") updated_kwargs = kwargs.copy() updated_kwargs[key] = val -- GitLab From f585143ffd6e86b284b3a74ba534a07ab3eff0e8 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Mon, 4 Jan 2021 14:05:31 -0600 Subject: [PATCH 04/10] testlib.py -> testlib_tags.py --- test/{testlib.py => testlib_tags.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{testlib.py => testlib_tags.py} (100%) diff --git a/test/testlib.py b/test/testlib_tags.py similarity index 100% rename from test/testlib.py rename to test/testlib_tags.py -- GitLab From 838592a46bb1d454fb3a0ea0b6b4adad15b295a0 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Mon, 4 Jan 2021 14:06:36 -0600 Subject: [PATCH 05/10] static tags parsing grammar - shortcuts must be prepended by a "." --- pytools/tag.py | 60 ++++++++++++++++++++++++----------------------- test/test_tags.py | 17 +++++++++++--- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/pytools/tag.py b/pytools/tag.py index 8de1a95..e4989f4 100644 --- a/pytools/tag.py +++ b/pytools/tag.py @@ -2,7 +2,6 @@ from dataclasses import dataclass from typing import Tuple, Any, FrozenSet import importlib from lark import Lark, Transformer -from mako.template import Template __copyright__ = """ Copyright (C) 2020 Andreas Kloeckner @@ -138,12 +137,9 @@ TagsType = FrozenSet[Tag] # {{{ parse -def build_tag_grammar(shortcuts): - tag_grammar_tmplt = """ - tag: tag_class "(" params ")" -> map_tag - % if shortcuts: - | SHORTCUT -> map_shortcut - % endif +TAG_GRAMMAR = """ + tag: tag_class "(" params ")" -> map_tag_from_python_class + | SHORTCUT -> map_tag_from_shortcut params: -> map_empty_args_params | args -> map_args_only_params @@ -168,18 +164,16 @@ def build_tag_grammar(shortcuts): | module "." name -> map_nested_module name: CNAME -> map_name - - % if shortcuts: - SHORTCUT: (${" | ".join('"' + name + '"' for name in shortcuts)}) - % endif - - %%import common.INT - %%import common.ESCAPED_STRING - %%import common.CNAME - %%import common.WS - %%ignore WS - """ - return Template(tag_grammar_tmplt).render(shortcuts=shortcuts).replace("%%", "%") + SHORTCUT: "." ("_"|LETTER) ("_"|LETTER|DIGIT|".")* + + %import common.INT + %import common.ESCAPED_STRING + %import common.DIGIT + %import common.LETTER + %import common.CNAME + %import common.WS + %ignore WS +""" class CallParams: @@ -195,9 +189,10 @@ class ToPythonObjectMapper(Transformer): """ Map a parsed tree to pythonic objects. """ - def __init__(self, shortcuts): + def __init__(self, shortcuts, caller_globals): super().__init__() self.shortcuts = shortcuts + self.caller_globals = caller_globals def _call_userfunc(self, tree, new_children=None): # Assumes tree is already transformed @@ -210,8 +205,11 @@ class ToPythonObjectMapper(Transformer): # flatten the args return f(*children) - def map_tag(self, cls, params): - return cls(*params.args, **params.kwargs) + def map_tag_from_python_class(self, cls, params): + try: + return cls(*params.args, **params.kwargs) + except TypeError as e: + raise TypeError(f"Error while instantiating '{cls.__name__}': {e}") def map_empty_args_params(self): return CallParams((), {}) @@ -229,7 +227,10 @@ class ToPythonObjectMapper(Transformer): return tok.value def map_top_level_module(self, modulename): - return importlib.import_module(modulename) + try: + return self.caller_globals[modulename] + except KeyError: + return importlib.import_module(modulename) def map_nested_module(self, module, child): return getattr(module, child) @@ -256,24 +257,25 @@ class ToPythonObjectMapper(Transformer): assert len(kwarg) == 1 (key, val), = kwarg.items() if key in kwargs: - # FIXME: This should probably be GrammarError raise ValueError(f"keyword argument '{key}' repeated") updated_kwargs = kwargs.copy() updated_kwargs[key] = val return updated_kwargs - def map_shortcut(self, name): - return self.shortcuts[name.value] + def map_tag_from_shortcut(self, name): + name = name[1:] # remove the starting "." + return self.shortcuts[name] def parse_tag(tag_text, shortcuts={}): """ Parses a :class:`Tag` from a provided dotted name. """ - tag_grammar = build_tag_grammar(shortcuts) - parser = Lark(tag_grammar, start="tag") - tag = ToPythonObjectMapper(shortcuts).transform(parser.parse(tag_text)) + import inspect + caller_globals = inspect.currentframe().f_back.f_globals + parser = Lark(TAG_GRAMMAR, start="tag") + tag = ToPythonObjectMapper(shortcuts, caller_globals).transform(parser.parse(tag_text)) return tag diff --git a/test/test_tags.py b/test/test_tags.py index cfb065a..dcd1b4d 100644 --- a/test/test_tags.py +++ b/test/test_tags.py @@ -1,5 +1,6 @@ import sys -import testlib # noqa +import pytest +import testlib_tags as testlib # noqa def test_parse_tags(): @@ -14,16 +15,26 @@ def test_parse_tags(): assert_same_as_python('testlib.ColorTag(color="blue")') assert_same_as_python("testlib.LocalAxisTag(axis=0)") - assert (parse_tag("testlib.FruitNameTag(mango)", + assert (parse_tag("testlib.FruitNameTag(.mango)", shortcuts={"mango": testlib.MangoTag(), "apple": testlib.AppleTag()}) == testlib.FruitNameTag(testlib.MangoTag())) - assert (parse_tag("l.0", + assert (parse_tag(".l.0", shortcuts={"l.0": testlib.LocalAxisTag(0)}) == testlib.LocalAxisTag(axis=0)) +def test_parse_tag_raises(): + from pytools.tag import parse_tag + + with pytest.raises(ValueError): + parse_tag('testlib.ColorTag(color="green",color="blue")') + + with pytest.raises(TypeError): + parse_tag('testlib.ColorTag(typoed_kwarg_name="typo",color="blue")') + + if __name__ == "__main__": if len(sys.argv) > 1: exec(sys.argv[1]) -- GitLab From 52599f81f2fbe4871f9e9529008b28f3a6b12090 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Mon, 4 Jan 2021 14:11:08 -0600 Subject: [PATCH 06/10] removes dep:Mako; makes 'lark' a soft dependency --- .github/workflows/ci.yml | 2 +- .gitlab-ci.yml | 2 +- setup.py | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab48ef5..50c3441 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,7 +74,7 @@ jobs: # AK, 2020-12-13 rm pytools/log.py - EXTRA_INSTALL="numpy" + EXTRA_INSTALL="numpy lark-parser" curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh . ./build-and-test-py-project.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6338ef8..0b024b5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,7 +7,7 @@ Pytest: # AK, 2020-12-13 rm pytools/log.py - export EXTRA_INSTALL="numpy" + export EXTRA_INSTALL="numpy lark-parser" curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh . ./build-and-test-py-project.sh tags: diff --git a/setup.py b/setup.py index 8f2a0ad..af0b0cc 100644 --- a/setup.py +++ b/setup.py @@ -42,10 +42,12 @@ setup(name="pytools", "appdirs>=1.4.0", "numpy>=1.6.0", "dataclasses>=0.7;python_version<='3.6'", - "Mako", - "lark-parser", ], + extras_require={ + "tag_parsing": ["lark-parser"], + }, + package_data={"pytools": ["py.typed"]}, author="Andreas Kloeckner", -- GitLab From db50fb9572e327669932ebb0968231efe2126bf6 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Mon, 4 Jan 2021 14:23:48 -0600 Subject: [PATCH 07/10] formatting - limit line columns length to 85 - install lark-parser for pylint,docs to resolve modules --- .github/workflows/ci.yml | 4 ++-- .gitlab-ci.yml | 4 ++-- pytools/tag.py | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50c3441..4a956c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: python-version: '3.x' - name: "Main Script" run: | - EXTRA_INSTALL="pymbolic" + EXTRA_INSTALL="pymbolic lark-parser" curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/prepare-and-run-pylint.sh . ./prepare-and-run-pylint.sh "$(basename $GITHUB_REPOSITORY)" test/test_*.py @@ -106,7 +106,7 @@ jobs: python-version: '3.x' - name: "Main Script" run: | - EXTRA_INSTALL="numpy" + EXTRA_INSTALL="numpy lark-parser" curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/ci-support.sh . ci-support.sh build_py_project_in_venv diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0b024b5..a062ffe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,7 +50,7 @@ Mypy: Pylint: script: - - EXTRA_INSTALL="pymbolic" + - EXTRA_INSTALL="pymbolic lark-parser" - py_version=3 - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/prepare-and-run-pylint.sh - . ./prepare-and-run-pylint.sh "$CI_PROJECT_NAME" test/test_*.py @@ -61,7 +61,7 @@ Pylint: Documentation: script: - - EXTRA_INSTALL="numpy" + - EXTRA_INSTALL="numpy lark-parser" - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-docs.sh - ". ./build-docs.sh" tags: diff --git a/pytools/tag.py b/pytools/tag.py index e4989f4..955cdeb 100644 --- a/pytools/tag.py +++ b/pytools/tag.py @@ -275,7 +275,8 @@ def parse_tag(tag_text, shortcuts={}): import inspect caller_globals = inspect.currentframe().f_back.f_globals parser = Lark(TAG_GRAMMAR, start="tag") - tag = ToPythonObjectMapper(shortcuts, caller_globals).transform(parser.parse(tag_text)) + tag = ToPythonObjectMapper(shortcuts, caller_globals).transform( + parser.parse(tag_text)) return tag -- GitLab From 6583c32b3c74745803243c0e4df0d2d96cf32a54 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Mon, 18 Jan 2021 00:28:35 -0600 Subject: [PATCH 08/10] moves grammar to tags.lark --- MANIFEST.in | 2 ++ pytools/tag.py | 41 +---------------------------------------- pytools/tags.lark | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 40 deletions(-) create mode 100644 pytools/tags.lark diff --git a/MANIFEST.in b/MANIFEST.in index c6965e3..d539d51 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,3 +3,5 @@ include LICENSE include doc/*rst include doc/Makefile include doc/conf.py + +include pytools/*.lark diff --git a/pytools/tag.py b/pytools/tag.py index 2530faa..1d93097 100644 --- a/pytools/tag.py +++ b/pytools/tag.py @@ -265,45 +265,6 @@ class Taggable: # {{{ parse -TAG_GRAMMAR = """ - tag: tag_class "(" params ")" -> map_tag_from_python_class - | SHORTCUT -> map_tag_from_shortcut - - params: -> map_empty_args_params - | args -> map_args_only_params - | kwargs -> map_kwargs_only_params - | args "," kwargs -> map_args_kwargs_params - - ?kwargs: kwarg - | kwargs "," kwarg -> map_kwargs - - args: arg -> map_singleton_args - | args "," arg -> map_args - - kwarg: name "=" arg -> map_kwarg - - ?arg: tag - | INT -> map_int - | ESCAPED_STRING -> map_string - - tag_class: module "." name -> map_tag_class - - module: name -> map_top_level_module - | module "." name -> map_nested_module - - name: CNAME -> map_name - SHORTCUT: "." ("_"|LETTER) ("_"|LETTER|DIGIT|".")* - - %import common.INT - %import common.ESCAPED_STRING - %import common.DIGIT - %import common.LETTER - %import common.CNAME - %import common.WS - %ignore WS -""" - - class CallParams: """ Intermediate data structure for :class:`ToPythonObjectMapper`. @@ -402,7 +363,7 @@ def parse_tag(tag_text, shortcuts={}): """ import inspect caller_globals = inspect.currentframe().f_back.f_globals - parser = Lark(TAG_GRAMMAR, start="tag") + parser = Lark.open("tags.lark", rel_to=__file__, parser="lalr", start="tag") tag = ToPythonObjectMapper(shortcuts, caller_globals).transform( parser.parse(tag_text)) diff --git a/pytools/tags.lark b/pytools/tags.lark new file mode 100644 index 0000000..f6ee248 --- /dev/null +++ b/pytools/tags.lark @@ -0,0 +1,35 @@ +tag: tag_class "(" params ")" -> map_tag_from_python_class + | SHORTCUT -> map_tag_from_shortcut + +params: -> map_empty_args_params + | args -> map_args_only_params + | kwargs -> map_kwargs_only_params + | args "," kwargs -> map_args_kwargs_params + +?kwargs: kwarg + | kwargs "," kwarg -> map_kwargs + +args: arg -> map_singleton_args + | args "," arg -> map_args + +kwarg: name "=" arg -> map_kwarg + +?arg: tag + | INT -> map_int + | ESCAPED_STRING -> map_string + +tag_class: module "." name -> map_tag_class + +module: name -> map_top_level_module + | module "." name -> map_nested_module + +name: CNAME -> map_name +SHORTCUT: "." ("_"|LETTER) ("_"|LETTER|DIGIT|".")* + +%import common.INT +%import common.ESCAPED_STRING +%import common.DIGIT +%import common.LETTER +%import common.CNAME +%import common.WS +%ignore WS -- GitLab From ff625d904bf91752d6c0e5dc1b4679e652c150a4 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Mon, 18 Jan 2021 00:43:10 -0600 Subject: [PATCH 09/10] memoize parser construction; remove pytools.tag's hard dep on lark --- pytools/tag.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/pytools/tag.py b/pytools/tag.py index 1d93097..2a73bfb 100644 --- a/pytools/tag.py +++ b/pytools/tag.py @@ -2,7 +2,6 @@ from dataclasses import dataclass from typing import Tuple, Any, FrozenSet, Union, Iterable, TypeVar import importlib -from lark import Lark, Transformer from pytools import memoize __copyright__ = """ @@ -274,7 +273,7 @@ class CallParams: self.kwargs = kwargs -class ToPythonObjectMapper(Transformer): +class ToPythonObjectMapper: """ Map a parsed tree to pythonic objects. """ @@ -357,14 +356,27 @@ class ToPythonObjectMapper(Transformer): return self.shortcuts[name] +@memoize +def construct_parser(): + from lark import Lark + return Lark.open("tags.lark", rel_to=__file__, parser="lalr", start="tag", + cache=True) + + def parse_tag(tag_text, shortcuts={}): """ Parses a :class:`Tag` from a provided dotted name. """ import inspect + from lark import Transformer + + class ToPythonObjectMapperMixin(ToPythonObjectMapper, Transformer): + pass + + parser = construct_parser() + caller_globals = inspect.currentframe().f_back.f_globals - parser = Lark.open("tags.lark", rel_to=__file__, parser="lalr", start="tag") - tag = ToPythonObjectMapper(shortcuts, caller_globals).transform( + tag = ToPythonObjectMapperMixin(shortcuts, caller_globals).transform( parser.parse(tag_text)) return tag -- GitLab From 6fb2eb3404e09d3f7c5950df20958df1f0a0044b Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Mon, 18 Jan 2021 00:57:17 -0600 Subject: [PATCH 10/10] moves the args flattening inside the mixin --- pytools/tag.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/pytools/tag.py b/pytools/tag.py index 2a73bfb..079fb8a 100644 --- a/pytools/tag.py +++ b/pytools/tag.py @@ -282,17 +282,6 @@ class ToPythonObjectMapper: self.shortcuts = shortcuts self.caller_globals = caller_globals - def _call_userfunc(self, tree, new_children=None): - # Assumes tree is already transformed - children = new_children if new_children is not None else tree.children - try: - f = getattr(self, tree.data) - except AttributeError: - return self.__default__(tree.data, children, tree.meta) - else: - # flatten the args - return f(*children) - def map_tag_from_python_class(self, cls, params): try: return cls(*params.args, **params.kwargs) @@ -371,7 +360,19 @@ def parse_tag(tag_text, shortcuts={}): from lark import Transformer class ToPythonObjectMapperMixin(ToPythonObjectMapper, Transformer): - pass + def _call_userfunc(self, tree, new_children=None): + """ + Flattens the arguments before feeding to the mapper methods. + """ + # Assumes tree is already transformed + children = new_children if new_children is not None else tree.children + try: + f = getattr(self, tree.data) + except AttributeError: + return self.__default__(tree.data, children, tree.meta) + else: + # flatten the args + return f(*children) parser = construct_parser() -- GitLab