model-bakery 1.17.0__tar.gz → 1.18.1__tar.gz

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.

Files changed (21) hide show
  1. {model_bakery-1.17.0 → model_bakery-1.18.1}/PKG-INFO +5 -5
  2. model_bakery-1.18.1/model_bakery/__about__.py +1 -0
  3. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/baker.py +31 -28
  4. model_bakery-1.18.1/model_bakery/content_types.py +14 -0
  5. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/generators.py +12 -54
  6. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/random_gen.py +1 -1
  7. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/recipe.py +5 -9
  8. {model_bakery-1.17.0 → model_bakery-1.18.1}/pyproject.toml +9 -7
  9. model_bakery-1.17.0/model_bakery/__about__.py +0 -1
  10. {model_bakery-1.17.0 → model_bakery-1.18.1}/.gitignore +0 -0
  11. {model_bakery-1.17.0 → model_bakery-1.18.1}/LICENSE +0 -0
  12. {model_bakery-1.17.0 → model_bakery-1.18.1}/README.md +0 -0
  13. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/__init__.py +0 -0
  14. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/_types.py +0 -0
  15. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/exceptions.py +0 -0
  16. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/gis.py +0 -0
  17. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/mock_file.txt +0 -0
  18. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/mock_img.jpeg +0 -0
  19. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/py.typed +0 -0
  20. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/timezone.py +0 -0
  21. {model_bakery-1.17.0 → model_bakery-1.18.1}/model_bakery/utils.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: model-bakery
3
- Version: 1.17.0
3
+ Version: 1.18.1
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>
@@ -9,9 +9,8 @@ License-File: LICENSE
9
9
  Keywords: django,factory,python,testing
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Framework :: Django
12
- Classifier: Framework :: Django :: 3.2
13
- Classifier: Framework :: Django :: 4.1
14
12
  Classifier: Framework :: Django :: 4.2
13
+ Classifier: Framework :: Django :: 5.0
15
14
  Classifier: Intended Audience :: Developers
16
15
  Classifier: License :: OSI Approved :: Apache Software License
17
16
  Classifier: Operating System :: OS Independent
@@ -24,8 +23,9 @@ Classifier: Programming Language :: Python :: 3.11
24
23
  Classifier: Programming Language :: Python :: 3.12
25
24
  Classifier: Topic :: Software Development
26
25
  Requires-Python: >=3.8
27
- Requires-Dist: django>=3.2
26
+ Requires-Dist: django>=4.2
28
27
  Provides-Extra: docs
28
+ Requires-Dist: myst-parser; extra == 'docs'
29
29
  Requires-Dist: sphinx; extra == 'docs'
30
30
  Requires-Dist: sphinx-rtd-theme; extra == 'docs'
31
31
  Provides-Extra: test
@@ -0,0 +1 @@
1
+ __version__ = "1.18.1"
@@ -15,10 +15,8 @@ from typing import (
15
15
  overload,
16
16
  )
17
17
 
18
- from django import VERSION as DJANGO_VERSION
19
18
  from django.apps import apps
20
19
  from django.conf import settings
21
- from django.contrib import contenttypes
22
20
  from django.db.models import (
23
21
  AutoField,
24
22
  BooleanField,
@@ -37,6 +35,7 @@ from django.db.models.fields.reverse_related import ManyToOneRel, OneToOneRel
37
35
 
38
36
  from . import generators, random_gen
39
37
  from ._types import M, NewM
38
+ from .content_types import BAKER_CONTENTTYPES
40
39
  from .exceptions import (
41
40
  AmbiguousModelName,
42
41
  CustomBakerNotFound,
@@ -50,6 +49,13 @@ from .utils import (
50
49
  seq, # noqa: F401 - Enable seq to be imported from recipes
51
50
  )
52
51
 
52
+ if BAKER_CONTENTTYPES:
53
+ from django.contrib.contenttypes import models as contenttypes_models
54
+ from django.contrib.contenttypes.fields import GenericRelation
55
+ else:
56
+ contenttypes_models = None
57
+ GenericRelation = None
58
+
53
59
  recipes = None
54
60
 
55
61
  # FIXME: use pkg_resource
@@ -78,8 +84,7 @@ def make(
78
84
  _using: str = "",
79
85
  _bulk_create: bool = False,
80
86
  **attrs: Any,
81
- ) -> M:
82
- ...
87
+ ) -> M: ...
83
88
 
84
89
 
85
90
  @overload
@@ -94,8 +99,7 @@ def make(
94
99
  _bulk_create: bool = False,
95
100
  _fill_optional: Union[List[str], bool] = False,
96
101
  **attrs: Any,
97
- ) -> List[M]:
98
- ...
102
+ ) -> List[M]: ...
99
103
 
