Skip to content

Commit

Permalink
Add json serialization support that is compatible with Cirq (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
NoureldinYosri authored Mar 5, 2025
2 parents 5158d08 + 20440f6 commit 1dbcd8d
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 2 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,10 @@ jobs:
- name: pytest
run: ci/pytest_unit.sh

- name: perf
- name: test performance
run: ci/pytest_perf.sh

- name: test compatibility with Cirq
run: |
pip install cirq-core
pytest test/* -m cirq
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ requires = ["setuptools", "wheel", "Cython"]
testpaths = [
"test",
"test_perf",
]
]
markers = [
"cirq: mark a test as a compatibility test with Cirq.",
]
addopts = '-m "not cirq"'
43 changes: 43 additions & 0 deletions test/cirq_compatibility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright 2025 The TUnits Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest
import tunits as tu
import cirq # type: ignore


@pytest.mark.cirq
def test_to_json() -> None:
assert (
cirq.to_json(tu.ns * 3)
== """{
"cirq_type": "tunits.Value",
"value": 3,
"unit": "ns"
}"""
)

assert (
cirq.to_json(tu.GHz * [1, 2, 3, -1])
== """{
"cirq_type": "tunits.ValueArray",
"value": [
1.0,
2.0,
3.0,
-1.0
],
"unit": "GHz"
}"""
)
5 changes: 5 additions & 0 deletions tunits/core/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ class WithUnit:
def __divmod__(self, other: Any) -> tuple[_NUMERICAL_TYPE_OR_ARRAY, 'WithUnit']: ...
def _value_class(self) -> type['Value']: ...
def _array_class(self) -> type['ValueArray']: ...
def _json_dict_(self) -> dict[str, Any]: ...
@classmethod
def _json_namespace_(cls) -> str: ...
@classmethod
def _from_json_dict_(cls: type[T], **kwargs: Any) -> T: ...

class Value(Generic[NumericalT], WithUnit, np.generic, SupportsIndex):
"""A floating-point value with associated units."""
Expand Down
11 changes: 11 additions & 0 deletions tunits/core/cython/with_unit.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,17 @@ cdef class WithUnit:
raise ValueError(f'{self} is not dimensionless')
return self.value_in_base_units()

def _json_dict_(self) -> dict[str, Any]:
return {"value": self.value, "unit": self.units}

@classmethod
def _json_namespace_(cls) -> str:
return "tunits"

@classmethod
def _from_json_dict_(cls, **kwargs):
return cls(kwargs["value"], kwargs["unit"])

_try_interpret_as_with_unit = None
_is_value_consistent_with_default_unit_database = None
def init_base_unit_functions(
Expand Down

0 comments on commit 1dbcd8d

Please sign in to comment.