Skip to content

Commit

Permalink
Attempt to compare pulser versions when abstract repr validation fails (
Browse files Browse the repository at this point in the history
#754)

* Attempt to compare pulser versions when abstract repr validation fails

* Protect against an invalid serialized version

* Allow pulser version in the JSON schema
  • Loading branch information
HGSilveri authored Oct 17, 2024
1 parent c6e9fbf commit c32b4bd
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"requires_layout": {
"description": "Whether the register used in the sequence must be created from a register layout. Only enforced in QPU execution.",
"type": "boolean"
Expand Down Expand Up @@ -335,6 +339,10 @@
"description": "The optimal fraction of a layout that should be filled with atoms.",
"type": "number"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"requires_layout": {
"description": "Whether the register used in the sequence must be created from a register layout. Only enforced in QPU execution.",
"type": "boolean"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"slug": {
"description": "An optional name for the layout.",
"type": "string"
Expand All @@ -54,6 +58,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"slug": {
"description": "An optional name for the layout.",
"type": "string"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@
"p_false_pos": {
"type": "number"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"relaxation_rate": {
"type": "number"
},
Expand Down
16 changes: 16 additions & 0 deletions pulser-core/pulser/json/abstract_repr/schemas/register-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"slug": {
"description": "An optional name for the layout.",
"type": "string"
Expand All @@ -94,6 +98,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"slug": {
"description": "An optional name for the layout.",
"type": "string"
Expand Down Expand Up @@ -125,6 +133,10 @@
"$ref": "#/definitions/Layout2D",
"description": "The trap layout underlying the register."
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"register": {
"description": "A 2D register containing a set of atoms.",
"items": {
Expand All @@ -145,6 +157,10 @@
"$ref": "#/definitions/Layout3D",
"description": "The trap layout underlying the register."
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"register": {
"description": "A 3D register containing a set of atoms.",
"items": {
Expand Down
20 changes: 20 additions & 0 deletions pulser-core/pulser/json/abstract_repr/schemas/sequence-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"slug": {
"description": "An optional name for the layout.",
"type": "string"
Expand All @@ -420,6 +424,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"slug": {
"description": "An optional name for the layout.",
"type": "string"
Expand Down Expand Up @@ -1013,6 +1021,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"register": {
"description": "A 2D register containing a set of atoms.",
"items": {
Expand Down Expand Up @@ -1110,6 +1122,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"register": {
"description": "A 3D register containing a set of atoms.",
"items": {
Expand Down Expand Up @@ -1207,6 +1223,10 @@
},
"type": "array"
},
"pulser_version": {
"description": "The pulser version used to serialize the object.",
"type": "string"
},
"register": {
"description": "A list of qubit IDs.",
"items": {
Expand Down
27 changes: 25 additions & 2 deletions pulser-core/pulser/json/abstract_repr/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@
from typing import Literal

import jsonschema
from packaging.version import InvalidVersion, Version
from referencing import Registry, Resource

import pulser
from pulser.json.abstract_repr import SCHEMAS, SCHEMAS_PATH
from pulser.json.exceptions import AbstractReprError

LEGACY_JSONSCHEMA = "4.18" > version("jsonschema") >= "4.17.3"
LEGACY_JSONSCHEMA = (
Version("4.18") > Version(version("jsonschema")) >= Version("4.17.3")
)

REGISTRY: Registry = Registry(
[
Expand Down Expand Up @@ -52,4 +57,22 @@ def validate_abstract_repr(
)
else: # pragma: no cover
validate_args["registry"] = REGISTRY
jsonschema.validate(**validate_args)
try:
jsonschema.validate(**validate_args)
except Exception as exc:
try:
ser_pulser_version = Version(obj.get("pulser_version", "0.0.0"))
except InvalidVersion:
# In case the serialized version is invalid
raise exc
if Version(pulser.__version__) < ser_pulser_version:
raise AbstractReprError(
"The provided object is invalid under the current abstract "
"representation schema. It appears it was serialized with a "
f"more recent version of pulser ({ser_pulser_version!s}) than "
f"the one currently being used ({pulser.__version__}). "
"It is possible validation failed because new features have "
"since been added; consider upgrading your pulser "
"installation and retrying."
) from exc
raise exc
1 change: 1 addition & 0 deletions pulser-core/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
jsonschema >= 4.17.3, < 5
referencing
matplotlib < 4
packaging # This is already required by matplotlib but we use it too
# Numpy 1.20 introduces type hints, 1.24.0 breaks matplotlib < 3.6.1
numpy >= 1.20, != 1.24.0, < 2
scipy < 2
17 changes: 17 additions & 0 deletions tests/test_abstract_repr.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import numpy as np
import pytest

import pulser
from pulser import Pulse, Register, Register3D, Sequence, devices
from pulser.channels import Rydberg
from pulser.channels.eom import RydbergBeam, RydbergEOM
Expand Down Expand Up @@ -575,6 +576,22 @@ def validate_schema(instance):
validate_abstract_repr(json.dumps(instance), "sequence")


def test_pulser_version_mismatch():
curr_ver = pulser.__version__
higher_ver = f"{int(curr_ver[0])+1}{curr_ver[1:]}"
obj_str = json.dumps({"pulser_version": higher_ver})
with pytest.raises(
AbstractReprError,
match="It is possible validation failed because new features have "
"since been added; consider upgrading your pulser "
"installation and retrying.",
):
validate_abstract_repr(obj_str, "device")
obj_str = json.dumps({"pulser_version": "bad_version"})
with pytest.raises(jsonschema.ValidationError):
validate_abstract_repr(obj_str, "device")


class TestSerialization:
@pytest.fixture
def triangular_lattice(self):
Expand Down

0 comments on commit c32b4bd

Please sign in to comment.