assertical 0.2.0__tar.gz → 0.3.0__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.
Files changed (29) hide show
  1. {assertical-0.2.0/src/assertical.egg-info → assertical-0.3.0}/PKG-INFO +4 -2
  2. {assertical-0.2.0 → assertical-0.3.0}/pyproject.toml +2 -1
  3. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fake/generator.py +20 -8
  4. {assertical-0.2.0 → assertical-0.3.0/src/assertical.egg-info}/PKG-INFO +4 -2
  5. {assertical-0.2.0 → assertical-0.3.0}/LICENSE.txt +0 -0
  6. {assertical-0.2.0 → assertical-0.3.0}/README.md +0 -0
  7. {assertical-0.2.0 → assertical-0.3.0}/setup.cfg +0 -0
  8. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/__init__.py +0 -0
  9. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/asserts/__init__.py +0 -0
  10. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/asserts/generator.py +0 -0
  11. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/asserts/pandas.py +0 -0
  12. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/asserts/time.py +0 -0
  13. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/asserts/type.py +0 -0
  14. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fake/__init__.py +0 -0
  15. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fake/asyncio.py +0 -0
  16. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fake/http.py +0 -0
  17. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fake/sqlalchemy.py +0 -0
  18. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fixtures/__init__.py +0 -0
  19. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fixtures/environment.py +0 -0
  20. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fixtures/fastapi.py +0 -0
  21. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fixtures/generator.py +0 -0
  22. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/fixtures/postgres.py +0 -0
  23. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/py.typed +0 -0
  24. {assertical-0.2.0 → assertical-0.3.0}/src/assertical/snapshot.py +0 -0
  25. {assertical-0.2.0 → assertical-0.3.0}/src/assertical.egg-info/SOURCES.txt +0 -0
  26. {assertical-0.2.0 → assertical-0.3.0}/src/assertical.egg-info/dependency_links.txt +0 -0
  27. {assertical-0.2.0 → assertical-0.3.0}/src/assertical.egg-info/requires.txt +0 -0
  28. {assertical-0.2.0 → assertical-0.3.0}/src/assertical.egg-info/top_level.txt +0 -0
  29. {assertical-0.2.0 → assertical-0.3.0}/tests/test_snapshot.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: assertical
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Assertical - a modular library for helping write (async) integration/unit tests for fastapi/sqlalchemy/postgres projects
5
5
  Author: Battery Storage and Grid Integration Program
6
6
  Project-URL: Homepage, https://github.com/bsgip/assertical
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Programming Language :: Python :: 3.9
15
15
  Classifier: Programming Language :: Python :: 3.10
16
16
  Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
17
18
  Requires-Python: >=3.9
18
19
  Description-Content-Type: text/markdown
19
20
  License-File: LICENSE.txt
@@ -45,6 +46,7 @@ Requires-Dist: psycopg; extra == "postgres"
45
46
  Requires-Dist: sqlalchemy>=2.0.0; extra == "postgres"
46
47
  Provides-Extra: xml
47
48
  Requires-Dist: pydantic_xml[lxml]; extra == "xml"
49
+ Dynamic: license-file
48
50
 
49
51
  # Assertical (assertical)
50
52
 
@@ -30,7 +30,7 @@ build-backend = "setuptools.build_meta"
30
30
 
31
31
  [project]
32
32
  name = "assertical"
33
- version = "0.2.0"
33
+ version = "0.3.0"
34
34
  description = "Assertical - a modular library for helping write (async) integration/unit tests for fastapi/sqlalchemy/postgres projects"
35
35
  authors = [{ name = "Battery Storage and Grid Integration Program" }]
36
36
  readme = "README.md"
@@ -52,6 +52,7 @@ classifiers = [
52
52
  "Programming Language :: Python :: 3.9",
53
53
  "Programming Language :: Python :: 3.10",
54
54
  "Programming Language :: Python :: 3.11",
55
+ "Programming Language :: Python :: 3.12",
55
56
  ]
56
57
 
57
58
  [project.urls]
@@ -1,5 +1,5 @@
1
- import sys
2
1
  import inspect
2
+ import sys
3
3
  from dataclasses import dataclass, fields, is_dataclass
4
4
  from datetime import datetime, time, timedelta, timezone
5
5
  from decimal import Decimal