100
104
 
101
105
  def make(
@@ -147,8 +151,7 @@ def prepare(
147
151
  _save_related: bool = False,
148
152
  _using: str = "",
149
153
  **attrs,
150
- ) -> M:
151
- ...
154
+ ) -> M: ...
152
155
 
153
156
 
154
157
  @overload
@@ -159,8 +162,7 @@ def prepare(
159
162
  _using: str = "",
160
163
  _fill_optional: Union[List[str], bool] = False,
161
164
  **attrs,
162
- ) -> List[M]:
163
- ...
165
+ ) -> List[M]: ...
164
166
 
165
167
 
166
168
  def prepare(
@@ -567,13 +569,9 @@ class Baker(Generic[M]):
567
569
  }
568
570
  self.model_attrs = {k: v for k, v in attrs.items() if not is_rel_field(k)}
569
571
  self.rel_attrs = {k: v for k, v in attrs.items() if is_rel_field(k)}
570
- self.rel_fields = [
571
- x.split("__")[0] for x in self.rel_attrs.keys() if is_rel_field(x)
572
- ]
573
-
574
- def _skip_field(self, field: Field) -> bool:
575
- from django.contrib.contenttypes.fields import GenericRelation
572
+ self.rel_fields = [x.split("__")[0] for x in self.rel_attrs if is_rel_field(x)]
576
573
 
574
+ def _skip_field(self, field: Field) -> bool: # noqa: C901
577
575
  # check for fill optional argument
578
576
  if isinstance(self.fill_in_optional, bool):
579
577
  field.fill_optional = self.fill_in_optional
@@ -595,10 +593,18 @@ class Baker(Generic[M]):
595
593
  if isinstance(field, OneToOneField) and self._remote_field(field).parent_link:
596
594
  return True
597
595
 
598
- if isinstance(field, (AutoField, GenericRelation, OrderWrt)):
596
+ other_fields_to_skip = [
597
+ AutoField,
598
+ OrderWrt,
599
+ ]
600
+
601
+ if BAKER_CONTENTTYPES:
602
+ other_fields_to_skip.append(GenericRelation)
603
+
604
+ if isinstance(field, tuple(other_fields_to_skip)):
599
605
  return True
600
606
 
