bumpver/src/pycalver/parse.py

86 lines
2.5 KiB
Python
Raw Normal View History

2018-09-02 21:48:12 +02:00
# This file is part of the pycalver project
2020-09-06 20:20:36 +00:00
# https://github.com/mbarkhau/pycalver
2018-09-02 21:48:12 +02:00
#
2020-09-06 20:20:36 +00:00
# Copyright (c) 2018-2020 Manuel Barkhau (mbarkhau@gmail.com) - MIT License
2018-09-02 21:48:12 +02:00
# SPDX-License-Identifier: MIT
2018-12-09 14:49:13 +01:00
"""Parse PyCalVer strings from files."""
2018-09-02 21:48:12 +02:00
import typing as typ
2020-09-19 22:35:48 +00:00
from .patterns import Pattern
2018-09-03 09:19:27 +02:00
2020-10-02 20:52:54 +00:00
LineNo = int
Start = int
End = int
class LineSpan(typ.NamedTuple):
lineno: LineNo
start : Start
end : End
LineSpans = typ.List[LineSpan]
def _has_overlap(needle: LineSpan, haystack: LineSpans) -> bool:
for span in haystack:
# assume needle is in the center
has_overlap = (
span.lineno == needle.lineno
# needle starts before (or at) span end
and needle.start <= span.end
# needle ends after (or at) span start
and needle.end >= span.start
)
if has_overlap:
return True
return False
2018-09-02 21:48:12 +02:00
class PatternMatch(typ.NamedTuple):
2018-11-15 22:16:16 +01:00
"""Container to mark a version string in a file."""
2018-09-02 21:48:12 +02:00
2020-10-02 20:52:54 +00:00
lineno : LineNo # zero based
2018-11-06 21:45:33 +01:00
line : str
2020-09-19 22:35:48 +00:00
pattern: Pattern
2020-10-02 20:52:54 +00:00
span : typ.Tuple[Start, End]
2018-11-06 21:45:33 +01:00
match : str
2018-09-02 21:48:12 +02:00
PatternMatches = typ.Iterable[PatternMatch]
2018-12-20 15:28:11 +01:00
2020-09-19 22:35:48 +00:00
def _iter_for_pattern(lines: typ.List[str], pattern: Pattern) -> PatternMatches:
for lineno, line in enumerate(lines):
2020-09-08 20:59:52 +00:00
match = pattern.regexp.search(line)
if match:
yield PatternMatch(lineno, line, pattern, match.span(), match.group(0))
2020-09-19 22:35:48 +00:00
def iter_matches(lines: typ.List[str], patterns: typ.List[Pattern]) -> PatternMatches:
"""Iterate over all matches of any pattern on any line.
2020-09-19 22:35:48 +00:00
>>> from . import v1patterns
>>> lines = ["__version__ = 'v201712.0002-alpha'"]
2020-09-19 22:35:48 +00:00
>>> version_pattern = "{pycalver}"
>>> raw_patterns = ["{pycalver}", "{pep440_pycalver}"]
>>> patterns = [v1patterns.compile_pattern(version_pattern, p) for p in raw_patterns]
>>> matches = list(iter_matches(lines, patterns))
>>> assert matches[0] == PatternMatch(
... lineno = 0,
... line = "__version__ = 'v201712.0002-alpha'",
2020-09-19 22:35:48 +00:00
... pattern= v1patterns.compile_pattern(version_pattern),
... span = (15, 33),
... match = "v201712.0002-alpha",
... )
"""
2020-10-02 20:52:54 +00:00
matched_spans: LineSpans = []
for pattern in patterns:
for match in _iter_for_pattern(lines, pattern):
2020-10-02 20:52:54 +00:00
needle_span = LineSpan(match.lineno, *match.span)
if not _has_overlap(needle_span, matched_spans):
yield match
matched_spans.append(needle_span)