boto3-assist 0.5.0__tar.gz → 0.5.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.
Files changed (115) hide show
  1. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/PKG-INFO +1 -1
  2. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/pyproject.toml +1 -1
  3. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cognito/user.py +8 -1
  4. boto3_assist-0.5.1/src/boto3_assist/models/serializable_model.py +30 -0
  5. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/utilities/serialization_utility.py +68 -26
  6. boto3_assist-0.5.1/src/boto3_assist/version.py +1 -0
  7. boto3_assist-0.5.1/tests/models/serializable_model_test.py +113 -0
  8. boto3_assist-0.5.1/tests/s3/__init__.py +0 -0
  9. boto3_assist-0.5.0/src/boto3_assist/version.py +0 -1
  10. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/.env.docker +0 -0
  11. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/.env.docker.001 +0 -0
  12. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/.env.docker.nosql.workbench +0 -0
  13. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/.env.unittest +0 -0
  14. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/.gitignore +0 -0
  15. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/.vscode/launch.json +0 -0
  16. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/.vscode/settings.json +0 -0
  17. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/.vscode/tasks.json +0 -0
  18. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/LICENSE-EXPLAINED.txt +0 -0
  19. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/LICENSE.txt +0 -0
  20. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/README.md +0 -0
  21. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/aws_regions_with_status.csv +0 -0
  22. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/aws_regions_with_status.json +0 -0
  23. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/devops/build.py +0 -0
  24. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/devops/readme.md +0 -0
  25. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/__init__.py +0 -0
  26. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/cloudwatch/log_report.py +0 -0
  27. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/models/order_item_model.py +0 -0
  28. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/models/order_model.py +0 -0
  29. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/models/product_model.py +0 -0
  30. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/models/user_model.py +0 -0
  31. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/models/user_post_model.py +0 -0
  32. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/order_example/main.py +0 -0
  33. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/order_example/products.json +0 -0
  34. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/services/order_item_service.py +0 -0
  35. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/services/order_service.py +0 -0
  36. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/services/product_service.py +0 -0
  37. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/services/table_service.py +0 -0
  38. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/services/user_post_service.py +0 -0
  39. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/services/user_service.py +0 -0
  40. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/services/user_service_client_example.py +0 -0
  41. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/services/user_service_resource_example.py +0 -0
  42. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/dynamodb/user_post_example/main.py +0 -0
  43. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/examples/ec2/regions_report.py +0 -0
  44. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/module-headers.txt +0 -0
  45. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/mypy.ini +0 -0
  46. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/requirements-dev.txt +0 -0
  47. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/requirements.txt +0 -0
  48. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/run-checks.sh +0 -0
  49. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/__init__.py +0 -0
  50. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/aws_lambda/event_info.py +0 -0
  51. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/boto3session.py +0 -0
  52. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cloudwatch/cloudwatch_connection.py +0 -0
  53. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +0 -0
  54. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cloudwatch/cloudwatch_log_connection.py +0 -0
  55. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cloudwatch/cloudwatch_logs.py +0 -0
  56. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cloudwatch/cloudwatch_query.py +0 -0
  57. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cognito/cognito_authorizer.py +0 -0
  58. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cognito/cognito_connection.py +0 -0
  59. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cognito/cognito_utility.py +0 -0
  60. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/cognito/jwks_cache.py +0 -0
  61. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/connection.py +0 -0
  62. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/connection_tracker.py +0 -0
  63. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb.py +0 -0
  64. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_connection.py +0 -0
  65. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_helpers.py +0 -0
  66. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_importer.py +0 -0
  67. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_index.py +0 -0
  68. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_iservice.py +0 -0
  69. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_key.py +0 -0
  70. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_model_base.py +0 -0
  71. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +0 -0
  72. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_reindexer.py +0 -0
  73. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_reserved_words.py +0 -0
  74. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/dynamodb_reserved_words.txt +0 -0
  75. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/readme.md +0 -0
  76. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/dynamodb/troubleshooting.md +0 -0
  77. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/ec2/ec2_connection.py +0 -0
  78. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/environment_services/__init__.py +0 -0
  79. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/environment_services/environment_loader.py +0 -0
  80. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/environment_services/environment_variables.py +0 -0
  81. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/errors/custom_exceptions.py +0 -0
  82. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/http_status_codes.py +0 -0
  83. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/s3/s3.py +0 -0
  84. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/s3/s3_connection.py +0 -0
  85. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/utilities/datetime_utility.py +0 -0
  86. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/utilities/dictionaroy_utility.py +0 -0
  87. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/utilities/file_operations.py +0 -0
  88. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/utilities/http_utility.py +0 -0
  89. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/utilities/logging_utility.py +0 -0
  90. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/utilities/numbers_utility.py +0 -0
  91. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/src/boto3_assist/utilities/string_utility.py +0 -0
  92. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/__init__.py +0 -0
  93. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/__top/__init__.py +0 -0
  94. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/__init__.py +0 -0
  95. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/dynamodb_model_base_test.py +0 -0
  96. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/dynamodb_model_projections_test.py +0 -0
  97. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/dynamodb_model_serializtion_test.py +0 -0
  98. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/dynamodb_moto_sorting_test.py +0 -0
  99. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/dynamodb_reindex_test.py +0 -0
  100. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/models/cms/base.py +0 -0
  101. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/models/cms/content_block.py +0 -0
  102. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/models/cms/page.py +0 -0
  103. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/models/cms/template.py +0 -0
  104. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/models/simple_model.py +0 -0
  105. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/models/user_model.py +0 -0
  106. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/dynamodb/models/user_required_fields_model.py +0 -0
  107. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/examples_test/__init__.py +0 -0
  108. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/examples_test/user_service_test.py +0 -0
  109. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/lambda/__init__.py +0 -0
  110. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/lambda/event_info_test.py +0 -0
  111. {boto3_assist-0.5.0/tests/s3 → boto3_assist-0.5.1/tests/models}/__init__.py +0 -0
  112. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/s3/files/test.txt +0 -0
  113. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/s3/s3_file_upload_test.py +0 -0
  114. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/utilities/__init__.py +0 -0
  115. {boto3_assist-0.5.0 → boto3_assist-0.5.1}/tests/utilities/serialization_utility_test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boto3_assist
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: Additional boto3 wrappers to make your life a little easier
5
5
  Author-email: Eric Wilson <boto3-assist@geekcafe.com>
