model-bakery 1.19.2__py3-none-any.whl → 1.21.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of model-bakery might be problematic. Click here for more details.

model_bakery/__about__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.19.2"
1
+ __version__ = "1.21.0"
model_bakery/baker.py CHANGED
@@ -1,16 +1,9 @@
1
1
  import collections
2
+ from collections.abc import Callable, Iterator
2
3
  from os.path import dirname, join
3
4
  from typing import (
4
5
  Any,
5
- Callable,
6
- Dict,
7
6
  Generic,
8
- Iterator,
9
- List,
10
- Optional,
11
- Set,
12
- Type,
13
- Union,
14
7
  cast,
15
8
  overload,
16
9
  )
@@ -27,6 +20,7 @@ from django.db.models import (
27
20
  Model,
28
21
  OneToOneField,
29
22
  )
23
+ from django.db.models.fields import NOT_PROVIDED
30
24
  from django.db.models.fields.proxy import OrderWrt
31
25
  from django.db.models.fields.related import (
32
26
  ReverseManyToOneDescriptor as ForeignRelatedObjectsDescriptor,
@@ -65,20 +59,24 @@ mock_file_txt = join(dirname(__file__), "mock_file.txt")
65
59
  MAX_MANY_QUANTITY = 5
66
60
 
67
61
 
68
- def _valid_quantity(quantity: Optional[Union[str, int]]) -> bool:
62
+ def _valid_quantity(quantity: str | int | None) -> bool:
69
63
  return quantity is not None and (not isinstance(quantity, int) or quantity < 1)
70
64
 
71
65
 
72
- def seed(seed: Union[int, float, str, bytes, bytearray, None]) -> None:
66
+ def _is_auto_datetime_field(field: Field) -> bool:
67
+ return getattr(field, "auto_now_add", False) or getattr(field, "auto_now", False)
68
+
69
+
70
+ def seed(seed: int | float | str | bytes | bytearray | None) -> None:
73
71
  Baker.seed(seed)
74
72
 
75
73
 
76
74
  @overload
77
75
  def make(
78
- _model: Union[str, Type[M]],
76
+ _model: str | type[M],
79
77
  _quantity: None = None,
80
78
  make_m2m: bool = False,
81
- _save_kwargs: Optional[Dict] = None,
79
+ _save_kwargs: dict[str, Any] | None = None,
82
80
  _refresh_after_create: bool = False,
83
81
  _create_files: bool = False,
84
82
  _using: str = "",
@@ -89,29 +87,29 @@ def make(
89
87
 
90
88
  @overload
91
89
  def make(
92
- _model: Union[str, Type[M]],
90
+ _model: str | type[M],
93
91
  _quantity: int,
94
92
  make_m2m: bool = False,
95
- _save_kwargs: Optional[Dict] = None,
93
+ _save_kwargs: dict[str, Any] | None = None,
96
94
  _refresh_after_create: bool = False,
97
95
  _create_files: bool = False,
98
96
  _using: str = "",
99
97
  _bulk_create: bool = False,
100
- _fill_optional: Union[List[str], bool] = False,
98
+ _fill_optional: list[str] | bool = False,
101
99
  **attrs: Any,
102
- ) -> List[M]: ...
100
+ ) -> list[M]: ...
103
101
 
104
102
 
105
103
  def make(
106
104
  _model,
107
- _quantity: Optional[int] = None,
105
+ _quantity: int | None = None,
108
106
  make_m2m: bool = False,
109
- _save_kwargs: Optional[Dict] = None,
107
+ _save_kwargs: dict[str, Any] | None = None,
110
108
  _refresh_after_create: bool = False,
111
109
  _create_files: bool = False,
112
110
  _using: str = "",
113
111
  _bulk_create: bool = False,
114
- _fill_optional: Union[List[str], bool] = False,
112
+ _fill_optional: list[str] | bool = False,
115
113
  **attrs: Any,
116
114
  ):
117
115
  """Create a persisted instance from a given model its associated models.
@@ -146,32 +144,32 @@ def make(
146
144
 
147
145
  @overload
148
146
  def prepare(
149
- _model: Union[str, Type[M]],
147
+ _model: str | type[M],
150
148
  _quantity: None = None,
151
149
  _save_related: bool = False,
152
150
  _using: str = "",
153
- **attrs,
151
+ **attrs: Any,
154
152
  ) -> M: ...
155
153
 
156
154
 
157
155
  @overload
158
156
  def prepare(
159
- _model: Union[str, Type[M]],
157
+ _model: str | type[M],
160
158
  _quantity: int,
161
159
  _save_related: bool = False,
162
160
  _using: str = "",
163
- _fill_optional: Union[List[str], bool] = False,
164
- **attrs,
165
- ) -> List[M]: ...
161
+ _fill_optional: list[str] | bool = False,
162
+ **attrs: Any,
163
+ ) -> list[M]: ...
166
164
 
167
165
 
168
166
  def prepare(
169
- _model: Union[str, Type[M]],
170
- _quantity: Optional[int] = None,
167
+ _model: str | type[M],
168
+ _quantity: int | None = None,
171
169
  _save_related: bool = False,
172
170
  _using: str = "",
173
- _fill_optional: Union[List[str], bool] = False,
174
- **attrs,
171
+ _fill_optional: list[str] | bool = False,
172
+ **attrs: Any,
175
173
  ):
176
174
  """Create but do not persist an instance from a given model.
177
175
 
@@ -219,10 +217,10 @@ def prepare_recipe(
219
217
  class ModelFinder:
220
218
  """Encapsulates all the logic for finding a model to Baker."""
221
219
 
222
- _unique_models: Optional[Dict[str, Type[Model]]] = None
223
- _ambiguous_models: Optional[List[str]] = None
220
+ _unique_models: dict[str, type[Model]] | None = None
221
+ _ambiguous_models: list[str] | None = None
224
222
 
225
- def get_model(self, name: str) -> Type[Model]:
223
+ def get_model(self, name: str) -> type[Model]:
226
224
  """Get a model.
227
225
 
228
226
  Args:
@@ -246,7 +244,7 @@ class ModelFinder:
246
244
 
247
245
  return model
248
246
 
249
- def get_model_by_name(self, name: str) -> Optional[Type[Model]]:
247
+ def get_model_by_name(self, name: str) -> type[Model] | None:
250
248
  """Get a model by name.
251
249
 
252
250
  If a model with that name exists in more than one app, raises
@@ -257,13 +255,13 @@ class ModelFinder:
257
255
  if self._unique_models is None or self._ambiguous_models is None:
258
256
  self._populate()
259
257
 
260
- if name in cast(List, self._ambiguous_models):
258
+ if name in cast(list, self._ambiguous_models):
261
259
  raise AmbiguousModelName(
262
260
  f"{name.title()} is a model in more than one app. "
263
261
  'Use the form "app.model".'
264
262
  )
265
263
 
266
- return cast(Dict, self._unique_models).get(name)
264
+ return cast(dict, self._unique_models).get(name)
267
265
 
268
266
  def _populate(self) -> None:
269
267
  """Cache models for faster self._get_model."""
@@ -290,7 +288,7 @@ def is_iterator(value: Any) -> bool:
290
288
  return isinstance(value, collections.abc.Iterator)
291
289
 
292
290
 
293
- def _custom_baker_class() -> Optional[Type]:
291
+ def _custom_baker_class() -> type | None:
294
292
  """Return the specified custom baker class.
295
293
 
296
294
  Returns:
@@ -321,54 +319,54 @@ def _custom_baker_class() -> Optional[Type]:
321
319
  class Baker(Generic[M]):
322
320
  SENTINEL = object()
323
321
 
324
- attr_mapping: Dict[str, Any] = {}
325
- type_mapping: Dict = {}
322
+ attr_mapping: dict[str, Any] = {}
323
+ type_mapping: dict = {}
326
324
 
327
- _global_seed: Union[object, int, float, str, bytes, bytearray, None] = SENTINEL
325
+ _global_seed: object | int | float | str | bytes | bytearray | None = SENTINEL
328
326
 
329
327
  # Note: we're using one finder for all Baker instances to avoid
330
328
  # rebuilding the model cache for every make_* or prepare_* call.
331
329
  finder = ModelFinder()
332
330
 
333
331
  @classmethod
334
- def seed(cls, seed: Union[int, float, str, bytes, bytearray, None]) -> None:
332
+ def seed(cls, seed: int | float | str | bytes | bytearray | None) -> None:
335
333
  random_gen.baker_random.seed(seed)
336
334
  cls._global_seed = seed
337
335
 
338
336
  @classmethod
339
337
  def create(
340
338
  cls,
341
- _model: Union[str, Type[NewM]],
339
+ _model: str | type[NewM],
342
340
  make_m2m: bool = False,
343
341
  create_files: bool = False,
344
342
  _using: str = "",
345
343
  ) -> "Baker[NewM]":
346
344
  """Create the baker class defined by the `BAKER_CUSTOM_CLASS` setting."""
347
345
  baker_class = _custom_baker_class() or cls
348
- return cast(Type[Baker[NewM]], baker_class)(
346
+ return cast(type[Baker[NewM]], baker_class)(
349
347
  _model, make_m2m, create_files, _using=_using
350
348
  )
351
349
 
352
350
  def __init__(
353
351
  self,
354
- _model: Union[str, Type[M]],
352
+ _model: str | type[M],
355
353
  make_m2m: bool = False,
356
354
  create_files: bool = False,
357
355
  _using: str = "",
358
356
  ) -> None:
359
357
  self.make_m2m = make_m2m
360
358
  self.create_files = create_files
361
- self.m2m_dict: Dict[str, List] = {}
362
- self.iterator_attrs: Dict[str, Iterator] = {}
363
- self.model_attrs: Dict[str, Any] = {}
364
- self.rel_attrs: Dict[str, Any] = {}
365
- self.rel_fields: List[str] = []
359
+ self.m2m_dict: dict[str, list] = {}
360
+ self.iterator_attrs: dict[str, Iterator] = {}
361
+ self.model_attrs: dict[str, Any] = {}
362
+ self.rel_attrs: dict[str, Any] = {}
363
+ self.rel_fields: list[str] = []
366
364
  self._using = _using
367
365
 
368
366
  if isinstance(_model, str):
369
- self.model = cast(Type[M], self.finder.get_model(_model))
367
+ self.model = cast(type[M], self.finder.get_model(_model))
370
368
  else:
371
- self.model = cast(Type[M], _model)
369
+ self.model = cast(type[M], _model)
372
370
 
373
371
  self.init_type_mapping()
374
372
 
@@ -382,10 +380,10 @@ class Baker(Generic[M]):
382
380
 
383
381
  def make(
384
382
  self,
385
- _save_kwargs: Optional[Dict[str, Any]] = None,
383
+ _save_kwargs: dict[str, Any] | None = None,
386
384
  _refresh_after_create: bool = False,
387
385
  _from_manager=None,
388
- _fill_optional: Union[List[str], bool] = False,
386
+ _fill_optional: list[str] | bool = False,
389
387
  **attrs: Any,
390
388
  ):
391
389
  """Create and persist an instance of the model associated with Baker instance."""
@@ -403,7 +401,7 @@ class Baker(Generic[M]):
403
401
  def prepare(
404
402
  self,
405
403
  _save_related=False,
406
- _fill_optional: Union[List[str], bool] = False,
404
+ _fill_optional: list[str] | bool = False,
407
405
  **attrs: Any,
408
406
  ) -> M:
409
407
  """Create, but do not persist, an instance of the associated model."""
@@ -415,7 +413,7 @@ class Baker(Generic[M]):
415
413
  params.update(attrs)
416
414
  return self._make(**params)
417
415
 
418
- def get_fields(self) -> Set[Any]:
416
+ def get_fields(self) -> set[Any]:
419
417
  return set(self.model._meta.get_fields()) - set(
420
418
  self.model._meta.related_objects
421
419
  )
@@ -489,7 +487,7 @@ class Baker(Generic[M]):
489
487
 
490
488
  return instance
491
489
 
492
- def m2m_value(self, field: ManyToManyField) -> List[Any]:
490
+ def m2m_value(self, field: ManyToManyField) -> list[Any]:
493
491
  if field.name in self.rel_fields:
494
492
  return self.generate_value(field)
495
493
  if not self.make_m2m or field.null and not field.fill_optional:
@@ -497,7 +495,7 @@ class Baker(Generic[M]):
497
495
  return self.generate_value(field)
498
496
 
499
497
  def instance(
500
- self, attrs: Dict[str, Any], _commit, _save_kwargs, _from_manager
498
+ self, attrs: dict[str, Any], _commit, _save_kwargs, _from_manager
501
499
  ) -> M:
502
500
  one_to_many_keys = {}
503
501
  auto_now_keys = {}
@@ -512,10 +510,7 @@ class Baker(Generic[M]):
512
510
  if isinstance(field, ForeignRelatedObjectsDescriptor):
513
511
  one_to_many_keys[k] = attrs.pop(k)
514
512
 
515
- if hasattr(field, "field") and (
516
- getattr(field.field, "auto_now_add", False)
517
- or getattr(field.field, "auto_now", False)
518
- ):
513
+ if hasattr(field, "field") and _is_auto_datetime_field(field.field):
519
514
  auto_now_keys[k] = attrs[k]
520
515
 
521
516
  if BAKER_CONTENTTYPES and isinstance(field, GenericForeignKey):
@@ -523,6 +518,7 @@ class Baker(Generic[M]):
523
518
  "value": attrs.pop(k),
524
519
  "content_type_field": field.ct_field,
525
520
  "object_id_field": field.fk_field,
521
+ "for_concrete_model": field.for_concrete_model,
526
522
  }
527
523
 
528
524
  instance = self.model(**attrs)
@@ -546,7 +542,7 @@ class Baker(Generic[M]):
546
542
  return instance
547
543
 
548
544
  def create_by_related_name(
549
- self, instance: Model, related: Union[ManyToOneRel, OneToOneRel]
545
+ self, instance: Model, related: ManyToOneRel | OneToOneRel
550
546
  ) -> None:
551
547
  rel_name = related.get_accessor_name()
552
548
  if not rel_name or rel_name not in self.rel_fields:
@@ -557,7 +553,7 @@ class Baker(Generic[M]):
557
553
 
558
554
  make(related.field.model, **kwargs)
559
555
 
560
- def _clean_attrs(self, attrs: Dict[str, Any]) -> None:
556
+ def _clean_attrs(self, attrs: dict[str, Any]) -> None:
561
557
  def is_rel_field(x: str):
562
558
  return "__" in x
563
559
 
@@ -638,13 +634,18 @@ class Baker(Generic[M]):
638
634
 
639
635
  return False
640
636
 
641
- def _handle_auto_now(self, instance: Model, attrs: Dict[str, Any]):
637
+ def _handle_auto_now(self, instance: Model, attrs: dict[str, Any]):
642
638
  if not attrs:
643
639
  return
644
640
 
641
+ # use .update() to force update auto_now fields
645
642
  instance.__class__.objects.filter(pk=instance.pk).update(**attrs)
646
643
 
647
- def _handle_one_to_many(self, instance: Model, attrs: Dict[str, Any]):
644
+ # to make the resulting instance has the specified values
645
+ for k, v in attrs.items():
646
+ setattr(instance, k, v)
647
+
648
+ def _handle_one_to_many(self, instance: Model, attrs: dict[str, Any]):
648
649
  for key, values in attrs.items():
649
650
  manager = getattr(instance, key)
650
651
 
@@ -692,26 +693,38 @@ class Baker(Generic[M]):
692
693
  }
693
694
  make(through_model, _using=self._using, **base_kwargs)
694
695
 
695
- def _handle_generic_foreign_keys(self, instance: Model, attrs: Dict[str, Any]):
696
+ def _handle_generic_foreign_keys(self, instance: Model, attrs: dict[str, Any]):
696
697
  """Set content type and object id for GenericForeignKey fields."""
697
698
  for field_name, data in attrs.items():
698
- content_type_field = data["content_type_field"]
699
- object_id_field = data["object_id_field"]
699
+ ct_field_name = data["content_type_field"]
700
+ oid_field_name = data["object_id_field"]
700
701
  value = data["value"]
702
+ if callable(value):
703
+ value = value()
701
704
  if is_iterator(value):
702
705
  value = next(value)
703
-
704
- setattr(instance, field_name, value)
705
- setattr(
706
- instance,
707
- content_type_field,
708
- contenttypes_models.ContentType.objects.get_for_model(value),
709
- )
710
- setattr(instance, object_id_field, value.pk)
706
+ if value is None:
707
+ # when GFK is None, we should try to set the content type and object id to None
708
+ content_type_field = instance._meta.get_field(ct_field_name)
709
+ object_id_field = instance._meta.get_field(oid_field_name)
710
+ if content_type_field.null:
711
+ setattr(instance, ct_field_name, None)
712
+ if object_id_field.null:
713
+ setattr(instance, oid_field_name, None)
714
+ else:
715
+ setattr(instance, field_name, value)
716
+ setattr(
717
+ instance,
718
+ ct_field_name,
719
+ contenttypes_models.ContentType.objects.get_for_model(
720
+ value, for_concrete_model=data["for_concrete_model"]
721
+ ),
722
+ )
723
+ setattr(instance, oid_field_name, value.pk)
711
724
 
712
725
  def _remote_field(
713
- self, field: Union[ForeignKey, OneToOneField]
714
- ) -> Union[OneToOneRel, ManyToOneRel]:
726
+ self, field: ForeignKey | OneToOneField
727
+ ) -> OneToOneRel | ManyToOneRel:
715
728
  return field.remote_field
716
729
 
717
730
  def generate_value(self, field: Field, commit: bool = True) -> Any: # noqa: C901
@@ -719,6 +732,7 @@ class Baker(Generic[M]):
719
732
 
720
733
  Generator Resolution Precedence Order:
721
734
  -- `field.default` - model field default value, unless explicitly overwritten during baking
735
+ -- `field.db_default` - model field db default value, unless explicitly overwritten
722
736
  -- `attr_mapping` - mapping per attribute name
723
737
  -- `choices` -- mapping from available field choices
724
738
  -- `type_mapping` - mapping from user defined type associated generators
@@ -742,10 +756,14 @@ class Baker(Generic[M]):
742
756
  if callable(field.default):
743
757
  return field.default()
744
758
  return field.default
759
+ elif getattr(field, "db_default", NOT_PROVIDED) != NOT_PROVIDED:
760
+ return field.db_default
745
761
  elif field.name in self.attr_mapping:
746
762
  generator = self.attr_mapping[field.name]
747
763
  elif field.choices:
748
- generator = random_gen.gen_from_choices(field.choices)
764
+ generator = random_gen.gen_from_choices(
765
+ field.choices, nullable=field.null, blankable=field.blank
766
+ )
749
767
  elif is_content_type_fk:
750
768
  generator = self.type_mapping[contenttypes_models.ContentType]
751
769
  elif generators.get(field.__class__):
@@ -780,14 +798,14 @@ class Baker(Generic[M]):
780
798
 
781
799
  def get_required_values(
782
800
  generator: Callable, field: Field
783
- ) -> Dict[str, Union[bool, int, str, List[Callable]]]:
801
+ ) -> dict[str, bool | int | str | list[Callable]]:
784
802
  """Get required values for a generator from the field.
785
803
 
786
804
  If required value is a function, calls it with field as argument. If
787
805
  required value is a string, simply fetch the value from the field
788
806
  and return.
789
807
  """
790
- required_values = {} # type: Dict[str, Any]
808
+ required_values = {} # type: dict[str, Any]
791
809
  if hasattr(generator, "required"):
792
810
  for item in generator.required: # type: ignore[attr-defined]
793
811
  if callable(item): # baker can deal with the nasty hacking too!
@@ -805,7 +823,7 @@ def get_required_values(
805
823
  return required_values
806
824
 
807
825
 
808
- def filter_rel_attrs(field_name: str, **rel_attrs) -> Dict[str, Any]:
826
+ def filter_rel_attrs(field_name: str, **rel_attrs) -> dict[str, Any]:
809
827
  clean_dict = {}
810
828
 
811
829
  for k, v in rel_attrs.items():
@@ -841,7 +859,7 @@ def _save_related_objs(model, objects, _using=None) -> None:
841
859
  setattr(objects[i], fk.name, fk_obj)
842
860
 
843
861
 
844
- def bulk_create(baker: Baker[M], quantity: int, **kwargs) -> List[M]:
862
+ def bulk_create(baker: Baker[M], quantity: int, **kwargs) -> list[M]:
845
863
  """
846
864
  Bulk create entries and all related FKs as well.
847
865
 
@@ -1,5 +1,6 @@
1
+ from collections.abc import Callable
1
2
  from decimal import Decimal
2
- from typing import Any, Callable, Dict, Optional, Type, Union
3
+ from typing import Any
3
4
 
4
5
  from django.db.backends.base.operations import BaseDatabaseOperations
5
6
  from django.db.models import (
@@ -108,7 +109,7 @@ default_mapping = {
108
109
  DecimalField: random_gen.gen_decimal,
109
110
  BinaryField: random_gen.gen_byte_string,
110
111
  CharField: random_gen.gen_string,
111
- TextField: random_gen.gen_text,
112
+ TextField: random_gen.gen_string,
112
113
  SlugField: random_gen.gen_slug,
113
114
  UUIDField: random_gen.gen_uuid,
114
115
  DateField: random_gen.gen_date,
@@ -122,7 +123,7 @@ default_mapping = {
122
123
  ImageField: random_gen.gen_image_field,
123
124
  DurationField: random_gen.gen_interval,
124
125
  JSONField: random_gen.gen_json,
125
- } # type: Dict[Type, Callable]
126
+ } # type: dict[type, Callable]
126
127
 
127
128
  if ArrayField:
128
129
  default_mapping[ArrayField] = random_gen.gen_array
@@ -133,7 +134,7 @@ if CICharField:
133
134
  if CIEmailField:
134
135
  default_mapping[CIEmailField] = random_gen.gen_email
135
136
  if CITextField:
136
- default_mapping[CITextField] = random_gen.gen_text
137
+ default_mapping[CITextField] = random_gen.gen_string
137
138
  if DecimalRangeField:
138
139
  default_mapping[DecimalRangeField] = random_gen.gen_pg_numbers_range(Decimal)
139
140
  if IntegerRangeField:
@@ -149,7 +150,7 @@ if DateTimeRangeField:
149
150
  # Add GIS fields
150
151
 
151
152
 
152
- def get_type_mapping() -> Dict[Type, Callable]:
153
+ def get_type_mapping() -> dict[type, Callable]:
153
154
  from .content_types import default_contenttypes_mapping
154
155
  from .gis import default_gis_mapping
155
156
 
@@ -162,9 +163,9 @@ def get_type_mapping() -> Dict[Type, Callable]:
162
163
  user_mapping = {}
163
164
 
164
165
 
165
- def add(field: str, func: Optional[Union[Callable, str]]) -> None:
166
+ def add(field: str, func: Callable | str | None) -> None:
166
167
  user_mapping[import_from_str(field)] = import_from_str(func)
167
168
 
168
169
 
169
- def get(field: Any) -> Optional[Callable]:
170
+ def get(field: Any) -> Callable | None:
170
171
  return user_mapping.get(field)
@@ -11,11 +11,12 @@ argument.
11
11
 
12
12
  import string
13
13
  import warnings
14
+ from collections.abc import Callable
14
15
  from datetime import date, datetime, time, timedelta
15
16
  from decimal import Decimal
16
17
  from os.path import abspath, dirname, join
17
18
  from random import Random
18
- from typing import Any, Callable, List, Optional, Tuple, Union
19
+ from typing import Any
19
20
  from uuid import UUID
20
21
 
21
22
  from django.core.files.base import ContentFile
@@ -48,7 +49,7 @@ def gen_image_field() -> ContentFile:
48
49
  return get_content_file(f.read(), name=name)
49
50
 
50
51
 
51
- def gen_from_list(a_list: Union[List[str], range]) -> Callable:
52
+ def gen_from_list(a_list: list[str] | range) -> Callable:
52
53
  """Make sure all values of the field are generated from a list.
53
54
 
54
55
  Examples:
@@ -65,14 +66,22 @@ def gen_from_list(a_list: Union[List[str], range]) -> Callable:
65
66
  # -- DEFAULT GENERATORS --
66
67
 
67
68
 
68
- def gen_from_choices(choices: List) -> Callable:
69
+ def gen_from_choices(
70
+ choices: list, nullable: bool = True, blankable: bool = True
71
+ ) -> Callable:
69
72
  choice_list = []
70
73
  for value, label in choices:
74
+ if not nullable and value is None:
75
+ continue
76
+ if not blankable and value == "":
77
+ continue
78
+
71
79
  if isinstance(label, (list, tuple)):
72
80
  for val, _lbl in label:
73
81
  choice_list.append(val)
74
82
  else:
75
83
  choice_list.append(value)
84
+
76
85
  return gen_from_list(choice_list)
77
86
 
78
87
 
@@ -80,8 +89,13 @@ def gen_integer(min_int: int = -MAX_INT, max_int: int = MAX_INT) -> int:
80
89
  return baker_random.randint(min_int, max_int)
81
90
 
82
91
 
83
- def gen_float() -> float:
84
- return baker_random.random() * gen_integer()
92
+ def gen_float(min_float: float = -1000000.0, max_float: float = 1000000.0) -> float:
93
+ """
94
+ Generate a random float uniformly distributed between `min_float` and `max_float`.
95
+
96
+ Defaults to ±1,000,000.0 which is suitable for most test data scenarios.
97
+ """
98
+ return baker_random.uniform(min_float, max_float)
85
99
 
86
100
 
87
101
  def gen_decimal(max_digits: int, decimal_places: int) -> Decimal:
@@ -115,7 +129,7 @@ def gen_string(max_length: int) -> str:
115
129
  return "".join(baker_random.choice(string.ascii_letters) for _ in range(max_length))
116
130
 
117
131
 
118
- def _gen_string_get_max_length(field: Field) -> Tuple[str, int]:
132
+ def _gen_string_get_max_length(field: Field) -> tuple[str, int]:
119
133
  max_length = getattr(field, "max_length", None)
120
134
  if max_length is None:
121
135
  max_length = MAX_LENGTH
@@ -134,6 +148,15 @@ gen_slug.required = ["max_length"] # type: ignore[attr-defined]
134
148
 
135
149
 
136
150
  def gen_text() -> str:
151
+ warnings.warn(
152
+ "\n"
153
+ "Accessing `model_bakery.random_gen.gen_text` is deprecated "
154
+ "and will be removed in a future major release. Please use "
155
+ "`model_bakery.random_gen.gen_string` instead."
156
+ "\n",
157
+ DeprecationWarning,
158
+ stacklevel=2,
159
+ )
137
160
  return gen_string(MAX_LENGTH)
138
161
 
139
162
 
@@ -166,7 +189,7 @@ def gen_ipv46() -> str:
166
189
  return ip_gen()
167
190
 
168
191
 
169
- def gen_ip(protocol: str, default_validators: List[Callable]) -> str:
192
+ def gen_ip(protocol: str, default_validators: list[Callable]) -> str:
170
193
  from django.core.exceptions import ValidationError
171
194
 
172
195
  protocol = (protocol or "").lower()
@@ -203,9 +226,18 @@ def gen_byte_string(max_length: int = 16) -> bytes:
203
226
  return bytes(generator)
204
227
 
205
228
 
206
- def gen_interval(interval_key: str = "milliseconds", offset: int = 0) -> timedelta:
207
- interval = gen_integer() + offset
208
- kwargs = {interval_key: interval}
229
+ def gen_interval(
230
+ interval_key: str = "milliseconds",
231
+ min_interval: int = -365 * 24 * 60 * 60 * 1000,
232
+ max_interval: int = 365 * 24 * 60 * 60 * 1000,
233
+ ) -> timedelta:
234
+ """
235
+ Generate a random timedelta for `DurationField` or date range calculations.
236
+
237
+ Defaults to ±1 year in milliseconds, suitable for most test scenarios.
238
+ The `interval_key` determines which timedelta argument is set (e.g., 'seconds', 'days').
239
+ """
240
+ kwargs = {interval_key: baker_random.randint(min_interval, max_interval)}
209
241
  return timedelta(**kwargs)
210
242
 
211
243
 
@@ -244,7 +276,7 @@ def gen_hstore():
244
276
  return {}
245
277
 
246
278
 
247
- def _fk_model(field: Field) -> Tuple[str, Optional[Model]]:
279
+ def _fk_model(field: Field) -> tuple[str, Model | None]:
248
280
  try:
249
281
  return ("model", field.related_model)
250
282
  except AttributeError:
@@ -253,7 +285,7 @@ def _fk_model(field: Field) -> Tuple[str, Optional[Model]]:
253
285
 
254
286
  def _prepare_related(
255
287
  model: str, _create_files=False, **attrs: Any
256
- ) -> Union[Model, List[Model]]:
288
+ ) -> Model | list[Model]:
257
289
  from .baker import prepare
258
290
 
259
291
  return prepare(model, **attrs)
@@ -333,37 +365,56 @@ def gen_geometry_collection() -> str:
333
365
 
334
366
 
335
367
  def gen_pg_numbers_range(number_cast: Callable[[int], Any]) -> Callable:
368
+ """
369
+ Factory that returns a generator for PostgreSQL numeric range fields.
370
+
371
+ The returned generator creates ranges like [-N, N] where N is a random value
372
+ between 1 and 100,000, cast to the appropriate numeric type (int, float, etc).
373
+ """
374
+
336
375
  def gen_range():
337
376
  try:
338
377
  from psycopg.types.range import Range
339
378
  except ImportError:
340
379
  from psycopg2._range import NumericRange as Range
341
380
 
342
- base_num = gen_integer(1, 100000)
381
+ base_num = baker_random.randint(1, 100000)
343
382
  return Range(number_cast(-1 * base_num), number_cast(base_num))
344
383
 
345
384
  return gen_range
346
385
 
347
386
 
348
387
  def gen_date_range():
388
+ """
389
+ Generate random `DateRange` for PostgreSQL `DateRangeField`.
390
+
391
+ The range spans a random date with a minimum interval of 1 day
392
+ to avoid empty ranges in tests.
393
+ """
349
394
  try:
350
395
  from psycopg.types.range import DateRange
351
396
  except ImportError:
352
397
  from psycopg2.extras import DateRange
353
398
 
354
399
  base_date = gen_date()
355
- interval = gen_interval(offset=24 * 60 * 60 * 1000) # force at least 1 day interval
400
+ interval = gen_interval(min_interval=24 * 60 * 60 * 1000)
356
401
  args = sorted([base_date - interval, base_date + interval])
357
402
  return DateRange(*args)
358
403
 
359
404
 
360
405
  def gen_datetime_range():
406
+ """
407
+ Generate random `TimestamptzRange` for PostgreSQL DateTimeRangeField.
408
+
409
+ The range spans a random datetime with a minimum interval of 1 day
410
+ to avoid empty ranges in tests.
411
+ """
361
412
  try:
362
413
  from psycopg.types.range import TimestamptzRange
363
414
  except ImportError:
364
415
  from psycopg2.extras import DateTimeTZRange as TimestamptzRange
365
416
 
366
417
  base_datetime = gen_datetime()
367
- interval = gen_interval()
418
+ interval = gen_interval(min_interval=24 * 60 * 60 * 1000)
368
419
  args = sorted([base_datetime - interval, base_datetime + interval])
369
420
  return TimestamptzRange(*args)
model_bakery/recipe.py CHANGED
@@ -1,14 +1,10 @@
1
1
  import collections
2
+ import copy
2
3
  import itertools
3
4
  from typing import (
4
5
  Any,
5
- Dict,
6
6
  Generic,
7
- List,
8
- Optional,
9
- Type,
10
7
  TypeVar,
11
- Union,
12
8
  cast,
13
9
  overload,
14
10
  )
@@ -29,15 +25,15 @@ finder = baker.ModelFinder()
29
25
  class Recipe(Generic[M]):
30
26
  _T = TypeVar("_T", bound="Recipe[M]")
31
27
 
32
- def __init__(self, _model: Union[str, Type[M]], **attrs: Any) -> None:
28
+ def __init__(self, _model: str | type[M], **attrs: Any) -> None:
33
29
  self.attr_mapping = attrs
34
30
  self._model = _model
35
31
  # _iterator_backups will hold values of the form (backup_iterator, usable_iterator).
36
- self._iterator_backups = {} # type: Dict[str, Any]
32
+ self._iterator_backups = {} # type: dict[str, Any]
37
33
 
38
34
  def _mapping( # noqa: C901
39
- self, _using: str, new_attrs: Dict[str, Any]
40
- ) -> Dict[str, Any]:
35
+ self, _using: str, new_attrs: dict[str, Any]
36
+ ) -> dict[str, Any]:
41
37
  _save_related = new_attrs.get("_save_related", True)
42
38
  _quantity = new_attrs.get("_quantity", 1)
43
39
  rel_fields_attrs = {k: v for k, v in new_attrs.items() if "__" in k}
@@ -79,6 +75,8 @@ class Recipe(Generic[M]):
79
75
  mapping[k] = v.recipe.prepare(_using=_using, **recipe_attrs)
80
76
  elif isinstance(v, related):
81
77
  mapping[k] = v.make
78
+ elif isinstance(v, collections.abc.Container):
79
+ mapping[k] = copy.deepcopy(v)
82
80
 
83
81
  mapping.update(new_attrs)
84
82
  mapping.update(rel_fields_attrs)
@@ -93,7 +91,7 @@ class Recipe(Generic[M]):
93
91
  _create_files: bool = False,
94
92
  _using: str = "",
95
93
  _bulk_create: bool = False,
96
- _save_kwargs: Optional[Dict[str, Any]] = None,
94
+ _save_kwargs: dict[str, Any] | None = None,
97
95
  **attrs: Any,
98
96
  ) -> M: ...
99
97
 
@@ -106,21 +104,21 @@ class Recipe(Generic[M]):
106
104
  _create_files: bool = False,
107
105
  _using: str = "",
108
106
  _bulk_create: bool = False,
109
- _save_kwargs: Optional[Dict[str, Any]] = None,
107
+ _save_kwargs: dict[str, Any] | None = None,
110
108
  **attrs: Any,
111
- ) -> List[M]: ...
109
+ ) -> list[M]: ...
112
110
 
113
111
  def make(
114
112
  self,
115
- _quantity: Optional[int] = None,
116
- make_m2m: Optional[bool] = None,
117
- _refresh_after_create: Optional[bool] = None,
118
- _create_files: Optional[bool] = None,
113
+ _quantity: int | None = None,
114
+ make_m2m: bool | None = None,
115
+ _refresh_after_create: bool | None = None,
116
+ _create_files: bool | None = None,
119
117
  _using: str = "",
120
- _bulk_create: Optional[bool] = None,
121
- _save_kwargs: Optional[Dict[str, Any]] = None,
118
+ _bulk_create: bool | None = None,
119
+ _save_kwargs: dict[str, Any] | None = None,
122
120
  **attrs: Any,
123
- ) -> Union[M, List[M]]:
121
+ ) -> M | list[M]:
124
122
  defaults = {}
125
123
  if _quantity is not None:
126
124
  defaults["_quantity"] = _quantity
@@ -154,19 +152,21 @@ class Recipe(Generic[M]):
154
152
  _save_related: bool = False,
155
153
  _using: str = "",
156
154
  **attrs: Any,
157
- ) -> List[M]: ...
155
+ ) -> list[M]: ...
158
156
 
159
157
  def prepare(
160
158
  self,
161
- _quantity: Optional[int] = None,
159
+ _quantity: int | None = None,
162
160
  _save_related: bool = False,
163
161
  _using: str = "",
164
162
  **attrs: Any,
165
- ) -> Union[M, List[M]]:
163
+ ) -> M | list[M]:
166
164
  defaults = {
167
- "_quantity": _quantity,
168
165
  "_save_related": _save_related,
169
166
  }
167
+ if _quantity is not None:
168
+ defaults["_quantity"] = _quantity # type: ignore[assignment]
169
+
170
170
  defaults.update(attrs)
171
171
  return baker.prepare(
172
172
  self._model, _using=_using, **self._mapping(_using, defaults)
@@ -207,7 +207,7 @@ class RecipeForeignKey(Generic[M]):
207
207
 
208
208
 
209
209
  def foreign_key(
210
- recipe: Union[Recipe[M], str], one_to_one: bool = False
210
+ recipe: Recipe[M] | str, one_to_one: bool = False
211
211
  ) -> RecipeForeignKey[M]:
212
212
  """Return a `RecipeForeignKey`.
213
213
 
@@ -230,8 +230,8 @@ def foreign_key(
230
230
 
231
231
 
232
232
  class related(Generic[M]): # FIXME
233
- def __init__(self, *args: Union[str, Recipe[M]]) -> None:
234
- self.related = [] # type: List[Recipe[M]]
233
+ def __init__(self, *args: str | Recipe[M]) -> None:
234
+ self.related = [] # type: list[Recipe[M]]
235
235
  for recipe in args:
236
236
  if isinstance(recipe, Recipe):
237
237
  self.related.append(recipe)
@@ -244,6 +244,6 @@ class related(Generic[M]): # FIXME
244
244
  else:
245
245
  raise TypeError("Not a recipe")
246
246
 
247
- def make(self) -> List[Union[M, List[M]]]:
247
+ def make(self) -> list[M | list[M]]:
248
248
  """Persist objects to m2m relation."""
249
249
  return [m.make() for m in self.related]
model_bakery/timezone.py CHANGED
@@ -8,6 +8,6 @@ from django.conf import settings
8
8
  def tz_aware(value: datetime) -> datetime:
9
9
  """Return an UTC-aware datetime in case of USE_TZ=True."""
10
10
  if settings.USE_TZ:
11
- value = value.replace(tzinfo=timezone.utc)
11
+ return value.replace(tzinfo=timezone.utc)
12
12
 
13
- return value
13
+ return value.replace(tzinfo=None)
model_bakery/utils.py CHANGED
@@ -3,8 +3,9 @@ import importlib
3
3
  import inspect
4
4
  import itertools
5
5
  import warnings
6
+ from collections.abc import Callable
6
7
  from types import ModuleType
7
- from typing import Any, Callable, Optional, Union
8
+ from typing import Any
8
9
 
9
10
  from django.apps import apps
10
11
 
@@ -13,7 +14,7 @@ from .timezone import tz_aware
13
14
  __all__ = ["import_from_str", "get_calling_module", "seq"]
14
15
 
15
16
 
16
- def import_from_str(import_string: Optional[Union[Callable, str]]) -> Any:
17
+ def import_from_str(import_string: Callable | str | None) -> Any:
17
18
  """Import an object defined as import if it is an string.
18
19
 
19
20
  If `import_string` follows the format `path.to.module.object_name`,
@@ -33,7 +34,7 @@ def import_from_str(import_string: Optional[Union[Callable, str]]) -> Any:
33
34
  return import_string
34
35
 
35
36
 
36
- def get_calling_module(levels_back: int) -> Optional[ModuleType]:
37
+ def get_calling_module(levels_back: int) -> ModuleType | None:
37
38
  """Get the module some number of stack frames back from the current one.
38
39
 
39
40
  Make sure to account for the number of frames between the "calling" code
@@ -86,7 +87,10 @@ def seq(value, increment_by=1, start=None, suffix=None):
86
87
  start = (date - epoch_datetime).total_seconds()
87
88
  increment_by = increment_by.total_seconds()
88
89
  for n in itertools.count(increment_by, increment_by):
89
- series_date = tz_aware(datetime.datetime.utcfromtimestamp(start + n))
90
+ series_date = tz_aware(
91
+ datetime.datetime.fromtimestamp(start + n, tz=datetime.timezone.utc)
92
+ )
93
+
90
94
  if type(value) is datetime.time:
91
95
  yield series_date.time()
92
96
  elif type(value) is datetime.date:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: model-bakery
3
- Version: 1.19.2
3
+ Version: 1.21.0
4
4
  Summary: Smart object creation facility for Django.
5
5
  Project-URL: Homepage, https://github.com/model-bakers/model_bakery
6
6
  Author-email: berin <bernardoxhc@gmail.com>, amureki <amureki@hey.com>
@@ -12,18 +12,20 @@ Classifier: Framework :: Django
12
12
  Classifier: Framework :: Django :: 4.2
13
13
  Classifier: Framework :: Django :: 5.0
14
14
  Classifier: Framework :: Django :: 5.1
15
+ Classifier: Framework :: Django :: 5.2
16
+ Classifier: Framework :: Django :: 6.0
15
17
  Classifier: Intended Audience :: Developers
16
18
  Classifier: License :: OSI Approved :: Apache Software License
17
19
  Classifier: Operating System :: OS Independent
18
20
  Classifier: Programming Language :: Python
19
21
  Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3.8
21
- Classifier: Programming Language :: Python :: 3.9
22
22
  Classifier: Programming Language :: Python :: 3.10
23
23
  Classifier: Programming Language :: Python :: 3.11
24
24
  Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Programming Language :: Python :: 3.14
25
27
  Classifier: Topic :: Software Development
26
- Requires-Python: >=3.8
28
+ Requires-Python: >=3.10
27
29
  Requires-Dist: django>=4.2
28
30
  Provides-Extra: docs
29
31
  Requires-Dist: myst-parser; extra == 'docs'
@@ -46,76 +48,83 @@ Description-Content-Type: text/markdown
46
48
  [![Latest PyPI version](https://img.shields.io/pypi/v/model_bakery.svg)](https://pypi.python.org/pypi/model_bakery/)
47
49
  [![Documentation Status](https://readthedocs.org/projects/model-bakery/badge/?version=latest)](https://model-bakery.readthedocs.io/en/latest/?badge=latest)
48
50
 
49
- *Model Bakery* offers you a smart way to create fixtures for testing in
50
- Django.
51
- With a simple and powerful API you can create many objects with a single
52
- line of code.
51
+ *Model Bakery* offers you a smart way to create fixtures for testing in Django. With a simple and powerful API, you can create many objects with a single line of code.
53
52
 
54
- Model Bakery is a rename of the legacy [Model Mommy project](https://pypi.org/project/model_mommy/).
53
+ > **Note:** Model Bakery is a rename of the legacy [Model Mommy project](https://pypi.org/project/model_mommy/).
55
54
 
56
- ## Install
55
+ ## Installation
57
56
 
58
57
  ```bash
59
58
  pip install model-bakery
60
59
  ```
61
60
 
62
- ## Usage and Info
61
+ ## Supported Versions
63
62
 
64
- ### Basic usage
63
+ Model Bakery follows the [Python](https://devguide.python.org/versions/) and [Django](https://docs.djangoproject.com/en/stable/internals/release-process/#supported-versions) release and support cycles. We drop support for Python and Django versions when they reach end-of-life.
65
64
 
66
- ```python
65
+ ## Basic usage
67
66
 
67
+ ```python
68
68
  # models.py
69
-
70
69
  from django.db import models
71
70
 
72
71
  class Customer(models.Model):
73
- enjoy_jards_macale = models.BooleanField()
74
72
  name = models.CharField(max_length=30)
75
73
  email = models.EmailField()
76
74
  age = models.IntegerField()
75
+ is_jards_macale_fan = models.BooleanField()
77
76
  bio = models.TextField()
78
- days_since_last_login = models.BigIntegerField()
79
77
  birthday = models.DateField()
80
78
  last_shopping = models.DateTimeField()
81
79
 
82
80
  # test_models.py
83
-
84
81
  from django.test import TestCase
85
82
  from model_bakery import baker
86
- from pprint import pprint
87
83
 
88
84
  class TestCustomerModel(TestCase):
89
85
  def setUp(self):
90
86
  self.customer = baker.make('shop.Customer')
91
- pprint(self.customer.__dict__)
87
+ print(self.customer.__dict__)
92
88
 
93
89
  """
94
90
  {'_state': <django.db.models.base.ModelState object at 0x1129a3240>,
95
91
  'age': 3841,
96
92
  'bio': 'vUFzMUMyKzlnTyiCxfgODIhrnkjzgQwHtzIbtnVDKflqevczfnaOACkDNqvCHwvtWdLwoiKrCqfppAlogSLECtMmfleeveyqefkGyTGnpbkVQTtviQVDESpXascHAluGHYEotSypSiHvHzFteKIcUebrzUVigiOacfnGdvijEPrZdSCIIBjuXZMaWLrMXyrsUCdKPLRBRYklRdtZhgtxuASXdhNGhDsrnPHrYRClhrSJSVFojMkUHBvSZhoXoCrTfHsAjenCEHvcLeCecsXwXgWJcnJPSFdOmOpiHRnhSgRF',
97
93
  'birthday': datetime.date(2019, 12, 3),
98
- 'enjoy_jards_macale': True,
94
+ 'email': 'rpNATNsxoj@example.com',
95
+ 'is_jards_macale_fan': True,
99
96
  'id': 1,
100
97
  'last_shopping': datetime.datetime(2019, 12, 3, 21, 42, 34, 77019),
101
- 'name': 'qiayYnESvqcYLLBzxpFOcGBIfnQEPx',
102
- 'days_since_last_login': 6016}
98
+ 'name': 'qiayYnESvqcYLLBzxpFOcGBIfnQEPx'}
103
99
  """
104
-
105
100
  ```
106
101
 
107
- Check out [documentation](<http://model-bakery.readthedocs.org/>) for more complete examples.
102
+ ## Documentation
103
+
104
+ For more detailed information, check out the [full documentation](https://model-bakery.readthedocs.io/).
108
105
 
109
106
  ## Contributing
110
107
 
111
- Detailed info [here](https://github.com/model-bakers/model_bakery/blob/main/CONTRIBUTING.md).
108
+ As an open-source project, Model Bakery welcomes contributions of many forms:
109
+
110
+ - Code patches
111
+ - Documentation improvements
112
+ - Bug reports
113
+
114
+ Take a look at our [contribution guidelines](CONTRIBUTING.md) for instructions
115
+ on how to set up your local environment.
112
116
 
113
117
  ## Maintainers
114
118
 
115
- - [Bernardo Fontes](https://github.com/berinhard/)
116
- - [Rustem Saiargaliev](https://github.com/amureki/)
117
- - [Tim Klein](https://github.com/timjklein36)
119
+ - [Bernardo Fontes](https://github.com/berinhard/)
120
+ - [Rustem Saiargaliev](https://github.com/amureki/)
121
+ - [Tim Klein](https://github.com/timjklein36)
118
122
 
119
123
  ## Creator
120
124
 
121
- - [Vanderson Mota](https://github.com/vandersonmota/)
125
+ - [Vanderson Mota](https://github.com/vandersonmota/)
126
+
127
+ ## License
128
+
129
+ Model Bakery is licensed under Apache License 2.0.
130
+ See the [LICENSE](LICENSE) file for more information.
@@ -0,0 +1,19 @@
1
+ model_bakery/__about__.py,sha256=oQdy_VDKQZm6_UKnVHbkyIDnpqXxS3OREilFLTax8MU,23
2
+ model_bakery/__init__.py,sha256=yY0xZUrr_mskBm07iF-MFBEiXzOuKrlMwpKWkXZs8v0,31
3
+ model_bakery/_types.py,sha256=P0iKC5-Cnh3lyzyZs1mlCfOW31zbEZpxqWCuYonucKo,130
4
+ model_bakery/baker.py,sha256=tjsldeGJUEyIKjhIb3AXt2AjIKJ4MXZKRFJxSqH3_j0,31295
5
+ model_bakery/content_types.py,sha256=3POJ12aqPuSvCdKYuwb1GlJpSocgByG2JW5kw7VBNxQ,395
6
+ model_bakery/exceptions.py,sha256=q1oBZvfxL7HAD-F9aWgiYs4P4rz-hJ5TjeX7gcb3Q0I,333
7
+ model_bakery/generators.py,sha256=pV8amdkkAGbf3ES7fIiRrRyYwKHVXzIe9eN7kR_Mms0,5159
8
+ model_bakery/gis.py,sha256=eTNOfT98_ncLAb4KmOYJhE-3ALU2_pQbUpWPTolFZJI,1028
9
+ model_bakery/mock_file.txt,sha256=CO5zPS6Uydk48ZRnGcRKVEYKd2YjaUMa9QOgF5gGMCo,10
10
+ model_bakery/mock_img.jpeg,sha256=iF2ybgAVtDvl48-8VKdv_QFHKfnqeOaeGwR6ZLexJkY,1916
11
+ model_bakery/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ model_bakery/random_gen.py,sha256=A_quvJAsihqI7JP94kbJEDTX_yNa76MPIn_p2OFWdVo,11508
13
+ model_bakery/recipe.py,sha256=Ok0cQzX8IKpQLHjf-_kQPdlVRmSt-GPrhJsRBh7tp2g,8450
14
+ model_bakery/timezone.py,sha256=IvrzSer02FkUd_8DcJVOwTcRzeBn4qZ2pYvcI3QOr9E,345
15
+ model_bakery/utils.py,sha256=H7iASipUahE6mluEbP3cZnCkRdY4qfN3QHD7rxoYZZM,4633
16
+ model_bakery-1.21.0.dist-info/METADATA,sha256=771BJtN6L4f4dFuhxpSWYwa1T7Sxj92BbHwksr8tHDU,4961
17
+ model_bakery-1.21.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
18
+ model_bakery-1.21.0.dist-info/licenses/LICENSE,sha256=kCwHls7z8Y7NyZCmdnV1qLSdLrQ8bHrXLji5HOasgUc,611
19
+ model_bakery-1.21.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,19 +0,0 @@
1
- model_bakery/__about__.py,sha256=V14nqouh0fns5BAgWrw5Aw8DW-D9yIY3TtnyECKUNxM,23
2
- model_bakery/__init__.py,sha256=yY0xZUrr_mskBm07iF-MFBEiXzOuKrlMwpKWkXZs8v0,31
3
- model_bakery/_types.py,sha256=P0iKC5-Cnh3lyzyZs1mlCfOW31zbEZpxqWCuYonucKo,130
4
- model_bakery/baker.py,sha256=NSDx3hezvEG0HpWVXJd1uJPLxhJjc2tI-ipCzMbmWvw,30140
5
- model_bakery/content_types.py,sha256=3POJ12aqPuSvCdKYuwb1GlJpSocgByG2JW5kw7VBNxQ,395
6
- model_bakery/exceptions.py,sha256=q1oBZvfxL7HAD-F9aWgiYs4P4rz-hJ5TjeX7gcb3Q0I,333
7
- model_bakery/generators.py,sha256=agY6pH14vjehVI0wJDw3Q-u4zt7mq2M1a3CUPTkAxp0,5169
8
- model_bakery/gis.py,sha256=eTNOfT98_ncLAb4KmOYJhE-3ALU2_pQbUpWPTolFZJI,1028
9
- model_bakery/mock_file.txt,sha256=CO5zPS6Uydk48ZRnGcRKVEYKd2YjaUMa9QOgF5gGMCo,10
10
- model_bakery/mock_img.jpeg,sha256=iF2ybgAVtDvl48-8VKdv_QFHKfnqeOaeGwR6ZLexJkY,1916
11
- model_bakery/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- model_bakery/random_gen.py,sha256=IYhDhqsRBftceQRHtc9B4bUWLTjvEXkgEwhNhp9DajE,9787
13
- model_bakery/recipe.py,sha256=3PVg8y-vvfOf7Z4o9J7QPoO8eegGmejFCVWco19AWIs,8378
14
- model_bakery/timezone.py,sha256=rd-KGVHqJoHdHKBgENPMBTRqqxgKE91CM9C0f9nS90M,325
15
- model_bakery/utils.py,sha256=fw4ewtwkJ6wZ9PbDzBGvODX7CV81ozy2_6JAQmITmX4,4581
16
- model_bakery-1.19.2.dist-info/METADATA,sha256=LjZgSNHtbrNUhoAHVpEwA0dgPudklKLP9jtJMkfYo0g,4355
17
- model_bakery-1.19.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
18
- model_bakery-1.19.2.dist-info/licenses/LICENSE,sha256=kCwHls7z8Y7NyZCmdnV1qLSdLrQ8bHrXLji5HOasgUc,611
19
- model_bakery-1.19.2.dist-info/RECORD,,