From 0db41b94fc0c3ad436d1ec890ec7ed1ebab497c9 Mon Sep 17 00:00:00 2001 From: Saugat Pachhai Date: Wed, 6 Jan 2021 21:40:19 +0545 Subject: [PATCH] parametrization: do not load parser on import (#5217) A great benefit to this is that, if the dvc.yaml file is never interpolated, the parser is never built, which reduces the gap even further between 1.0 and 2.0 files --- dvc/parsing/interpolate.py | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/dvc/parsing/interpolate.py b/dvc/parsing/interpolate.py index f186209f2..9984ebec6 100644 --- a/dvc/parsing/interpolate.py +++ b/dvc/parsing/interpolate.py @@ -3,14 +3,7 @@ import typing from collections.abc import Mapping from functools import singledispatch -from funcy import rpartial -from pyparsing import ( - CharsNotIn, - ParseException, - ParserElement, - Suppress, - ZeroOrMore, -) +from funcy import memoize, rpartial from dvc.exceptions import DvcException from dvc.utils import colorize @@ -18,6 +11,8 @@ from dvc.utils import colorize if typing.TYPE_CHECKING: from typing import List, Match + from pyparsing import ParseException + from .context import Context BRACE_OPEN = "${" @@ -36,14 +31,20 @@ KEYCRE = re.compile( re.VERBOSE, ) -ParserElement.enablePackrat() +@memoize +def get_parser(): + from pyparsing import CharsNotIn, ParserElement, Suppress, ZeroOrMore -word = CharsNotIn(f"{PERIOD}{LBRACK}{RBRACK}") -idx = Suppress(LBRACK) + word + Suppress(RBRACK) -attr = Suppress(PERIOD) + word -parser = word + ZeroOrMore(attr ^ idx) -parser.setParseAction(PERIOD.join) + ParserElement.enablePackrat() + + word = CharsNotIn(f"{PERIOD}{LBRACK}{RBRACK}") + idx = Suppress(LBRACK) + word + Suppress(RBRACK) + attr = Suppress(PERIOD) + word + parser = word + ZeroOrMore(attr ^ idx) + parser.setParseAction(PERIOD.join) + + return parser class ParseError(DvcException): @@ -80,7 +81,9 @@ def _(obj: bool): return "true" if obj else "false" -def _format_exc_msg(exc: ParseException): +def _format_exc_msg(exc: "ParseException"): + from pyparsing import ParseException + exc.loc += 2 # 2 because we append `${` at the start of expr below expr = exc.pstr @@ -126,8 +129,10 @@ def check_expression(s: str): def parse_expr(s: str): + from pyparsing import ParseException + try: - result = parser.parseString(s, parseAll=True) + result = get_parser().parseString(s, parseAll=True) except ParseException as exc: format_and_raise_parse_error(exc)