601
- if all(
607
+ if all( # noqa: SIM102
602
608
  [
603
609
  field.name not in self.model_attrs,
604
610
  field.name not in self.rel_fields,
@@ -614,7 +620,7 @@ class Baker(Generic[M]):
614
620
  ):
615
621
  return True
616
622
 
617
- if field.name not in self.model_attrs:
623
+ if field.name not in self.model_attrs: # noqa: SIM102
618
624
  if field.name not in self.rel_fields and (
619
625
  field.null and not field.fill_optional
620
626
  ):
@@ -689,9 +695,11 @@ class Baker(Generic[M]):
689
695
  `attr_mapping` and `type_mapping` can be defined easily overwriting the
690
696
  model.
691
697
  """
692
- is_content_type_fk = isinstance(field, ForeignKey) and issubclass(
693
- self._remote_field(field).model, contenttypes.models.ContentType
694
- )
698
+ is_content_type_fk = False
699
+ if BAKER_CONTENTTYPES:
700
+ is_content_type_fk = isinstance(field, ForeignKey) and issubclass(
701
+ self._remote_field(field).model, contenttypes_models.ContentType
702
+ )
695
703
  # we only use default unless the field is overwritten in `self.rel_fields`
696
704
  if field.has_default() and field.name not in self.rel_fields:
697
705
  if callable(field.default):
@@ -702,7 +710,7 @@ class Baker(Generic[M]):
702
710
  elif field.choices:
703
711
  generator = random_gen.gen_from_choices(field.choices)
704
712
  elif is_content_type_fk:
705
- generator = self.type_mapping[contenttypes.models.ContentType]
713
+ generator = self.type_mapping[contenttypes_models.ContentType]
706
714
  elif generators.get(field.__class__):
707
715
  generator = generators.get(field.__class__)
708
716
  elif field.__class__ in self.type_mapping:
@@ -820,12 +828,7 @@ def bulk_create(baker: Baker[M], quantity: int, **kwargs) -> List[M]:
820
828
  else:
821
829
  manager = baker.model._base_manager
822
830
 
823
- existing_entries = list(manager.values_list("pk", flat=True))
824
831
  created_entries = manager.bulk_create(entries)
825
- # bulk_create in Django < 4.0 does not return ids of created objects.
826
- # drop this after 01 Apr 2024 (Django 3.2 LTS end of life)
827
- if DJANGO_VERSION < (4, 0):
828
- created_entries = manager.exclude(pk__in=existing_entries)
829
832
 
830
833
  # set many-to-many relations from kwargs
831
834
  for entry in created_entries:
@@ -0,0 +1,14 @@
1
+ from django.apps import apps
2
+
3
+ BAKER_CONTENTTYPES = apps.is_installed("django.contrib.contenttypes")
4
+
5
+ default_contenttypes_mapping = {}
6
+
7
+ __all__ = ["BAKER_CONTENTTYPES", "default_contenttypes_mapping"]
8
+
9
+ if BAKER_CONTENTTYPES:
10
+ from django.contrib.contenttypes.models import ContentType
11
+
12
+ from . import random_gen
13
+
14
+ default_contenttypes_mapping[ContentType] = random_gen.gen_content_type
@@ -3,6 +3,8 @@ from typing import Any, Callable, Dict, Optional, Type, Union
3
3
 
4
4
  from django.db.backends.base.operations import BaseDatabaseOperations
5
5
  from django.db.models import (
6
+ AutoField,
7
+ BigAutoField,
6
8
  BigIntegerField,
7
9
  BinaryField,
8
10
  BooleanField,
@@ -19,11 +21,14 @@ from django.db.models import (
19
21
  ImageField,
20
22
  IntegerField,
21
23
  IPAddressField,
24
+ JSONField,
22
25
  ManyToManyField,
23
26
  OneToOneField,
27
+ PositiveBigIntegerField,
24
28
  PositiveIntegerField,
25
29
  PositiveSmallIntegerField,
26
30
  SlugField,
31
+ SmallAutoField,
27
32
  SmallIntegerField,
28
33
  TextField,
29
34
  TimeField,
@@ -34,40 +39,12 @@ from django.db.models import (
34
39
  from . import random_gen
35
40
  from .utils import import_from_str
36
41
 
37
- try:
38
- # Proper support starts with Django 3.0
39
- # (as it uses `django/db/backends/base/operations.py` for matching ranges)
40
- from django.db.models import AutoField, BigAutoField, SmallAutoField
41
- except ImportError:
42
- AutoField = None
43
- BigAutoField = None
44
- SmallAutoField = None
45
-
46
- try:
47
- # added in Django 3.1
48
- from django.db.models import PositiveBigIntegerField
49
- except ImportError:
50
- PositiveBigIntegerField = None
51
-
52
- try:
53
- # Replaced `django.contrib.postgres.fields.JSONField` in Django 3.1
54
- from django.db.models import JSONField
55
- except ImportError:
56
- JSONField = None
57
-
58
42
  try:
59
43
  # PostgreSQL-specific field (only available when psycopg is installed)
60
44
  from django.contrib.postgres.fields import ArrayField
61
45
  except ImportError:
62
46
  ArrayField = None
63
47
 
64
- try:
65
- # Deprecated since Django 3.1, removed in Django 4.0
66
- # PostgreSQL-specific field (only available when psycopg is installed)
67
- from django.contrib.postgres.fields import JSONField as PostgresJSONField
68
- except ImportError:
69
- PostgresJSONField = None
70
-
71
48
  try:
72
49
  # PostgreSQL-specific field (only available when psycopg is installed)
73
50
  from django.contrib.postgres.fields import HStoreField
@@ -86,12 +63,6 @@ except ImportError:
86
63
  CIEmailField = None
87
64
  CITextField = None
88
65
 
89
- try:
90
- # Deprecated since Django 3.1, removed in Django 4.0
91
- from django.db.models import NullBooleanField
92
- except ImportError:
93
- NullBooleanField = None
94
-
95
66
 
96
67
  try:
97
68
  # PostgreSQL-specific fields (only available when psycopg is installed)
@@ -124,9 +95,13 @@ default_mapping = {
124
95
  OneToOneField: random_gen.gen_related,
125
96
  ManyToManyField: random_gen.gen_m2m,
126
97
  BooleanField: random_gen.gen_boolean,
98
+ AutoField: _make_integer_gen_by_range(AutoField),
99
+ BigAutoField: _make_integer_gen_by_range(BigAutoField),
127
100
  IntegerField: _make_integer_gen_by_range(IntegerField),
101
+ SmallAutoField: _make_integer_gen_by_range(SmallAutoField),
128
102
  BigIntegerField: _make_integer_gen_by_range(BigIntegerField),
129
103
  SmallIntegerField: _make_integer_gen_by_range(SmallIntegerField),
104
+ PositiveBigIntegerField: _make_integer_gen_by_range(PositiveBigIntegerField),
130
105
  PositiveIntegerField: _make_integer_gen_by_range(PositiveIntegerField),
131
106
  PositiveSmallIntegerField: _make_integer_gen_by_range(PositiveSmallIntegerField),
132
107
  FloatField: random_gen.gen_float,
@@ -146,14 +121,11 @@ default_mapping = {
146
121
  FileField: random_gen.gen_file_field,
147
122
  ImageField: random_gen.gen_image_field,
148
123
  DurationField: random_gen.gen_interval,
124
+ JSONField: random_gen.gen_json,
149
125
  } # type: Dict[Type, Callable]
150
126
 
151
127
  if ArrayField:
152
128
  default_mapping[ArrayField] = random_gen.gen_array
153
- if JSONField:
154
- default_mapping[JSONField] = random_gen.gen_json
155
- if PostgresJSONField:
156
- default_mapping[PostgresJSONField] = random_gen.gen_json
157
129
  if HStoreField:
158
130
  default_mapping[HStoreField] = random_gen.gen_hstore
159
131
  if CICharField:
@@ -162,16 +134,6 @@ if CIEmailField:
162
134
  default_mapping[CIEmailField] = random_gen.gen_email
163
135
  if CITextField:
164
136
  default_mapping[CITextField] = random_gen.gen_text
165
- if AutoField:
166
- default_mapping[AutoField] = _make_integer_gen_by_range(AutoField)
167
- if BigAutoField:
168
- default_mapping[BigAutoField] = _make_integer_gen_by_range(BigAutoField)
169
- if SmallAutoField:
170
- default_mapping[SmallAutoField] = _make_integer_gen_by_range(SmallAutoField)
171
- if PositiveBigIntegerField:
172
- default_mapping[PositiveBigIntegerField] = _make_integer_gen_by_range(
173
- PositiveBigIntegerField
174
- )
175
137
  if DecimalRangeField:
176
138
  default_mapping[DecimalRangeField] = random_gen.gen_pg_numbers_range(Decimal)
177
139
  if IntegerRangeField:
@@ -182,22 +144,18 @@ if DateRangeField:
182
144
  default_mapping[DateRangeField] = random_gen.gen_date_range
183
145
  if DateTimeRangeField:
184
146
  default_mapping[DateTimeRangeField] = random_gen.gen_datetime_range
185
- if NullBooleanField:
186
- default_mapping[NullBooleanField] = random_gen.gen_boolean
187
147
 
188
148
 
189
149
  # Add GIS fields
190
150
 
191
151
 
192
152
  def get_type_mapping() -> Dict[Type, Callable]:
193
- from django.contrib.contenttypes.models import ContentType
194
-
153
+ from .content_types import default_contenttypes_mapping
195
154
  from .gis import default_gis_mapping
196
155
 
197
156
  mapping = default_mapping.copy()
198
- mapping[ContentType] = random_gen.gen_content_type
157
+ mapping.update(default_contenttypes_mapping)
199
158
  mapping.update(default_gis_mapping)
200
-
201
159
  return mapping.copy()
202
160
 
203
161
 
@@ -27,7 +27,7 @@ MAX_LENGTH = 300
27
27
  # Postgres database.
28
28
  MAX_INT = 100000000000
29
29
 
30
- baker_random = Random()
30
+ baker_random = Random() # noqa: S311
31
31
 
32
32
 
33
33
  def get_content_file(content: bytes, name: str) -> ContentFile:
@@ -52,7 +52,7 @@ class Recipe(Generic[M]):
52
52
  m = finder.get_model(self._model)
53
53
  else:
54
54
  m = self._model
55
- if k not in self._iterator_backups or m.objects.count() == 0:
55
+ if k not in self._iterator_backups or not m.objects.exists():
56
56
  self._iterator_backups[k] = itertools.tee(
57
57
  self._iterator_backups.get(k, [v])[0]
58
58
  )
@@ -94,8 +94,7 @@ class Recipe(Generic[M]):
94
94
  _bulk_create: bool = False,
95
95
  _save_kwargs: Optional[Dict[str, Any]] = None,
96
96
  **attrs: Any,
97
- ) -> M:
98
- ...
97
+ ) -> M: ...
99
98
 
100
99
  @overload
101
100
  def make(
@@ -108,8 +107,7 @@ class Recipe(Generic[M]):
108
107
  _bulk_create: bool = False,
109
108
  _save_kwargs: Optional[Dict[str, Any]] = None,
110
109
  **attrs: Any,
111
- ) -> List[M]:
112
- ...
110
+ ) -> List[M]: ...
113
111
 
114
112
  def make(
115
113
  self,
@@ -146,8 +144,7 @@ class Recipe(Generic[M]):
146
144
  _save_related: bool = False,
147
145
  _using: str = "",
148
146
  **attrs: Any,
149
- ) -> M:
150
- ...
147
+ ) -> M: ...
151
148
 
152
149
  @overload
153
150
  def prepare(
@@ -156,8 +153,7 @@ class Recipe(Generic[M]):
156
153
  _save_related: bool = False,
157
154
  _using: str = "",
158
155
  **attrs: Any,
159
- ) -> List[M]:
160
- ...
156
+ ) -> List[M]: ...
161
157
 
162
158
  def prepare(
163
159
  self,
@@ -22,9 +22,8 @@ keywords = [
22
22
  classifiers = [
23
23
  "Development Status :: 5 - Production/Stable",
24
24
  "Framework :: Django",
25
- "Framework :: Django :: 3.2",
26
- "Framework :: Django :: 4.1",
27
25
  "Framework :: Django :: 4.2",
26
+ "Framework :: Django :: 5.0",
28
27
  "Intended Audience :: Developers",
29
28
  "License :: OSI Approved :: Apache Software License",
30
29
  "Operating System :: OS Independent",
@@ -38,7 +37,7 @@ classifiers = [
38
37
  "Topic :: Software Development",
39
38
  ]
40
39
  dependencies = [
41
- "django>=3.2",
40
+ "django>=4.2",
42
41
  ]
43
42
 
44
43
  [project.optional-dependencies]
@@ -54,6 +53,7 @@ test = [
54
53
  docs = [
55
54
  "Sphinx",
56
55
  "sphinx-rtd-theme",
56
+ "myst-parser",
57
57
  ]
58
58
 
59
59
  [project.urls]
@@ -98,15 +98,17 @@ addopts = "--tb=short -rxs --nomigrations"
98
98
  target-version = "py38"
99
99
 
100
100
  select = [
101
+ "S", # flake8-bandit
102
+ "B", # flake8-bugbear
103
+ "C", # flake8-comprehensions
104
+ "SIM", # flake8-simplify
105
+ "I", # isort
101
106
  "E", # pycodestyle errors
102
107
  "W", # pycodestyle warnings
103
108
  "F", # pyflakes
104
- "I", # isort
105
- "S", # flake8-bandit
106
109
  "D", # pydocstyle
107
110
  "UP", # pyupgrade
108
- "B", # flake8-bugbear
109
- "C", # flake8-comprehensions
111
+ "RUF100", # Unused noqa directive
110
112
  ]
111
113
 
112
114
  ignore = ["B904", "E501", "S101", "D1", "D212"]
@@ -1 +0,0 @@
1
- __version__ = "1.17.0"
File without changes
File without changes
File without changes