From 14ab3876850874346c4f5369eb2a4c9698841a01 Mon Sep 17 00:00:00 2001 From: doug-q <141026920+doug-q@users.noreply.github.com> Date: Tue, 21 May 2024 09:33:36 +0100 Subject: [PATCH 1/2] chore: correct __version__ in hugr.py (#1085) --- hugr-py/src/hugr/__init__.py | 4 +++- hugr-py/tests/test_version.py | 16 ++++++++++++++++ poetry.lock | 15 +++++++++++++-- pyproject.toml | 1 + 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 hugr-py/tests/test_version.py diff --git a/hugr-py/src/hugr/__init__.py b/hugr-py/src/hugr/__init__.py index 807626cf0..7b63396f5 100644 --- a/hugr-py/src/hugr/__init__.py +++ b/hugr-py/src/hugr/__init__.py @@ -2,7 +2,9 @@ representation. """ -__version__ = "0.2.0a1" +# This is updated by our release-please workflow, triggered by this +# annotation: x-release-please-version +__version__ = "0.2.1" def it_works() -> str: diff --git a/hugr-py/tests/test_version.py b/hugr-py/tests/test_version.py new file mode 100644 index 000000000..ac9e154d6 --- /dev/null +++ b/hugr-py/tests/test_version.py @@ -0,0 +1,16 @@ +# from https://github.com/python-poetry/poetry/issues/144#issuecomment-877835259 +import toml # type: ignore[import-untyped] +from pathlib import Path +import hugr + + +def test_versions_are_in_sync(): + """Checks if the pyproject.toml and package.__init__.py __version__ are in sync.""" + + path = Path(__file__).resolve().parents[1] / "pyproject.toml" + pyproject = toml.loads(open(str(path)).read()) + pyproject_version = pyproject["tool"]["poetry"]["version"] + + package_init_version = hugr.__version__ + + assert package_init_version == pyproject_version diff --git a/poetry.lock b/poetry.lock index 77c94471d..24e529051 100644 --- a/poetry.lock +++ b/poetry.lock @@ -143,7 +143,7 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "hugr" -version = "0.1.0" +version = "0.2.1" description = "Quantinuum's common representation for quantum programs" optional = false python-versions = ">=3.10" @@ -565,6 +565,17 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + [[package]] name = "tomli" version = "2.0.1" @@ -610,4 +621,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "3904741f2d3fffd8b5ef03ab33de64905761fe0b07c70a7a4c151a8fb8981067" +content-hash = "487ddc7148ab4801c38871d976104e32eb884e91342ea1cdc05d2aa090489a0c" diff --git a/pyproject.toml b/pyproject.toml index 48eff6fa7..3138b5893 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ pytest = "^8.1.1" pytest-cov = "^4.1.0" mypy = "^1.9.0" ruff = "^0.3.3" +toml = "^0.10.0" [tool.poetry.group.hugr.dependencies] hugr = { path = "hugr-py", develop = true } From 52fcb9dc88e95e9660fc291181a37dc9d1802a3d Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Tue, 21 May 2024 10:13:46 +0100 Subject: [PATCH 2/2] fix(py): get rid of pydantic config deprecation warnings (#1084) add a test that triggers the warnings https://docs.pydantic.dev/2.7/migration/#changes-to-config --- hugr-py/src/hugr/serialization/ops.py | 36 ++++++++++--------- hugr-py/src/hugr/serialization/serial_hugr.py | 9 ++--- hugr-py/src/hugr/serialization/tys.py | 22 ++++++------ hugr-py/tests/serialization/test_basic.py | 15 ++++++-- 4 files changed, 46 insertions(+), 36 deletions(-) diff --git a/hugr-py/src/hugr/serialization/ops.py b/hugr-py/src/hugr/serialization/ops.py index 0c62bd108..af127bfbd 100644 --- a/hugr-py/src/hugr/serialization/ops.py +++ b/hugr-py/src/hugr/serialization/ops.py @@ -3,7 +3,7 @@ from abc import ABC from typing import Any, Literal -from pydantic import Field, RootModel +from pydantic import Field, RootModel, ConfigDict from . import tys from .tys import ( @@ -108,15 +108,14 @@ class SumValue(ConfiguredBaseModel): tag: int typ: SumType vs: list["Value"] - - class Config: - # Needed to avoid random '\n's in the pydantic description - json_schema_extra = { + model_config = ConfigDict( + json_schema_extra={ "description": ( "A Sum variant For any Sum type where this value meets the type " "of the variant indicated by the tag." ), } + ) class Value(RootModel): @@ -126,8 +125,7 @@ class Value(RootModel): discriminator="v" ) - class Config: - json_schema_extra = {"required": ["v"]} + model_config = ConfigDict(json_schema_extra={"required": ["v"]}) class Const(BaseOp): @@ -168,11 +166,13 @@ def insert_child_dfg_signature(self, inputs: TypeRow, outputs: TypeRow) -> None: self.sum_rows.append(variant) self.other_outputs = outputs[1:] - class Config: # Needed to avoid random '\n's in the pydantic description - json_schema_extra = { + + model_config = ConfigDict( + json_schema_extra={ "description": "A CFG basic block node. The signature is that of the internal Dataflow graph.", } + ) class ExitBlock(BaseOp): @@ -182,11 +182,12 @@ class ExitBlock(BaseOp): op: Literal["ExitBlock"] = "ExitBlock" cfg_outputs: TypeRow - class Config: - json_schema_extra = { + model_config = ConfigDict( + json_schema_extra={ # Needed to avoid random '\n's in the pydantic description "description": "The single exit node of the CFG, has no children, stores the types of the CFG node output.", } + ) # --------------------------------------------- @@ -234,9 +235,9 @@ class Call(DataflowOp): type_args: list[tys.TypeArg] instantiation: FunctionType - class Config: + model_config = ConfigDict( # Needed to avoid random '\n's in the pydantic description - json_schema_extra = { + json_schema_extra={ "description": ( "Operation to call a function directly. The first port is " "connected to the def/declare of the function being called directly, " @@ -244,6 +245,7 @@ class Config: "ports matches the function being called." ) } + ) class CallIndirect(DataflowOp): @@ -386,14 +388,15 @@ def insert_port_types(self, in_types: TypeRow, out_types: TypeRow) -> None: def display_name(self) -> str: return self.op_name - class Config: + model_config = ConfigDict( # Needed to avoid random '\n's in the pydantic description - json_schema_extra = { + json_schema_extra={ "description": ( "A user-defined operation that can be downcasted by the extensions that " "define it." ) } + ) class Noop(DataflowOp): @@ -491,8 +494,7 @@ class OpType(RootModel): | AliasDefn ) = Field(discriminator="op") - class Config: - json_schema_extra = {"required": ["parent", "op"]} + model_config = ConfigDict(json_schema_extra={"required": ["parent", "op"]}) # -------------------------------------- diff --git a/hugr-py/src/hugr/serialization/serial_hugr.py b/hugr-py/src/hugr/serialization/serial_hugr.py index 2928f4c93..49bfbd2f7 100644 --- a/hugr-py/src/hugr/serialization/serial_hugr.py +++ b/hugr-py/src/hugr/serialization/serial_hugr.py @@ -42,8 +42,9 @@ def _pydantic_rebuild(cls, config: ConfigDict = ConfigDict(), **kwargs): my_classes[cls.__name__] = cls model_rebuild(my_classes, config=config, **kwargs) - class Config: - title = "Hugr" - json_schema_extra = { + model_config = ConfigDict( + title="Hugr", + json_schema_extra={ "required": ["version", "nodes", "edges"], - } + }, + ) diff --git a/hugr-py/src/hugr/serialization/tys.py b/hugr-py/src/hugr/serialization/tys.py index 86078fc27..92942fd5d 100644 --- a/hugr-py/src/hugr/serialization/tys.py +++ b/hugr-py/src/hugr/serialization/tys.py @@ -99,8 +99,7 @@ class TypeParam(RootModel): WrapValidator(_json_custom_error_validator), ] = Field(discriminator="tp") - class Config: - json_schema_extra = {"required": ["tp"]} + model_config = ConfigDict(json_schema_extra={"required": ["tp"]}) # ------------------------------------------ @@ -153,8 +152,7 @@ class TypeArg(RootModel): WrapValidator(_json_custom_error_validator), ] = Field(discriminator="tya") - class Config: - json_schema_extra = {"required": ["tya"]} + model_config = ConfigDict(json_schema_extra={"required": ["tya"]}) # -------------------------------------------- @@ -197,8 +195,7 @@ class SumType(RootModel): def t(self) -> str: return self.root.t - class Config: - json_schema_extra = {"required": ["s"]} + model_config = ConfigDict(json_schema_extra={"required": ["s"]}) # ---------------------------------------------- @@ -235,14 +232,15 @@ class FunctionType(ConfiguredBaseModel): def empty(cls) -> "FunctionType": return FunctionType(input=[], output=[], extension_reqs=[]) - class Config: + model_config = ConfigDict( # Needed to avoid random '\n's in the pydantic description - json_schema_extra = { + json_schema_extra={ "description": ( "A graph encoded as a value. It contains a concrete signature and " "a set of required resources." ) } + ) class PolyFuncType(ConfiguredBaseModel): @@ -261,14 +259,15 @@ class PolyFuncType(ConfiguredBaseModel): def empty(cls) -> "PolyFuncType": return PolyFuncType(params=[], body=FunctionType.empty()) - class Config: + model_config = ConfigDict( # Needed to avoid random '\n's in the pydantic description - json_schema_extra = { + json_schema_extra={ "description": ( "A polymorphic type scheme, i.e. of a FuncDecl, FuncDefn or OpDef. " "(Nodes/operations in the Hugr are not polymorphic.)" ) } + ) class TypeBound(Enum): @@ -326,8 +325,7 @@ class Type(RootModel): Field(discriminator="t"), ] - class Config: - json_schema_extra = {"required": ["t"]} + model_config = ConfigDict(json_schema_extra={"required": ["t"]}) # ------------------------------------------- diff --git a/hugr-py/tests/serialization/test_basic.py b/hugr-py/tests/serialization/test_basic.py index e29fd40c0..5c3b41ace 100644 --- a/hugr-py/tests/serialization/test_basic.py +++ b/hugr-py/tests/serialization/test_basic.py @@ -1,3 +1,12 @@ -def test_it_works(): - """TODO: Replace this with a real test.""" - assert 2 + 2 != "🐟" +from hugr.serialization import SerialHugr + + +def test_empty(): + h = SerialHugr(nodes=[], edges=[]) + assert h.model_dump() == { + "version": "v1", + "nodes": [], + "edges": [], + "metadata": None, + "encoder": None, + }