1
1
import json
2
2
import yaml
3
+ import bson
3
4
import sys
4
5
5
6
import numpy as np
23
24
24
25
from cattr .gen import make_dict_unstructure_fn , override
25
26
from cattr .preconf .pyyaml import make_converter as make_yaml_converter
27
+ from cattr .preconf .bson import make_converter as make_bson_converter
26
28
27
29
from tabulate import tabulate
28
30
@@ -72,7 +74,7 @@ def print_v(text: str):
72
74
# A setup an additional converter to apply when we are serializing using PyYAML.
73
75
# This handles things like tuples as lists.
74
76
yaml_converter = make_yaml_converter ()
75
-
77
+ bson_converter = make_bson_converter ()
76
78
77
79
# A simple converter that handles only value expressions.
78
80
value_expr_converter = cattr .Converter ()
@@ -104,6 +106,12 @@ def to_json(self) -> str:
104
106
"""
105
107
return json .dumps (self .to_dict (), indent = 4 )
106
108
109
+ def to_bson (self ) -> str :
110
+ """
111
+ Convert the Base object to a BSON string representation.
112
+ """
113
+ return bson .encode (self .to_dict ())
114
+
107
115
@classmethod
108
116
def from_dict (cls , d : Dict [str , Any ]) -> "Base" :
109
117
"""Instantiate an Base object from a dictionary"""
@@ -130,6 +138,11 @@ def from_json(cls, json_str: str) -> "Base":
130
138
"""Instantiate an modelspec object from a JSON string"""
131
139
return cls .from_dict (json .loads (json_str ))
132
140
141
+ @classmethod
142
+ def from_bson (cls , bson_str : str ) -> "Base" :
143
+ """Instantiate an modelspec object from a BSON string"""
144
+ return cls .from_dict (bson .decode (bson_str ))
145
+
133
146
def to_json_file (
134
147
self , filename : Optional [str ] = None , include_metadata : bool = True
135
148
) -> str :
@@ -155,6 +168,26 @@ def to_json_file(
155
168
156
169
return filename
157
170
171
+ def to_bson_file (self , filename : str , include_metadata : bool = True ) -> str :
172
+ """Convert modelspec format to bson format
173
+
174
+ Args:
175
+ filename: File in modelspec format (Filename extension: .bson )
176
+ include_metadata: Contains contact information, citations, acknowledgements, pointers to sample data,
177
+ benchmark results, and environments in which the specified model was originally implemented
178
+ Returns:
179
+ The name of the generated bson file
180
+ """
181
+
182
+ if filename is None :
183
+ filename = f"{ self .id } .bson"
184
+
185
+ with open (filename , "wb" ) as outfile :
186
+ bson_data = bson .encode (bson_converter .unstructure (self .to_dict ()),)
187
+ outfile .write (bson_data )
188
+
189
+ return filename
190
+
158
191
def to_yaml (self , include_metadata : bool = True ) -> str :
159
192
"""
160
193
Convert the Base object to a YAML dictionary representation.
@@ -211,6 +244,8 @@ def from_file(cls, filename: str) -> "Base":
211
244
return cls .from_yaml_file (filename )
212
245
elif filename .endswith (".json" ):
213
246
return cls .from_json_file (filename )
247
+ elif filename .endswith (".bson" ):
248
+ return cls .from_bson_file (filename )
214
249
else :
215
250
raise ValueError (
216
251
f"Cannot auto-detect modelspec serialization format from filename ({ filename } ). The filename "
@@ -232,6 +267,22 @@ def from_json_file(cls, filename: str) -> "Base":
232
267
d = json .load (infile )
233
268
return cls .from_dict (d )
234
269
270
+ @classmethod
271
+ def from_bson_file (cls , filename : str ) -> "Base" :
272
+ """
273
+ Create a :class:`.Base` from its BSON representation stored in a file.
274
+
275
+ Args:
276
+ filename: The file from which to load the BSON data.
277
+
278
+ Returns:
279
+ An modelspec :class:`.Base` for this BSON
280
+ """
281
+ with open (filename , "rb" ) as infile :
282
+ data_encoded = infile .read ()
283
+ d = bson .decode (data_encoded )
284
+ return cls .from_dict (d )
285
+
235
286
@classmethod
236
287
def from_yaml_file (cls , filename : str ) -> "Base" :
237
288
"""
@@ -615,13 +666,11 @@ def insert_links(text, format=MARKDOWN_FORMAT):
615
666
doc_dict [name ]["allowed_parameters" ][f ]["description" ] = description
616
667
617
668
elif format == MARKDOWN_FORMAT :
618
- doc_string += (
619
- "\n <tr>\n <td><b>{}</b></td>\n <td>{}</td>" .format (
620
- f ,
621
- f'<a href="#{ type_str .lower ()} ">{ type_str } </a>'
622
- if referencable
623
- else type_str ,
624
- )
669
+ doc_string += "\n <tr>\n <td><b>{}</b></td>\n <td>{}</td>" .format (
670
+ f ,
671
+ f'<a href="#{ type_str .lower ()} ">{ type_str } </a>'
672
+ if referencable
673
+ else type_str ,
625
674
)
626
675
doc_string += "\n <td><i>%s</i></td>\n </tr>\n \n " % (
627
676
insert_links (description )
@@ -676,13 +725,11 @@ def insert_links(text, format=MARKDOWN_FORMAT):
676
725
][0 ]
677
726
678
727
elif format == MARKDOWN_FORMAT :
679
- doc_string += (
680
- "\n <tr>\n <td><b>{}</b></td>\n <td>{}</td>" .format (
681
- c ,
682
- f'<a href="#{ type_str .lower ()} ">{ type_str } </a>'
683
- if referencable
684
- else type_str ,
685
- )
728
+ doc_string += "\n <tr>\n <td><b>{}</b></td>\n <td>{}</td>" .format (
729
+ c ,
730
+ f'<a href="#{ type_str .lower ()} ">{ type_str } </a>'
731
+ if referencable
732
+ else type_str ,
686
733
)
687
734
doc_string += "\n <td><i>%s</i></td>\n </tr>\n \n " % (
688
735
insert_links (description )
@@ -868,8 +915,7 @@ def _is_list_base(cl):
868
915
869
916
converter .register_unstructure_hook_factory (_is_list_base , _unstructure_list_base )
870
917
converter .register_unstructure_hook_factory (
871
- lambda cl : issubclass (cl , Base ),
872
- _base_unstruct_hook_factory ,
918
+ lambda cl : issubclass (cl , Base ), _base_unstruct_hook_factory ,
873
919
)
874
920
875
921
converter .register_structure_hook_factory (_is_list_base , _structure_list_base )
0 commit comments