@@ -128,6 +128,23 @@ def _json_dict_(self) -> Union[None, NotImplementedType, Dict[Any, Any]]:
128
128
pass
129
129
130
130
131
+ class HasJSONNamespace (Protocol ):
132
+ """An object which prepends a namespace to its JSON cirq_type.
133
+
134
+ Classes which implement this method have the following cirq_type format:
135
+
136
+ f"{obj._json_namespace_()}.{obj.__class__.__name__}
137
+
138
+ Classes outside of Cirq or its submodules MUST implement this method to be
139
+ used in type serialization.
140
+ """
141
+
142
+ @doc_private
143
+ @classmethod
144
+ def _json_namespace_ (cls ) -> str :
145
+ pass
146
+
147
+
131
148
def obj_to_dict_helper (
132
149
obj : Any , attribute_names : Iterable [str ], namespace : Optional [str ] = None
133
150
) -> Dict [str , Any ]:
@@ -350,13 +367,7 @@ def _cirq_object_hook(d, resolvers: Sequence[JsonResolver], context_map: Dict[st
350
367
if d ['cirq_type' ] == '_ContextualSerialization' :
351
368
return _ContextualSerialization .deserialize_with_context (** d )
352
369
353
- for resolver in resolvers :
354
- cls = resolver (d ['cirq_type' ])
355
- if cls is not None :
356
- break
357
- else :
358
- raise ValueError (f"Could not resolve type '{ d ['cirq_type' ]} ' during deserialization" )
359
-
370
+ cls = factory_from_json (d ['cirq_type' ], resolvers = resolvers )
360
371
from_json_dict = getattr (cls , '_from_json_dict_' , None )
361
372
if from_json_dict is not None :
362
373
return from_json_dict (** d )
@@ -505,6 +516,97 @@ def get_serializable_by_keys(obj: Any) -> List[SerializableByKey]:
505
516
return []
506
517
507
518
519
+ def json_namespace (type_obj : Type ) -> str :
520
+ """Returns a namespace for JSON serialization of `type_obj`.
521
+
522
+ Types can provide custom namespaces with `_json_namespace_`; otherwise, a
523
+ Cirq type will not include a namespace in its cirq_type. Non-Cirq types
524
+ must provide a namespace for serialization in Cirq.
525
+
526
+ Args:
527
+ type_obj: Type to retrieve the namespace from.
528
+
529
+ Returns:
530
+ The namespace to prepend `type_obj` with in its JSON cirq_type.
531
+
532
+ Raises:
533
+ ValueError: if `type_obj` is not a Cirq type and does not explicitly
534
+ define its namespace with _json_namespace_.
535
+ """
536
+ if hasattr (type_obj , '_json_namespace_' ):
537
+ return type_obj ._json_namespace_ ()
538
+ if type_obj .__module__ .startswith ('cirq' ):
539
+ return ''
540
+ raise ValueError (f'{ type_obj } is not a Cirq type, and does not define _json_namespace_.' )
541
+
542
+
543
+ def json_cirq_type (type_obj : Type ) -> str :
544
+ """Returns a string type for JSON serialization of `type_obj`.
545
+
546
+ This method is not part of the base serialization path. Together with
547
+ `cirq_type_from_json`, it can be used to provide type-object serialization
548
+ for classes that need it.
549
+ """
550
+ namespace = json_namespace (type_obj )
551
+ if namespace :
552
+ return f'{ namespace } .{ type_obj .__name__ } '
553
+ return type_obj .__name__
554
+
555
+
556
+ def factory_from_json (
557
+ type_str : str , resolvers : Optional [Sequence [JsonResolver ]] = None
558
+ ) -> ObjectFactory :
559
+ """Returns a factory for constructing objects of type `type_str`.
560
+
561
+ DEFAULT_RESOLVERS is updated dynamically as cirq submodules are imported.
562
+
563
+ Args:
564
+ type_str: string representation of the type to deserialize.
565
+ resolvers: list of JsonResolvers to use in type resolution. If this is
566
+ left blank, DEFAULT_RESOLVERS will be used.
567
+
568
+ Returns:
569
+ An ObjectFactory that can be called to construct an object whose type
570
+ matches the name `type_str`.
571
+
572
+ Raises:
573
+ ValueError: if type_str does not have a match in `resolvers`.
574
+ """
575
+ resolvers = resolvers if resolvers is not None else DEFAULT_RESOLVERS
576
+ for resolver in resolvers :
577
+ cirq_type = resolver (type_str )
578
+ if cirq_type is not None :
579
+ return cirq_type
580
+ raise ValueError (f"Could not resolve type '{ type_str } ' during deserialization" )
581
+
582
+
583
+ def cirq_type_from_json (type_str : str , resolvers : Optional [Sequence [JsonResolver ]] = None ) -> Type :
584
+ """Returns a type object for JSON deserialization of `type_str`.
585
+
586
+ This method is not part of the base deserialization path. Together with
587
+ `json_cirq_type`, it can be used to provide type-object deserialization
588
+ for classes that need it.
589
+
590
+ Args:
591
+ type_str: string representation of the type to deserialize.
592
+ resolvers: list of JsonResolvers to use in type resolution. If this is
593
+ left blank, DEFAULT_RESOLVERS will be used.
594
+
595
+ Returns:
596
+ The type object T for which json_cirq_type(T) matches `type_str`.
597
+
598
+ Raises:
599
+ ValueError: if type_str does not have a match in `resolvers`, or if the
600
+ match found is a factory method instead of a type.
601
+ """
602
+ cirq_type = factory_from_json (type_str , resolvers )
603
+ if isinstance (cirq_type , type ):
604
+ return cirq_type
605
+ # We assume that if factory_from_json returns a factory, there is not
606
+ # another resolver which resolves `type_str` to a type object.
607
+ raise ValueError (f"Type { type_str } maps to a factory method instead of a type." )
608
+
609
+
508
610
# pylint: disable=function-redefined
509
611
@overload
510
612
def to_json (
0 commit comments