Source code for syside.json

  1"""
  2Convenience module intending to match the standard library ``json`` module.
  3"""
  4
  5from typing import overload
  6from warnings import warn
  7from dataclasses import dataclass
  8
  9from .. import core as syside
 10
 11
[docs] 12@dataclass 13class SerializationError(Exception): 14 """ 15 Error serializing element to SysML v2 JSON. 16 """ 17 18 report: syside.SerdeReport[syside.Element]
19 20
[docs] 21@dataclass 22class DeserializationError(Exception): 23 """ 24 Error serializing element to SysML v2 JSON. 25 """ 26 27 model: syside.DeserializedModel 28 report: syside.SerdeReport[syside.Element | str | syside.DocumentSegment]
29 30
[docs] 31class SerdeWarning(Warning): 32 """ 33 Class for warnings from serialization and deserialization 34 """
35 36
[docs] 37def dumps( 38 element: syside.Element, 39 options: syside.SerializationOptions, 40 indent: int = 2, 41 use_spaces: bool = True, 42 final_new_line: bool = True, 43 include_cross_ref_uris: bool = True, 44) -> str: 45 """ 46 Serialize ``element`` to a SysML v2 JSON ``str``. 47 48 See the documentation of the :py:class:`SerializationOptions 49 <syside.SerializationOptions>` class for documentation of the possible 50 options. The options object constructed with 51 :py:meth:`SerializationOptions.minimal 52 <syside.SerializationOptions.minimal>` instructs to produce a minimal JSON 53 without any redundant elements that results in significantly smaller JSONs. 54 Examples of redundant information that is avoided using minimal 55 configuration are: 56 57 + including fields for null values; 58 + including fields whose values match the default values; 59 + including redefined fields that are duplicates of redefining fields; 60 + including derived fields that can be computed from minimal JSON (for 61 example, the result value of evaluating an expression); 62 + including implied relationships. 63 64 .. note:: 65 66 SysIDE does not construct all derived properties yet. Therefore, setting 67 ``options.include_derived`` to ``True`` may result in a JSON that does 68 not satisfy the schema. 69 70 :param element: 71 The SysML v2 element to be serialized to SysML v2 JSON. 72 :param options: 73 The serialization options to use when serializing SysML v2 to JSON. 74 :param indent: 75 How many space or tab characters to use for indenting the JSON. 76 :param use_spaces: 77 Whether use spaces or tabs for indentation. 78 :param final_new_line: 79 Whether to add a newline character at the end of the generated string. 80 :param include_cross_ref_uris: 81 Whether to add potentially relative URIs as ``@uri`` property to 82 references of Elements from documents other than the one owning 83 ``element``. Note that while such references are non-standard, they 84 match the behaviour of XMI exports in Pilot implementation which use 85 relative URIs for references instead of plain element IDs. 86 :return: 87 ``element`` serialized as JSON. 88 """ 89 90 writer = syside.JsonStringWriter( 91 indent=indent, 92 use_spaces=use_spaces, 93 final_new_line=final_new_line, 94 include_cross_ref_uris=include_cross_ref_uris, 95 ) 96 97 report = syside.serialize(element, writer, options) 98 99 if not report: 100 raise SerializationError(report) 101 102 for msg in report.messages: 103 if msg.severity == syside.DiagnosticSeverity.Warning: 104 warn(msg.message, category=SerdeWarning, stacklevel=2) 105 106 return writer.result
107 108 109@overload 110def loads( 111 s: str, 112 document: syside.Document, 113 attributes: syside.AttributeMap | None = None, 114) -> syside.DeserializedModel: 115 """ 116 Deserialize a model from ``s`` into an already existing ``document``. 117 118 Root node will be inferred as: 119 120 1. The first ``Namespace`` (not subtype) without an owning relationship. 121 2. The first ``Element`` that has no serialized owning related element or owning relationship, 122 starting from the first element in the JSON array, and following owning elements up. 123 3. The first element in the array otherwise. 124 125 :param s: 126 The string contained serialized SysML model in JSON array. 127 :param document: 128 The document the model will be deserialized into. 129 :param attributes: 130 Attribute mapping of ``s``. If none provided, this will attempt to infer 131 a corresponding mapping or raise a ``ValueError``. 132 :return: 133 Model deserialized from JSON array. Note that references into other 134 documents will not be resolved, users will need to resolve them by 135 calling ``link`` on the returned model. See also :py:class:`IdMap 136 <syside.IdMap>`. 137 """ 138 139 140@overload 141def loads( 142 s: str, 143 document: syside.Url | str, 144 attributes: syside.AttributeMap | None = None, 145) -> tuple[syside.DeserializedModel, syside.SharedMutex[syside.Document]]: 146 """ 147 Create a new ``document`` and deserialize a model from ``s`` into it. 148 149 Root node will be inferred as: 150 151 1. The first ``Namespace`` (not subtype) without an owning relationship. 152 2. The first ``Element`` that has no serialized owning related element or owning relationship, 153 starting from the first element in the JSON array, and following owning elements up. 154 3. The first element in the array otherwise. 155 156 :param s: 157 The string contained serialized SysML model in JSON array. 158 :param document: 159 A URI in the form of :py:class:`Url <syside.Url>` or a string, new 160 document will be created with. If URI path has no extension, or the 161 extension does not match ``sysml`` or ``kerml``, ``ValueError`` is 162 raised. 163 :param attributes: 164 Attribute mapping of ``s``. If none provided, this will attempt to infer 165 a corresponding mapping or raise a ``ValueError``. 166 :return: 167 Model deserialized from JSON array and the newly created document. Note that 168 references into other documents will not be resolved, users will need to 169 resolve them by calling ``link`` on the returned model. See also 170 :py:class:`IdMap <syside.IdMap>`. 171 """ 172 173
[docs] 174def loads( 175 s: str, 176 document: syside.Document | syside.Url | str, 177 attributes: syside.AttributeMap | None = None, 178) -> ( 179 syside.DeserializedModel 180 | tuple[syside.DeserializedModel, syside.SharedMutex[syside.Document]] 181): 182 """loads implementation""" 183 reader = syside.JsonReader() 184 185 new_doc: syside.SharedMutex[syside.Document] | None = None 186 if isinstance(document, str): 187 document = syside.Url(document) 188 if isinstance(document, syside.Url): 189 ext = document.path.rsplit(".", 1)[-1].lower() 190 if ext == "sysml": 191 lang = syside.ModelLanguage.SysML 192 elif ext == "kerml": 193 lang = syside.ModelLanguage.KerML 194 else: 195 raise ValueError(f"Unknown document language, could not infer from '{ext}'") 196 new_doc = syside.Document.create_st(url=document, language=lang) 197 with new_doc.lock() as doc: 198 document = doc # appease pylint 199 200 with reader.bind(s) as json: 201 if attributes is None: 202 attributes = json.attribute_hint() 203 if attributes is None: 204 raise ValueError("Cannot deserialize model with unmapped attributes") 205 206 model, report = syside.deserialize(document, json, attributes) 207 208 if not report: 209 raise DeserializationError(model, report) 210 211 for msg in report.messages: 212 if msg.severity == syside.DiagnosticSeverity.Warning: 213 warn(msg.message, category=SerdeWarning, stacklevel=2) 214 215 if new_doc: 216 return model, new_doc 217 return model