44from collections import ChainMap
55from copy import deepcopy
66from datetime import datetime
7- from itertools import count
87from pathlib import Path
98from types import MappingProxyType
109from typing import Any , Dict , List , Optional , Tuple , Union
@@ -68,7 +67,7 @@ def __init__(
6867 self .root_schema = schema
6968 self .definitions = {}
7069 self .base_state = {
71- "__counter__" : count ( start = 1 ),
70+ "__counter__" : _PicklableCounter ( ),
7271 "__all_json_paths__" : [],
7372 "__depth__" : 0 ,
7473 ** initial_state ,
@@ -107,10 +106,16 @@ def from_json(
107106 """
108107 with open (path ) as f :
109108 return JSF (
110- json .load (f ), context , initial_state , allow_none_optionals , max_recursive_depth
109+ json .load (f ),
110+ context ,
111+ initial_state ,
112+ allow_none_optionals ,
113+ max_recursive_depth ,
111114 )
112115
113- def __parse_primitive (self , name : str , path : str , schema : Dict [str , Any ]) -> PrimitiveTypes :
116+ def __parse_primitive (
117+ self , name : str , path : str , schema : Dict [str , Any ]
118+ ) -> PrimitiveTypes :
114119 item_type , is_nullable = self .__is_field_nullable (schema )
115120 cls = Primitives .get (item_type )
116121 return cls .from_dict (
@@ -125,7 +130,11 @@ def __parse_primitive(self, name: str, path: str, schema: Dict[str, Any]) -> Pri
125130 )
126131
127132 def __parse_object (
128- self , name : str , path : str , schema : Dict [str , Any ], root : Optional [AllTypes ] = None
133+ self ,
134+ name : str ,
135+ path : str ,
136+ schema : Dict [str , Any ],
137+ root : Optional [AllTypes ] = None ,
129138 ) -> Object :
130139 _ , is_nullable = self .__is_field_nullable (schema )
131140 model = Object .from_dict (
@@ -142,20 +151,28 @@ def __parse_object(
142151 props = []
143152 for _name , definition in schema .get ("properties" , {}).items ():
144153 props .append (
145- self .__parse_definition (_name , path = f"{ path } /{ _name } " , schema = definition , root = root )
154+ self .__parse_definition (
155+ _name , path = f"{ path } /{ _name } " , schema = definition , root = root
156+ )
146157 )
147158 model .properties = props
148159 pattern_props = []
149160 for _name , definition in schema .get ("patternProperties" , {}).items ():
150161 pattern_props .append (
151- self .__parse_definition (_name , path = f"{ path } /{ _name } " , schema = definition , root = root )
162+ self .__parse_definition (
163+ _name , path = f"{ path } /{ _name } " , schema = definition , root = root
164+ )
152165 )
153166 model .patternProperties = pattern_props
154167
155168 return model
156169
157170 def __parse_array (
158- self , name : str , path : str , schema : Dict [str , Any ], root : Optional [AllTypes ] = None
171+ self ,
172+ name : str ,
173+ path : str ,
174+ schema : Dict [str , Any ],
175+ root : Optional [AllTypes ] = None ,
159176 ) -> Array :
160177 _ , is_nullable = self .__is_field_nullable (schema )
161178 arr = Array .from_dict (
@@ -169,11 +186,17 @@ def __parse_array(
169186 }
170187 )
171188 root = arr if root is None else root
172- arr .items = self .__parse_definition (name , f"{ path } /items" , schema ["items" ], root = root )
189+ arr .items = self .__parse_definition (
190+ name , f"{ path } /items" , schema ["items" ], root = root
191+ )
173192 return arr
174193
175194 def __parse_tuple (
176- self , name : str , path : str , schema : Dict [str , Any ], root : Optional [AllTypes ] = None
195+ self ,
196+ name : str ,
197+ path : str ,
198+ schema : Dict [str , Any ],
199+ root : Optional [AllTypes ] = None ,
177200 ) -> JSFTuple :
178201 _ , is_nullable = self .__is_field_nullable (schema )
179202 arr = JSFTuple .from_dict (
@@ -190,7 +213,9 @@ def __parse_tuple(
190213 arr .items = []
191214 for i , item in enumerate (schema ["items" ]):
192215 arr .items .append (
193- self .__parse_definition (name , path = f"{ path } /{ name } [{ i } ]" , schema = item , root = root )
216+ self .__parse_definition (
217+ name , path = f"{ path } /{ name } [{ i } ]" , schema = item , root = root
218+ )
194219 )
195220 return arr
196221
@@ -207,9 +232,15 @@ def __is_field_nullable(self, schema: Dict[str, Any]) -> Tuple[str, bool]:
207232 return item_type , False
208233
209234 def __parse_anyOf (
210- self , name : str , path : str , schema : Dict [str , Any ], root : Optional [AllTypes ] = None
235+ self ,
236+ name : str ,
237+ path : str ,
238+ schema : Dict [str , Any ],
239+ root : Optional [AllTypes ] = None ,
211240 ) -> AnyOf :
212- model = AnyOf (name = name , path = path , max_recursive_depth = self .max_recursive_depth , ** schema )
241+ model = AnyOf (
242+ name = name , path = path , max_recursive_depth = self .max_recursive_depth , ** schema
243+ )
213244 root = model if root is None else root
214245 schemas = []
215246 for d in schema ["anyOf" ]:
@@ -218,18 +249,32 @@ def __parse_anyOf(
218249 return model
219250
220251 def __parse_allOf (
221- self , name : str , path : str , schema : Dict [str , Any ], root : Optional [AllTypes ] = None
252+ self ,
253+ name : str ,
254+ path : str ,
255+ schema : Dict [str , Any ],
256+ root : Optional [AllTypes ] = None ,
222257 ) -> AllOf :
223258 combined_schema = dict (ChainMap (* schema ["allOf" ]))
224- model = AllOf (name = name , path = path , max_recursive_depth = self .max_recursive_depth , ** schema )
259+ model = AllOf (
260+ name = name , path = path , max_recursive_depth = self .max_recursive_depth , ** schema
261+ )
225262 root = model if root is None else root
226- model .combined_schema = self .__parse_definition (name , path , combined_schema , root = root )
263+ model .combined_schema = self .__parse_definition (
264+ name , path , combined_schema , root = root
265+ )
227266 return model
228267
229268 def __parse_oneOf (
230- self , name : str , path : str , schema : Dict [str , Any ], root : Optional [AllTypes ] = None
269+ self ,
270+ name : str ,
271+ path : str ,
272+ schema : Dict [str , Any ],
273+ root : Optional [AllTypes ] = None ,
231274 ) -> OneOf :
232- model = OneOf (name = name , path = path , max_recursive_depth = self .max_recursive_depth , ** schema )
275+ model = OneOf (
276+ name = name , path = path , max_recursive_depth = self .max_recursive_depth , ** schema
277+ )
233278 root = model if root is None else root
234279 schemas = []
235280 for d in schema ["oneOf" ]:
@@ -247,13 +292,20 @@ def __parse_named_definition(self, path: str, def_name: str, root) -> AllTypes:
247292 definition = schema .get (def_tag , {}).get (def_name )
248293 if definition is not None :
249294 parsed_definition = self .__parse_definition (
250- def_name , path = f"{ path } /#/{ def_tag } /{ def_name } " , schema = definition , root = root
295+ def_name ,
296+ path = f"{ path } /#/{ def_tag } /{ def_name } " ,
297+ schema = definition ,
298+ root = root ,
251299 )
252300 self .definitions [f"#/{ def_tag } /{ def_name } " ] = parsed_definition
253301 return parsed_definition
254302
255303 def __parse_definition (
256- self , name : str , path : str , schema : Dict [str , Any ], root : Optional [AllTypes ] = None
304+ self ,
305+ name : str ,
306+ path : str ,
307+ schema : Dict [str , Any ],
308+ root : Optional [AllTypes ] = None ,
257309 ) -> AllTypes :
258310 self .base_state ["__all_json_paths__" ].append (path )
259311 item_type , is_nullable = self .__is_field_nullable (schema )
@@ -264,7 +316,8 @@ def __parse_definition(
264316 enum_list = schema ["enum" ]
265317 assert len (enum_list ) > 0 , "Enum List is Empty"
266318 assert all (
267- isinstance (item , (int , float , str , dict , type (None ))) for item in enum_list
319+ isinstance (item , (int , float , str , dict , type (None )))
320+ for item in enum_list
268321 ), "Enum Type is not null, int, float, string or dict"
269322 return JSFEnum .from_dict (
270323 {
@@ -286,7 +339,9 @@ def __parse_definition(
286339 elif item_type == "object" and "oneOf" in schema :
287340 return self .__parse_oneOf (name , path , schema , root )
288341 elif item_type == "array" :
289- if (schema .get ("contains" ) is not None ) or isinstance (schema .get ("items" ), dict ):
342+ if (schema .get ("contains" ) is not None ) or isinstance (
343+ schema .get ("items" ), dict
344+ ):
290345 return self .__parse_array (name , path , schema , root )
291346 if isinstance (schema .get ("items" ), list ) and all (
292347 isinstance (x , dict ) for x in schema .get ("items" , [])
@@ -320,7 +375,9 @@ def __parse_definition(
320375 elif "oneOf" in schema :
321376 return self .__parse_oneOf (name , path , schema , root )
322377 elif not any (key in schema for key in ["not" , "if" , "then" , "else" ]):
323- return self .__parse_primitive (name , path , {** schema , "type" : list (Primitives .keys ())})
378+ return self .__parse_primitive (
379+ name , path , {** schema , "type" : list (Primitives .keys ())}
380+ )
324381 else :
325382 raise ValueError (f"Cannot parse schema { repr (schema )} " ) # pragma: no cover
326383
@@ -340,7 +397,11 @@ def context(self):
340397 return {** self .base_context , "state" : deepcopy (self .base_state )}
341398
342399 def generate (
343- self , n : Optional [int ] = None , * , use_defaults : bool = False , use_examples : bool = False
400+ self ,
401+ n : Optional [int ] = None ,
402+ * ,
403+ use_defaults : bool = False ,
404+ use_examples : bool = False ,
344405 ) -> Any :
345406 """Generates a fake object from the provided schema, and returns the
346407 output.
@@ -350,7 +411,11 @@ def generate(
350411 use_defaults (bool, optional): prefer the default value as defined in the schema over a randomly generated object. Defaults to False.
351412 use_examples (bool, optional): prefer an example as defined in the schema over a randomly generated object. This parameter is preceded by the `use_defaults` parameter if set. Defaults to False.
352413 """
353- context = {** self .context , "use_defaults" : use_defaults , "use_examples" : use_examples }
414+ context = {
415+ ** self .context ,
416+ "use_defaults" : use_defaults ,
417+ "use_examples" : use_examples ,
418+ }
354419 if n is None or n == 1 :
355420 return self .root .generate (context = context )
356421 return [self .root .generate (context = context ) for _ in range (n )]
@@ -371,3 +436,15 @@ def to_json(self, path: Path, **kwargs) -> None:
371436 output to the given path."""
372437 with open (path , "w" ) as f :
373438 json .dump (self .generate (), f , ** kwargs )
439+
440+
441+ class _PicklableCounter :
442+ def __init__ (self ):
443+ self ._counter = 0
444+
445+ def __iter__ (self ):
446+ return self
447+
448+ def __next__ (self ):
449+ self ._counter += 1
450+ return self ._counter
0 commit comments