@@ -9,6 +9,7 @@ from typing import (
9
9
  Callable,
10
10
  Generator,
11
11
  Optional,
12
+ TypeVar,
12
13
  Union,
13
14
  cast,
14
15
  get_args,
@@ -21,6 +22,12 @@ try:
21
22
  except ImportError:
22
23
  NoneType = type(None) # type: ignore
23
24
 
25
+
26
+ try:
27
+ from types import UnionType
28
+ except ImportError:
29
+ UnionType = type(None) # type: ignore
30
+
24
31
  try:
25
32
  from pydantic import BaseModel
26
33
  except ImportError:
@@ -84,6 +91,9 @@ class _PlaceholderDataclassBase:
84
91
  """Dataclass has no base class - instead we fall back to using this as a placeholder"""
85
92
 
86
93
 
94
+ AnyType = TypeVar("AnyType")
95
+
96
+
87
97
  def safe_is_subclass(class_to_check: Optional[type], parent_class: type) -> bool:
88
98
  if class_to_check is None:
89
99
  return False
@@ -123,7 +133,8 @@ def get_enum_type(t: Optional[type], include_optional: bool) -> Optional[type]:
123
133
  inner_enum_type = get_optional_type_argument(t)
124
134
  assert inner_enum_type is not None
125
135
 
126
- is_union = get_origin(t) == Union and len([a for a in get_args(t) if a is not NoneType]) > 1
136
+ t_origin = get_origin(t)
137
+ is_union = (t_origin == Union or t_origin == UnionType) and len([a for a in get_args(t) if a is not NoneType]) > 1
127
138
  if is_union:
128
139
  for union_arg in get_args(t):
129
140
  arg_enum = get_enum_type(union_arg, include_optional)
@@ -197,7 +208,7 @@ def get_first_generatable_primitive(t: type, include_optional: bool) -> Optional
197
208
  # extract the type
198
209
  origin_type = get_origin(t)
199
210
  include_optional_type = include_optional and is_optional_type(t)
200
- if origin_type == Union:
211
+ if origin_type == Union or origin_type == UnionType:
201
212
  for union_arg in get_args(t):
202
213
  prim_type = get_first_generatable_primitive(union_arg, include_optional=False)
203
214
  if prim_type is not None:
@@ -257,7 +268,8 @@ def get_optional_type_argument(t: type) -> Optional[type]:
257
268
 
258
269
  If None is returned then t is NOT an optional type"""
259
270
  target_type = remove_passthrough_type(t)
260
- if get_origin(target_type) != Union:
271
+ target_type_origin = get_origin(target_type)
272
+ if target_type_origin != Union and target_type_origin != UnionType:
261
273
  return None
262
274
 
263
275
  # is this an Optional union?
@@ -365,13 +377,13 @@ def enumerate_class_properties(t: type) -> Generator[PropertyGenerationDetails,
365
377
 
366
378
 
367
379
  def generate_class_instance( # noqa: C901
368
- t: type,
380
+ t: type[AnyType],
369
381
  seed: int = 1,
370
382
  optional_is_none: bool = False,
371
383
  generate_relationships: bool = False,
372
384
  _visited_type_stack: Optional[list[type]] = None,
373
385
  **kwargs: Any,
374
- ) -> Any:
386
+ ) -> AnyType:
375
387
  """Given a child class of a key to CLASS_INSTANCE_GENERATORS - generate an instance of that class
376
388
  with all properties being assigned unique values based off of seed. The values will match type hints
377
389
 
@@ -395,7 +407,7 @@ def generate_class_instance( # noqa: C901
395
407
  if _visited_type_stack is None:
396
408
  _visited_type_stack = []
397
409
  if t in _visited_type_stack:
398
- return None
410
+ return None # type: ignore # This only happens in recursion - the top level object will never be None
399
411
  _visited_type_stack.append(t)
400
412
 
401
413
  # We can only generate class instances of classes that inherit from a known base
@@ -483,7 +495,7 @@ def generate_class_instance( # noqa: C901
483
495
  return CLASS_INSTANCE_GENERATORS[t_generatable_base](t, values)
484
496
 
485
497
 
486
- def clone_class_instance(obj: Any, ignored_properties: Optional[set[str]] = None) -> Any:
498
+ def clone_class_instance(obj: AnyType, ignored_properties: Optional[set[str]] = None) -> AnyType:
487
499
  """Given an instance of a child class of a key to CLASS_INSTANCE_GENERATORS - generate a new instance of that class
488
500
  using references to the values in the current public properties in obj (i.e. a shallow clone).
489
501
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: assertical
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Assertical - a modular library for helping write (async) integration/unit tests for fastapi/sqlalchemy/postgres projects
5
5
  Author: Battery Storage and Grid Integration Program
6
6
  Project-URL: Homepage, https://github.com/bsgip/assertical
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Programming Language :: Python :: 3.9
15
15
  Classifier: Programming Language :: Python :: 3.10
16
16
  Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
17
18
  Requires-Python: >=3.9
18
19
  Description-Content-Type: text/markdown
19
20
  License-File: LICENSE.txt
@@ -45,6 +46,7 @@ Requires-Dist: psycopg; extra == "postgres"
45
46
  Requires-Dist: sqlalchemy>=2.0.0; extra == "postgres"
46
47
  Provides-Extra: xml
47
48
  Requires-Dist: pydantic_xml[lxml]; extra == "xml"
49
+ Dynamic: license-file
48
50
 
49
51
  # Assertical (assertical)
50
52
 
File without changes
File without changes
File without changes