From 57d39afa30f432716a078ffbf0e17b98c5ec4911 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Mon, 27 May 2024 12:19:55 +0200 Subject: [PATCH] Tweaks for Python 3.8 compatibility --- tatsu/bootstrap.py | 2 ++ tatsu/collections/orderedset.py | 21 ++++++++++----------- tatsu/g2e/semantics.py | 4 ++-- tatsu/grammars.py | 2 +- tatsu/infos.py | 9 ++++++++- tatsu/mixins/indent.py | 2 ++ tatsu/ngcodegen/objectmodel.py | 2 ++ tatsu/ngcodegen/python.py | 4 +++- tatsu/objectmodel.py | 4 ++-- tatsu/parser.py | 2 ++ tatsu/synth.py | 2 ++ tatsu/util/_common.py | 10 +++++----- tatsu/walkers.py | 2 +- test/grammar/semantics_test.py | 2 +- 14 files changed, 43 insertions(+), 25 deletions(-) diff --git a/tatsu/bootstrap.py b/tatsu/bootstrap.py index 4f656b2a..2c4abe03 100644 --- a/tatsu/bootstrap.py +++ b/tatsu/bootstrap.py @@ -11,6 +11,8 @@ # ruff: noqa: C405, COM812, I001, F401, PLR1702, PLC2801, SIM117 +from __future__ import annotations + import sys from pathlib import Path diff --git a/tatsu/collections/orderedset.py b/tatsu/collections/orderedset.py index 5efc2137..17fc97fb 100644 --- a/tatsu/collections/orderedset.py +++ b/tatsu/collections/orderedset.py @@ -1,14 +1,13 @@ # NOTE: from https://github.com/LuminosoInsight/ordered-set/blob/master/ordered_set.py +from __future__ import annotations + import itertools from collections.abc import ( - Iterable, Iterator, Mapping, MutableSequence, - MutableSet, - Sequence, ) -from typing import Any, TypeVar +from typing import Any, Iterable, MutableSet, Sequence, TypeVar T = TypeVar('T') @@ -29,7 +28,7 @@ def __getitem__(self, i): self._list_cache = list(self._map.keys()) return self._list_cache[i] - def copy(self) -> 'OrderedSet[T]': + def copy(self) -> OrderedSet[T]: return self.__class__(self) def __getstate__(self): @@ -78,25 +77,25 @@ def __repr__(self) -> str: def __eq__(self, other: Any) -> bool: return all(item in other for item in self) - def union(self, *other: Iterable[T]) -> 'OrderedSet[T]': + def union(self, *other: Iterable[T]) -> OrderedSet[T]: # do not split `str` outer = tuple( - [o] if not isinstance(o, set | Mapping | MutableSequence) else o + [o] if not isinstance(o, (set, Mapping, MutableSequence)) else o for o in other ) inner = itertools.chain([self], *outer) items = itertools.chain.from_iterable(inner) return type(self)(itertools.chain(items)) - def __and__(self, other: Iterable[Iterable[T]]) -> 'OrderedSet[T]': + def __and__(self, other: Iterable[Iterable[T]]) -> OrderedSet[T]: return self.intersection(other) - def intersection(self, *other: Iterable[Iterable[T]]) -> 'OrderedSet[T]': + def intersection(self, *other: Iterable[Iterable[T]]) -> OrderedSet[T]: common = set.intersection(*other) # type: ignore[var-annotated, arg-type] items = (item for item in self if item in common) return type(self)(items) - def difference(self, *other: Iterable[T]) -> 'OrderedSet[T]': + def difference(self, *other: Iterable[T]) -> OrderedSet[T]: other = set.union(*other) # type: ignore[assignment, arg-type] items = (item for item in self if item not in other) return type(self)(items) @@ -109,7 +108,7 @@ def issuperset(self, other: set[T]) -> bool: return False return all(item in self for item in other) - def symmetric_difference(self, other: set[T]) -> 'OrderedSet[T]': + def symmetric_difference(self, other: set[T]) -> OrderedSet[T]: cls = type(self) diff1 = cls(self).difference(other) diff2 = cls(other).difference(self) diff --git a/tatsu/g2e/semantics.py b/tatsu/g2e/semantics.py index 982ed777..c811e7ae 100644 --- a/tatsu/g2e/semantics.py +++ b/tatsu/g2e/semantics.py @@ -85,12 +85,12 @@ def syntactic_predicate(self, ast): return None def optional(self, ast): - if isinstance(ast, model.Group | model.Optional | model.Closure): + if isinstance(ast, (model.Group, model.Optional, model.Closure)): ast = ast.exp return model.Optional(ast) def closure(self, ast): - if isinstance(ast, model.Group | model.Optional): + if isinstance(ast, (model.Group, model.Optional)): ast = ast.exp return model.Closure(ast) diff --git a/tatsu/grammars.py b/tatsu/grammars.py index 726225f1..f9d4908c 100644 --- a/tatsu/grammars.py +++ b/tatsu/grammars.py @@ -865,7 +865,7 @@ def _nullable(self): @staticmethod def param_repr(p): - if isinstance(p, int | float) or (isinstance(p, str) and p.isalnum()): + if isinstance(p, (int, float)) or (isinstance(p, str) and p.isalnum()): return str(p) else: return repr(p) diff --git a/tatsu/infos.py b/tatsu/infos.py index 0efb982f..97c980a0 100644 --- a/tatsu/infos.py +++ b/tatsu/infos.py @@ -3,6 +3,7 @@ import copy import dataclasses import re +import sys from collections.abc import Callable, Mapping from itertools import starmap from typing import Any, NamedTuple @@ -11,6 +12,12 @@ from .tokenizing import Tokenizer from .util.unicode_characters import C_DERIVE +if sys.version_info < (3, 10): + import builtins + + def zip(*iterables, strict=False): + return builtins.zip(*iterables) + class UndefinedStr(str): pass @@ -234,7 +241,7 @@ class RuleResult(NamedTuple): newstate: Any -@dataclasses.dataclass(slots=True) +@dataclasses.dataclass(**({'slots': True} if sys.version_info >= (3, 10) else {})) class ParseState: pos: int = 0 ast: AST = dataclasses.field(default_factory=AST) diff --git a/tatsu/mixins/indent.py b/tatsu/mixins/indent.py index e1026a7f..c982d5e6 100644 --- a/tatsu/mixins/indent.py +++ b/tatsu/mixins/indent.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import io from contextlib import contextmanager diff --git a/tatsu/ngcodegen/objectmodel.py b/tatsu/ngcodegen/objectmodel.py index f67e5272..6fa0c1ab 100644 --- a/tatsu/ngcodegen/objectmodel.py +++ b/tatsu/ngcodegen/objectmodel.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import builtins from collections import namedtuple diff --git a/tatsu/ngcodegen/python.py b/tatsu/ngcodegen/python.py index 30725801..b5a51e50 100644 --- a/tatsu/ngcodegen/python.py +++ b/tatsu/ngcodegen/python.py @@ -27,6 +27,8 @@ # ruff: noqa: C405, COM812, I001, F401, PLR1702, PLC2801, SIM117 + from __future__ import annotations + import sys from pathlib import Path @@ -94,7 +96,7 @@ def walk_Grammar(self, grammar: grammars.Grammar): def walk_Rule(self, rule: grammars.Rule): def param_repr(p): - if isinstance(p, int | float): + if isinstance(p, (int, float)): return str(p) else: return repr(p.split('::')[0]) diff --git a/tatsu/objectmodel.py b/tatsu/objectmodel.py index 7c8fad2e..7e4a786d 100644 --- a/tatsu/objectmodel.py +++ b/tatsu/objectmodel.py @@ -112,7 +112,7 @@ def with_parent(node): return node def children_of(child): - if isinstance(child, weakref.ReferenceType | weakref.ProxyType): + if isinstance(child, (weakref.ReferenceType, weakref.ProxyType)): return elif isinstance(child, Node): yield with_parent(child) @@ -121,7 +121,7 @@ def children_of(child): if name.startswith('_'): continue yield from children_of(value) - elif isinstance(child, list | tuple): + elif isinstance(child, (list, tuple)): yield from ( with_parent(c) for c in child if isinstance(c, Node) ) diff --git a/tatsu/parser.py b/tatsu/parser.py index 0e25fe5f..c598b293 100644 --- a/tatsu/parser.py +++ b/tatsu/parser.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re from typing import Any diff --git a/tatsu/synth.py b/tatsu/synth.py index 97841007..3890f530 100644 --- a/tatsu/synth.py +++ b/tatsu/synth.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections.abc import Mapping from typing import Any diff --git a/tatsu/util/_common.py b/tatsu/util/_common.py index c0819064..daee7416 100644 --- a/tatsu/util/_common.py +++ b/tatsu/util/_common.py @@ -186,7 +186,7 @@ def decode_match(match): def isiter(value): return isinstance(value, Iterable) and not isinstance( - value, str | bytes | bytearray, + value, (str, bytes, bytearray), ) @@ -241,7 +241,7 @@ def timestamp(): def asjson(obj, seen=None): # noqa: PLR0911, PLR0912 - if obj is None or isinstance(obj, int | float | str | bool): + if obj is None or isinstance(obj, (int, float, str, bool)): return obj if seen is None: @@ -249,11 +249,11 @@ def asjson(obj, seen=None): # noqa: PLR0911, PLR0912 elif id(obj) in seen: return f'{type(obj).__name__}@{id(obj)}' - if isinstance(obj, Mapping | AsJSONMixin) or isiter(obj): + if isinstance(obj, (Mapping, AsJSONMixin)) or isiter(obj): seen.add(id(obj)) try: - if isinstance(obj, weakref.ReferenceType | weakref.ProxyType): + if isinstance(obj, (weakref.ReferenceType, weakref.ProxyType)): return f'{obj.__class__.__name__}@0x{hex(id(obj)).upper()[2:]}' elif hasattr(obj, '__json__'): return obj.__json__(seen=seen) @@ -304,7 +304,7 @@ def plainjson(obj): for name, value in obj.items() if name not in {'__class__', 'parseinfo'} } - elif isinstance(obj, weakref.ReferenceType | weakref.ProxyType): + elif isinstance(obj, (weakref.ReferenceType, weakref.ProxyType)): return '@ref' elif isinstance(obj, str) and obj.startswith('@'): return '@ref' diff --git a/tatsu/walkers.py b/tatsu/walkers.py index 3de070ea..cf102b9f 100644 --- a/tatsu/walkers.py +++ b/tatsu/walkers.py @@ -25,7 +25,7 @@ def __init__(self): )._walker_cache # pylint: disable=no-member def walk(self, node: Node | list[Node], *args, **kwargs) -> Any: - if isinstance(node, list | tuple): + if isinstance(node, (list, tuple)): return [self.walk(n, *args, **kwargs) for n in node] if isinstance(node, Mapping): diff --git a/test/grammar/semantics_test.py b/test/grammar/semantics_test.py index 51deebd7..4de537a4 100644 --- a/test/grammar/semantics_test.py +++ b/test/grammar/semantics_test.py @@ -100,7 +100,7 @@ def test_builder_basetype_codegen(self): self.assertTrue(hasattr(ast, 'a')) self.assertTrue(hasattr(ast, 'b')) - self.assertTrue(issubclass(D, A | B | C)) + self.assertTrue(issubclass(D, (A, B, C))) def test_optional_attributes(self): grammar = r"""