11import copy
2- from typing import Any , Dict , Optional
3- from pydantic . v1 import BaseModel
2+ from typing import Any
3+
44
55class DeepCopyError (Exception ):
66 """Custom exception raised when an object cannot be deep-copied."""
7+
78 pass
89
10+
11+ def is_boto3_client (obj ):
12+ import sys
13+
14+ # check boto3 module imprort
15+ boto3_module = sys .modules .get ("boto3" )
16+
17+ if boto3_module :
18+ # boto3 use botocore client so here we import botocore
19+ # if boto3 was imported the botocore will be import automatically normally
20+ try :
21+ from botocore .client import BaseClient
22+
23+ return isinstance (obj , BaseClient )
24+ except (AttributeError , ImportError ):
25+ # if the module is not imported, or the BaseClient class does not exist, return False
26+ # if custome module name is boto3, the BaseClient class does not exist,
27+ return False
28+ return False
29+
30+
931def safe_deepcopy (obj : Any ) -> Any :
1032 """
1133 Attempts to create a deep copy of the object using `copy.deepcopy`
1234 whenever possible. If that fails, it falls back to custom deep copy
1335 logic. If that also fails, it raises a `DeepCopyError`.
14-
36+
1537 Args:
1638 obj (Any): The object to be copied, which can be of any type.
1739
@@ -24,7 +46,7 @@ def safe_deepcopy(obj: Any) -> Any:
2446 """
2547
2648 try :
27-
49+
2850 # Try to use copy.deepcopy first
2951 return copy .deepcopy (obj )
3052 except (TypeError , AttributeError ) as e :
@@ -33,43 +55,40 @@ def safe_deepcopy(obj: Any) -> Any:
3355 # Handle dictionaries
3456 if isinstance (obj , dict ):
3557 new_obj = {}
36-
58+
3759 for k , v in obj .items ():
3860 new_obj [k ] = safe_deepcopy (v )
3961 return new_obj
4062
4163 # Handle lists
4264 elif isinstance (obj , list ):
4365 new_obj = []
44-
66+
4567 for v in obj :
4668 new_obj .append (safe_deepcopy (v ))
4769 return new_obj
4870
4971 # Handle tuples (immutable, but might contain mutable objects)
5072 elif isinstance (obj , tuple ):
5173 new_obj = tuple (safe_deepcopy (v ) for v in obj )
52-
74+
5375 return new_obj
5476
5577 # Handle frozensets (immutable, but might contain mutable objects)
5678 elif isinstance (obj , frozenset ):
5779 new_obj = frozenset (safe_deepcopy (v ) for v in obj )
5880 return new_obj
5981
82+ elif is_boto3_client (obj ):
83+ return obj
84+
6085 # Handle objects with attributes
61- elif hasattr ( obj , "__dict__" ) :
86+ else :
6287 # If an object cannot be deep copied, then the sub-properties of \
6388 # the object will not be analyzed and shallow copy will be used directly.
6489 try :
6590 return copy .copy (obj )
6691 except (TypeError , AttributeError ):
67- raise DeepCopyError (f"Cannot deep copy the object of type { type (obj )} " ) from e
68-
69-
70- # Attempt shallow copy as a fallback
71- try :
72- return copy .copy (obj )
73- except (TypeError , AttributeError ):
74- raise DeepCopyError (f"Cannot deep copy the object of type { type (obj )} " ) from e
75-
92+ raise DeepCopyError (
93+ f"Cannot deep copy the object of type { type (obj )} "
94+ ) from e
0 commit comments