Skip to content

Commit 7010841

Browse files
committed
renamed deepcopy argument, removed from method for now
1 parent 8ac61b1 commit 7010841

File tree

3 files changed

+18
-44
lines changed

3 files changed

+18
-44
lines changed

automapper/mapper.py

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,16 @@ def map(
6565
*,
6666
skip_none_values: bool = False,
6767
fields_mapping: FieldsMap = None,
68-
deepcopy: bool = True,
68+
use_deepcopy: bool = True,
6969
) -> T:
7070
"""Produces output object mapped from source object and custom arguments.
7171
72-
Parameters:
73-
skip_none_values - do not map fields that has None value
74-
fields_mapping - mapping for fields with different names
75-
deepcopy - should we deepcopy all attributes? [default: True]
76-
7772
Args:
7873
obj (S): _description_
7974
skip_none_values (bool, optional): Skip None values when creating `target class` obj. Defaults to False.
8075
fields_mapping (FieldsMap, optional): Custom mapping.
8176
Specify dictionary in format {"field_name": value_object}. Defaults to None.
82-
deepcopy (bool, optional): Applies deepcopy to all child objects when copy into output instance.
77+
use_deepcopy (bool, optional): Apply deepcopy to all child objects when copy from source to target object.
8378
Defaults to True.
8479
8580
Raises:
@@ -94,14 +89,14 @@ def map(
9489
set(),
9590
skip_none_values=skip_none_values,
9691
fields_mapping=fields_mapping,
97-
deepcopy=deepcopy,
92+
use_deepcopy=use_deepcopy,
9893
)
9994

10095

10196
class Mapper:
10297
def __init__(self) -> None:
10398
"""Initializes internal containers"""
104-
self._mappings: Dict[Type[S], Tuple[T, FieldsMap, bool]] = {} # type: ignore [valid-type]
99+
self._mappings: Dict[Type[S], Tuple[T, FieldsMap]] = {} # type: ignore [valid-type]
105100
self._class_specs: Dict[Type[T], SpecFunction[T]] = {} # type: ignore [valid-type]
106101
self._classifier_specs: Dict[ # type: ignore [valid-type]
107102
ClassifierFunction[T], SpecFunction[T]
@@ -156,7 +151,6 @@ def add(
156151
target_cls: Type[T],
157152
override: bool = False,
158153
fields_mapping: FieldsMap = None,
159-
deepcopy: bool = True,
160154
) -> None:
161155
"""Adds mapping between object of `source class` to an object of `target class`.
162156
@@ -167,8 +161,6 @@ def add(
167161
Defaults to False.
168162
fields_mapping (FieldsMap, optional): Custom mapping.
169163
Specify dictionary in format {"field_name": value_object}. Defaults to None.
170-
deepcopy (bool, optional): Applies deepcopy to all child objects when copy into output instance.
171-
Defaults to True.
172164
173165
Raises:
174166
DuplicatedRegistrationError: Same mapping for `source class` was added.
@@ -180,15 +172,15 @@ def add(
180172
raise DuplicatedRegistrationError(
181173
f"source_cls {source_cls} was already added for mapping"
182174
)
183-
self._mappings[source_cls] = (target_cls, fields_mapping, deepcopy)
175+
self._mappings[source_cls] = (target_cls, fields_mapping)
184176

185177
def map(
186178
self,
187179
obj: object,
188180
*,
189181
skip_none_values: bool = False,
190182
fields_mapping: FieldsMap = None,
191-
deepcopy: bool = True,
183+
use_deepcopy: bool = True,
192184
) -> T: # type: ignore [type-var]
193185
"""Produces output object mapped from source object and custom arguments
194186
@@ -197,7 +189,7 @@ def map(
197189
skip_none_values (bool, optional): Skip None values when creating `target class` obj. Defaults to False.
198190
fields_mapping (FieldsMap, optional): Custom mapping.
199191
Specify dictionary in format {"field_name": value_object}. Defaults to None.
200-
deepcopy (bool, optional): Applies deepcopy to all child objects when copy into output instance.
192+
use_deepcopy (bool, optional): Apply deepcopy to all child objects when copy from source to target object.
201193
Defaults to True.
202194
203195
Raises:
@@ -213,9 +205,7 @@ def map(
213205
raise MappingError(f"Missing mapping type for input type {obj_type}")
214206
obj_type_preffix = f"{obj_type.__name__}."
215207

216-
target_cls, target_cls_field_mappings, target_deepcopy = self._mappings[
217-
obj_type
218-
]
208+
target_cls, target_cls_field_mappings = self._mappings[obj_type]
219209

220210
common_fields_mapping = fields_mapping
221211
if target_cls_field_mappings:
@@ -233,17 +223,13 @@ def map(
233223
**fields_mapping,
234224
} # merge two dict into one, fields_mapping has priority
235225

236-
# If deepcopy is not explicitly given, we use target_deepcopy
237-
if deepcopy is None:
238-
deepcopy = target_deepcopy
239-
240226
return self._map_common(
241227
obj,
242228
target_cls,
243229
set(),
244230
skip_none_values=skip_none_values,
245231
fields_mapping=common_fields_mapping,
246-
deepcopy=deepcopy,
232+
use_deepcopy=use_deepcopy,
247233
)
248234

249235
def _get_fields(self, target_cls: Type[T]) -> Iterable[str]:
@@ -272,7 +258,7 @@ def _map_subobject(
272258
raise CircularReferenceError()
273259

274260
if type(obj) in self._mappings:
275-
target_cls, _, _ = self._mappings[type(obj)]
261+
target_cls, _ = self._mappings[type(obj)]
276262
result: Any = self._map_common(
277263
obj, target_cls, _visited_stack, skip_none_values=skip_none_values
278264
)
@@ -310,7 +296,7 @@ def _map_common(
310296
_visited_stack: Set[int],
311297
skip_none_values: bool = False,
312298
fields_mapping: FieldsMap = None,
313-
deepcopy: bool = True,
299+
use_deepcopy: bool = True,
314300
) -> T:
315301
"""Produces output object mapped from source object and custom arguments.
316302
@@ -321,7 +307,7 @@ def _map_common(
321307
skip_none_values (bool, optional): Skip None values when creating `target class` obj. Defaults to False.
322308
fields_mapping (FieldsMap, optional): Custom mapping.
323309
Specify dictionary in format {"field_name": value_object}. Defaults to None.
324-
deepcopy (bool, optional): Applies deepcopy to all child objects when copy into output instance.
310+
use_deepcopy (bool, optional): Apply deepcopy to all child objects when copy from source to target object.
325311
Defaults to True.
326312
327313
Raises:
@@ -354,13 +340,11 @@ def _map_common(
354340
value = obj[field_name] # type: ignore [index]
355341

356342
if value is not None:
357-
if deepcopy:
343+
if use_deepcopy:
358344
mapped_values[field_name] = self._map_subobject(
359345
value, _visited_stack, skip_none_values
360346
)
361-
else:
362-
# if deepcopy is disabled, we can act as if value was a primitive type and
363-
# avoid the ._map_subobject() call entirely.
347+
else: # if use_deepcopy is False, simply assign value to target obj.
364348
mapped_values[field_name] = value
365349
elif not skip_none_values:
366350
mapped_values[field_name] = None

tests/test_automapper_dict_field.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ def test_map__with_dict_field(self):
6161
self.assertEqual(public_info.products["candies"][1].name, "Snickers")
6262
self.assertEqual(public_info.products["candies"][1].brand, "Mars, Incorporated")
6363

64-
def test_deepcopy_disabled(self):
65-
public_info_deep = mapper.to(ShopPublicInfo).map(self.shop, deepcopy=False)
64+
def test_map__use_deepcopy_false(self):
65+
public_info_deep = mapper.to(ShopPublicInfo).map(self.shop, use_deepcopy=False)
6666
public_info = mapper.to(ShopPublicInfo).map(self.shop)
6767

6868
self.assertIsNot(public_info.products, self.shop.products)
@@ -78,13 +78,3 @@ def test_deepcopy_disabled(self):
7878
id(public_info_deep.products["magazines"]),
7979
id(self.shop.products["magazines"]),
8080
)
81-
82-
def test_deepcopy_disabled_in_add(self):
83-
self.mapper.add(Shop, ShopPublicInfo, deepcopy=False)
84-
public_info: ShopPublicInfo = self.mapper.map(self.shop)
85-
86-
self.assertIs(public_info.products, self.shop.products)
87-
88-
# Manually enable deepcopy on .map()
89-
public_info2: ShopPublicInfo = self.mapper.map(self.shop, deepcopy=True)
90-
self.assertIsNot(public_info2.products, self.shop.products)

tests/test_automapper_sample.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,12 @@ def test_map__override_field_value_register():
104104
mapper._mappings.clear()
105105

106106

107-
def test_deepcopy():
107+
def test_map__check_deepcopy_not_applied_if_use_deepcopy_false():
108108
address = Address(street="Main Street", number=1, zip_code=100001, city="Test City")
109109
info = PersonInfo("John Doe", age=35, address=address)
110110

111111
public_info = mapper.to(PublicPersonInfo).map(info)
112112
assert address is not public_info.address
113113

114-
public_info = mapper.to(PublicPersonInfo).map(info, deepcopy=False)
114+
public_info = mapper.to(PublicPersonInfo).map(info, use_deepcopy=False)
115115
assert address is public_info.address

0 commit comments

Comments
 (0)