Skip to content

Commit

Permalink
Refactor select_lines
Browse files Browse the repository at this point in the history
Reworks select_lines into a new cached helper function (_split_line_selector) that returns the parsed lines and selectors eliminating repeat parsing of the same file.
  • Loading branch information
kenodegard committed Mar 15, 2024
1 parent c89995d commit b57721a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 25 deletions.
76 changes: 51 additions & 25 deletions conda_build/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
)

if TYPE_CHECKING:
from typing import Literal
from typing import Any, Literal

try:
import yaml
Expand Down Expand Up @@ -267,38 +267,64 @@ def eval_selector(selector_string, namespace, variants_in_place):
return eval_selector(next_string, namespace, variants_in_place)


def select_lines(data, namespace, variants_in_place):
lines = []

for i, line in enumerate(data.splitlines()):
@lru_cache(maxsize=None)
def _split_line_selector(text: str) -> tuple[tuple[str | None, str], ...]:
lines: list[tuple[str | None, str]] = []
for line in text.splitlines():
line = line.rstrip()

# skip comment lines, include a blank line as a placeholder
if line.lstrip().startswith("#"):
lines.append((None, ""))
continue

# include blank lines
if not line:
lines.append((None, ""))
continue

# user may have quoted entire line to make YAML happy
trailing_quote = ""
if line and line[-1] in ("'", '"'):
trailing_quote = line[-1]

if line.lstrip().startswith("#"):
# Don't bother with comment only lines
continue
m = sel_pat.match(line)
if m:
cond = m.group(3)
try:
if eval_selector(cond, namespace, variants_in_place):
lines.append(m.group(1) + trailing_quote)
except Exception as e:
sys.exit(
"""\
Error: Invalid selector in meta.yaml line %d:
offending line:
%s
exception:
%s
"""
% (i + 1, line, str(e))
)
match = sel_pat.match(line)
if match and (selector := match.group(3)):
# found a selector
lines.append((selector, (match.group(1) + trailing_quote).rstrip()))
else:
# no selector found
lines.append((None, line))
return tuple(lines)


def select_lines(text: str, namespace: dict[str, Any], variants_in_place: bool) -> str:
lines = []
selector_cache: dict[str, bool] = {}
for i, (selector, line) in enumerate(_split_line_selector(text)):
if not selector:
# no selector? include line as is
lines.append(line)
else:
# include lines with a selector that evaluates to True
try:
if selector_cache[selector]:
lines.append(line)
except KeyError:
# KeyError: cache miss
try:
value = bool(eval_selector(selector, namespace, variants_in_place))
selector_cache[selector] = value
if value:
lines.append(line)
except Exception as e:
sys.exit(
f"Error: Invalid selector in meta.yaml line {i + 1}:\n"
f"offending line:\n"
f"{line}\n"
f"exception:\n"
f"{e.__class__.__name__}: {e}\n"
)
return "\n".join(lines) + "\n"


Expand Down
2 changes: 2 additions & 0 deletions tests/test_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def test_select_lines():
" ' test '",
' " test "',
"",
"",
"test",
" 'quoted'",
' "quoted"',
Expand All @@ -108,6 +109,7 @@ def test_select_lines():
" ' test '",
' " test "',
"",
"",
"test {{ JINJA_VAR[:2] }}",
"", # trailing newline
)
Expand Down

0 comments on commit b57721a

Please sign in to comment.