6
6
  License-File: LICENSE-EXPLAINED.txt
@@ -7,7 +7,7 @@ packages = ["src/boto3_assist"]
7
7
 
8
8
  [project]
9
9
  name = "boto3_assist"
10
- version = "0.5.0"
10
+ version = "0.5.1"
11
11
 
12
12
  authors = [
13
13
  { name="Eric Wilson", email="boto3-assist@geekcafe.com" }
@@ -1,7 +1,14 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
1
7
  from typing import Optional
8
+ from boto3_assist.models.serializable_model import SerializableModel
2
9
 
3
10
 
4
- class CognitoUser:
11
+ class CognitoUser(SerializableModel):
5
12
  """A generic way to represent a cognito user"""
6
13
 
7
14
  def __init__(
@@ -0,0 +1,30 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ from __future__ import annotations
8
+ from typing import TypeVar
9
+ from boto3_assist.utilities.serialization_utility import Serialization
10
+
11
+
12
+ class SerializableModel:
13
+ """Library to Serialize object to a DynamoDB Format"""
14
+
15
+ T = TypeVar("T", bound="SerializableModel")
16
+
17
+ @staticmethod
18
+ def map(source: dict | object, target: T, coerce: bool = True) -> T:
19
+ """
20
+ Map the source dictionary to the target object.
21
+
22
+ Args:
23
+ - source: The dictionary to map from.
24
+ - target: The object to map to.
25
+ """
26
+ mapped = Serialization.map(source, target, coerce=coerce)
27
+ if mapped is None:
28
+ raise ValueError("Unable to map source to target")
29
+
30
+ return mapped
@@ -5,11 +5,11 @@ from decimal import Decimal
5
5
  from typing import Dict, List, TypeVar
6
6
  import json
7
7
  import jsons
8
- from aws_lambda_powertools import Logger, Tracer
8
+ from aws_lambda_powertools import Logger
9
9
 
10
10
  T = TypeVar("T")
11
11
 
12
- tracer = Tracer()
12
+
13
13
  logger = Logger()
14
14
 
15
15
 
@@ -67,7 +67,7 @@ class Serialization:
67
67
  raise ValueError("Unable to convert object to dictionary")
68
68
 
69
69
  @staticmethod
70
- def map(source: object, target: T) -> T | None:
70
+ def map(source: object, target: T, coerce: bool = True) -> T | None:
71
71
  """Map an object from one object to another"""
72
72
  source_dict: dict | object
73
73
  if isinstance(source, dict):
@@ -76,12 +76,26 @@ class Serialization:
76
76
  source_dict = Serialization.convert_object_to_dict(source)
77
77
  if not isinstance(source_dict, dict):
78
78
  return None
79
- return Serialization.load_properties(source_dict, target=target)
79
+ return Serialization.load_properties(
80
+ source=source_dict, target=target, coerce=coerce
81
+ )
80
82
 
81
83
  @staticmethod
82
- def load_properties(source: dict, target: T) -> T | None:
84
+ def load_properties(
85
+ source: dict,
86
+ target: T,
87
+ coerce: bool = True,
88
+ ) -> T | None:
83
89
  """
84
- Converts a source to an object
90
+ Converts a source dictionary to a target object.
91
+
92
+ Args:
93
+ source (dict): The source dictionary containing properties.
94
+ target (T): The target object to populate.
95
+ coerce (bool): If True, attempts to convert values to the target attribute types. If False, raises an error for type mismatches.
96
+
97
+ Returns:
98
+ T | None: The populated target object, or None if an error occurred.
85
99
  """
86
100
  # Ensure target is an instance of the class
87
101
  if isinstance(target, type):
@@ -95,28 +109,56 @@ class Serialization:
95
109
  setattr(target, "__actively_serializing_data__", True)
96
110
 
97
111
  for key, value in source.items():
98
- if Serialization.has_attribute(target, key): # hasattr(target, key):
112
+ if Serialization.has_attribute(target, key):
99
113
  attr = getattr(target, key)
100
- if isinstance(attr, (int, float, str, bool, type(None))):
101
- try:
114
+ expected_type = type(attr)
115
+
116
+ try:
117
+ if isinstance(attr, (int, float, str, bool)):
118
+ if not isinstance(value, expected_type):
119
+ if coerce:
120
+ # Attempt to coerce the value to the expected type
121
+ try:
122
+ value = expected_type(value)
123
+ except ValueError as e:
124
+ logger.warning(
125
+ f"Warning coercing attribute {key} with value {value}: {e}"
126
+ )
127
+ # TODO: should we set numbers to 0 or a NaN or raise an error
128
+
129
+ setattr(target, key, value)
130
+ # raise ValueError( # pylint: disable=w0707
131
+ # f"Type mismatch for attribute {key}. Expected {expected_type}, got {type(value)}."
132
+ # )
133
+ else:
134
+ raise ValueError(
135
+ f"Type mismatch for attribute {key}. Expected {expected_type}, got {type(value)}."
136
+ )
137
+ setattr(target, key, value)
138
+ elif isinstance(attr, type(None)):
139
+ setattr(target, key, value)
140
+ elif isinstance(attr, list) and isinstance(value, list):
141
+ attr.clear()
142
+ attr.extend(value)
143
+ elif isinstance(attr, dict) and isinstance(value, dict):
144
+ Serialization.load_properties(value, attr, coerce=coerce)
145
+ elif hasattr(attr, "__dict__") and isinstance(value, dict):
146
+ Serialization.load_properties(value, attr, coerce=coerce)
147
+ else:
102
148
  setattr(target, key, value)
103
- except Exception as e: # pylint: disable=w0718
104
- logger.error(
105
- f"Error setting attribute {key} with value {value}: {e}. "
106
- "This usually occurs on properties that don't have setters. "
107
- "You can add a setter (even with a pass action) for this property, "
108
- "decorate it with the @exclude_from_serialization "
109
- "or ignore this error. "
110
- )
111
- elif isinstance(attr, list) and isinstance(value, list):
112
- attr.clear()
113
- attr.extend(value)
114
- elif isinstance(attr, dict) and isinstance(value, dict):
115
- Serialization.load_properties(value, attr)
116
- elif hasattr(attr, "__dict__") and isinstance(value, dict):
117
- Serialization.load_properties(value, attr)
118
- else:
119
- setattr(target, key, value)
149
+ except ValueError as e:
150
+ logger.error(
151
+ f"Error setting attribute {key} with value {value}: {e}"
152
+ )
153
+ raise
154
+ except Exception as e: # pylint: disable=w0718
155
+ logger.error(
156
+ f"Error setting attribute {key} with value {value}: {e}. "
157
+ "This usually occurs on properties that don't have setters. "
158
+ "You can add a setter (even with a pass action) for this property, "
159
+ "decorate it with the @exclude_from_serialization "
160
+ "or ignore this error. "
161
+ )
120
162
 
121
163
  if hasattr(target, "__actively_serializing_data__"):
122
164
  setattr(target, "__actively_serializing_data__", False)
@@ -0,0 +1 @@
1
+ __version__ = '0.5.1'
@@ -0,0 +1,113 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ import unittest
8
+ from typing import Dict
9
+ from boto3_assist.models.serializable_model import SerializableModel
10
+
11
+
12
+ class ExampleModel(SerializableModel):
13
+ """A model that inherits the serializable"""
14
+
15
+ def __init__(self, name: str = "", age: int = 0, active: bool = False):
16
+ self.name = name
17
+ self.age = age
18
+ self.active = active
19
+
20
+
21
+ class TestSerializableModel(unittest.TestCase):
22
+ """Testing Serialzing Models"""
23
+
24
+ def setUp(self) -> None:
25
+ self.source_dict: Dict[str, any] = {
26
+ "name": "John Doe",
27
+ "age": 30,
28
+ "active": True,
29
+ }
30
+
31
+ self.target_object = ExampleModel()
32
+
33
+ def test_map_valid_data(self):
34
+ """
35
+ Test mapping a valid dictionary to an object instance.
36
+ """
37
+ result = ExampleModel.map(self.source_dict, self.target_object)
38
+
39
+ self.assertEqual(result.name, "John Doe")
40
+ self.assertEqual(result.age, 30)
41
+ self.assertEqual(result.active, True)
42
+
43
+ def test_map_partial_data(self):
44
+ """
45
+ Test mapping a dictionary with partial data.
46
+ """
47
+ partial_dict = {"name": "Jane Doe"}
48
+ result = ExampleModel.map(partial_dict, self.target_object)
49
+
50
+ self.assertEqual(result.name, "Jane Doe")
51
+ self.assertEqual(result.age, 0) # Default value
52
+ self.assertEqual(result.active, False) # Default value
53
+
54
+ def test_map_empty_data(self):
55
+ """
56
+ Test mapping an empty dictionary.
57
+ """
58
+ empty_dict = {}
59
+ result = ExampleModel.map(empty_dict, self.target_object)
60
+
61
+ self.assertEqual(result.name, "") # Default value
62
+ self.assertEqual(result.age, 0) # Default value
63
+ self.assertEqual(result.active, False) # Default value
64
+
65
+ def test_map_invalid_data(self):
66
+ """
67
+ Test mapping a dictionary with invalid data types.
68
+ """
69
+ invalid_dict = {"name": 123, "age": "thirty", "active": "yes"}
70
+
71
+ with self.assertRaises(ValueError):
72
+ ExampleModel.map(invalid_dict, self.target_object, coerce=False)
73
+
74
+ def test_map_invalid_data_coerce_with_failure(self):
75
+ """
76
+ Test mapping a dictionary with invalid data types.
77
+ """
78
+ invalid_dict = {"name": 123, "age": "thirty", "active": "yes"}
79
+
80
+ result = ExampleModel.map(invalid_dict, self.target_object)
81
+
82
+ self.assertEqual(result.name, "123")
83
+ # currently we're allowing this to happen
84
+ self.assertEqual(result.age, "thirty")
85
+ self.assertEqual(result.active, True)
86
+
87
+ def test_map_invalid_data_coerce(self):
88
+ """
89
+ Test mapping a dictionary with invalid data types.
90
+ """
91
+ invalid_dict = {"name": 123, "age": 30, "active": "yes"}
92
+
93
+ result = ExampleModel.map(invalid_dict, self.target_object)
94
+
95
+ self.assertEqual(result.name, "123")
96
+ self.assertEqual(result.age, 30)
97
+ self.assertEqual(result.active, True)
98
+
99
+ def test_map_non_dict_source(self):
100
+ """
101
+ Test mapping from a non-dictionary source object.
102
+ """
103
+ source_object = ExampleModel(name="Alice", age=25, active=True)
104
+
105
+ result = ExampleModel.map(source_object, self.target_object)
106
+
107
+ self.assertEqual(result.name, "Alice")
108
+ self.assertEqual(result.age, 25)
109
+ self.assertEqual(result.active, True)
110
+
111
+
112
+ if __name__ == "__main__":
113
+ unittest.main()
File without changes
@@ -1 +0,0 @@
1
- __version__ = '0.5.0'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes