diff --git a/cirq-core/cirq/__init__.py b/cirq-core/cirq/__init__.py index 41b160a4c44..65588f17ea6 100644 --- a/cirq-core/cirq/__init__.py +++ b/cirq-core/cirq/__init__.py @@ -604,7 +604,6 @@ JsonResolver, json_cirq_type, json_namespace, - json_serializable_dataclass, dataclass_json_dict, kraus, LabelEntity, diff --git a/cirq-core/cirq/protocols/__init__.py b/cirq-core/cirq/protocols/__init__.py index c568aa95682..ba3cd92fafc 100644 --- a/cirq-core/cirq/protocols/__init__.py +++ b/cirq-core/cirq/protocols/__init__.py @@ -65,7 +65,6 @@ DEFAULT_RESOLVERS, HasJSONNamespace, JsonResolver, - json_serializable_dataclass, json_cirq_type, json_namespace, to_json_gzip, diff --git a/cirq-core/cirq/protocols/json_serialization.py b/cirq-core/cirq/protocols/json_serialization.py index 757037edf24..bf411b17785 100644 --- a/cirq-core/cirq/protocols/json_serialization.py +++ b/cirq-core/cirq/protocols/json_serialization.py @@ -40,7 +40,6 @@ import sympy from typing_extensions import Protocol -from cirq._compat import deprecated, deprecated_parameter from cirq._doc import doc_private from cirq.type_workarounds import NotImplementedType @@ -148,23 +147,7 @@ def _json_namespace_(cls) -> str: pass -# TODO: remove once deprecated parameter goes away. -def _obj_to_dict_helper_helper(obj: Any, attribute_names: Iterable[str]) -> Dict[str, Any]: - d = {} - for attr_name in attribute_names: - d[attr_name] = getattr(obj, attr_name) - return d - - -@deprecated_parameter( - deadline='v0.15', - fix='Define obj._json_namespace_ to return namespace instead.', - parameter_desc='namespace', - match=lambda args, kwargs: 'namespace' in kwargs, -) -def obj_to_dict_helper( - obj: Any, attribute_names: Iterable[str], namespace: Optional[str] = None -) -> Dict[str, Any]: +def obj_to_dict_helper(obj: Any, attribute_names: Iterable[str]) -> Dict[str, Any]: """Construct a dictionary containing attributes from obj This is useful as a helper function in objects implementing the @@ -178,88 +161,15 @@ def obj_to_dict_helper( obj: A python object with attributes to be placed in the dictionary. attribute_names: The names of attributes to serve as keys in the resultant dictionary. The values will be the attribute values. - namespace: An optional prefix to the value associated with the - key "cirq_type". The namespace name will be joined with the - class name via a dot (.) """ d = {} - if namespace is not None: - d['cirq_type'] = f'{namespace}.' + obj.__class__.__name__ - d.update(_obj_to_dict_helper_helper(obj, attribute_names)) + for attr_name in attribute_names: + d[attr_name] = getattr(obj, attr_name) return d -# Copying the Python API, whose usage of `repr` annoys pylint. -# pylint: disable=redefined-builtin -@deprecated(deadline='v0.15', fix='Implement _json_dict_ using cirq.dataclass_json_dict()') -def json_serializable_dataclass( - _cls: Optional[Type] = None, - *, - namespace: Optional[str] = None, - init: bool = True, - repr: bool = True, - eq: bool = True, - order: bool = False, - unsafe_hash: bool = False, - frozen: bool = False, -): - """Create a dataclass that supports JSON serialization. - - This function defers to the ordinary ``dataclass`` decorator but appends - the ``_json_dict_`` protocol method which automatically determines - the appropriate fields from the dataclass. - - Dataclasses are implemented with somewhat complex metaprogramming, and - tooling (PyCharm, mypy) have special cases for dealing with classes - decorated with @dataclass. There is very little support (and no plans for - support) for decorators that wrap @dataclass like this. Consider explicitly - defining `_json_dict_` on your dataclasses which simply - `return dataclass_json_dict(self)`. - - Args: - _cls: The class to add JSON serializatin to. - namespace: An optional prefix to the value associated with the - key "cirq_type". The namespace name will be joined with the - class name via a dot (.) - init: Forwarded to the `dataclass` constructor. - repr: Forwarded to the `dataclass` constructor. - eq: Forwarded to the `dataclass` constructor. - order: Forwarded to the `dataclass` constructor. - unsafe_hash: Forwarded to the `dataclass` constructor. - frozen: Forwarded to the `dataclass` constructor. - """ - - def wrap(cls): - cls = dataclasses.dataclass( - cls, init=init, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen - ) - - cls._json_namespace_ = lambda: namespace - - cls._json_dict_ = lambda obj: obj_to_dict_helper( - obj, [f.name for f in dataclasses.fields(cls)] - ) - - return cls - - # _cls is used to deduce if we're being called as - # @json_serializable_dataclass or @json_serializable_dataclass(). - if _cls is None: - # We're called with parens. - return wrap - - # We're called as @dataclass without parens. - return wrap(_cls) - - # pylint: enable=redefined-builtin -@deprecated_parameter( - deadline='v0.15', - fix='Define obj._json_namespace_ to return namespace instead.', - parameter_desc='namespace', - match=lambda args, kwargs: 'namespace' in kwargs, -) -def dataclass_json_dict(obj: Any, namespace: str = None) -> Dict[str, Any]: +def dataclass_json_dict(obj: Any) -> Dict[str, Any]: """Return a dictionary suitable for _json_dict_ from a dataclass. Dataclasses keep track of their relevant fields, so we can automatically generate these. @@ -272,10 +182,7 @@ def dataclass_json_dict(obj: Any, namespace: str = None) -> Dict[str, Any]: dataclasses which simply `return dataclass_json_dict(self)`. """ attribute_names = [f.name for f in dataclasses.fields(obj)] - if namespace is not None: - return obj_to_dict_helper(obj, attribute_names, namespace=namespace) - else: - return _obj_to_dict_helper_helper(obj, attribute_names) + return obj_to_dict_helper(obj, attribute_names) def _json_dict_with_cirq_type(obj: Any): diff --git a/cirq-core/cirq/protocols/json_serialization_test.py b/cirq-core/cirq/protocols/json_serialization_test.py index 76883c56afb..fab73078f48 100644 --- a/cirq-core/cirq/protocols/json_serialization_test.py +++ b/cirq-core/cirq/protocols/json_serialization_test.py @@ -21,7 +21,7 @@ import pathlib import sys import warnings -from typing import ClassVar, Dict, List, Optional, Tuple, Type +from typing import Dict, List, Optional, Tuple, Type from unittest import mock import networkx as nx @@ -103,68 +103,6 @@ def custom_resolver(name): assert_json_roundtrip_works(HasOldJsonDict(), resolvers=test_resolvers) -def test_deprecated_obj_to_dict_helper_namespace(): - class HasOldJsonDict: - # Required for testing serialization of non-cirq objects. - __module__ = 'test.noncirq.namespace' # type: ignore - - def __init__(self, x): - self.x = x - - def __eq__(self, other): - return isinstance(other, HasOldJsonDict) and other.x == self.x - - def _json_dict_(self): - return json_serialization.obj_to_dict_helper( - self, ['x'], namespace='test.noncirq.namespace' - ) - - @classmethod - def _from_json_dict_(cls, x, **kwargs): - return cls(x) - - with pytest.raises(ValueError, match='not a Cirq type'): - _ = cirq.json_cirq_type(HasOldJsonDict) - - def custom_resolver(name): - if name == 'test.noncirq.namespace.HasOldJsonDict': - return HasOldJsonDict - - test_resolvers = [custom_resolver] + cirq.DEFAULT_RESOLVERS - with cirq.testing.assert_deprecated( - "Found 'cirq_type'", 'Define obj._json_namespace_', deadline='v0.15', count=3 - ): - assert_json_roundtrip_works(HasOldJsonDict(1), resolvers=test_resolvers) - - -def test_deprecated_dataclass_json_dict_namespace(): - @dataclasses.dataclass - class HasOldJsonDict: - # Required for testing serialization of non-cirq objects. - __module__: ClassVar = 'test.noncirq.namespace' # type: ignore - x: int - - def _json_dict_(self): - return json_serialization.dataclass_json_dict(self, namespace='test.noncirq.namespace') - - @classmethod - def _from_json_dict_(cls, x, **kwargs): - return cls(x) - - with pytest.raises(ValueError, match='not a Cirq type'): - _ = cirq.json_cirq_type(HasOldJsonDict) - - def custom_resolver(name): - if name == 'test.noncirq.namespace.HasOldJsonDict': - return HasOldJsonDict - - test_resolvers = [custom_resolver] + cirq.DEFAULT_RESOLVERS - with cirq.testing.assert_deprecated( - "Found 'cirq_type'", 'Define obj._json_namespace_', deadline='v0.15', count=5 - ): - assert_json_roundtrip_works(HasOldJsonDict(1), resolvers=test_resolvers) - - def test_line_qubit_roundtrip(): q1 = cirq.LineQubit(12) assert_json_roundtrip_works( @@ -829,59 +767,6 @@ def test_pathlib_paths(tmpdir): assert cirq.read_json_gzip(gzip_path) == cirq.X -def test_json_serializable_dataclass(): - with cirq.testing.assert_deprecated( - "Implement _json_dict_ using cirq.dataclass_json_dict()", deadline="v0.15" - ): - - @cirq.json_serializable_dataclass - class MyDC: - q: cirq.LineQubit - desc: str - - my_dc = MyDC(cirq.LineQubit(4), 'hi mom') - - def custom_resolver(name): - if name == 'MyDC': - return MyDC - - assert_json_roundtrip_works( - my_dc, - text_should_be="\n".join( - [ - '{', - ' "cirq_type": "MyDC",', - ' "q": {', - ' "cirq_type": "LineQubit",', - ' "x": 4', - ' },', - ' "desc": "hi mom"', - '}', - ] - ), - resolvers=[custom_resolver] + cirq.DEFAULT_RESOLVERS, - ) - - -def test_json_serializable_dataclass_parenthesis(): - with cirq.testing.assert_deprecated( - "Implement _json_dict_ using cirq.dataclass_json_dict()", deadline="v0.15" - ): - - @cirq.json_serializable_dataclass() - class MyDC: - q: cirq.LineQubit - desc: str - - def custom_resolver(name): - if name == 'MyDC': - return MyDC - - my_dc = MyDC(cirq.LineQubit(4), 'hi mom') - - assert_json_roundtrip_works(my_dc, resolvers=[custom_resolver] + cirq.DEFAULT_RESOLVERS) - - def test_dataclass_json_dict(): @dataclasses.dataclass(frozen=True) class MyDC: @@ -900,26 +785,6 @@ def custom_resolver(name): assert_json_roundtrip_works(my_dc, resolvers=[custom_resolver, *cirq.DEFAULT_RESOLVERS]) -def test_json_serializable_dataclass_namespace(): - with cirq.testing.assert_deprecated( - "Implement _json_dict_ using cirq.dataclass_json_dict()", deadline="v0.15" - ): - - @cirq.json_serializable_dataclass(namespace='cirq.experiments') - class QuantumVolumeParams: - width: int - depth: int - circuit_i: int - - qvp = QuantumVolumeParams(width=5, depth=5, circuit_i=0) - - def custom_resolver(name): - if name == 'cirq.experiments.QuantumVolumeParams': - return QuantumVolumeParams - - assert_json_roundtrip_works(qvp, resolvers=[custom_resolver] + cirq.DEFAULT_RESOLVERS) - - def test_numpy_values(): assert ( cirq.to_json({'value': np.array(1)})