Skip to content

Commit

Permalink
Merge pull request BerkeleyLearnVerify#24 from UCSCFormalMethods/pars…
Browse files Browse the repository at this point in the history
…er-py38-backport

Parser Python 3.8 Backport
  • Loading branch information
dfremont authored Mar 6, 2023
2 parents 67021ba + da95657 commit 546c2f5
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 49 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ sphinx_rtd_theme = {version = "^0.5.2", optional = true}
astor = {version = "^0.8.1", optional = true}
inflect = {version = "^5.5.2", optional = true}
rv-ltl = "0.1.0a1"
pegen = {git = "git@github.com:we-like-parsers/pegen.git", rev = "db7552d", optional = true}
pegen = "^0.2.0"

[tool.poetry.extras]
guideways = ["pyproj"]
Expand Down
7 changes: 4 additions & 3 deletions src/scenic/core/propositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from functools import reduce
import operator
from typing import List

import rv_ltl

Expand Down Expand Up @@ -55,14 +56,14 @@ def check_constrains_sampling(self):
return eligible

@property
def children(self) -> list["PropositionNode"]:
def children(self) -> List["PropositionNode"]:
"""returns all children of proposition tree
Returns:
list: proposition nodes that are directly under this node
"""
return []

def flatten(self) -> list["PropositionNode"]:
def flatten(self) -> List["PropositionNode"]:
"""flattens the tree and return the list of nodes
Returns:
list: list of all children nodes
Expand All @@ -71,7 +72,7 @@ def flatten(self) -> list["PropositionNode"]:
operator.concat, [node.flatten() for node in self.children], []
)

def atomics(self) -> list["Atomic"]:
def atomics(self) -> List["Atomic"]:
return list(filter(lambda n: isinstance(n, Atomic), self.flatten()))

def create_monitor(self) -> rv_ltl.Monitor:
Expand Down
5 changes: 3 additions & 2 deletions src/scenic/simulators/webots/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import abc
import math
from typing import List

import numpy as np
from scipy.spatial.transform import Rotation as R
Expand Down Expand Up @@ -44,7 +45,7 @@ def positionFromScenic(self, pos):
"""Convert a Scenic position to a Webots position."""
return list(self.invMult[i] * pos[self.invAxisMap[i]] for i in range(3))

def orientationFromScenic(self, orientation: Orientation, offset: Orientation) -> list[float]:
def orientationFromScenic(self, orientation: Orientation, offset: Orientation) -> List[float]:
# TODO(shun): Support other coordinate systems
if self.system != "ENU":
raise ValueError("Coordinate systems other than ENU is not fully supported")
Expand All @@ -60,7 +61,7 @@ def orientationFromScenic(self, orientation: Orientation, offset: Orientation) -
webotsRotation = rotvec.tolist() + [norm]
return webotsRotation

def orientationToScenic(self, webotsOrientation: list[float], offset: Orientation) -> Orientation:
def orientationToScenic(self, webotsOrientation: List[float], offset: Orientation) -> Orientation:
# TODO(shun): Support other coordinate systems
if self.system != "ENU":
raise ValueError("Coordinate systems other than ENU is not fully supported")
Expand Down
46 changes: 23 additions & 23 deletions src/scenic/syntax/ast.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ast
from typing import Optional, Union
from typing import Optional, Union, List


class AST(ast.AST):
Expand Down Expand Up @@ -27,11 +27,11 @@ class TryInterrupt(AST):

def __init__(
self,
body: list[ast.stmt],
interrupt_when_handlers: list["InterruptWhenHandler"],
except_handlers: list[ast.ExceptHandler],
orelse: list[ast.stmt],
finalbody: list[ast.AST],
body: List[ast.stmt],
interrupt_when_handlers: List["InterruptWhenHandler"],
except_handlers: List[ast.ExceptHandler],
orelse: List[ast.stmt],
finalbody: List[ast.AST],
*args: any,
**kwargs: any
) -> None:
Expand All @@ -55,7 +55,7 @@ class InterruptWhenHandler(AST):
__match_args__ = ("cond", "body")

def __init__(
self, cond: ast.AST, body: list[ast.AST], *args: any, **kwargs: any
self, cond: ast.AST, body: List[ast.AST], *args: any, **kwargs: any
) -> None:
super().__init__(*args, **kwargs)
self.cond = cond
Expand Down Expand Up @@ -102,7 +102,7 @@ class PropertyDef(AST):
def __init__(
self,
property: str,
attributes: list[Union["Additive", "Dynamic", "Final"]],
attributes: List[Union["Additive", "Dynamic", "Final"]],
value=ast.AST,
*args: any,
**kwargs: any
Expand Down Expand Up @@ -146,8 +146,8 @@ def __init__(
name: str,
args: ast.arguments,
docstring: Optional[str],
header: list[Union["Precondition", "Invariant"]],
body: list[any],
header: List[Union["Precondition", "Invariant"]],
body: List[any],
*_args: any,
**kwargs: any
) -> None:
Expand All @@ -167,7 +167,7 @@ def __init__(
self,
name: str,
docstring: Optional[str],
body: list[ast.AST],
body: List[ast.AST],
*args: any,
**kwargs: any
) -> None:
Expand Down Expand Up @@ -207,9 +207,9 @@ def __init__(
name: str,
args: ast.arguments,
docstring: Optional[str],
header: Optional[list[Union[Precondition, Invariant]]],
setup: list[ast.AST],
compose: list[ast.AST],
header: Optional[List[Union[Precondition, Invariant]]],
setup: List[ast.AST],
compose: List[ast.AST],
*_args: any,
**kwargs: any
) -> None:
Expand Down Expand Up @@ -240,7 +240,7 @@ class Param(AST):

__match_args__ = ("elts",)

def __init__(self, elts: list["parameter"], *args: any, **kwargs: any) -> None:
def __init__(self, elts: List["parameter"], *args: any, **kwargs: any) -> None:
super().__init__(*args, **kwargs)
self.elts = elts
self._fields = ["elts"]
Expand Down Expand Up @@ -378,7 +378,7 @@ class Mutate(AST):

def __init__(
self,
elts: list[ast.Name],
elts: List[ast.Name],
scale: Optional[ast.AST] = None,
*args: any,
**kwargs: any
Expand All @@ -393,7 +393,7 @@ class Override(AST):
__match_args__ = ("target", "specifiers")

def __init__(
self, target: ast.AST, specifiers: list[ast.AST], *args: any, **kwargs: any
self, target: ast.AST, specifiers: List[ast.AST], *args: any, **kwargs: any
) -> None:
super().__init__(*args, **kwargs)
self.target = target
Expand All @@ -408,7 +408,7 @@ class Abort(AST):
class Take(AST):
__match_args__ = ("elts",)

def __init__(self, elts: list[ast.AST], *args: any, **kwargs: any) -> None:
def __init__(self, elts: List[ast.AST], *args: any, **kwargs: any) -> None:
super().__init__(*args, **kwargs)
self.elts = elts
self._fields = ["elts"]
Expand Down Expand Up @@ -456,7 +456,7 @@ class DoFor(AST):

def __init__(
self,
elts: list[ast.AST],
elts: List[ast.AST],
duration: Union["Seconds", "Steps"],
*args: any,
**kwargs: any
Expand Down Expand Up @@ -491,7 +491,7 @@ class DoUntil(AST):
__match_args__ = ("elts", "cond")

def __init__(
self, elts: list[ast.AST], cond: ast.AST, *args: any, **kwargs: any
self, elts: List[ast.AST], cond: ast.AST, *args: any, **kwargs: any
) -> None:
super().__init__(*args, **kwargs)
self.elts = elts
Expand All @@ -502,7 +502,7 @@ def __init__(
class DoChoose(AST):
__match_args__ = ("elts",)

def __init__(self, elts: list[ast.AST], *args: any, **kwargs: any) -> None:
def __init__(self, elts: List[ast.AST], *args: any, **kwargs: any) -> None:
super().__init__(*args, **kwargs)
self.elts = elts
self._fields = ["elts"]
Expand All @@ -511,7 +511,7 @@ def __init__(self, elts: list[ast.AST], *args: any, **kwargs: any) -> None:
class DoShuffle(AST):
__match_args__ = ("elts",)

def __init__(self, elts: list[ast.AST], *args: any, **kwargs: any) -> None:
def __init__(self, elts: List[ast.AST], *args: any, **kwargs: any) -> None:
super().__init__(*args, **kwargs)
self.elts = elts
self._fields = ["elts"]
Expand All @@ -520,7 +520,7 @@ def __init__(self, elts: list[ast.AST], *args: any, **kwargs: any) -> None:
class Do(AST):
__match_args__ = ("elts",)

def __init__(self, elts: list[ast.AST], *args: any, **kwargs: any) -> None:
def __init__(self, elts: List[ast.AST], *args: any, **kwargs: any) -> None:
super().__init__(*args, **kwargs)
self.elts = elts
self._fields = ["elts"]
Expand Down
34 changes: 17 additions & 17 deletions src/scenic/syntax/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def compileScenicAST(
inCompose: bool = False,
inSetup: bool = False,
inInterruptBlock: bool = False,
) -> Tuple[Union[ast.AST, list[ast.AST]], List[ast.AST]]:
) -> Tuple[Union[ast.AST, List[ast.AST]], List[ast.AST]]:
"""Compiles Scenic AST to Python AST"""
compiler = ScenicToPythonTransformer()

Expand Down Expand Up @@ -219,7 +219,7 @@ def __init__(self) -> None:

def transform(
self, node: ast.AST, nextSyntaxId=0
) -> Tuple[ast.AST, list[ast.AST], int]:
) -> Tuple[ast.AST, List[ast.AST], int]:
"""`transform` takes an AST node and apply transformations needed for temporal evaluation
Args:
Expand Down Expand Up @@ -507,7 +507,7 @@ def generic_visit(self, node):
return super().generic_visit(node)

