abstract-utilities 0.2.2.495__py3-none-any.whl → 0.2.2.504__py3-none-any.whl

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 (126) hide show
  1. abstract_utilities/__init__.py +5 -9
  2. abstract_utilities/class_utils/__init__.py +7 -0
  3. abstract_utilities/class_utils/abstract_classes.py +74 -0
  4. abstract_utilities/class_utils/caller_utils.py +35 -0
  5. abstract_utilities/class_utils/class_utils.py +109 -0
  6. abstract_utilities/class_utils/function_utils.py +153 -0
  7. abstract_utilities/class_utils/global_utils.py +56 -0
  8. abstract_utilities/class_utils/imports/__init__.py +2 -0
  9. abstract_utilities/class_utils/imports/imports.py +2 -0
  10. abstract_utilities/class_utils/imports/utils.py +40 -0
  11. abstract_utilities/class_utils/module_utils.py +63 -0
  12. abstract_utilities/env_utils/imports/imports.py +3 -2
  13. abstract_utilities/error_utils/__init__.py +2 -0
  14. abstract_utilities/error_utils/error_utils.py +25 -0
  15. abstract_utilities/error_utils/imports/__init__.py +2 -0
  16. abstract_utilities/error_utils/imports/imports.py +1 -0
  17. abstract_utilities/error_utils/imports/module_imports.py +1 -0
  18. abstract_utilities/file_utils/imports/imports.py +3 -18
  19. abstract_utilities/file_utils/imports/module_imports.py +3 -6
  20. abstract_utilities/file_utils/src/type_checks.py +0 -1
  21. abstract_utilities/hash_utils/__init__.py +2 -0
  22. abstract_utilities/hash_utils/hash_utils.py +5 -0
  23. abstract_utilities/hash_utils/imports/__init__.py +2 -0
  24. abstract_utilities/hash_utils/imports/imports.py +1 -0
  25. abstract_utilities/hash_utils/imports/module_imports.py +0 -0
  26. abstract_utilities/history_utils/__init__.py +2 -0
  27. abstract_utilities/history_utils/history_utils.py +37 -0
  28. abstract_utilities/history_utils/imports/__init__.py +2 -0
  29. abstract_utilities/history_utils/imports/imports.py +1 -0
  30. abstract_utilities/history_utils/imports/module_imports.py +0 -0
  31. abstract_utilities/import_utils/imports/imports.py +1 -1
  32. abstract_utilities/import_utils/imports/module_imports.py +1 -1
  33. abstract_utilities/import_utils/src/__init__.py +1 -1
  34. abstract_utilities/import_utils/src/clean_imports.py +31 -5
  35. abstract_utilities/import_utils/src/dot_utils.py +9 -0
  36. abstract_utilities/import_utils/src/package_utilss/__init__.py +139 -0
  37. abstract_utilities/import_utils/src/package_utilss/context_utils.py +27 -0
  38. abstract_utilities/import_utils/src/package_utilss/import_collectors.py +53 -0
  39. abstract_utilities/import_utils/src/package_utilss/path_utils.py +28 -0
  40. abstract_utilities/import_utils/src/package_utilss/safe_import.py +27 -0
  41. abstract_utilities/import_utils/src/pkg_utils.py +140 -0
  42. abstract_utilities/imports.py +18 -0
  43. abstract_utilities/json_utils/__init__.py +2 -0
  44. abstract_utilities/json_utils/imports/__init__.py +2 -0
  45. abstract_utilities/json_utils/imports/imports.py +2 -0
  46. abstract_utilities/json_utils/imports/module_imports.py +5 -0
  47. abstract_utilities/json_utils/json_utils.py +743 -0
  48. abstract_utilities/list_utils/__init__.py +2 -0
  49. abstract_utilities/list_utils/imports/__init__.py +2 -0
  50. abstract_utilities/list_utils/imports/imports.py +1 -0
  51. abstract_utilities/list_utils/imports/module_imports.py +0 -0
  52. abstract_utilities/list_utils/list_utils.py +199 -0
  53. abstract_utilities/log_utils/__init__.py +5 -0
  54. abstract_utilities/log_utils/abstractLogManager.py +64 -0
  55. abstract_utilities/log_utils/call_response.py +68 -0
  56. abstract_utilities/log_utils/imports/__init__.py +2 -0
  57. abstract_utilities/log_utils/imports/imports.py +7 -0
  58. abstract_utilities/log_utils/imports/module_imports.py +2 -0
  59. abstract_utilities/log_utils/log_file.py +56 -0
  60. abstract_utilities/log_utils/logger_callable.py +49 -0
  61. abstract_utilities/math_utils/__init__.py +2 -0
  62. abstract_utilities/math_utils/imports/__init__.py +2 -0
  63. abstract_utilities/math_utils/imports/imports.py +2 -0
  64. abstract_utilities/math_utils/imports/module_imports.py +1 -0
  65. abstract_utilities/math_utils/math_utils.py +208 -0
  66. abstract_utilities/parse_utils/__init__.py +2 -0
  67. abstract_utilities/parse_utils/imports/__init__.py +3 -0
  68. abstract_utilities/parse_utils/imports/constants.py +10 -0
  69. abstract_utilities/parse_utils/imports/imports.py +2 -0
  70. abstract_utilities/parse_utils/imports/module_imports.py +4 -0
  71. abstract_utilities/parse_utils/parse_utils.py +516 -0
  72. abstract_utilities/path_utils/__init__.py +2 -0
  73. abstract_utilities/path_utils/imports/__init__.py +2 -0
  74. abstract_utilities/path_utils/imports/imports.py +1 -0
  75. abstract_utilities/path_utils/imports/module_imports.py +6 -0
  76. abstract_utilities/path_utils/path_utils.py +715 -0
  77. abstract_utilities/path_utils.py +94 -2
  78. abstract_utilities/read_write_utils/__init__.py +1 -0
  79. abstract_utilities/read_write_utils/imports/__init__.py +2 -0
  80. abstract_utilities/read_write_utils/imports/imports.py +2 -0
  81. abstract_utilities/read_write_utils/imports/module_imports.py +5 -0
  82. abstract_utilities/read_write_utils/read_write_utils.py +338 -0
  83. abstract_utilities/read_write_utils.py +2 -4
  84. abstract_utilities/safe_utils/__init__.py +2 -0
  85. abstract_utilities/safe_utils/imports/__init__.py +3 -0
  86. abstract_utilities/safe_utils/imports/imports.py +1 -0
  87. abstract_utilities/safe_utils/imports/module_imports.py +2 -0
  88. abstract_utilities/safe_utils/safe_utils.py +130 -0
  89. abstract_utilities/ssh_utils/__init__.py +2 -1
  90. abstract_utilities/ssh_utils/classes.py +0 -1
  91. abstract_utilities/ssh_utils/cmd_utils.py +207 -0
  92. abstract_utilities/ssh_utils/imports/__init__.py +3 -0
  93. abstract_utilities/ssh_utils/imports/imports.py +5 -0
  94. abstract_utilities/ssh_utils/imports/module_imports.py +5 -0
  95. abstract_utilities/ssh_utils/imports/utils.py +189 -0
  96. abstract_utilities/ssh_utils/pexpect_utils.py +11 -18
  97. abstract_utilities/string_utils/__init__.py +4 -0
  98. abstract_utilities/string_utils/clean_utils.py +28 -0
  99. abstract_utilities/string_utils/eat_utils.py +103 -0
  100. abstract_utilities/string_utils/imports/__init__.py +3 -0
  101. abstract_utilities/string_utils/imports/imports.py +2 -0
  102. abstract_utilities/string_utils/imports/module_imports.py +2 -0
  103. abstract_utilities/string_utils/imports/utils.py +81 -0
  104. abstract_utilities/string_utils/replace_utils.py +27 -0
  105. abstract_utilities/thread_utils/__init__.py +2 -0
  106. abstract_utilities/thread_utils/imports/__init__.py +2 -0
  107. abstract_utilities/thread_utils/imports/imports.py +2 -0
  108. abstract_utilities/thread_utils/imports/module_imports.py +2 -0
  109. abstract_utilities/thread_utils/thread_utils.py +140 -0
  110. abstract_utilities/time_utils/__init__.py +2 -0
  111. abstract_utilities/time_utils/imports/__init__.py +2 -0
  112. abstract_utilities/time_utils/imports/imports.py +3 -0
  113. abstract_utilities/time_utils/imports/module_imports.py +1 -0
  114. abstract_utilities/time_utils/time_utils.py +392 -0
  115. abstract_utilities/type_utils/__init__.py +3 -0
  116. abstract_utilities/type_utils/alpha_utils.py +59 -0
  117. abstract_utilities/type_utils/imports/__init__.py +2 -0
  118. abstract_utilities/type_utils/imports/imports.py +4 -0
  119. abstract_utilities/type_utils/imports/module_imports.py +1 -0
  120. abstract_utilities/type_utils/num_utils.py +19 -0
  121. abstract_utilities/type_utils/type_utils.py +981 -0
  122. {abstract_utilities-0.2.2.495.dist-info → abstract_utilities-0.2.2.504.dist-info}/METADATA +1 -1
  123. abstract_utilities-0.2.2.504.dist-info/RECORD +229 -0
  124. abstract_utilities-0.2.2.495.dist-info/RECORD +0 -123
  125. {abstract_utilities-0.2.2.495.dist-info → abstract_utilities-0.2.2.504.dist-info}/WHEEL +0 -0
  126. {abstract_utilities-0.2.2.495.dist-info → abstract_utilities-0.2.2.504.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,2 @@
1
+ from .imports import *
2
+ from .list_utils import *
@@ -0,0 +1,2 @@
1
+ from .imports import *
2
+ from .module_imports import *
@@ -0,0 +1,199 @@
1
+ """
2
+ list_utils.py
3
+
4
+ This module provides a set of utility functions tailored for manipulating lists. It offers capabilities to:
5
+
6
+ - Sort lists and retrieve elements at specific positions.
7
+ - Combine two lists.
8
+ - Ensure that objects are contained within nested lists.
9
+ - Add multiple values to a list.
10
+
11
+ The `list_utils` module is designed to simplify and abstract common list operations, enhancing code readability and reusability.
12
+
13
+ Note: While Python's native list methods are comprehensive, the functions here provide additional checks and transformations that might be commonly needed in various applications.
14
+
15
+ This module is part of the `abstract_utilities` package.
16
+
17
+ Author: putkoff
18
+ Date: 05/31/2023
19
+ Version: 0.1.2
20
+ """
21
+ def get_sort(ls: list, k: int = 0):
22
+ """
23
+ Sorts a list in ascending order and returns the element at index k.
24
+
25
+ Args:
26
+ ls (list): The list to be sorted.
27
+ k (int, optional): The index of the element to return. Defaults to 0.
28
+
29
+ Returns:
30
+ any: The element at index k after sorting the list.
31
+ """
32
+ ls.sort()
33
+ return ls[k]
34
+
35
+ def combineList(ls: list, lsN: list) -> list:
36
+ """
37
+ Combines two lists and returns the combined list.
38
+
39
+ Args:
40
+ ls (list): The first list.
41
+ lsN (list): The second list.
42
+
43
+ Returns:
44
+ list: The combined list.
45
+ """
46
+ for k in range(len(lsN)):
47
+ ls.append(lsN[k])
48
+ return ls
49
+
50
+ def find_original_case(input_list, search_string):
51
+ """
52
+ Searches for a case-insensitive match of 'search_string' within 'input_list'
53
+ and returns the first matching element in its original case.
54
+
55
+ Args:
56
+ input_list (list): The list of strings to search within.
57
+ search_string (str): The case-insensitive string to search for.
58
+
59
+ Returns:
60
+ str or None: The first element in 'input_list' that matches 'search_string'
61
+ in its original case, or None if no match is found.
62
+ """
63
+ for obj in input_list:
64
+ if obj.lower() == search_string.lower():
65
+ return obj
66
+ return None
67
+
68
+ def ensure_nested_list(obj):
69
+ """
70
+ Ensure that the input object is a nested list.
71
+
72
+ Args:
73
+ obj (any): The object to ensure as a nested list.
74
+
75
+ Returns:
76
+ list: A nested list containing the object or the original list if it's already nested.
77
+ """
78
+ # Check if the input object is a list
79
+ if not isinstance(obj, list):
80
+ # If it's not a list, create a new nested list containing the object
81
+ return [obj]
82
+ # If it is a list, check if any of its elements are non-list objects
83
+ for element in obj:
84
+ if not isinstance(element, list):
85
+ # If at least one element is not a list, wrap the original list in a new list
86
+ return [obj]
87
+ # If all elements are lists, return the original list
88
+ return obj
89
+ def make_list_add(obj,values):
90
+ """
91
+ Add multiple values to a list and return the resulting list.
92
+
93
+ Args:
94
+ obj (list): The original list.
95
+ values (iterable): Values to be added to the list.
96
+
97
+ Returns:
98
+ list: The modified list containing the original elements and the added values.
99
+ """
100
+ obj = list(obj)
101
+ for each in list(values):
102
+ obj.append(each)
103
+ return obj
104
+
105
+ def recursive_json_list(json_list:dict,desired_values:dict)->list:
106
+ """
107
+ Filters the json list based on the desired_values.
108
+
109
+ Returns:
110
+ - list: A filtered json list of desired_values held within json object keys.
111
+ """
112
+ # Start with the full list of json objects
113
+ # For each key in the selection values, filter the list if the key's value is set
114
+ recursed_list=[]
115
+ for json_obj in json_list:
116
+ bool_count = 0
117
+ for desired_key, desired_value in desired_values.items():
118
+ if desired_key in json_obj:
119
+ if json_obj[desired_key] == desired_value:
120
+ bool_count +=1
121
+ static = desired_value
122
+ if bool_count == len(list(desired_values.keys())):
123
+ recursed_list.append(json_obj)
124
+ return recursed_list
125
+
126
+ def filter_json_list_values(json_list:list,keys:list)->None:
127
+ """
128
+ Updates the GUI dropdown lists based on the filtered RPC list.
129
+ """
130
+ # Get the filtered list of json values based on current key selections
131
+ all_keys={}
132
+ for key in keys:
133
+ unique_values=[]
134
+ for json_obj in json_list:
135
+ if key in json_obj:
136
+ if json_obj[key] not in unique_values:
137
+ unique_values.append(json_obj[key])
138
+ all_keys[key]= unique_values
139
+ return all_keys
140
+ def get_highest_value_obj(obj_list, function):
141
+ return max(obj_list, key=function)
142
+
143
+ def safe_list_return(current_list,list_num=0):
144
+ if len(current_list) >= list_num+1:
145
+ return current_list[int(list_num)]
146
+ def get_actual_number(reference_object,number_value):
147
+ try:
148
+ reference_length = len(reference_object)
149
+ except:
150
+ reference_length = 0
151
+ if reference_length ==0:
152
+ return None
153
+ return max(0, min(number_value, reference_length-1))
154
+ def compare_lists(list_1,list_2):
155
+ if len(list_1)>len(list_2):
156
+ return False
157
+ for each in list_1:
158
+ if each not in list_2:
159
+ return False
160
+ return True
161
+ def remove_from_list(list_obj, key, value):
162
+ return [obj for obj in list_obj if not (isinstance(obj, dict) and obj.get(key) == value)]
163
+
164
+ def list_set(obj):
165
+ try:
166
+ obj = list(set(obj))
167
+ except Exception as e:
168
+ print(f"{e}")
169
+ return obj
170
+
171
+ def get_symetric_difference(obj_1,obj_2):
172
+ set1 = set(obj_1)
173
+ set2 = set(obj_2)
174
+ # Find elements that are unique to each list
175
+ unique_elements = set1.symmetric_difference(set2)
176
+ # Convert the set back to a list, if needed
177
+ return list(unique_elements)
178
+ def make_list(obj:any) -> list:
179
+ """
180
+ Converts the input object to a list. If the object is already a list, it is returned as is.
181
+
182
+ Args:
183
+ obj: The object to convert.
184
+
185
+ Returns:
186
+ list: The object as a list.
187
+ """
188
+ if isinstance(obj,str):
189
+ if ',' in obj:
190
+ obj = obj.split(',')
191
+ if isinstance(obj,set) or isinstance(obj,tuple):
192
+ return list(obj)
193
+ if isinstance(obj, list):
194
+ return obj
195
+ return [obj]
196
+
197
+ def make_list_it(obj=None):
198
+ obj = make_list(obj or [])
199
+ return obj
@@ -0,0 +1,5 @@
1
+ from .abstractLogManager import *
2
+ from .imports import *
3
+ from .call_response import *
4
+ from .log_file import *
5
+ from .logger_callable import *
@@ -0,0 +1,64 @@
1
+ from .imports import *
2
+ class AbstractLogManager(metaclass=SingletonMeta):
3
+ def __init__(self):
4
+ # Create a logger; use __name__ to have a module-specific logger if desired.
5
+ self.logger = logging.getLogger("AbstractLogManager")
6
+ self.logger.setLevel(logging.DEBUG) # Set to lowest level to let handlers filter as needed.
7
+
8
+ # Create a console handler with a default level.
9
+ self.console_handler = logging.StreamHandler()
10
+ # Default level: show warnings and above.
11
+ self.console_handler.setLevel(logging.WARNING)
12
+
13
+ # Formatter for the logs.
14
+ formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
15
+ self.console_handler.setFormatter(formatter)
16
+
17
+ # If there are no handlers already attached, add our console handler.
18
+ if not self.logger.hasHandlers():
19
+ self.logger.addHandler(self.console_handler)
20
+
21
+ def set_debug(self, enabled: bool) -> None:
22
+ """
23
+ Enable or disable DEBUG level messages.
24
+ When enabled, the console handler will output DEBUG messages and above.
25
+ When disabled, it falls back to INFO or WARNING (adjust as needed).
26
+ """
27
+ if enabled:
28
+ self.console_handler.setLevel(logging.DEBUG)
29
+ self.logger.debug("DEBUG logging enabled.")
30
+ else:
31
+ # For example, disable DEBUG by raising the level to INFO.
32
+ self.console_handler.setLevel(logging.INFO)
33
+ self.logger.info("DEBUG logging disabled; INFO level active.")
34
+
35
+ def set_info(self, enabled: bool) -> None:
36
+ """
37
+ Enable or disable INFO level messages.
38
+ When enabled, INFO and above are shown; when disabled, only WARNING and above.
39
+ """
40
+ if enabled:
41
+ # Lower the handler level to INFO if currently higher.
42
+ self.console_handler.setLevel(logging.INFO)
43
+ self.logger.info("INFO logging enabled.")
44
+ else:
45
+ self.console_handler.setLevel(logging.WARNING)
46
+ self.logger.warning("INFO logging disabled; only WARNING and above will be shown.")
47
+
48
+ def set_warning(self, enabled: bool) -> None:
49
+ """
50
+ Enable or disable WARNING level messages.
51
+ When disabled, only ERROR and CRITICAL messages are shown.
52
+ """
53
+ if enabled:
54
+ # WARNING messages enabled means handler level is WARNING.
55
+ self.console_handler.setLevel(logging.WARNING)
56
+ self.logger.warning("WARNING logging enabled.")
57
+ else:
58
+ self.console_handler.setLevel(logging.ERROR)
59
+ self.logger.error("WARNING logging disabled; only ERROR and CRITICAL messages will be shown.")
60
+
61
+ def get_logger(self) -> logging.Logger:
62
+ """Return the configured logger instance."""
63
+ return self.logger
64
+
@@ -0,0 +1,68 @@
1
+ from .imports import *
2
+ from .logger_callable import *
3
+ def initialize_call_log(value=None,
4
+ data=None,
5
+ logMsg=None,
6
+ log_level=None):
7
+ """
8
+ Inspect the stack to find the first caller *outside* this module,
9
+ then log its function name and file path.
10
+ """
11
+ # Grab the current stack
12
+ stack = inspect.stack()
13
+ caller_name = "<unknown>"
14
+ caller_path = "<unknown>"
15
+ log_level = log_level or 'info'
16
+ try:
17
+ # Starting at index=1 to skip initialize_call_log itself
18
+ for frame_info in stack[1:]:
19
+ modname = frame_info.frame.f_globals.get("__name__", "")
20
+ # Skip over frames in your logging modules:
21
+ if not modname.startswith("abstract_utilities.log_utils") \
22
+ and not modname.startswith("abstract_flask.request_utils") \
23
+ and not modname.startswith("logging"):
24
+ caller_name = frame_info.function
25
+ caller_path = frame_info.filename
26
+ break
27
+ finally:
28
+ # Avoid reference cycles
29
+ del stack
30
+
31
+ logMsg = logMsg or "initializing"
32
+ full_message = (
33
+ f"{logMsg}\n"
34
+ f"calling_function: {caller_name}\n"
35
+ f"path: {caller_path}\n"
36
+ f"data: {data}"
37
+ )
38
+
39
+ print_or_log(full_message,level=log_level)
40
+ def _normalize(obj):
41
+ """Recursively turn PosixPath into str, sets into list, etc."""
42
+ if isinstance(obj, Path):
43
+ return str(obj)
44
+ if isinstance(obj, dict):
45
+ return {k: _normalize(v) for k, v in obj.items()}
46
+ if isinstance(obj, (list, tuple, set)):
47
+ return [_normalize(x) for x in obj]
48
+ return obj
49
+ def get_json_call_response(value=None, status_code=None, data=None, logMsg=None, callLog=False):
50
+ response_body = {}
51
+ if status_code == 200:
52
+ response_body["success"] = True
53
+ response_body["result"] = _normalize(value)
54
+ logMsg = logMsg or "success"
55
+ if callLog:
56
+ initialize_call_log(value=value,
57
+ data=data,
58
+ logMsg=logMsg,
59
+ log_level='info')
60
+ else:
61
+ response_body["success"] = False
62
+ response_body["error"] = _normalize(value)
63
+ logMsg = logMsg or f"ERROR: {logMsg}"
64
+ initialize_call_log(value=value,
65
+ data=data,
66
+ logMsg=logMsg,
67
+ log_level='error')
68
+ return jsonify(response_body), status_code
@@ -0,0 +1,2 @@
1
+ from .imports import *
2
+ from .module_imports import *
@@ -0,0 +1,7 @@
1
+ from ...imports import logging
2
+ from ...imports import os
3
+ from ...imports import inspect
4
+ from flask import jsonify
5
+ from logging.handlers import RotatingFileHandler
6
+ from pathlib import Path
7
+
@@ -0,0 +1,2 @@
1
+ from ...path_utils import mkdirs
2
+ from ...class_utils import SingletonMeta
@@ -0,0 +1,56 @@
1
+ from .imports import *
2
+ def get_logFile(bpName: str = None, maxBytes: int = 100_000, backupCount: int = 3) -> logging.Logger:
3
+ """
4
+ If bpName is None, use the “caller module’s basename” as the logger name.
5
+ Otherwise, use the explicitly provided bpName.
6
+ """
7
+ if bpName is None:
8
+ # Find the first frame outside logging_utils.py
9
+ frame_idx = _find_caller_frame_index()
10
+ frame_info = inspect.stack()[frame_idx]
11
+ caller_path = frame_info.filename # e.g. "/home/joe/project/app/routes.py"
12
+ bpName = os.path.splitext(os.path.basename(caller_path))[0]
13
+ del frame_info
14
+
15
+ log_dir = mkdirs("logs")
16
+ log_path = os.path.join(log_dir, f"{bpName}.log")
17
+
18
+ logger = logging.getLogger(bpName)
19
+ logger.setLevel(logging.INFO)
20
+
21
+ if not logger.handlers:
22
+ handler = RotatingFileHandler(log_path, maxBytes=maxBytes, backupCount=backupCount)
23
+ handler.setLevel(logging.INFO)
24
+
25
+ fmt = "%(asctime)s - %(levelname)s - %(pathname)s - %(message)s"
26
+ formatter = logging.Formatter(fmt)
27
+ handler.setFormatter(formatter)
28
+ logger.addHandler(handler)
29
+
30
+ console = logging.StreamHandler()
31
+ console.setLevel(logging.INFO)
32
+ console.setFormatter(formatter)
33
+ logger.addHandler(console)
34
+
35
+ return logger
36
+
37
+ def _find_caller_frame_index():
38
+ """
39
+ Scan up the call stack until we find a frame whose module is NOT logging_utils.
40
+ Return that index in inspect.stack().
41
+ """
42
+ for idx, frame_info in enumerate(inspect.stack()):
43
+ # Ignore the very first frame (idx=0), which is this function itself.
44
+ if idx == 0:
45
+ continue
46
+ module = inspect.getmodule(frame_info.frame)
47
+ # If module is None (e.g. interactive), skip it;
48
+ # else get module.__name__ and compare:
49
+ module_name = module.__name__ if module else None
50
+
51
+ # Replace 'yourpackage.logging_utils' with whatever your actual module path is:
52
+ if module_name != __name__ and not module_name.startswith("logging"):
53
+ # We found a frame that isn’t in this helper module or the stdlib logging.
54
+ return idx
55
+ # Fallback to 1 (the immediate caller) if nothing else matches:
56
+ return 1
@@ -0,0 +1,49 @@
1
+ from .imports import *
2
+ from .log_file import *
3
+ def get_logger_callable(logger, level="info"):
4
+ if logger is None:
5
+ return None
6
+ elif isinstance(logger, logging.Logger):
7
+ return getattr(logger, level.lower(), None)
8
+ elif callable(logger) and hasattr(logger, "__self__") and isinstance(logger.__self__, logging.Logger):
9
+ return logger
10
+ else:
11
+ return None
12
+
13
+
14
+ def _find_caller_frame_index():
15
+ """
16
+ Return the index in inspect.stack() of the first frame
17
+ that’s not in this module or the logging stdlib.
18
+ """
19
+ for idx, frame_info in enumerate(inspect.stack()):
20
+ fn = frame_info.filename
21
+ if not fn.endswith("logging_utils.py") and "logging" not in os.path.basename(fn):
22
+ return idx
23
+ return 0 # fallback
24
+
25
+ def get_caller_info():
26
+ """
27
+ Returns (caller_path, caller_idx).
28
+ caller_idx is the index into inspect.stack() where the call came from.
29
+ """
30
+ idx = _find_caller_frame_index()
31
+ frame = inspect.stack()[idx]
32
+ return frame.filename, idx
33
+
34
+ def print_or_log(message, logger=True, level="info"):
35
+ # 1) grab both the path and the numeric index
36
+ caller_path, caller_idx = get_caller_info()
37
+
38
+ # 2) decide which logger object to use
39
+ if logger is True:
40
+ bpName = os.path.splitext(os.path.basename(caller_path))[0]
41
+ logger = get_logFile(bpName)
42
+
43
+ # 3) pick the right logging method
44
+ log_callable = get_logger_callable(logger, level=level)
45
+ if log_callable:
46
+ # pass the integer stacklevel = caller_idx + 1
47
+ log_callable(message, stacklevel=caller_idx + 1)
48
+ else:
49
+ print(message)
@@ -0,0 +1,2 @@
1
+ from .imports import *
2
+ from .math_utils import *
@@ -0,0 +1,2 @@
1
+ from .imports import *
2
+ from .module_imports import *
@@ -0,0 +1,2 @@
1
+ from ...imports import math
2
+ from functools import reduce
@@ -0,0 +1 @@
1
+ from ...type_utils import det_bool_T,is_number