Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pyleri for openSUSE:Factory checked in at 2026-04-22 17:20:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pyleri (Old) and /work/SRC/openSUSE:Factory/.python-pyleri.new.11940 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyleri" Wed Apr 22 17:20:56 2026 rev:4 rq:1348801 version:1.5.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pyleri/python-pyleri.changes 2024-04-07 22:13:20.674727600 +0200 +++ /work/SRC/openSUSE:Factory/.python-pyleri.new.11940/python-pyleri.changes 2026-04-22 17:20:58.488954218 +0200 @@ -1,0 +2,8 @@ +Mon Apr 20 14:33:55 UTC 2026 - John Paul Adrian Glaubitz <[email protected]> + +- Update to 1.5.0 + * Added Typing. + * Dropped support for Python 3.7 and 3.8. +- Update upstream URL in Source field + +------------------------------------------------------------------- Old: ---- pyleri-1.4.3.tar.gz New: ---- pyleri-1.5.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pyleri.spec ++++++ --- /var/tmp/diff_new_pack.pXB575/_old 2026-04-22 17:20:59.224984616 +0200 +++ /var/tmp/diff_new_pack.pXB575/_new 2026-04-22 17:20:59.228984781 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-pyleri # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # Copyright (c) 2021, Martin Hauke <[email protected]> # # All modifications and additions to the file contributed by third parties @@ -19,12 +19,12 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-pyleri -Version: 1.4.3 +Version: 1.5.0 Release: 0 Summary: Python Left-Right Parser License: MIT URL: https://github.com/transceptor-technology/pyleri -Source: https://github.com/transceptor-technology/pyleri/archive/refs/tags/%{version}.tar.gz#/pyleri-%{version}.tar.gz +Source: https://github.com/transceptor-technology/pyleri/archive/refs/tags/v%{version}.tar.gz#/pyleri-%{version}.tar.gz BuildRequires: %{python_module pip} BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} ++++++ pyleri-1.4.3.tar.gz -> pyleri-1.5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/.github/workflows/ci.yml new/pyleri-1.5.0/.github/workflows/ci.yml --- old/pyleri-1.4.3/.github/workflows/ci.yml 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/.github/workflows/ci.yml 2025-11-12 21:19:22.000000000 +0100 @@ -12,22 +12,25 @@ runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pytest pycodestyle + pip install pytest pycodestyle pyright if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Run tests with pytest run: | pytest - name: Lint with PyCodeStyle run: | - find . -name \*.py -exec pycodestyle {} + \ No newline at end of file + find . -name \*.py -exec pycodestyle {} + + - name: Check with PyRight + run: | + pyright diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/__init__.py new/pyleri-1.5.0/pyleri/__init__.py --- old/pyleri-1.4.3/pyleri/__init__.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/__init__.py 2025-11-12 21:19:22.000000000 +0100 @@ -41,4 +41,4 @@ __author__ = 'Jeroen van der Heijden' __maintainer__ = 'Jeroen van der Heijden' __email__ = '[email protected]' -__version__ = '1.4.3' +__version__ = '1.5.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/choice.py new/pyleri-1.5.0/pyleri/choice.py --- old/pyleri-1.4.3/pyleri/choice.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/choice.py 2025-11-12 21:19:22.000000000 +0100 @@ -6,6 +6,7 @@ :copyright: 2021, Jeroen van der Heijden <[email protected]> """ +import typing as t from .elements import Element, NamedElement, c_export, go_export, java_export @@ -15,7 +16,7 @@ def __init__( self, - *elements: Element, + *elements: t.Union[Element, str], most_greedy: bool = True): self._elements = self._validate_elements(elements) self._get_node_result = \ @@ -43,6 +44,7 @@ return mg_is_valid, mg_pos def _stop_at_first_match(self, root, tree, rule, s, node): + is_valid, pos = True, node.start for elem in self._elements: children = [] is_valid, pos = root._walk(elem, node.start, children, rule, True) @@ -66,10 +68,8 @@ new_indent, classes)) for elem in self._elements]) return 'Choice(\n{val},\n{indent}most_greedy={mg})'.format( - mg='{mg}'.format( - indent=py_indent * (indent + 1), - mg=('False', 'True')[ - self._get_node_result == self._most_greedy_result]), + mg=('False', 'True')[ + self._get_node_result == self._most_greedy_result], val=value, indent=py_indent * new_indent) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/elements.py new/pyleri-1.5.0/pyleri/elements.py --- old/pyleri-1.4.3/pyleri/elements.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/elements.py 2025-11-12 21:19:22.000000000 +0100 @@ -5,6 +5,10 @@ :copyright: 2021, Jeroen van der Heijden <[email protected]> """ import typing as t +from abc import abstractmethod +if t.TYPE_CHECKING: + from .grammar import Grammar + from .node import Node def camel_case(s: str) -> str: @@ -17,10 +21,17 @@ return ''.join(p[0].upper() + p[1:] for p in s.split('_') if p) -_cref = None +_cref: t.Optional['Element'] = None +T = t.TypeVar('T', bound='Element') -def c_export(func): +def c_export(func: t.Callable[ + [T, str, int, t.Set[str], str], + str + ]) -> t.Callable[ + [T, str, int, t.Set[str], t.Optional['Element']], + str + ]: def wrapper(self, c_indent, indent, enums, ref=None): global _cref @@ -35,8 +46,13 @@ return wrapper -def go_export(func): - +def go_export(func: t.Callable[ + [T, str, int, t.Set[str], str], + str + ]) -> t.Callable[ + [T, str, int, t.Set[str]], + str + ]: def wrapper(self, go_indent, indent, enums): gid = getattr(self, 'name', getattr(self, '_name', 'NoGid')) if gid != 'NoGid': @@ -47,12 +63,19 @@ return wrapper -def java_export(func): +def java_export(func: t.Callable[ + [T, str, int, t.Set[str], t.Set[str], t.Optional[str]], + str + ]) -> t.Callable[ + [T, str, int, t.Set[str], t.Set[str]], + str + ]: def wrapper(self, java_indent, indent, enums, classes): classes.add('jleri.{}'.format(self.__class__.__name__.lstrip('_'))) gid = getattr(self, 'name', getattr(self, '_name', None)) if gid is not None: + assert isinstance(gid, str) gid = gid.upper() enums.add(gid) return func(self, java_indent, indent, enums, classes, gid) @@ -63,8 +86,8 @@ class Element: __slots__ = tuple() - - name: t.Optional[str] + name: str + _name: str @staticmethod def _validate_element(element: t.Union[str, 'Element']) -> 'Element': @@ -77,9 +100,35 @@ 'but received type: {}'.format(type(element))) @classmethod - def _validate_elements(cls, elements) -> t.List['Element']: + def _validate_elements(cls, + elements: t.Tuple[t.Union[str, 'Element'], ...] + ) -> t.List['Element']: return [cls._validate_element(elem) for elem in elements] + @abstractmethod + def _get_node_result(self, + root: 'Grammar', + tree: t.List['Node'], + rule: 'Element', + s: str, + node: 'Node') -> t.Tuple[bool, int]: + pass + + def _export_py(self, *args, **kwargs) -> str: + return "must_be_called_on_named_element" + + def _export_js(self, *args, **kwargs) -> str: + return "must_be_called_on_named_element" + + def _export_c(self, *args, **kwargs) -> str: + return "must_be_called_on_named_element" + + def _export_go(self, *args, **kwargs) -> str: + return "must_be_called_on_named_element" + + def _export_java(self, *args, **kwargs) -> str: + return "must_be_called_on_named_element" + class NamedElement(Element): @@ -87,67 +136,97 @@ def _export_js( self, - js_indent: int, + js_indent: str, indent: int, - classes, - cname) -> str: + classes: t.Set[str], + cname: t.Optional[str]) -> str: classes.add(self.__class__.__name__.lstrip('_')) if hasattr(self, 'name') and indent > 0: return '{}.{}'.format(cname, self.name) if cname else self.name indent = 0 if indent < 0 else 1 if indent == 0 else indent return self._run_export_js(js_indent, indent, classes, cname) - def _export_js_elements(self, js_indent, indent, classes, cname): + def _export_js_elements( + self, + js_indent: str, + indent: int, + classes: t.Set[str], + cname: t.Optional[str]) -> str: new_indent = indent + 1 value = ',\n'.join(['{indent}{elem}'.format( indent=js_indent * new_indent, elem=elem._export_js( js_indent, - new_indent, classes, cname)) for elem in self._elements]) + new_indent, classes, cname)) + for elem in self._elements]) # type: ignore return '{class_name}(\n{value}\n{indent})'.format( class_name=self.__class__.__name__.lstrip('_'), value=value, indent=js_indent * indent) - def _run_export_js(self, js_indent, indent, classes, cname): + def _run_export_js(self, + js_indent: str, + indent: int, + classes: t.Set[str], + cname: t.Optional[str]) -> str: return 'not_implemented' - def _export_py(self, py_indent, indent, classes): + def _export_py(self, + py_indent: str, + indent: int, + classes: t.Set[str]) -> str: classes.add(self.__class__.__name__.lstrip('_')) if hasattr(self, 'name') and indent: return self.name return self._run_export_py(py_indent, indent or 1, classes) - def _export_py_elements(self, py_indent, indent, classes): + def _export_py_elements(self, + py_indent: str, + indent: int, + classes: t.Set[str]) -> str: new_indent = indent + 1 value = ',\n'.join(['{indent}{elem}'.format( indent=py_indent * new_indent, elem=elem._export_py( py_indent, - new_indent, classes)) for elem in self._elements]) + new_indent, + classes)) + for elem in self._elements]) # type: ignore return '{class_name}(\n{value}\n{indent})'.format( class_name=self.__class__.__name__.lstrip('_'), value=value, indent=py_indent * indent) - def _run_export_py(self, py_indent, indent, classes): + def _run_export_py(self, + py_indent: str, + indent: int, + classes: t.Set[str]) -> str: return 'not_implemented' @c_export - def _export_c(self, c_indent, indent, enums, gid): + def _export_c(self, + c_indent: str, + indent: int, + enums: t.Set[str], + gid: str) -> str: if hasattr(self, 'name') and indent: return self.name - return self._run_export_c(c_indent, indent or 1, enums) + return self._run_export_c(c_indent, indent or 1, enums) # type: ignore @c_export - def _export_c_elements(self, c_indent, indent, enums, gid): + def _export_c_elements(self, + c_indent: str, + indent: int, + enums: t.Set[str], + gid: str) -> str: new_indent = indent + 1 value = ',\n'.join(['{indent}{elem}'.format( indent=c_indent * new_indent, elem=elem._export_c( c_indent, new_indent, - enums)) for elem in self._elements]) + enums)) + for elem in self._elements]) # type: ignore return \ 'cleri_{class_name}(\n{gid},\n{num},\n{value}\n{indent})'.format( class_name=self.__class__.__name__.lstrip('_').lower(), @@ -156,28 +235,41 @@ gid=gid), num='{indent}{num}'.format( indent=c_indent * (indent + 1), - num=len(self._elements)), + num=len(self._elements)), # type: ignore value=value, indent=c_indent * indent) - def _run_export_c(self, c_indent, indent, enums): + @c_export + def _run_export_c(self, + c_indent: str, + indent: int, + enums: t.Set[str], + gid: str) -> str: return 'not_implemented' @go_export - def _export_go(self, go_indent, indent, enums, gid): + def _export_go(self, + go_indent: str, + indent: int, + enums: t.Set[str], + gid: str) -> str: if hasattr(self, 'name') and indent: return camel_case(self.name) return self._run_export_go(go_indent, indent or 1, enums) @go_export - def _export_go_elements(self, go_indent, indent, enums, gid): + def _export_go_elements(self, + go_indent: str, + indent: int, + enums: t.Set[str], + gid: str) -> str: new_indent = indent + 1 value = ',\n'.join(['{indent}{elem}'.format( indent=go_indent * new_indent, elem=elem._export_go( go_indent, new_indent, - enums)) for elem in self._elements]) + enums)) for elem in self._elements]) # type: ignore return '{class_name}(\n{gid},\n{value},\n{indent})'.format( class_name='goleri.New' + self.__class__.__name__.lstrip('_'), gid='{indent}{gid}'.format( @@ -186,19 +278,33 @@ value=value, indent=go_indent * indent) - def _run_export_go(self, go_indent, indent, enums): + @go_export + def _run_export_go(self, + go_indent: str, + indent: int, + enums: t.Set[str], + gid: str) -> str: return 'not_implemented' @java_export - def _export_java(self, java_indent, indent, enums, classes, gid): + def _export_java(self, + java_indent: str, + indent: int, + enums: t.Set[str], + classes: t.Set[str], + gid: t.Optional[str]) -> str: if hasattr(self, 'name') and indent > 0: return self.name.upper() return self._run_export_java( java_indent, abs(indent) or 1, enums, classes) @java_export - def _export_java_elements( - self, java_indent, indent, enums, classes, gid): + def _export_java_elements(self, + java_indent: str, + indent: int, + enums: t.Set[str], + classes: t.Set[str], + gid: t.Optional[str]) -> str: new_indent = indent + 1 value = ',\n'.join(['{indent}{elem}'.format( indent=java_indent * new_indent, @@ -206,7 +312,7 @@ java_indent, new_indent, enums, - classes)) for elem in self._elements]) + classes)) for elem in self._elements]) # type: ignore return '{class_name}({gid}\n{value}\n{indent})'.format( class_name='new ' + self.__class__.__name__.lstrip('_'), gid='' if gid is None else '\n{indent}Ids.{gid},'.format( @@ -215,7 +321,13 @@ value=value, indent=java_indent * indent) - def _run_export_java(self, java_indent, indent, enums, classes): + @java_export + def _run_export_java(self, + java_indent: str, + indent: int, + enums: t.Set[str], + classes: t.Set[str], + gid: t.Optional[str]): return 'not_implemented' # Added this import to the bottom to prevent circular import cycle. @@ -224,4 +336,4 @@ # is sub-classed from the 'NamedElement' class. -from .token import Token # nopep8 +from .token import Token # nopep8 # noqa: E402 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/endofstatement.py new/pyleri-1.5.0/pyleri/endofstatement.py --- old/pyleri-1.4.3/pyleri/endofstatement.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/endofstatement.py 2025-11-12 21:19:22.000000000 +0100 @@ -5,9 +5,10 @@ :copyright: 2021, Jeroen van der Heijden <[email protected]> """ +from .elements import Element -class _EndOfStatement: +class _EndOfStatement(Element): def __repr__(self): return 'end_of_statement' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/grammar.py new/pyleri-1.5.0/pyleri/grammar.py --- old/pyleri-1.4.3/pyleri/grammar.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/grammar.py 2025-11-12 21:19:22.000000000 +0100 @@ -14,6 +14,7 @@ import re import time +import typing as t from .node import Node from .expecting import Expecting from .endofstatement import end_of_statement @@ -36,9 +37,9 @@ class _KeepOrder(dict): def __init__(self, *args): - self._order = [] - self._refs = {} - self._re_keywords = _RE_KEYWORDS + self._order: t.List[str] = [] + self._refs: t.Dict[str, Ref] = {} + self._re_keywords: re.Pattern = _RE_KEYWORDS self._has_keywords = False super().__setitem__('_order', self._order) super().__setitem__('_refs', self._refs) @@ -55,7 +56,7 @@ for elem in element._elements: self._check_keywords(elem) - def __setitem__(self, key, value): + def __setitem__(self, key: str, value: t.Any): if key not in self: for k in self._order: if k.upper() == key.upper(): @@ -78,6 +79,7 @@ raise ReKeywordsChangedError( 'RE_KEYWORDS must be set on top of Grammar before ' 'keywords are set.') + assert isinstance(value, re.Pattern) self._re_keywords = value if isinstance(value, NamedElement): @@ -92,24 +94,24 @@ super().__setitem__(key, value) -def _used_checker(elem, used): +def _used_checker(elem: Element, used: t.Set[str]): if hasattr(elem, 'name') and not isinstance(elem, Ref): if elem.name in used: return used.add(elem.name) if hasattr(elem, '_element'): - _used_checker(elem._element, used) + _used_checker(elem._element, used) # type: ignore if hasattr(elem, '_delimiter'): - _used_checker(elem._delimiter, used) + _used_checker(elem._delimiter, used) # type: ignore elif hasattr(elem, '_elements'): - for el in elem._elements: + for el in elem._elements: # type: ignore _used_checker(el, used) class _OrderedClass(type): @classmethod - def __prepare__(mcs, name, bases): + def __prepare__(mcs, name, bases, **kwds): return _KeepOrder() def __new__(mcs, name, bases, attrs, **kwargs): @@ -122,7 +124,7 @@ raise MissingStartError( 'Grammar is missing the required START element entry point.') if bases: - used = set() + used: t.Set[str] = set() _used_checker(attrs['START'], used) elems = { elem for elem in attrs['_order'] @@ -137,7 +139,8 @@ class Grammar(metaclass=_OrderedClass): - __slots__ = ('_element', '_string', '_expecting', '_cached_kw_match') + _order: t.List[str] + _refs: t.Dict[str, Ref] RE_KEYWORDS = _RE_KEYWORDS @@ -333,9 +336,9 @@ Note: usually you should only initialize a Grammar instance once in a project. """ - self._element = self.START - self._string = None - self._expecting = None + self._element: Element = self.START # type: ignore + self._string = '' + self._expecting = Expecting() self._cached_kw_match = {} def export_js( @@ -453,12 +456,12 @@ self, target=C_TARGET, c_indent=C_INDENTATION, - headerf=None) -> str: + headerf=None) -> t.Tuple[str, str]: """Export the grammar to a c (source and header) file which can be used with the libcleri module.""" language = [] indent = 0 - enums = set() + enums: t.Set[str] = set() for name in self._order: elem = getattr(self, name, None) if not isinstance(elem, Element): @@ -487,7 +490,7 @@ if not pattern.startswith('^'): pattern = '^' + pattern - enums = ',\n'.join([ + enum_str = ',\n'.join([ '{}{}'.format(c_indent, gid) for gid in sorted(enums)]) + ',' @@ -515,7 +518,7 @@ '%Y-%m-%d %H:%M:%S', time.localtime()), language='\n'.join(language), - enums=enums)) + enums=enum_str)) def export_go( self, @@ -633,7 +636,7 @@ enums=enum_str, public='public ' if is_public else '') - def parse(self, string) -> Result: + def parse(self, string: str) -> Result: """Parse some string to the Grammar. Returns a nodeResult with the following attributes: @@ -646,11 +649,12 @@ - tree: the parse_tree containing a structured result for the given string. """ + self._s = '' self._string = string self._expecting = Expecting() self._cached_kw_match.clear() self._len_string = len(string) - self._pos = None + self._pos = -1 tree = Node(self._element, string, 0, self._len_string) node_res = Result(*self._walk( self._element, @@ -686,7 +690,12 @@ node.end = pos tree.append(node) - def _walk(self, element, pos, tree, rule, is_required): + def _walk(self, + element: Element, + pos: int, + tree: t.List[Node], + rule: Element, + is_required: bool) -> t.Tuple[bool, int]: if self._pos != pos: self._s = self._string[pos:].lstrip() self._pos = self._len_string - len(self._s) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/keyword.py new/pyleri-1.5.0/pyleri/keyword.py --- old/pyleri-1.4.3/pyleri/keyword.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/keyword.py 2025-11-12 21:19:22.000000000 +0100 @@ -6,6 +6,7 @@ :copyright: 2021, Jeroen van der Heijden <[email protected]> """ +import typing as t from .elements import NamedElement, c_export, go_export, java_export @@ -36,11 +37,11 @@ re_match = \ root._cached_kw_match[node.start] = \ root.RE_KEYWORDS.match(s) - is_valid = \ - re_match and \ + is_valid = bool( + re_match and (re_match.group(0) == self._keyword or (self._ign_case and - re_match.group(0).lower() == self._keyword.lower())) + re_match.group(0).lower() == self._keyword.lower()))) if is_valid: root._append_tree(tree, node, node.start + len(self._keyword)) else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/list.py new/pyleri-1.5.0/pyleri/list.py --- old/pyleri-1.4.3/pyleri/list.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/list.py 2025-11-12 21:19:22.000000000 +0100 @@ -21,7 +21,7 @@ def __init__( self, - element: Element, + element: t.Union[str, Element], delimiter: t.Union[str, Element] = ',', mi: int = 0, ma: t.Optional[int] = None, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/node.py new/pyleri-1.5.0/pyleri/node.py --- old/pyleri-1.4.3/pyleri/node.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/node.py 2025-11-12 21:19:22.000000000 +0100 @@ -19,7 +19,7 @@ end: t.Optional[int] = None): self.element = element self.start = start - self.end = end + self.end = end or 0 self._string = string self.children: t.List['Node'] = [] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/optional.py new/pyleri-1.5.0/pyleri/optional.py --- old/pyleri-1.4.3/pyleri/optional.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/optional.py 2025-11-12 21:19:22.000000000 +0100 @@ -2,21 +2,22 @@ :copyright: 2021, Jeroen van der Heijden <[email protected]> """ -from .elements import NamedElement, c_export, go_export, java_export +import typing as t +from .elements import Element, NamedElement, c_export, go_export, java_export class Optional(NamedElement): __slots__ = ('_element',) - def __init__(self, element): + def __init__(self, element: t.Union[str, Element]): self._element = self._validate_element(element) @property def _elements(self): yield self._element - def _get_node_result(self, root, tree, rule, _s, node): + def _get_node_result(self, root, tree, rule, s, node): is_valid, pos = root._walk( self._element, node.start, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/prio.py new/pyleri-1.5.0/pyleri/prio.py --- old/pyleri-1.4.3/pyleri/prio.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/prio.py 2025-11-12 21:19:22.000000000 +0100 @@ -17,6 +17,7 @@ self._elements = self._validate_elements(elements) def _get_node_result(self, root, tree, rule, s, node): + assert isinstance(rule, Rule) if rule._depth == _Prio.MAX_RECURSION: raise MaxRecursionError( 'Max recursion depth of {} is reached' @@ -47,8 +48,8 @@ def _run_export_py(self, py_indent, indent, classes): return self._export_py_elements(py_indent, indent, classes) - def _run_export_c(self, c_indent, indent, enums): - return self._export_c_elements(c_indent, indent, enums) + def _run_export_c(self, c_indent, indent, enums): # type: ignore + return self._export_c_elements(c_indent, indent, enums) # type: ignore def _run_export_go(self, go_indent, indent, enums): return self._export_go_elements(go_indent, indent, enums) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/ref.py new/pyleri-1.5.0/pyleri/ref.py --- old/pyleri-1.4.3/pyleri/ref.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/ref.py 2025-11-12 21:19:22.000000000 +0100 @@ -29,7 +29,7 @@ def _run_export_py(self, py_indent, indent, classes): return 'Ref()' - def _run_export_c(self, c_indent, indent, enums): + def _run_export_c(self, c_indent, indent, enums): # type: ignore return 'cleri_ref()' def _run_export_go(self, go_indent, indent, classes): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/repeat.py new/pyleri-1.5.0/pyleri/repeat.py --- old/pyleri-1.4.3/pyleri/repeat.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/repeat.py 2025-11-12 21:19:22.000000000 +0100 @@ -12,14 +12,14 @@ def __init__( self, - element: Element, + element: t.Union[Element, str], mi: int = 0, ma: t.Optional[int] = None): self._element = self._validate_element(element) if not isinstance(mi, int) or mi < 0: raise TypeError('Repeat(): "mi" must be an integer value larger ' - 'than or equal to 0, got: {mi}'.format(mi)) + 'than or equal to 0, got: {mi}'.format(mi=mi)) self._min = mi @@ -101,6 +101,7 @@ @java_export def _run_export_java(self, java_indent, indent, enums, classes, gid): + assert isinstance(self._element, NamedElement) return 'new Repeat({}{}, {}, {})'.format( '' if gid is None else 'Ids.{}, '.format(gid), self._element._export_java(java_indent, indent, enums, classes), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/result.py new/pyleri-1.5.0/pyleri/result.py --- old/pyleri-1.4.3/pyleri/result.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/result.py 2025-11-12 21:19:22.000000000 +0100 @@ -10,6 +10,7 @@ if t.TYPE_CHECKING: from .node import Node from .expecting import Expecting + from .elements import Element TOSTR = (Keyword, Token, Tokens, _EndOfStatement) @@ -22,7 +23,7 @@ def __init__(self, is_valid: bool, pos: int, tree: 'Node'): self.is_valid: bool = is_valid self.pos: int = pos - self.expecting: t.Optional['Expecting'] = None + self.expecting: t.Set[Element] = set() self.tree: 'Node' = tree def as_str(self, translate=None, line_number=False): @@ -36,7 +37,8 @@ else: res = ['error at position {}'.format(self.pos)] arr = [] - for elem in (self.expecting): + assert self.expecting is not None + for elem in self.expecting: expectstr = translate(elem) if translate else None if expectstr is None and isinstance(elem, TOSTR): expectstr = str(elem) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/rule.py new/pyleri-1.5.0/pyleri/rule.py --- old/pyleri-1.4.3/pyleri/rule.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/rule.py 2025-11-12 21:19:22.000000000 +0100 @@ -12,7 +12,7 @@ def __init__(self, element: Element): self._element = element - def _get_node_result(self, root, tree, rule, _s, node): + def _get_node_result(self, root, tree, rule, s, node): self._tested = {} self._tree = {} self._depth = -1 @@ -32,7 +32,7 @@ def _run_export_py(self, py_indent, indent, classes): return self._element._export_py(py_indent, indent, classes) - def _run_export_c(self, c_indent, indent, enums): + def _run_export_c(self, c_indent, indent, enums): # type: ignore name = getattr(self, 'name', None) if name is not None: self._element._name = name diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/sequence.py new/pyleri-1.5.0/pyleri/sequence.py --- old/pyleri-1.4.3/pyleri/sequence.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/sequence.py 2025-11-12 21:19:22.000000000 +0100 @@ -2,18 +2,20 @@ :copyright: 2021, Jeroen van der Heijden <[email protected]> """ -from .elements import Element, NamedElement, c_export +import typing as t +from .elements import Element, NamedElement class Sequence(NamedElement): __slots__ = ('_elements',) - def __init__(self, *elements: Element): + def __init__(self, *elements: t.Union[Element, str]): self._elements = self._validate_elements(elements) - def _get_node_result(self, root, tree, rule, _s, node): + def _get_node_result(self, root, tree, rule, s, node): pos = node.start + is_valid = True for elem in self._elements: is_valid, pos = root._walk(elem, pos, node.children, rule, True) @@ -30,8 +32,8 @@ def _run_export_py(self, py_indent, indent, classes): return self._export_py_elements(py_indent, indent, classes) - def _run_export_c(self, c_indent, indent, enums): - return self._export_c_elements(c_indent, indent, enums) + def _run_export_c(self, c_indent, indent, enums): # type: ignore + return self._export_c_elements(c_indent, indent, enums) # type: ignore def _run_export_go(self, go_indent, indent, enums): return self._export_go_elements(go_indent, indent, enums) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/this.py new/pyleri-1.5.0/pyleri/this.py --- old/pyleri-1.4.3/pyleri/this.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/this.py 2025-11-12 21:19:22.000000000 +0100 @@ -3,11 +3,13 @@ :copyright: 2021, Jeroen van der Heijden <[email protected]> """ from .elements import Element +from .rule import Rule class This(Element): - def _get_node_result(self, root, tree, rule, _s, node): + def _get_node_result(self, root, tree, rule, s, node): + assert isinstance(rule, Rule) if node.start not in rule._tested: rule._tested[node.start] = root._walk( rule._element, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/token.py new/pyleri-1.5.0/pyleri/token.py --- old/pyleri-1.4.3/pyleri/token.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/token.py 2025-11-12 21:19:22.000000000 +0100 @@ -2,6 +2,7 @@ :copyright: 2021, Jeroen van der Heijden <[email protected]> """ +import typing as t from .elements import NamedElement, c_export, go_export, java_export @@ -35,19 +36,32 @@ return 'Token(\'{}\')'.format(self._token.replace('\'', '\\\'')) @c_export - def _run_export_c(self, js_indent, indent, enums, gid): + def _run_export_c(self, + js_indent: str, + indent: int, + enums: t.Set[str], + gid: str) -> str: return 'cleri_token({}, "{}")'.format( gid, self._token.replace('"', '\\"')) @go_export - def _run_export_go(self, go_indent, indent, enums, gid): + def _run_export_go(self, + go_indent: str, + indent: int, + enums: t.Set[str], + gid: str) -> str: return 'goleri.NewToken({}, "{}")'.format( gid, self._token.replace('"', '\\"')) @java_export - def _run_export_java(self, java_indent, indent, enums, classes, gid): + def _run_export_java(self, + java_indent: str, + indent: int, + enums: t.Set[str], + classes: t.Set[str], + gid: t.Optional[str]) -> str: return 'new Token({}"{}")'.format( '' if gid is None else 'Ids.{}, '.format(gid), self._token.replace('"', '\\"')) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/pyleri/tokens.py new/pyleri-1.5.0/pyleri/tokens.py --- old/pyleri-1.4.3/pyleri/tokens.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/pyleri/tokens.py 2025-11-12 21:19:22.000000000 +0100 @@ -2,6 +2,7 @@ :copyright: 2021, Jeroen van der Heijden <[email protected]> """ +import typing as t from .elements import NamedElement, c_export, go_export, java_export @@ -26,7 +27,11 @@ return False, node.start - def _run_export_js(self, js_indent, indent, classes, cname): + def _run_export_js(self, + js_indent: str, + indent: int, + classes: t.Set[str], + cname) -> str: return 'Tokens(\'{}\')'.format( ' '.join(self._tokens).replace('\'', '\\\'')) @@ -41,13 +46,22 @@ ' '.join(self._tokens).replace('"', '\\"')) @go_export - def _run_export_go(self, go_indent, indent, enums, gid): + def _run_export_go(self, + go_indent: str, + indent: int, + enums: t.Set[str], + gid: str) -> str: return 'goleri.NewTokens({}, "{}")'.format( gid, ' '.join(self._tokens).replace('"', '\\"')) @java_export - def _run_export_java(self, java_indent, indent, enums, classes, gid): + def _run_export_java(self, + java_indent: str, + indent: int, + enums: t.Set[str], + classes: t.Set[str], + gid: t.Optional[str]) -> str: return 'new Tokens({}"{}")'.format( '' if gid is None else 'Ids.{}, '.format(gid), ' '.join(self._tokens).replace('"', '\\"')) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyleri-1.4.3/test/test_keyword.py new/pyleri-1.5.0/test/test_keyword.py --- old/pyleri-1.4.3/test/test_keyword.py 2024-03-26 10:19:45.000000000 +0100 +++ new/pyleri-1.5.0/test/test_keyword.py 2025-11-12 21:19:22.000000000 +0100 @@ -1,6 +1,7 @@ import unittest import os import sys +import re if os.environ.get('USELIB') != '1': sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) @@ -44,7 +45,9 @@ str(grammar.parse('Hi Iris'))) def test_keyword_alt_regkw(self): - grammar = create_grammar(Choice(Keyword('hi'), Token('HI')), r'[a-z]+') + grammar = create_grammar( + Choice(Keyword('hi'), Token('HI')), + re.compile(r'[a-z]+')) self.assertTrue(grammar.parse('hi').is_valid) self.assertTrue(grammar.parse('HI').is_valid) self.assertFalse(grammar.parse('').is_valid)