# add support for list of nodes
def visit(self, node: ast.AST | list[ast.AST]):
def visit(self, node: Union[ast.AST, List[ast.AST]]):
if isinstance(node, ast.AST):
return super().visit(node)
elif isinstance(node, list):
Expand Down Expand Up @@ -714,7 +714,7 @@ def visit_ClassDef(self, node: ast.ClassDef) -> any:
node.bases = [ast.Name("Object", loadCtx)]

# extract all property definitions
propertyDefs: list[s.PropertyDef] = []
propertyDefs: List[s.PropertyDef] = []
newBody = []
for stmt in node.body:
if isinstance(stmt, s.PropertyDef):
Expand Down Expand Up @@ -854,9 +854,9 @@ def visit_ScenarioDef(self, node: s.ScenarioDef):
def makeGuardCheckers(
self,
args: ast.arguments,
preconditions: list[s.Precondition],
invariants: list[s.Invariant],
) -> list[ast.AST]:
preconditions: List[s.Precondition],
invariants: List[s.Invariant],
) -> List[ast.AST]:
"""Create a list of statements that defines precondition and invariant checker"""

# Statements that check preconditions are satisfied
Expand Down Expand Up @@ -908,18 +908,18 @@ def makeGuardCheckers(
return preamble

def separatePreconditionsAndInvariants(
self, header: list[Union[s.Precondition, s.Invariant]]
) -> tuple[list[s.Precondition], list[s.Invariant]]:
self, header: List[Union[s.Precondition, s.Invariant]]
) -> Tuple[List[s.Precondition], List[s.Invariant]]:
"""Given a list of preconditions and invariants, separate items into the list of preconditions and list of invariants
Args:
header (list[Union[s.Precondition, s.Invariant]]): List of preconditions and invariants
header (List[Union[s.Precondition, s.Invariant]]): List of preconditions and invariants
Returns:
tuple[list[s.Precondition], list[s.Invariant]]: Tuple of precondition list and invariant list
Tuple[List[s.Precondition], List[s.Invariant]]: Tuple of precondition list and invariant list
"""
preconditions: list[s.Precondition] = []
invariants: list[s.Invariant] = []
preconditions: List[s.Precondition] = []
invariants: List[s.Invariant] = []
for n in header:
if isinstance(n, s.Precondition):
preconditions.append(n)
Expand All @@ -935,8 +935,8 @@ def makeBehaviorLikeDef(
name: str,
args: Optional[ast.arguments],
docstring: Optional[str],
header: list[Union[s.Precondition, s.Invariant]],
body: list[ast.AST],
header: List[Union[s.Precondition, s.Invariant]],
body: List[ast.AST],
):
if baseClassName == "Behavior":
ctxFlag = "inBehavior"
Expand All @@ -952,7 +952,7 @@ def makeBehaviorLikeDef(
# list of all arguments
allArgs = itertools.chain(args.posonlyargs, args.args, args.kwonlyargs)
# statements that create argument variables
copyArgs: list[ast.AST] = []
copyArgs: List[ast.AST] = []
for arg in allArgs:
dest = ast.Attribute(
ast.Name(behaviorArgName, loadCtx), arg.arg, ast.Store()
Expand Down Expand Up @@ -1207,7 +1207,7 @@ def generateInvocation(self, node: ast.AST, actionlike, invoker=ast.Yield):
def makeDoLike(
self,
node: ast.AST,
elts: list[ast.AST],
elts: List[ast.AST],
modifier: Optional[ast.Call] = None,
schedule: Optional[str] = None,
):
Expand Down
2 changes: 1 addition & 1 deletion src/scenic/syntax/scenic.gram
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ class Parser(Parser):
self.raise_syntax_error_known_location(msg, invalid_target)

# scenic helpers
def extend_new_specifiers(self, node: s.New, specifiers: list[ast.AST]) -> s.New:
def extend_new_specifiers(self, node: s.New, specifiers: List[ast.AST]) -> s.New:
node.specifiers.extend(specifiers)
return node
'''
Expand Down
11 changes: 9 additions & 2 deletions src/scenic/syntax/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,14 @@ def compileStream(stream, namespace, params={}, model=None, filename='<stream>')

if dumpScenicAST:
print(f'### Begin Scenic AST of {filename}')
print(ast.dump(scenic_tree, include_attributes=False, indent=4))
print(dump(scenic_tree, include_attributes=False, indent=4))
print('### End Scenic AST')

tree, requirements = compileScenicAST(scenic_tree, filename=filename)

if dumpFinalAST:
print(f'### Begin final AST of {filename}')
print(ast.dump(tree, include_attributes=True, indent=4))
print(dump(tree, include_attributes=True, indent=4))
print('### End final AST')

if dumpASTPython:
Expand Down Expand Up @@ -267,6 +267,13 @@ def compileStream(stream, namespace, params={}, model=None, filename='<stream>')
allNewSource = ''.join(newSourceBlocks)
return code, allNewSource

def dump(node: ast.AST, annotate_fields: bool = True, include_attributes: bool = False, *, indent: int):
if sys.version_info >= (3, 9):
print(ast.dump(node, annotate_fields, include_attributes, indent=indent))
else:
# omit `indent` if not supported
print(ast.dump(node, annotate_fields, include_attributes))

### TRANSLATION PHASE ZERO: definitions of language elements not already in Python

## Options
Expand Down
18 changes: 18 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import subprocess
from pathlib import Path
from contextlib import contextmanager
import re
import sys

import pytest

Expand Down Expand Up @@ -67,3 +69,19 @@ def pytest_collection_modifyitems(config, items):
for item in items:
if 'slow' in item.keywords:
item.add_marker(mark)

def pytest_ignore_collect(path, config):
"""
Some test files use Python syntax (e.g., structural pattern matching) that is only available in newer versions of Python.
To avoid syntax errors on older versions, put `# pytest: python>=x.y` where x and y represent major and minor versions, respectively,
required to run the test file.
"""
if path.isfile():
firstLine = ""
with path.open() as f:
firstLine = f.readline()
m = re.search("^#\s*pytest:\s*python\s*>=\s*(?P<major>\d+)\.(?P<minor>\d+)\s*$", firstLine)
if m:
target = (int(m.group("major")), int(m.group("minor")))
return True if sys.version_info < target else None
return None
Loading

0 comments on commit 546c2f5

Please sign in to comment.