-
Notifications
You must be signed in to change notification settings - Fork 8
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
feat!: Serialised extensions #1371
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1371 +/- ##
==========================================
- Coverage 87.71% 87.67% -0.05%
==========================================
Files 113 116 +3
Lines 20081 20270 +189
Branches 17815 17969 +154
==========================================
+ Hits 17615 17771 +156
- Misses 1691 1717 +26
- Partials 775 782 +7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
4a37118
to
4a3424a
Compare
hugr-core/src/extension/op_def.rs
Outdated
poly_func: PolyFuncTypeRV, | ||
#[serde(skip)] | ||
pub(crate) validate: Box<dyn ValidateTypeArgs>, | ||
pub(crate) validate: Option<Box<dyn ValidateTypeArgs>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If None
here means "no custom validation required" then agreed, but in that case let's rename (or even inline) struct CustomValidator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a rename or inline would be a breaking change, which certainly doesn't have to be
avoided but in this case I think just enough docstrings should do the trick?
I intend to pull out the CLI extension dumping in to a follow up PR. In this PR will test that serialisations of standard extensions validate against schema. In follow up will validate against schema when generating from CLI + store cli-generated extensions in source tree + add a test that running generation matches stored extensions (an update-extensions script for updating them). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far looks good! I haven't seen the problem(s) yet, although I was thinking perhaps adding a struct for Hugr+extensions, with a validate
method (maybe making a trait Validatable
would be a good start), might come first
/// A custom binary which computes a polymorphic function type given values | ||
/// for its static type parameters. | ||
CustomFunc(Box<dyn CustomSignatureFunc>), | ||
/// Declaration specified a custom binary but it was not provided. | ||
MissingComputeFunc, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about a missing custom validation func? In either case I think we just have to trust the cache, maybe with a warning, so I guess if the warning is the same then we don't have to distinguish, is that the plan?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure - in the case of missing validation function do you trust the cached signature or use the type scheme to generate the signature and check against cache as you would without custom validation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Given the validation function can only say one of two things - invalid, or use the type scheme - you can try the latter (which might reject if TypeArgs don't match the TypeParams, say) and see if that matches; that might get you an error, but even if the typescheme says ok, if there's a binary validation function that you haven't got, then that still has to be a warning
hugr-core/src/extension/op_def.rs
Outdated
/// If the type scheme is available explicitly, store it. | ||
signature: Option<PolyFuncTypeRV>, | ||
/// Whether an associated binary function is expected. | ||
/// If `signature` is `None`, a true value here indicates a custom compute function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, and good docs, ok, that makes sense
hugr-core/src/extension/op_def.rs
Outdated
{ | ||
let SerSignatureFunc { signature, .. } = SerSignatureFunc::deserialize(deserializer)?; | ||
|
||
// TODO for now, an indication of expected custom validation function is ignored. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok. Maybe just add a bool field in SignatureFunc::MissingComputeFunc (renaming to MissingFunc and using an enum rather than bool would be better)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've decided to capture missing validation explicitly.
hugr-core/src/extension/op_def.rs
Outdated
let SerSignatureFunc { signature, .. } = SerSignatureFunc::deserialize(deserializer)?; | ||
|
||
// TODO for now, an indication of expected custom validation function is ignored. | ||
Ok(if let Some(sig) = signature { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit - this is something like signature.map_or(MissingComputeFunc, super::SignatureFunc::From)
where the MissingComputeFunc
is the default for None
hugr-core/src/extension/op_def.rs
Outdated
fn static_params(&self) -> &[TypeParam] { | ||
match self { | ||
fn static_params(&self) -> Result<&[TypeParam], SignatureError> { | ||
Ok(match self { | ||
SignatureFunc::PolyFuncType(ts) => ts.poly_func.params(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aaiieeee is this one even correct? "static_params" are the ones to pass to binary compute_signature, so if there isn't such, I think this should be the empty list
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah I found these functions aren't actually used (therefore aren't tested...) will add an issue.
Edit: #1375
pub enum TypeDefBound { | ||
/// Defined by an explicit bound. | ||
Explicit(TypeBound), | ||
Explicit { bound: TypeBound }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably we will be able to stop doing these annoying renames-to-support serde when we have hugr-model
:)
Does a PR that just tackles "Extension+OpDef can state there is a binary compute_signature/validate function but we don't have it here" work on its own, and then enable separate/parallel follow-up PRs/threads of (a) serialization, cli, .... (b) remove opaqueop? |
18872f4
to
ee00843
Compare
hugr: Any | ||
|
||
|
||
class OpDef(ConfiguredBaseModel, populate_by_name=True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to extension.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes good call
4540dfd
to
6573761
Compare
…bility. BREAKING CHANGE: exernally tagged TypedDefBound serialisation will no longer work.
New "binary" field in serialisation may indicate that binary validation/computation functions are expected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice :). All major design considerations from earlier comments neatly addressed, thanks. Minor issues only, thanks!
(I think - if I'm barking up the wrong tree in places then feel free to ping me but I think you can probably take it from here)
hugr-core/src/extension/op_def.rs
Outdated
poly_func: PolyFuncTypeRV, | ||
#[serde(skip)] | ||
//Optional custom function for validating type arguments before returning the signature. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look very optional ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I'd started commenting in a different direction, but making this non-optional is a different way of doing what I was going to suggest, that works for me. Just correct the comment tho :)
hugr-core/src/extension/op_def.rs
Outdated
#[serde(skip)] | ||
/// An explicit polymorphic function type. | ||
PolyFuncType(PolyFuncTypeRV), | ||
/// A polymorphic function type with a custom binary for validating type arguments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we could slightly emphasize that this is mostly the same as the previous case but PLUS a custom binary
hugr-core/src/extension/op_def.rs
Outdated
} | ||
|
||
#[derive(PartialEq, Eq, Debug)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Methinks we should not need NoValidate
. One should use Signature::PolyFuncType
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, moved it just to the test that used it
hugr-core/src/extension/op_def.rs
Outdated
SignatureFunc::PolyFuncType(custom) => { | ||
custom.validate.validate(args, def, exts)?; | ||
SignatureFunc::CustomValidator(custom) => { | ||
custom.validate.as_ref().validate(args, def, exts)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
presumably this extra as_ref()
is needed? Code looks very similar to what we had before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wasn't needed, removed
// This is ruled out by `new()` but leave it here for later. | ||
SignatureFunc::CustomFunc(_) => None, | ||
SignatureFunc::CustomFunc(_) | SignatureFunc::MissingComputeFunc => None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect the comment on the previous line can go (I suspect "later" meant "when we have implemented serialization", essentially!), please clarify if I'm wrong
for (_, ext) in std_reg.into_iter() { | ||
let val = serde_json::to_value(ext).unwrap(); | ||
NamedSchema::check_schemas(&val, get_schemas(true)); | ||
// check deserialises correctly, can't check equality because of custom binaries. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However I think you could try reserializing the deserialized Extension to check equality with the original?
deserialize(serialize(ext)) != ext // because custom binaries
serialize(deserialize(serialize(ext))) == serialize(ext) // I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes nice thanks
@@ -26,6 +26,8 @@ repository = "https://github.com/CQCL/hugr" | |||
[tool.poetry.dependencies] | |||
python = ">=3.10" | |||
pydantic = ">=2.7,<2.9" | |||
pydantic-extra-types = "^2.9.0" | |||
semver = "^3.0.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: does this belong in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you added Rust semver in an earlier PR but didn't update the python, and tests added here reveal this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the earlier PR added versions to the rust struct, but there was not matching python model. This PR adds the python model, and with it the semver dependency for the python model.
return get_serialisation_version() | ||
|
||
@classmethod | ||
def _pydantic_rebuild(cls, config: pd.ConfigDict | None = None, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to comment why you need this for the uninitiated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
hugr: Any | ||
|
||
|
||
class OpDef(ConfiguredBaseModel, populate_by_name=True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes good call
## 🤖 New release * `hugr`: 0.10.0 -> 0.11.0 * `hugr-core`: 0.7.0 -> 0.8.0 * `hugr-passes`: 0.6.2 -> 0.7.0 * `hugr-cli`: 0.3.0 -> 0.4.0 <details><summary><i><b>Changelog</b></i></summary><p> ## `hugr` <blockquote> ## 0.11.0 (2024-08-12) ### Bug Fixes - [**breaking**] BasicBlockExits should not be `OpTag::DataflowParent` ([#1409](#1409)) ### Documentation - Clarify CustomConst::equal_consts ([#1396](#1396)) ### Features - [**breaking**] Serialised extensions ([#1371](#1371)) - Serialised standard extensions ([#1377](#1377)) - [**breaking**] Update remaining builder methods to "infer by default" ([#1386](#1386)) - Add Eq op to logic extension ([#1398](#1398)) - Improve error message on failed custom op validation ([#1416](#1416)) - [**breaking**] `Extension` requires a version ([#1367](#1367)) </blockquote> ## `hugr-core` <blockquote> ## 0.8.0 (2024-08-12) ### Bug Fixes - [**breaking**] BasicBlockExits should not be `OpTag::DataflowParent` ([#1409](#1409)) ### Documentation - Clarify CustomConst::equal_consts ([#1396](#1396)) ### Features - [**breaking**] `Extension` requires a version ([#1367](#1367)) - [**breaking**] Serialised extensions ([#1371](#1371)) - Serialised standard extensions ([#1377](#1377)) - [**breaking**] Update remaining builder methods to "infer by default" ([#1386](#1386)) - Add Eq op to logic extension ([#1398](#1398)) - Improve error message on failed custom op validation ([#1416](#1416)) </blockquote> ## `hugr-passes` <blockquote> ## 0.7.0 (2024-08-12) ### Features - [**breaking**] `Extension` requires a version ([#1367](#1367)) </blockquote> ## `hugr-cli` <blockquote> ## 0.4.0 (2024-08-12) ### Features - Serialised standard extensions ([#1377](#1377)) - Validate with extra extensions and packages ([#1389](#1389)) - [**breaking**] Move mermaid to own sub-command ([#1390](#1390)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/MarcoIeni/release-plz/). --------- Co-authored-by: Craig Roy <[email protected]>
🤖 I have created a release *beep* *boop* --- ## [0.6.0](hugr-py-v0.5.0...hugr-py-v0.6.0) (2024-08-12) ### ⚠ BREAKING CHANGES * **hugr-py:** Moved `hugr.get_serialization_version` to `hugr.serialization.serial_hugr.serialization_version` * **hugr-cli:** Cli validate command no longer has a mermaid option, use `mermaid` sub-command instead. * `TypeDefBound` uses struct-variants for serialization. `SignatureFunc` now has variants for missing binary functions, and serializes in to a new format that indicates expected binaries. ### Features * `Package` pydantic model for modules + extensions ([#1387](#1387)) ([68cfac5](68cfac5)), closes [#1358](#1358) * Define `Const` inline by default, and add a parameter to change the parent ([#1404](#1404)) ([3609736](3609736)) * **hugr-cli:** move mermaid to own sub-command ([#1390](#1390)) ([77795b9](77795b9)) * **hugr-py:** add type_bound method to `Type` ([#1410](#1410)) ([bd5ba47](bd5ba47)), closes [#1365](#1365) * **hugr-py:** Allow defining functions, consts, and aliases inside DFGs ([#1394](#1394)) ([d554072](d554072)) * **hugr-py:** Reexport commonly used classes from the package root ([#1393](#1393)) ([69925d0](69925d0)) * **py:** `Hugr.to_json` and `.load_json` helpers ([#1403](#1403)) ([e7f9f4c](e7f9f4c)) * **py:** Allow pre-declaring a `Function`'s output types ([#1417](#1417)) ([fa0f5a4](fa0f5a4)) * **py:** implement `iter` on `ToNode` ([#1399](#1399)) ([e88910b](e88910b)) * **py:** Parametric int type helper, and arbitrary width int constants ([#1406](#1406)) ([abd70c9](abd70c9)) * Serialised extensions ([#1371](#1371)) ([31be204](31be204)) ### Bug Fixes * **py:** `Hugr.__iter__` returning `NodeData | None` instead of `Node`s ([#1401](#1401)) ([c134584](c134584)) * **py:** Set output cont for Conditionals ([#1415](#1415)) ([67bb8a0](67bb8a0)) ### Documentation * **hugr-py:** expand toctree ([#1411](#1411)) ([aa81c9a](aa81c9a)) * **hugr-py:** remove multiversion + add justfile command ([#1381](#1381)) ([dd1dc48](dd1dc48)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Fear not the diff, mostly schema update.
SignatureFunc
serialisation to be compatible with this.SignatureFunc
reports this if they are missing, and it is up to the caller (typically validation) to decide how to recover from this.Closes #1360
Closes #1361
Addresses parts of #1228
Best reviewed as individual commits.
BREAKING CHANGE:
TypeDefBound
uses struct-variants for serialization.SignatureFunc
now has variants for missing binary functions, and serializes in to a new format that indicates expected binaries.