Skip to content

Commit fe98885

Browse files
better instrospection unit tests
1 parent 52a0b18 commit fe98885

2 files changed

Lines changed: 709 additions & 119 deletions

File tree

energyml-utils/src/energyml/utils/introspection.py

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ def get_module_name(domain: str, domain_version: str):
281281
ns = ENERGYML_NAMESPACES[domain]
282282
if not domain_version.startswith("v"):
283283
domain_version = "v" + domain_version
284+
285+
if "." in domain_version:
286+
domain_version = domain_version.replace(".", "_")
284287
return f"energyml.{domain}.{domain_version}.{ns[ns.rindex('/') + 1:]}"
285288

286289

@@ -368,6 +371,9 @@ def get_class_attributes(cls: Union[type, Any]) -> List[str]:
368371

369372

370373
def get_class_attribute_type(cls: Union[type, Any], attribute_name: str):
374+
"""
375+
Return the type of an attribute of a class.
376+
"""
371377
fields = get_class_fields(cls)
372378
try:
373379
return fields[attribute_name].type
@@ -430,7 +436,7 @@ def get_object_attribute(obj: Any, attr_dot_path: str, force_snake_case=True) ->
430436
431437
:param obj:
432438
:param attr_dot_path:
433-
:param force_snake_case:
439+
:param force_snake_case: if True, the method will try to find the attribute name in snake case (only for class attribute, not for dict keys nor list index)
434440
:return:
435441
"""
436442
current_attrib_name, path_next = path_next_attribute(attr_dot_path)
@@ -439,16 +445,15 @@ def get_object_attribute(obj: Any, attr_dot_path: str, force_snake_case=True) ->
439445
logging.error(f"Attribute path '{attr_dot_path}' is invalid.")
440446
return None
441447

442-
if force_snake_case:
443-
current_attrib_name = snake_case(current_attrib_name)
444-
445448
value = None
446449
if isinstance(obj, list):
447450
value = obj[int(current_attrib_name)]
448451
elif isinstance(obj, dict):
449452
value = obj.get(current_attrib_name, None)
450453
else:
451454
try:
455+
if force_snake_case:
456+
current_attrib_name = snake_case(current_attrib_name)
452457
value = getattr(obj, current_attrib_name)
453458
except AttributeError:
454459
return None
@@ -960,7 +965,7 @@ def search_attribute_matching_name_with_path(
960965
re_flags=re_flags,
961966
current_path=matched_path,
962967
deep_search=deep_search, # no deep with partial
963-
search_in_sub_obj=True,
968+
search_in_sub_obj=search_in_sub_obj,
964969
)
965970
if search_in_sub_obj:
966971
for not_matched_path, not_matched in not_match_path_and_obj:
@@ -989,8 +994,8 @@ def search_attribute_matching_name(
989994
:param obj:
990995
:param name_rgx:
991996
:param re_flags:
992-
:param deep_search:
993-
:param search_in_sub_obj:
997+
:param deep_search: if True, the method will search for matching attribute in the sub attributes of a matching attribute (recursive search). If False, only the first level of attributes will be searched for a match.
998+
:param search_in_sub_obj: if True, the method will search for matching attribute in the sub attributes of a non-matching attribute (recursive search). If False, only the first level of attributes will be searched for a match.
994999
:return:
9951000
"""
9961001
return [
@@ -1136,7 +1141,14 @@ def get_obj_uuid(obj: Any) -> Optional[str]:
11361141
:param obj:
11371142
:return:
11381143
"""
1139-
return getattr(obj, "uuid", None) or getattr(obj, "uid", None)
1144+
try:
1145+
return getattr(obj, "uuid", None) or getattr(obj, "uid")
1146+
except AttributeError:
1147+
if isinstance(obj, dict):
1148+
for k in obj.keys():
1149+
if re.match(r"[Uu]u?id|UUID", k):
1150+
return obj[k]
1151+
return None
11401152
# return get_object_attribute_rgx(obj, "[Uu]u?id|UUID")
11411153

11421154

@@ -1150,7 +1162,7 @@ def get_obj_version(obj: Any) -> Optional[str]:
11501162
return (
11511163
getattr(obj, "object_version", None)
11521164
or getattr(obj, "version_string", None)
1153-
or (getattr(obj, "citation", None) and getattr(obj.citation, "version_string", None))
1165+
or getattr(getattr(obj, "citation"), "version_string", None)
11541166
)
11551167
except AttributeError:
11561168
# Log with full call stack to see WHO called this function
@@ -1159,6 +1171,14 @@ def get_obj_version(obj: Any) -> Optional[str]:
11591171
# exc_info=True,
11601172
# stack_info=True, # This shows the full call stack including caller
11611173
# )
1174+
if isinstance(obj, dict):
1175+
for k in obj.keys():
1176+
if re.match(r"object_version|version_string", k, re.IGNORECASE):
1177+
return obj[k]
1178+
elif re.match(r"citation", k, re.IGNORECASE) and isinstance(obj[k], dict):
1179+
for ck in obj[k].keys():
1180+
if re.match(r"version_string", ck, re.IGNORECASE):
1181+
return obj[k][ck]
11621182
pass
11631183
return None
11641184
# raise e
@@ -1171,10 +1191,15 @@ def get_obj_title(obj: Any) -> Optional[str]:
11711191
:return:
11721192
"""
11731193
try:
1174-
return getattr(obj, "citation", None) and getattr(obj.citation, "title", None)
1175-
# return get_object_attribute_advanced(obj, "citation.title")
1194+
return getattr(getattr(obj, "citation"), "title", None)
11761195
except AttributeError:
1177-
return None
1196+
if isinstance(obj, dict):
1197+
for k in obj.keys():
1198+
if re.match(r"citation", k, re.IGNORECASE) and isinstance(obj[k], dict):
1199+
for ck in obj[k].keys():
1200+
if re.match(r"title", ck, re.IGNORECASE):
1201+
return obj[k][ck]
1202+
return None
11781203

11791204

11801205
def get_obj_pkg_pkgv_type_uuid_version(

0 commit comments

Comments
 (0)