Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: add pre-commit, typos and ruff, fix several #64

Merged
merged 11 commits into from
Dec 7, 2023
65 changes: 65 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0 # Use the ref you want to point at
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-merge-conflict
- id: check-toml
- id: check-vcs-permalinks
- id: check-yaml
- id: detect-private-key
- id: end-of-file-fixer
- id: fix-byte-order-marker
- id: mixed-line-ending
# - id: trailing-whitespace
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't work well with .err files.

# Python-specific
- id: check-ast
- id: check-docstring-first
- id: debug-statements

- repo: https://github.com/crate-ci/typos
rev: v1.16.23
hooks:
- id: typos
args: []

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.7
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format

- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.3.0'
hooks:
- id: mypy
pass_filenames: false
args: [--package=guppy]
additional_dependencies: [
ormsgpack,
pydantic,
]

- repo: local
hooks:
- id: cargo-check
name: Cargo check
entry: bash -c 'cd validator && exec cargo check'
pass_filenames: false
types: [file, rust]
language: system
- id: rust-linting
name: Rust linting
entry: bash -c 'cd validator && exec cargo fmt --all --'
pass_filenames: true
types: [file, rust]
language: system
- id: rust-clippy
name: Rust clippy
entry: bash -c 'cd validator && exec cargo clippy --all-targets --all-features -- -Dclippy::all'
pass_filenames: false
types: [file, rust]
language: system
3 changes: 3 additions & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[default.extend-words]
inot = "inot"
fle = "fle"
12 changes: 12 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
include *.toml
include *.txt
include *.yaml
recursive-include examples *.ipynb
recursive-include guppy *.py
recursive-include tests *.err
recursive-include tests *.py
recursive-include tests *.sh
recursive-exclude validator *.lock
recursive-exclude validator *.rs
recursive-exclude validator *.toml
exclude .git-blame-ignore-revs
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ pip install -e '.[dev]'

### Git blame

You can configure Git to ignore formatting commits when using `git blame` by running
You can configure Git to ignore formatting commits when using `git blame` by running

```sh
git config blame.ignoreRevsFile .git-blame-ignore-revs
```
Expand All @@ -41,14 +42,14 @@ TODO

## Testing

First, build the PyO3 Hugr validation library using
First, build the PyO3 Hugr validation library from the `validator` directory using

```sh
maturin develop
```

from the `validator` directory.

Run tests using

```sh
pytest -v
```
Expand All @@ -59,6 +60,7 @@ Integration test cases can be exported to a directory using
pytest --export-test-cases=guppy-exports

