From 634877a43fe3248d44372e5e2a7141c70cdb7b4e Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Fri, 12 Jan 2024 12:11:35 +0000 Subject: [PATCH] refactor!: conform to hugr schema - script to generate scheme - aliases for named types - delete vestigial types - rename to match hugr naming schemes --- guppy/custom.py | 4 +- guppy/decorator.py | 4 +- guppy/gtypes.py | 18 ++-- guppy/hugr/hugr.py | 6 +- guppy/hugr/ops.py | 205 ++++++++++--------------------------- guppy/hugr/tys.py | 117 ++++++++++++--------- guppy/hugr/val.py | 9 +- guppy/prelude/_internal.py | 2 +- poetry.lock | 38 +++---- pyproject.toml | 4 + scripts/__init__.py | 0 scripts/generate_schema.py | 15 +++ 12 files changed, 187 insertions(+), 235 deletions(-) create mode 100644 scripts/__init__.py create mode 100644 scripts/generate_schema.py diff --git a/guppy/custom.py b/guppy/custom.py index f228f46f..bd109f15 100644 --- a/guppy/custom.py +++ b/guppy/custom.py @@ -233,9 +233,9 @@ def compile(self, args: list[OutPortV]) -> list[OutPortV]: class OpCompiler(CustomCallCompiler): - op: ops.OpType + op: ops.BaseOp - def __init__(self, op: ops.OpType) -> None: + def __init__(self, op: ops.BaseOp) -> None: self.op = op def compile(self, args: list[OutPortV]) -> list[OutPortV]: diff --git a/guppy/decorator.py b/guppy/decorator.py index 7585d4fd..d4518f7b 100644 --- a/guppy/decorator.py +++ b/guppy/decorator.py @@ -77,7 +77,7 @@ def dec(c: type) -> type: def type( self, module: GuppyModule, - hugr_ty: tys.SimpleType, + hugr_ty: tys.Type, name: str = "", linear: bool = False, ) -> ClassDecorator: @@ -114,7 +114,7 @@ def type_args(self) -> Iterator[GuppyType]: def linear(self) -> bool: return linear - def to_hugr(self) -> tys.SimpleType: + def to_hugr(self) -> tys.Type: return hugr_ty def transform(self, transformer: TypeTransformer) -> GuppyType: diff --git a/guppy/gtypes.py b/guppy/gtypes.py index 9046e2cb..9ac0b432 100644 --- a/guppy/gtypes.py +++ b/guppy/gtypes.py @@ -67,7 +67,7 @@ def linear(self) -> bool: pass @abstractmethod - def to_hugr(self) -> tys.SimpleType: + def to_hugr(self) -> tys.Type: pass @abstractmethod @@ -106,7 +106,7 @@ def transform(self, transformer: "TypeTransformer") -> GuppyType: def __str__(self) -> str: return self.display_name - def to_hugr(self) -> tys.SimpleType: + def to_hugr(self) -> tys.Type: return tys.Variable(i=self.idx, b=tys.TypeBound.from_linear(self.linear)) @@ -146,7 +146,7 @@ def __str__(self) -> str: def __hash__(self) -> int: return self.id - def to_hugr(self) -> tys.SimpleType: + def to_hugr(self) -> tys.Type: from guppy.error import InternalGuppyError raise InternalGuppyError("Tried to convert free type variable to Hugr") @@ -195,7 +195,7 @@ def to_hugr(self) -> tys.PolyFuncType: func_ty = tys.FunctionType(input=ins, output=outs, extension_reqs=[]) return tys.PolyFuncType( params=[ - tys.TypeParam(b=tys.TypeBound.from_linear(v.linear)) + tys.TypeTypeParam(b=tys.TypeBound.from_linear(v.linear)) for v in self.quantified ], body=func_ty, @@ -267,9 +267,9 @@ def linear(self) -> bool: def type_args(self) -> Iterator[GuppyType]: return iter(self.element_types) - def to_hugr(self) -> tys.SimpleType: + def to_hugr(self) -> tys.Type: ts = [t.to_hugr() for t in self.element_types] - return tys.Tuple(inner=ts) + return tys.TupleType(inner=ts) def transform(self, transformer: "TypeTransformer") -> GuppyType: return transformer.transform(self) or TupleType( @@ -300,7 +300,7 @@ def linear(self) -> bool: def type_args(self) -> Iterator[GuppyType]: return iter(self.element_types) - def to_hugr(self) -> tys.SimpleType: + def to_hugr(self) -> tys.Type: if all( isinstance(e, TupleType) and len(e.element_types) == 0 for e in self.element_types @@ -342,8 +342,8 @@ def substitute(self, s: Subst) -> GuppyType: def __str__(self) -> str: return "None" - def to_hugr(self) -> tys.SimpleType: - return tys.Tuple(inner=[]) + def to_hugr(self) -> tys.Type: + return tys.TupleType(inner=[]) def transform(self, transformer: "TypeTransformer") -> GuppyType: return transformer.transform(self) or self diff --git a/guppy/hugr/hugr.py b/guppy/hugr/hugr.py index fb671bb5..73bed1eb 100644 --- a/guppy/hugr/hugr.py +++ b/guppy/hugr/hugr.py @@ -81,7 +81,7 @@ class Node(ABC): """ idx: NodeIdx - op: ops.OpType + op: ops.BaseOp parent: Optional["Node"] meta_data: dict[str, Any] @@ -301,7 +301,7 @@ def _insert_node(self, node: Node, inputs: list[OutPortV] | None = None) -> None def add_node( self, - op: ops.OpType, + op: ops.BaseOp, input_types: TypeList | None = None, output_types: TypeList | None = None, parent: Node | None = None, @@ -539,7 +539,7 @@ def add_type_apply( result_ty = func_port.ty.instantiate(args) ta = ops.TypeApplication( input=func_port.ty.to_hugr(), - args=[tys.TypeArg(ty=ty.to_hugr()) for ty in args], + args=[tys.TypeTypeArg(ty=ty.to_hugr()) for ty in args], output=result_ty.to_hugr(), ) return self.add_node( diff --git a/guppy/hugr/ops.py b/guppy/hugr/ops.py index ce6d3780..d78d832c 100644 --- a/guppy/hugr/ops.py +++ b/guppy/hugr/ops.py @@ -1,9 +1,10 @@ import inspect import sys from abc import ABC -from typing import Annotated, Any, Literal +from typing import Annotated, Any, Literal, cast from pydantic import BaseModel, Field +from typing_extensions import TypeAliasType import guppy.hugr.tys as tys @@ -12,7 +13,7 @@ ExtensionSet, FunctionType, PolyFuncType, - SimpleType, + Type, TypeRow, ) from .val import Value @@ -97,7 +98,7 @@ class Const(BaseOp): op: Literal["Const"] = "Const" value: Value - typ: SimpleType + typ: Type # ----------------------------------------------- @@ -128,12 +129,12 @@ def insert_child_dfg_signature(self, inputs: TypeRow, outputs: TypeRow) -> None: pred = outputs[0] assert isinstance(pred, tys.UnitSum | tys.GeneralSum) if isinstance(pred, tys.UnitSum): - self.tuple_sum_rows = [[] for _ in range(pred.size)] + self.tuple_sum_rows = [[] for _ in range(cast(tys.UnitSum, pred).size)] else: assert isinstance(pred, tys.GeneralSum) self.tuple_sum_rows = [] for variant in pred.row: - assert isinstance(variant, tys.Tuple) + assert isinstance(variant, tys.TupleType) self.tuple_sum_rows.append(variant.inner) self.other_outputs = outputs[1:] @@ -193,6 +194,7 @@ def insert_port_types(self, in_types: TypeRow, out_types: TypeRow) -> None: # The constE edge comes after the value inputs fun_ty = in_types[-1] assert isinstance(fun_ty, PolyFuncType) + fun_ty = cast(PolyFuncType, fun_ty) assert len(fun_ty.params) == 0 self.signature = fun_ty.body @@ -208,6 +210,7 @@ class CallIndirect(DataflowOp): def insert_port_types(self, in_types: TypeRow, out_types: TypeRow) -> None: fun_ty = in_types[0] assert isinstance(fun_ty, PolyFuncType) + fun_ty = cast(PolyFuncType, fun_ty) assert len(fun_ty.params) == 0 assert len(fun_ty.body.input) == len(in_types) - 1 assert len(fun_ty.body.output) == len(out_types) @@ -218,7 +221,7 @@ class LoadConstant(DataflowOp): """Load a static constant in to the local dataflow graph.""" op: Literal["LoadConstant"] = "LoadConstant" - datatype: SimpleType + datatype: Type class LeafOp(DataflowOp): @@ -262,12 +265,12 @@ def insert_port_types(self, in_types: TypeRow, out_types: TypeRow) -> None: # those into a list of type rows pred = in_types[0] if isinstance(pred, tys.UnitSum): - self.tuple_sum_rows = [[] for _ in range(pred.size)] + self.tuple_sum_rows = [[] for _ in range(cast(tys.UnitSum, pred).size)] else: assert isinstance(pred, tys.GeneralSum) self.tuple_sum_rows = [] for ty in pred.row: - assert isinstance(ty, tys.Tuple) + assert isinstance(ty, tys.TupleType) self.tuple_sum_rows.append(ty.inner) self.other_inputs = list(in_types[1:]) self.outputs = list(out_types) @@ -331,7 +334,7 @@ class CustomOp(LeafOp): op_name: str signature: tys.FunctionType | None = None description: str = "" - args: list[tys.TypeArgUnion] = Field(default_factory=list) + args: list[tys.TypeArg] = Field(default_factory=list) def insert_port_types(self, in_types: TypeRow, out_types: TypeRow) -> None: self.signature = tys.FunctionType(input=list(in_types), output=list(out_types)) @@ -340,103 +343,19 @@ def display_name(self) -> str: return self.op_name -class H(LeafOp): - """A Hadamard gate.""" - - lop: Literal["H"] = "H" - - -class T(LeafOp): - """A T gate.""" - - lop: Literal["T"] = "T" - - -class S(LeafOp): - """An S gate.""" - - lop: Literal["S"] = "S" - - -class X(LeafOp): - """A Pauli X gate.""" - - lop: Literal["X"] = "X" - - -class Y(LeafOp): - """A Pauli Y gate.""" - - lop: Literal["Y"] = "Y" - - -class Z(LeafOp): - """A Pauli Z gate.""" - - lop: Literal["Z"] = "Z" - - -class Tadj(LeafOp): - """An adjoint T gate.""" - - lop: Literal["Tadj"] = "Tadj" - - -class Sadj(LeafOp): - """An adjoint S gate.""" - - lop: Literal["Sadj"] = "Sadj" - - -class CX(LeafOp): - """A controlled X gate.""" - - lop: Literal["CX"] = "CX" - - -class ZZMax(LeafOp): - """A maximally entangling ZZ phase gate.""" - - lop: Literal["ZZMax"] = "ZZMax" - - -class Reset(LeafOp): - """A qubit reset operation.""" - - lop: Literal["Reset"] = "Reset" - - class Noop(LeafOp): """A no-op operation.""" lop: Literal["Noop"] = "Noop" - ty: SimpleType + ty: Type def insert_port_types(self, in_types: TypeRow, out_types: TypeRow) -> None: assert len(in_types) == 1 assert len(out_types) == 1 - assert in_types[0] == out_types[0] + assert in_types[0] == out_types[0] # type: ignore[operator] # mypy doesn't understand the type union self.ty = in_types[0] -class Measure(LeafOp): - """A qubit measurement operation.""" - - lop: Literal["Measure"] = "Measure" - - -class RzF64(LeafOp): - """A rotation of a qubit about the Pauli Z axis by an input float angle.""" - - lop: Literal["RzF64"] = "RzF64" - - -class Xor(LeafOp): - """A bitwise XOR operation.""" - - lop: Literal["Xor"] = "Xor" - - class MakeTuple(LeafOp): """An operation that packs all its inputs into a tuple.""" @@ -465,7 +384,7 @@ class MakeNewType(LeafOp): lop: Literal["MakeNewType"] = "MakeNewType" name: str # The new type name. - typ: SimpleType # The wrapped type. + typ: Type # The wrapped type. class Tag(LeafOp): @@ -492,62 +411,46 @@ class TypeApplication(BaseModel): """ input: PolyFuncType - args: list[tys.TypeArg] + args: list[tys.TypeTypeArg] output: PolyFuncType -LeafOpUnion = Annotated[ - ( - CustomOp - | H - | S - | T - | X - | Y - | Z - | Tadj - | Sadj - | CX - | ZZMax - | Reset - | Noop - | Measure - | RzF64 - | Xor - | MakeTuple - | UnpackTuple - | MakeNewType - | Tag - | TypeApply - ), - Field(discriminator="lop"), -] - - -OpType = Annotated[ - ( - Module - | Case - | Module - | FuncDefn - | FuncDecl - | Const - | DummyOp - | DataflowBlock - | ExitBlock - | Conditional - | TailLoop - | CFG - | Input - | Output - | Call - | CallIndirect - | LoadConstant - | LeafOpUnion - | DFG - ), - Field(discriminator="op"), -] +LeafOpUnion = TypeAliasType( + "LeafOpUnion", + Annotated[ + (CustomOp | Noop | MakeTuple | UnpackTuple | MakeNewType | Tag | TypeApply), + Field(discriminator="lop"), + ], +) + + +OpType = TypeAliasType( + "OpType", + Annotated[ + ( + Module + | Case + | Module + | FuncDefn + | FuncDecl + | Const + | DummyOp + | DataflowBlock + | ExitBlock + | Conditional + | TailLoop + | CFG + | Input + | Output + | Call + | CallIndirect + | LoadConstant + | LeafOpUnion + | DFG + ), + Field(discriminator="op"), + ], +) # -------------------------------------- @@ -560,8 +463,8 @@ class OpDef(BaseOp, populate_by_name=True): name: str # Unique identifier of the operation. description: str # Human readable description of the operation. - inputs: list[tuple[str | None, SimpleType]] - outputs: list[tuple[str | None, SimpleType]] + inputs: list[tuple[str | None, Type]] + outputs: list[tuple[str | None, Type]] misc: dict[str, Any] # Miscellaneous data associated with the operation. def_: str | None = Field( ..., alias="def" diff --git a/guppy/hugr/tys.py b/guppy/hugr/tys.py index 0d8339bb..bed19801 100644 --- a/guppy/hugr/tys.py +++ b/guppy/hugr/tys.py @@ -1,9 +1,36 @@ import inspect import sys from enum import Enum -from typing import Annotated, Literal +from typing import Annotated, Any, Literal + +from pydantic import ( + BaseModel, + Field, + ValidationError, + ValidationInfo, + ValidatorFunctionWrapHandler, + WrapValidator, +) +from pydantic_core import PydanticCustomError +from typing_extensions import TypeAliasType + + +def _json_custom_error_validator( + value: Any, handler: ValidatorFunctionWrapHandler, _info: ValidationInfo +) -> Any: + """Simplify the error message to avoid a gross error stemming + from exhaustive checking of all union options. + + Used to define named recursive alias types. + """ + try: + return handler(value) + except ValidationError as err: + raise PydanticCustomError( + "invalid_json", + "Input is not valid json", + ) from err -from pydantic import BaseModel, Field ExtensionId = str ExtensionSet = list[ # TODO: Set not supported by MessagePack. Is list correct here? @@ -16,7 +43,7 @@ # -------------------------------------------- -class TypeParam(BaseModel): +class TypeTypeParam(BaseModel): tp: Literal["Type"] = "Type" b: "TypeBound" @@ -33,18 +60,22 @@ class OpaqueParam(BaseModel): class ListParam(BaseModel): tp: Literal["List"] = "List" - param: "TypeParamUnion" + param: "TypeParam" class TupleParam(BaseModel): tp: Literal["Tuple"] = "Tuple" - params: list["TypeParamUnion"] + params: list["TypeParam"] -TypeParamUnion = Annotated[ - TypeParam | BoundedNatParam | OpaqueParam | ListParam | TupleParam, - Field(discriminator="tp"), -] +TypeParam = TypeAliasType( + "TypeParam", + Annotated[ + TypeTypeParam | BoundedNatParam | OpaqueParam | ListParam | TupleParam, + Field(discriminator="tp"), + WrapValidator(_json_custom_error_validator), + ], +) # ------------------------------------------ @@ -57,9 +88,9 @@ class CustomTypeArg(BaseModel): value: str -class TypeArg(BaseModel): +class TypeTypeArg(BaseModel): tya: Literal["Type"] = "Type" - ty: "SimpleType" + ty: "Type" class BoundedNatArg(BaseModel): @@ -74,7 +105,7 @@ class OpaqueArg(BaseModel): class SequenceArg(BaseModel): tya: Literal["Sequence"] = "Sequence" - args: list["TypeArgUnion"] + args: list["TypeArg"] class ExtensionsArg(BaseModel): @@ -82,10 +113,14 @@ class ExtensionsArg(BaseModel): es: ExtensionSet -TypeArgUnion = Annotated[ - TypeArg | BoundedNatArg | OpaqueArg | SequenceArg | ExtensionsArg, - Field(discriminator="tya"), -] +TypeArg = TypeAliasType( + "TypeArg", + Annotated[ + TypeTypeArg | BoundedNatArg | OpaqueArg | SequenceArg | ExtensionsArg, + Field(discriminator="tya"), + WrapValidator(_json_custom_error_validator), + ], +) # -------------------------------------------- @@ -94,13 +129,7 @@ class ExtensionsArg(BaseModel): class MultiContainer(BaseModel): - ty: "SimpleType" - - -class List(MultiContainer): - """Variable sized list of types""" - - t: Literal["List"] = "List" + ty: "Type" class Array(MultiContainer): @@ -110,7 +139,7 @@ class Array(MultiContainer): len: int -class Tuple(BaseModel): +class TupleType(BaseModel): """Product type, known-size tuple over elements of type row""" t: Literal["Tuple"] = "Tuple" @@ -156,16 +185,16 @@ class Int(BaseModel): width: int -class F64(BaseModel): - """A 64-bit floating point number.""" +# class F64(BaseModel): +# """A 64-bit floating point number.""" - t: Literal["F"] = "F" +# t: Literal["F"] = "F" -class String(BaseModel): - """An arbitrary length string.""" +# class String(BaseModel): +# """An arbitrary length string.""" - t: Literal["S"] = "S" +# t: Literal["S"] = "S" class FunctionType(BaseModel): @@ -192,7 +221,7 @@ class PolyFuncType(BaseModel): # number of TypeArgs before the function can be called. Note that within the body, # variable (DeBruijn) index 0 is element 0 of this array, i.e. the variables are # bound from right to left. - params: list[TypeParamUnion] + params: list[TypeParam] # Template for the function. May contain variables up to length of `params` body: FunctionType @@ -218,7 +247,7 @@ class Opaque(BaseModel): t: Literal["Opaque"] = "Opaque" extension: ExtensionId id: str # Unique identifier of the opaque type. - args: list[TypeArgUnion] + args: list[TypeArg] bound: TypeBound @@ -233,27 +262,21 @@ class Qubit(BaseModel): t: Literal["Q"] = "Q" -SimpleType = Annotated[ - Qubit - | Variable - | Int - | F64 - | String - | PolyFuncType - | List - | Array - | Tuple - | Sum - | Opaque, - Field(discriminator="t"), -] +Type = TypeAliasType( + "Type", + Annotated[ + Qubit | Variable | Int | PolyFuncType | Array | TupleType | Sum | Opaque, + Field(discriminator="t"), + WrapValidator(_json_custom_error_validator), + ], +) # ------------------------------------------- # --------------- TypeRow ------------------- # ------------------------------------------- -TypeRow = list[SimpleType] +TypeRow = list[Type] # ------------------------------------------- diff --git a/guppy/hugr/val.py b/guppy/hugr/val.py index 896c45c0..c59313b8 100644 --- a/guppy/hugr/val.py +++ b/guppy/hugr/val.py @@ -3,6 +3,7 @@ from typing import Annotated, Any, Literal from pydantic import BaseModel, Field +from typing_extensions import TypeAliasType CustomConst = Any # TODO @@ -39,7 +40,13 @@ class Sum(BaseModel): value: "Value" -Value = Annotated[ExtensionVal | FunctionVal | Tuple | Sum, Field(discriminator="v")] +Value = TypeAliasType( + "Value", + Annotated[ + ExtensionVal | FunctionVal | Tuple | Sum, + Field(discriminator="v"), + ], +) # Now that all classes are defined, we need to update the ForwardRefs in all type diff --git a/guppy/prelude/_internal.py b/guppy/prelude/_internal.py index 9f52593c..d9ee0b84 100644 --- a/guppy/prelude/_internal.py +++ b/guppy/prelude/_internal.py @@ -67,7 +67,7 @@ def float_value(f: float) -> val.Value: return val.ExtensionVal(c=(ConstF64(value=f),)) -def logic_op(op_name: str, args: list[tys.TypeArgUnion] | None = None) -> ops.OpType: +def logic_op(op_name: str, args: list[tys.TypeArg] | None = None) -> ops.OpType: """Utility method to create Hugr logic ops.""" return ops.CustomOp(extension="logic", op_name=op_name, args=args or []) diff --git a/poetry.lock b/poetry.lock index c265c99c..7616bebb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -542,28 +542,28 @@ files = [ [[package]] name = "ruff" -version = "0.1.11" +version = "0.1.12" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a7f772696b4cdc0a3b2e527fc3c7ccc41cdcb98f5c80fdd4f2b8c50eb1458196"}, - {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:934832f6ed9b34a7d5feea58972635c2039c7a3b434fe5ba2ce015064cb6e955"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea0d3e950e394c4b332bcdd112aa566010a9f9c95814844a7468325290aabfd9"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bd4025b9c5b429a48280785a2b71d479798a69f5c2919e7d274c5f4b32c3607"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ad00662305dcb1e987f5ec214d31f7d6a062cae3e74c1cbccef15afd96611d"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4b077ce83f47dd6bea1991af08b140e8b8339f0ba8cb9b7a484c30ebab18a23f"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a88efecec23c37b11076fe676e15c6cdb1271a38f2b415e381e87fe4517f18"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b25093dad3b055667730a9b491129c42d45e11cdb7043b702e97125bcec48a1"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231d8fb11b2cc7c0366a326a66dafc6ad449d7fcdbc268497ee47e1334f66f77"}, - {file = "ruff-0.1.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:09c415716884950080921dd6237767e52e227e397e2008e2bed410117679975b"}, - {file = "ruff-0.1.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f58948c6d212a6b8d41cd59e349751018797ce1727f961c2fa755ad6208ba45"}, - {file = "ruff-0.1.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:190a566c8f766c37074d99640cd9ca3da11d8deae2deae7c9505e68a4a30f740"}, - {file = "ruff-0.1.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6464289bd67b2344d2a5d9158d5eb81025258f169e69a46b741b396ffb0cda95"}, - {file = "ruff-0.1.11-py3-none-win32.whl", hash = "sha256:9b8f397902f92bc2e70fb6bebfa2139008dc72ae5177e66c383fa5426cb0bf2c"}, - {file = "ruff-0.1.11-py3-none-win_amd64.whl", hash = "sha256:eb85ee287b11f901037a6683b2374bb0ec82928c5cbc984f575d0437979c521a"}, - {file = "ruff-0.1.11-py3-none-win_arm64.whl", hash = "sha256:97ce4d752f964ba559c7023a86e5f8e97f026d511e48013987623915431c7ea9"}, - {file = "ruff-0.1.11.tar.gz", hash = "sha256:f9d4d88cb6eeb4dfe20f9f0519bd2eaba8119bde87c3d5065c541dbae2b5a2cb"}, + {file = "ruff-0.1.12-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:544038693543c11edc56bb94a9875df2dc249e3616f90c15964c720dcccf0745"}, + {file = "ruff-0.1.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8a0e3ef6299c4eab75a7740730e4b4bd4a36e0bd8102ded01553403cad088fd4"}, + {file = "ruff-0.1.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47f6d939461e3273f10f4cd059fd0b83c249d73f1736032fffbac83a62939395"}, + {file = "ruff-0.1.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25be18abc1fc3f3d3fb55855c41ed5d52063316defde202f413493bb3888218c"}, + {file = "ruff-0.1.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d41e9f100b50526d80b076fc9c103c729387ff3f10f63606ed1038c30a372a40"}, + {file = "ruff-0.1.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:472a0548738d4711549c7874b43fab61aacafb1fede29c5232d4cfb8e2d13f69"}, + {file = "ruff-0.1.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46685ef2f106b827705df876d38617741ed4f858bbdbc0817f94476c45ab6669"}, + {file = "ruff-0.1.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf6073749c70b616d7929897b14824ec6713a6c3a8195dfd2ffdcc66594d880c"}, + {file = "ruff-0.1.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bdf26e5a2efab4c3aaf6b61648ea47a525dc12775810a85c285dc9ca03e5ac0"}, + {file = "ruff-0.1.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b631c6a95e4b6d5c4299e599067b5a89f5b18e2f2d9a6c22b879b3c4b077c96e"}, + {file = "ruff-0.1.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f193f460e231e63af5fc7516897cf5ab257cbda72ae83cf9a654f1c80c3b758a"}, + {file = "ruff-0.1.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:718523c3a0b787590511f212d30cc9b194228ef369c8bdd72acd1282cc27c468"}, + {file = "ruff-0.1.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1c49e826de55d81a6ef93808b760925e492bad7cc470aaa114a3be158b2c7f99"}, + {file = "ruff-0.1.12-py3-none-win32.whl", hash = "sha256:fbb1c002eeacb60161e51d77b2274c968656599477a1c8c65066953276e8ee2b"}, + {file = "ruff-0.1.12-py3-none-win_amd64.whl", hash = "sha256:7fe06ba77e5b7b78db1d058478c47176810f69bb5be7c1b0d06876af59198203"}, + {file = "ruff-0.1.12-py3-none-win_arm64.whl", hash = "sha256:bb29f8e3e6c95024902eaec5a9ce1fd5ac4e77f4594f4554e67fbb0f6d9a2f37"}, + {file = "ruff-0.1.12.tar.gz", hash = "sha256:97189f38c655e573f6bea0d12e9f18aad5539fd08ab50651449450999f45383a"}, ] [[package]] @@ -627,4 +627,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "39bad245bee7bd6fb9aa376d1eb518909b55ccbe69b9463d31e3280cd0a8d3d2" +content-hash = "bead4d4f62358ea017cc9d615496d5561bff2cd28ecd35f57b438c8eb3afc728" diff --git a/pyproject.toml b/pyproject.toml index 8c9a9516..9818cbea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ graphviz = "^0.20.1" networkx = "^3.2.1" ormsgpack = "^1.4.1" pydantic = "^2.5.3" +typing-extensions = "^4.9.0" [tool.poetry.group.dev.dependencies] pytest = "^7.4.4" @@ -28,3 +29,6 @@ build-backend = "poetry.core.masonry.api" plugins = ["pydantic.mypy"] strict = true allow_redefinition = true +# mypy doesn't support TypeAliasType fully yet +# https://github.com/python/mypy/issues/16614 +disable_error_code = "valid-type" \ No newline at end of file diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/scripts/generate_schema.py b/scripts/generate_schema.py new file mode 100644 index 00000000..fb03b89e --- /dev/null +++ b/scripts/generate_schema.py @@ -0,0 +1,15 @@ +# dump json schema to a directory +# usage: python generate_schema.py +import json +import sys +from pathlib import Path + +from pydantic import TypeAdapter + +from guppy.hugr.raw import RawHugr + +if __name__ == "__main__": + out_dir = Path(sys.argv[-1]) + + with (out_dir / "hugr_schema_v0.json").open("w") as f: + json.dump(TypeAdapter(RawHugr).json_schema(), f)