Skip to content

Commit

Permalink
Tweaks for Python 3.8 compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
dnicolodi committed May 27, 2024
1 parent 9387109 commit 7196548
Show file tree
Hide file tree
Showing 14 changed files with 46 additions and 25 deletions.
2 changes: 2 additions & 0 deletions tatsu/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

# ruff: noqa: C405, COM812, I001, F401, PLR1702, PLC2801, SIM117

from __future__ import annotations

import sys
from pathlib import Path

Expand Down
21 changes: 10 additions & 11 deletions tatsu/collections/orderedset.py
Original file line number Diff line number Diff line change
@@ -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')

Expand All @@ -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):
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions tatsu/g2e/semantics.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion tatsu/grammars.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 11 additions & 1 deletion tatsu/infos.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -234,7 +241,10 @@ class RuleResult(NamedTuple):
newstate: Any


@dataclasses.dataclass(slots=True)
import sys


@dataclasses.dataclass(**({'slots': True} if sys.version_info >= (3, 10) else {}))
class ParseState:
pos: int = 0
ast: AST = dataclasses.field(default_factory=AST)
Expand Down
2 changes: 2 additions & 0 deletions tatsu/mixins/indent.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import io
from contextlib import contextmanager

Expand Down
2 changes: 2 additions & 0 deletions tatsu/ngcodegen/objectmodel.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import builtins
from collections import namedtuple

Expand Down
4 changes: 3 additions & 1 deletion tatsu/ngcodegen/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
# ruff: noqa: C405, COM812, I001, F401, PLR1702, PLC2801, SIM117
from __future__ import annotations
import sys
from pathlib import Path
Expand Down Expand Up @@ -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])
Expand Down
4 changes: 2 additions & 2 deletions tatsu/objectmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
)
Expand Down
2 changes: 2 additions & 0 deletions tatsu/parser.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import re
from typing import Any

Expand Down
2 changes: 2 additions & 0 deletions tatsu/synth.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from collections.abc import Mapping
from typing import Any

Expand Down
10 changes: 5 additions & 5 deletions tatsu/util/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)


Expand Down Expand Up @@ -241,19 +241,19 @@ 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:
seen = set()
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)
Expand Down Expand Up @@ -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'
Expand Down
2 changes: 1 addition & 1 deletion tatsu/walkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion test/grammar/semantics_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"""
Expand Down

0 comments on commit 7196548

Please sign in to comment.