```

which will create a directory `./guppy-exports` populated with hugr modules serialised in msgpack.

## Packaging
Expand Down
34 changes: 18 additions & 16 deletions guppy/ast_util.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import ast
from typing import Any, TypeVar, Generic, Union, Optional, TYPE_CHECKING
from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar

if TYPE_CHECKING:
from guppy.gtypes import GuppyType

AstNode = Union[
ast.AST,
ast.operator,
ast.expr,
ast.arg,
ast.stmt,
ast.Name,
ast.keyword,
ast.FunctionDef,
]
AstNode = (
ast.AST
| ast.operator
| ast.expr
| ast.arg
| ast.stmt
| ast.Name
| ast.keyword
| ast.FunctionDef
)

T = TypeVar("T", covariant=True)

Expand Down Expand Up @@ -114,7 +114,9 @@ def set_location_from(node: ast.AST, loc: ast.AST) -> None:
node.end_col_offset = loc.end_col_offset

source, file, line_offset = get_source(loc), get_file(loc), get_line_offset(loc)
assert source is not None and file is not None and line_offset is not None
assert source is not None
assert file is not None
assert line_offset is not None
annotate_location(node, source, file, line_offset)


Expand All @@ -126,7 +128,7 @@ def annotate_location(
setattr(node, "source", source)

if recurse:
for field, value in ast.iter_fields(node):
for _field, value in ast.iter_fields(node):
if isinstance(value, list):
for item in value:
if isinstance(item, ast.AST):
Expand All @@ -135,7 +137,7 @@ def annotate_location(
annotate_location(value, source, file, line_offset, recurse)


def get_file(node: AstNode) -> Optional[str]:
def get_file(node: AstNode) -> str | None:
"""Tries to retrieve a file annotation from an AST node."""
try:
file = getattr(node, "file")
Expand All @@ -144,7 +146,7 @@ def get_file(node: AstNode) -> Optional[str]:
return None


def get_source(node: AstNode) -> Optional[str]:
def get_source(node: AstNode) -> str | None:
"""Tries to retrieve a source annotation from an AST node."""
try:
source = getattr(node, "source")
Expand All @@ -153,7 +155,7 @@ def get_source(node: AstNode) -> Optional[str]:
return None


def get_line_offset(node: AstNode) -> Optional[int]:
def get_line_offset(node: AstNode) -> int | None:
"""Tries to retrieve a line offset annotation from an AST node."""
try:
line_offset = getattr(node, "line_offset")
Expand Down
11 changes: 3 additions & 8 deletions guppy/cfg/analysis.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from abc import ABC, abstractmethod
from typing import TypeVar, Generic, Iterable
from collections.abc import Iterable
from typing import Generic, TypeVar

from guppy.cfg.bb import BB


# Type variable for the lattice domain
T = TypeVar("T")

Expand All @@ -21,20 +21,17 @@ def eq(self, t1: T, t2: T, /) -> bool:
@abstractmethod
def initial(self) -> T:
"""Initial lattice value"""
pass

@abstractmethod
def join(self, *ts: T) -> T:
"""Lattice join operation"""
pass

@abstractmethod
def run(self, bbs: Iterable[BB]) -> Result[T]:
"""Runs the analysis pass.

Returns a mapping from basic blocks to lattice values at the start of each BB.
"""
pass


class ForwardAnalysis(Analysis[T], ABC, Generic[T]):
Expand All @@ -43,7 +40,6 @@ class ForwardAnalysis(Analysis[T], ABC, Generic[T]):
@abstractmethod
def apply_bb(self, val_before: T, bb: BB, /) -> T:
"""Transformation a basic block applies to a lattice value"""
pass

def run(self, bbs: Iterable[BB]) -> Result[T]:
"""Runs the analysis pass.
Expand All @@ -69,7 +65,6 @@ class BackwardAnalysis(Analysis[T], ABC, Generic[T]):
@abstractmethod
def apply_bb(self, val_after: T, bb: BB, /) -> T:
"""Transformation a basic block applies to a lattice value"""
pass

def run(self, bbs: Iterable[BB]) -> Result[T]:
"""Runs the analysis pass.
Expand Down Expand Up @@ -106,7 +101,7 @@ def eq(self, live1: LivenessDomain, live2: LivenessDomain) -> bool:
return live1.keys() == live2.keys()

def initial(self) -> LivenessDomain:
return dict()
return {}

def join(self, *ts: LivenessDomain) -> LivenessDomain:
res: LivenessDomain = {}
Expand Down
22 changes: 13 additions & 9 deletions guppy/cfg/bb.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import ast
from abc import ABC
from dataclasses import dataclass, field
from typing import Optional, TYPE_CHECKING, Union
from typing import TYPE_CHECKING

from typing_extensions import Self

from guppy.ast_util import AstNode, name_nodes_in_ast
Expand Down Expand Up @@ -34,9 +35,14 @@ def update_used(self, node: ast.AST) -> None:
self.used[name.id] = name


BBStatement = Union[
ast.Assign, ast.AugAssign, ast.AnnAssign, ast.Expr, ast.Return, NestedFunctionDef
]
BBStatement = (
ast.Assign
| ast.AugAssign
| ast.AnnAssign
| ast.Expr
| ast.Return
| NestedFunctionDef
)


@dataclass(eq=False) # Disable equality to recover hash from `object`
Expand All @@ -57,10 +63,10 @@ class BB(ABC):

# If the BB has multiple successors, we need a predicate to decide to which one to
# jump to
branch_pred: Optional[ast.expr] = None
branch_pred: ast.expr | None = None

# Information about assigned/used variables in the BB
_vars: Optional[VariableStats] = None
_vars: VariableStats | None = None

@property
def vars(self) -> VariableStats:
Expand Down Expand Up @@ -123,9 +129,7 @@ def visit_NestedFunctionDef(self, node: NestedFunctionDef) -> None:
# Only store used *external* variables: things defined in the current BB, as
# well as the function name and argument names should not be included
assigned_before_in_bb = (
self.stats.assigned.keys()
| {node.name}
| set(a.arg for a in node.args.args)
self.stats.assigned.keys() | {node.name} | {a.arg for a in node.args.args}
)
self.stats.used |= {
x: using_bb.vars.used[x]
Expand Down
Loading