Return type as is for immutable built-in types Use obj.copy() for built-in empty collections Use copy.deepcopy() for non-empty collections and unknown objects.
(obj: Obj)
| 334 | |
| 335 | |
| 336 | def smart_deepcopy(obj: Obj) -> Obj: |
| 337 | """Return type as is for immutable built-in types |
| 338 | Use obj.copy() for built-in empty collections |
| 339 | Use copy.deepcopy() for non-empty collections and unknown objects. |
| 340 | """ |
| 341 | if obj is MISSING or obj is PydanticUndefined: |
| 342 | return obj # pyright: ignore[reportReturnType] |
| 343 | obj_type = obj.__class__ |
| 344 | if obj_type in IMMUTABLE_NON_COLLECTIONS_TYPES: |
| 345 | return obj # fastest case: obj is immutable and not collection therefore will not be copied anyway |
| 346 | try: |
| 347 | if not obj and obj_type in BUILTIN_COLLECTIONS: |
| 348 | # faster way for empty collections, no need to copy its members |
| 349 | return obj if obj_type is tuple else obj.copy() # tuple doesn't have copy method # type: ignore |
| 350 | except (TypeError, ValueError, RuntimeError): |
| 351 | # do we really dare to catch ALL errors? Seems a bit risky |
| 352 | pass |
| 353 | |
| 354 | return deepcopy(obj) # slowest way when we actually might need a deepcopy |
| 355 | |
| 356 | |
| 357 | _SENTINEL = object() |