bear-utils 0.7.11__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.
- bear_utils/__init__.py +13 -0
- bear_utils/ai/__init__.py +30 -0
- bear_utils/ai/ai_helpers/__init__.py +130 -0
- bear_utils/ai/ai_helpers/_common.py +19 -0
- bear_utils/ai/ai_helpers/_config.py +24 -0
- bear_utils/ai/ai_helpers/_parsers.py +188 -0
- bear_utils/ai/ai_helpers/_types.py +20 -0
- bear_utils/cache/__init__.py +119 -0
- bear_utils/cli/__init__.py +4 -0
- bear_utils/cli/commands.py +59 -0
- bear_utils/cli/prompt_helpers.py +166 -0
- bear_utils/cli/shell/__init__.py +0 -0
- bear_utils/cli/shell/_base_command.py +74 -0
- bear_utils/cli/shell/_base_shell.py +390 -0
- bear_utils/cli/shell/_common.py +19 -0
- bear_utils/config/__init__.py +11 -0
- bear_utils/config/config_manager.py +92 -0
- bear_utils/config/dir_manager.py +64 -0
- bear_utils/config/settings_manager.py +232 -0
- bear_utils/constants/__init__.py +16 -0
- bear_utils/constants/_exceptions.py +3 -0
- bear_utils/constants/_lazy_typing.py +15 -0
- bear_utils/constants/date_related.py +36 -0
- bear_utils/constants/time_related.py +22 -0
- bear_utils/database/__init__.py +6 -0
- bear_utils/database/_db_manager.py +104 -0
- bear_utils/events/__init__.py +16 -0
- bear_utils/events/events_class.py +52 -0
- bear_utils/events/events_module.py +65 -0
- bear_utils/extras/__init__.py +17 -0
- bear_utils/extras/_async_helpers.py +15 -0
- bear_utils/extras/_tools.py +178 -0
- bear_utils/extras/platform_utils.py +53 -0
- bear_utils/extras/wrappers/__init__.py +0 -0
- bear_utils/extras/wrappers/add_methods.py +98 -0
- bear_utils/files/__init__.py +4 -0
- bear_utils/files/file_handlers/__init__.py +3 -0
- bear_utils/files/file_handlers/_base_file_handler.py +93 -0
- bear_utils/files/file_handlers/file_handler_factory.py +278 -0
- bear_utils/files/file_handlers/json_file_handler.py +44 -0
- bear_utils/files/file_handlers/log_file_handler.py +33 -0
- bear_utils/files/file_handlers/txt_file_handler.py +34 -0
- bear_utils/files/file_handlers/yaml_file_handler.py +57 -0
- bear_utils/files/ignore_parser.py +298 -0
- bear_utils/graphics/__init__.py +4 -0
- bear_utils/graphics/bear_gradient.py +140 -0
- bear_utils/graphics/image_helpers.py +39 -0
- bear_utils/gui/__init__.py +3 -0
- bear_utils/gui/gui_tools/__init__.py +5 -0
- bear_utils/gui/gui_tools/_settings.py +37 -0
- bear_utils/gui/gui_tools/_types.py +12 -0
- bear_utils/gui/gui_tools/qt_app.py +145 -0
- bear_utils/gui/gui_tools/qt_color_picker.py +119 -0
- bear_utils/gui/gui_tools/qt_file_handler.py +138 -0
- bear_utils/gui/gui_tools/qt_input_dialog.py +306 -0
- bear_utils/logging/__init__.py +25 -0
- bear_utils/logging/logger_manager/__init__.py +0 -0
- bear_utils/logging/logger_manager/_common.py +47 -0
- bear_utils/logging/logger_manager/_console_junk.py +131 -0
- bear_utils/logging/logger_manager/_styles.py +91 -0
- bear_utils/logging/logger_manager/loggers/__init__.py +0 -0
- bear_utils/logging/logger_manager/loggers/_base_logger.py +238 -0
- bear_utils/logging/logger_manager/loggers/_base_logger.pyi +50 -0
- bear_utils/logging/logger_manager/loggers/_buffer_logger.py +55 -0
- bear_utils/logging/logger_manager/loggers/_console_logger.py +249 -0
- bear_utils/logging/logger_manager/loggers/_console_logger.pyi +64 -0
- bear_utils/logging/logger_manager/loggers/_file_logger.py +141 -0
- bear_utils/logging/logger_manager/loggers/_level_sin.py +58 -0
- bear_utils/logging/logger_manager/loggers/_logger.py +18 -0
- bear_utils/logging/logger_manager/loggers/_sub_logger.py +110 -0
- bear_utils/logging/logger_manager/loggers/_sub_logger.pyi +38 -0
- bear_utils/logging/loggers.py +76 -0
- bear_utils/monitoring/__init__.py +10 -0
- bear_utils/monitoring/host_monitor.py +350 -0
- bear_utils/time/__init__.py +16 -0
- bear_utils/time/_helpers.py +91 -0
- bear_utils/time/_time_class.py +316 -0
- bear_utils/time/_timer.py +80 -0
- bear_utils/time/_tools.py +17 -0
- bear_utils/time/time_manager.py +218 -0
- bear_utils-0.7.11.dist-info/METADATA +260 -0
- bear_utils-0.7.11.dist-info/RECORD +83 -0
- bear_utils-0.7.11.dist-info/WHEEL +4 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
|
3
|
+
from PyQt6.QtGui import QColor
|
4
|
+
from PyQt6.QtWidgets import QColorDialog
|
5
|
+
from rich.color_triplet import ColorTriplet
|
6
|
+
|
7
|
+
from .qt_app import QTApplication
|
8
|
+
|
9
|
+
|
10
|
+
@dataclass
|
11
|
+
class ColorInfo:
|
12
|
+
qcolor: QColor
|
13
|
+
hex: str
|
14
|
+
rgb: ColorTriplet
|
15
|
+
rgba: tuple[int, int, int, int]
|
16
|
+
hsv: tuple[int, int, int]
|
17
|
+
|
18
|
+
|
19
|
+
class QTColorPicker(QTApplication):
|
20
|
+
"""Singleton class to manage the color picker dialog."""
|
21
|
+
|
22
|
+
def select_color(self, initial_color=None, title="Select Color", options=None) -> ColorInfo | None:
|
23
|
+
"""
|
24
|
+
Shows a color selection dialog and returns the selected color.
|
25
|
+
|
26
|
+
Args:
|
27
|
+
initial_color: Initial color to show in the dialog. Can be:
|
28
|
+
- QColor object
|
29
|
+
- Hex string (e.g., "#FF5733")
|
30
|
+
- RGB tuple (e.g., (255, 87, 51))
|
31
|
+
title (str): The dialog window title
|
32
|
+
options: QColorDialog options (optional)
|
33
|
+
|
34
|
+
Returns:
|
35
|
+
dict: Color information with keys:
|
36
|
+
- 'qcolor': QColor object
|
37
|
+
- 'hex': Hex string (e.g., "#FF5733")
|
38
|
+
- 'rgb': RGB tuple (e.g., (255, 87, 51))
|
39
|
+
- 'rgba': RGBA tuple (e.g., (255, 87, 51, 255))
|
40
|
+
- 'hsv': HSV tuple (e.g., (16, 80, 100))
|
41
|
+
Or None if dialog was canceled
|
42
|
+
"""
|
43
|
+
try:
|
44
|
+
dialog = QColorDialog()
|
45
|
+
|
46
|
+
if title:
|
47
|
+
dialog.setWindowTitle(title)
|
48
|
+
|
49
|
+
if options:
|
50
|
+
dialog.setOptions(options)
|
51
|
+
|
52
|
+
if initial_color:
|
53
|
+
if isinstance(initial_color, QColor):
|
54
|
+
dialog.setCurrentColor(initial_color)
|
55
|
+
elif isinstance(initial_color, str) and initial_color.startswith("#"):
|
56
|
+
dialog.setCurrentColor(QColor(initial_color))
|
57
|
+
elif isinstance(initial_color, tuple) and len(initial_color) >= 3:
|
58
|
+
r, g, b = initial_color[:3]
|
59
|
+
a = initial_color[3] if len(initial_color) > 3 else 255
|
60
|
+
dialog.setCurrentColor(QColor(r, g, b, a))
|
61
|
+
|
62
|
+
if dialog.exec() == QColorDialog.DialogCode.Accepted:
|
63
|
+
selected_color = dialog.selectedColor()
|
64
|
+
|
65
|
+
if not selected_color.isValid():
|
66
|
+
return None
|
67
|
+
|
68
|
+
return ColorInfo(
|
69
|
+
qcolor=selected_color,
|
70
|
+
hex=selected_color.name(),
|
71
|
+
rgb=ColorTriplet(selected_color.red(), selected_color.green(), selected_color.blue()),
|
72
|
+
rgba=(
|
73
|
+
selected_color.red(),
|
74
|
+
selected_color.green(),
|
75
|
+
selected_color.blue(),
|
76
|
+
selected_color.alpha(),
|
77
|
+
),
|
78
|
+
hsv=(selected_color.hue(), selected_color.saturation(), selected_color.value()),
|
79
|
+
)
|
80
|
+
else:
|
81
|
+
return None
|
82
|
+
except Exception as e:
|
83
|
+
self.console.error(f"Error in color selection dialog: {e}")
|
84
|
+
return None
|
85
|
+
|
86
|
+
|
87
|
+
def select_color(initial_color=None, title="Select Color", options=None) -> ColorInfo | None:
|
88
|
+
"""
|
89
|
+
Select a color using the QTColorPicker singleton instance.
|
90
|
+
|
91
|
+
Args:
|
92
|
+
initial_color: Initial color to show in the dialog. Can be:
|
93
|
+
- QColor object
|
94
|
+
- Hex string (e.g., "#FF5733")
|
95
|
+
- RGB tuple (e.g., (255, 87, 51))
|
96
|
+
title (str): The dialog window title
|
97
|
+
options: QColorDialog options (optional)
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
dict: Color information with keys:
|
101
|
+
- 'qcolor': QColor object
|
102
|
+
- 'hex': Hex string (e.g., "#FF5733")
|
103
|
+
- 'rgb': RGB tuple (e.g., (255, 87, 51))
|
104
|
+
- 'rgba': RGBA tuple (e.g., (255, 87, 51, 255))
|
105
|
+
- 'hsv': HSV tuple (e.g., (16, 80, 100))
|
106
|
+
Or None if dialog was canceled
|
107
|
+
"""
|
108
|
+
qt_color_picker = QTColorPicker()
|
109
|
+
return qt_color_picker.select_color(initial_color, title, options)
|
110
|
+
|
111
|
+
|
112
|
+
if __name__ == "__main__":
|
113
|
+
# Example usage
|
114
|
+
color_picker = QTColorPicker()
|
115
|
+
selected_color: ColorInfo | None = color_picker.select_color(initial_color="#FF5733", title="Choose a Color")
|
116
|
+
if selected_color:
|
117
|
+
color_picker.console.info(f"Selected Color: {selected_color}")
|
118
|
+
else:
|
119
|
+
color_picker.console.warning("No color selected.")
|
@@ -0,0 +1,138 @@
|
|
1
|
+
from PyQt6.QtWidgets import QFileDialog
|
2
|
+
|
3
|
+
from .qt_app import QTApplication
|
4
|
+
|
5
|
+
|
6
|
+
class QTFileHandler(QTApplication):
|
7
|
+
"""A singleton class to handle file selection dialogs using PyQt6."""
|
8
|
+
|
9
|
+
def select_file(self, caption="Select File", directory="", filter="All Files (*)"):
|
10
|
+
"""
|
11
|
+
Shows a file selection dialog and returns the selected file path.
|
12
|
+
|
13
|
+
Args:
|
14
|
+
caption (str): The dialog window title
|
15
|
+
directory (str): The starting directory
|
16
|
+
filter (str): File filter pattern (e.g., "Images (*.png *.jpg);;Text files (*.txt)")
|
17
|
+
|
18
|
+
Returns:
|
19
|
+
str: Selected file path or empty string if canceled
|
20
|
+
"""
|
21
|
+
file_path, _ = QFileDialog.getOpenFileName(None, caption, directory, filter)
|
22
|
+
return file_path
|
23
|
+
|
24
|
+
def select_files(self, caption="Select Files", directory="", filter="All Files (*)"):
|
25
|
+
"""
|
26
|
+
Shows a file selection dialog that allows multiple selections.
|
27
|
+
|
28
|
+
Returns:
|
29
|
+
list: List of selected file paths
|
30
|
+
"""
|
31
|
+
file_paths, _ = QFileDialog.getOpenFileNames(None, caption, directory, filter)
|
32
|
+
return file_paths
|
33
|
+
|
34
|
+
def select_directory(self, caption="Select Directory", directory=""):
|
35
|
+
"""
|
36
|
+
Shows a directory selection dialog.
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
str: Selected directory path or empty string if canceled
|
40
|
+
"""
|
41
|
+
dir_path = QFileDialog.getExistingDirectory(None, caption, directory)
|
42
|
+
return dir_path
|
43
|
+
|
44
|
+
def save_file_dialog(self, caption="Save File", directory="", filter="All Files (*)"):
|
45
|
+
"""
|
46
|
+
Shows a save file dialog.
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
str: Selected save file path or empty string if canceled
|
50
|
+
"""
|
51
|
+
|
52
|
+
file_path, _ = QFileDialog.getSaveFileName(None, caption, directory, filter)
|
53
|
+
return file_path
|
54
|
+
|
55
|
+
|
56
|
+
def select_file(caption="Select File", directory="", filter="All Files (*)"):
|
57
|
+
"""
|
58
|
+
Select a file using the QTApplication singleton instance.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
caption (str): The dialog window title
|
62
|
+
directory (str): The starting directory
|
63
|
+
filter (str): File filter pattern (e.g., "Images (*.png *.jpg);;Text files (*.txt)")
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
str: Selected file path or empty string if canceled
|
67
|
+
"""
|
68
|
+
qt_app = QTFileHandler()
|
69
|
+
return qt_app.select_file(caption, directory, filter)
|
70
|
+
|
71
|
+
|
72
|
+
def select_files(caption="Select Files", directory="", filter="All Files (*)"):
|
73
|
+
"""
|
74
|
+
Select multiple files using the QTApplication singleton instance.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
caption (str): The dialog window title
|
78
|
+
directory (str): The starting directory
|
79
|
+
filter (str): File filter pattern (e.g., "Images (*.png *.jpg);;Text files (*.txt)")
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
list: List of selected file paths
|
83
|
+
"""
|
84
|
+
qt_app = QTFileHandler()
|
85
|
+
return qt_app.select_files(caption, directory, filter)
|
86
|
+
|
87
|
+
|
88
|
+
def select_directory(caption="Select Directory", directory=""):
|
89
|
+
"""
|
90
|
+
Select a directory using the QTApplication singleton instance.
|
91
|
+
|
92
|
+
Args:
|
93
|
+
caption (str): The dialog window title
|
94
|
+
directory (str): The starting directory
|
95
|
+
|
96
|
+
Returns:
|
97
|
+
str: Selected directory path or empty string if canceled
|
98
|
+
"""
|
99
|
+
qt_app = QTFileHandler()
|
100
|
+
return qt_app.select_directory(caption, directory)
|
101
|
+
|
102
|
+
|
103
|
+
def save_file_dialog(caption="Save File", directory="", filter="All Files (*)"):
|
104
|
+
"""
|
105
|
+
Show a save file dialog using the QTApplication singleton instance.
|
106
|
+
|
107
|
+
Args:
|
108
|
+
caption (str): The dialog window title
|
109
|
+
directory (str): The starting directory
|
110
|
+
filter (str): File filter pattern (e.g., "Images (*.png *.jpg);;Text files (*.txt)")
|
111
|
+
|
112
|
+
Returns:
|
113
|
+
str: Selected save file path or empty string if canceled
|
114
|
+
"""
|
115
|
+
qt_app = QTFileHandler()
|
116
|
+
return qt_app.save_file_dialog(caption, directory, filter)
|
117
|
+
|
118
|
+
|
119
|
+
__all__ = [
|
120
|
+
"QTFileHandler",
|
121
|
+
"select_file",
|
122
|
+
"select_files",
|
123
|
+
"select_directory",
|
124
|
+
"save_file_dialog",
|
125
|
+
]
|
126
|
+
|
127
|
+
|
128
|
+
# if __name__ == "__main__":
|
129
|
+
# # Example usage
|
130
|
+
# selected_file = select_file(
|
131
|
+
# "Select a file", filter="Python files (*.py);;All files (*)"
|
132
|
+
# )
|
133
|
+
# print(f"Selected file: {selected_file}")
|
134
|
+
|
135
|
+
# selected_files = select_files(
|
136
|
+
# "Select multiple files", filter="Images (*.png *.jpg);;All files (*)"
|
137
|
+
# )
|
138
|
+
# print(f"Selected files: {selected_files}")
|
@@ -0,0 +1,306 @@
|
|
1
|
+
from PyQt6.QtCore import Qt
|
2
|
+
from PyQt6.QtWidgets import QInputDialog, QLineEdit
|
3
|
+
|
4
|
+
from .qt_app import QTApplication
|
5
|
+
|
6
|
+
|
7
|
+
class InputDialog(QTApplication):
|
8
|
+
def get_text(
|
9
|
+
self,
|
10
|
+
title: str = "Input",
|
11
|
+
label: str = "Enter text:",
|
12
|
+
default: str = "",
|
13
|
+
echo_mode: QLineEdit.EchoMode = QLineEdit.EchoMode.Normal,
|
14
|
+
) -> str | None:
|
15
|
+
"""
|
16
|
+
Shows a text input dialog.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
title: Dialog window title
|
20
|
+
label: Text label above the input field
|
21
|
+
default: Default text in the input field
|
22
|
+
echo_mode: How text is displayed (Normal, Password, etc.)
|
23
|
+
input_mode: Type of text input (TextInput, IntInput, etc.)
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
str: Entered text or None if canceled
|
27
|
+
"""
|
28
|
+
try:
|
29
|
+
text, ok = QInputDialog.getText(
|
30
|
+
None,
|
31
|
+
title,
|
32
|
+
label,
|
33
|
+
echo_mode,
|
34
|
+
default,
|
35
|
+
Qt.WindowType.Dialog | Qt.WindowType.WindowCloseButtonHint,
|
36
|
+
)
|
37
|
+
return text if ok else None
|
38
|
+
except Exception as e:
|
39
|
+
self.console.error(f"Error in text input dialog: {e}")
|
40
|
+
return None
|
41
|
+
|
42
|
+
def get_password(
|
43
|
+
self,
|
44
|
+
title: str = "Password",
|
45
|
+
label: str = "Enter password:",
|
46
|
+
default: str = "",
|
47
|
+
) -> str | None:
|
48
|
+
"""
|
49
|
+
Shows a password input dialog with masked text.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
title: Dialog window title
|
53
|
+
label: Text label above the input field
|
54
|
+
default: Default text in the input field
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
str: Entered password or None if canceled
|
58
|
+
"""
|
59
|
+
return self.get_text(
|
60
|
+
title=title,
|
61
|
+
label=label,
|
62
|
+
default=default,
|
63
|
+
echo_mode=QLineEdit.EchoMode.Password,
|
64
|
+
)
|
65
|
+
|
66
|
+
def get_int(
|
67
|
+
self,
|
68
|
+
title: str = "Input",
|
69
|
+
label: str = "Enter number:",
|
70
|
+
default: int = 0,
|
71
|
+
min_value: int = -2147483647,
|
72
|
+
max_value: int = 2147483647,
|
73
|
+
step: int = 1,
|
74
|
+
) -> int | None:
|
75
|
+
"""
|
76
|
+
Shows an integer input dialog with spinner.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
title: Dialog window title
|
80
|
+
label: Text label above the input field
|
81
|
+
default: Default value
|
82
|
+
min_value: Minimum allowed value
|
83
|
+
max_value: Maximum allowed value
|
84
|
+
step: Step size for spinner buttons
|
85
|
+
|
86
|
+
Returns:
|
87
|
+
int: Entered integer or None if canceled
|
88
|
+
"""
|
89
|
+
try:
|
90
|
+
value, ok = QInputDialog.getInt(
|
91
|
+
None,
|
92
|
+
title,
|
93
|
+
label,
|
94
|
+
default,
|
95
|
+
min_value,
|
96
|
+
max_value,
|
97
|
+
step,
|
98
|
+
Qt.WindowType.Dialog | Qt.WindowType.WindowCloseButtonHint,
|
99
|
+
)
|
100
|
+
return value if ok else None
|
101
|
+
except Exception as e:
|
102
|
+
self.console.error(f"Error in integer input dialog: {e}")
|
103
|
+
return None
|
104
|
+
|
105
|
+
def get_double(
|
106
|
+
self,
|
107
|
+
title: str = "Input",
|
108
|
+
label: str = "Enter number:",
|
109
|
+
default: float = 0.0,
|
110
|
+
min_value: float = -2147483647.0,
|
111
|
+
max_value: float = 2147483647.0,
|
112
|
+
decimals: int = 2,
|
113
|
+
) -> float | None:
|
114
|
+
"""
|
115
|
+
Shows a floating-point input dialog with spinner.
|
116
|
+
|
117
|
+
Args:
|
118
|
+
title: Dialog window title
|
119
|
+
label: Text label above the input field
|
120
|
+
default: Default value
|
121
|
+
min_value: Minimum allowed value
|
122
|
+
max_value: Maximum allowed value
|
123
|
+
decimals: Number of decimal places to show
|
124
|
+
|
125
|
+
Returns:
|
126
|
+
float: Entered value or None if canceled
|
127
|
+
"""
|
128
|
+
try:
|
129
|
+
value, ok = QInputDialog.getDouble(
|
130
|
+
None,
|
131
|
+
title,
|
132
|
+
label,
|
133
|
+
default,
|
134
|
+
min_value,
|
135
|
+
max_value,
|
136
|
+
decimals,
|
137
|
+
Qt.WindowType.Dialog | Qt.WindowType.WindowCloseButtonHint,
|
138
|
+
)
|
139
|
+
return value if ok else None
|
140
|
+
except Exception as e:
|
141
|
+
self.console.error(f"Error in double input dialog: {e}")
|
142
|
+
return None
|
143
|
+
|
144
|
+
def get_item(
|
145
|
+
self,
|
146
|
+
title: str = "Select",
|
147
|
+
label: str = "Select an item:",
|
148
|
+
items: list[str] | None = None,
|
149
|
+
current: int = 0,
|
150
|
+
editable: bool = False,
|
151
|
+
) -> str | None:
|
152
|
+
"""
|
153
|
+
Shows a dropdown selection dialog.
|
154
|
+
|
155
|
+
Args:
|
156
|
+
title: Dialog window title
|
157
|
+
label: Text label above the dropdown
|
158
|
+
items: List of items to choose from
|
159
|
+
current: Index of the initially selected item
|
160
|
+
editable: Whether the text can be edited
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
str: Selected or entered text, or None if canceled
|
164
|
+
"""
|
165
|
+
if items is None:
|
166
|
+
items = ["Item 1", "Item 2", "Item 3"]
|
167
|
+
|
168
|
+
try:
|
169
|
+
item, ok = QInputDialog.getItem(
|
170
|
+
None,
|
171
|
+
title,
|
172
|
+
label,
|
173
|
+
items,
|
174
|
+
current,
|
175
|
+
editable,
|
176
|
+
Qt.WindowType.Dialog | Qt.WindowType.WindowCloseButtonHint,
|
177
|
+
)
|
178
|
+
return item if ok else None
|
179
|
+
except Exception as e:
|
180
|
+
self.console.error(f"Error in item selection dialog: {e}")
|
181
|
+
return None
|
182
|
+
|
183
|
+
def get_multiline_text(self, title: str = "Input", label: str = "Enter text:", default: str = "") -> str | None:
|
184
|
+
"""
|
185
|
+
Shows a multi-line text input dialog.
|
186
|
+
|
187
|
+
Args:
|
188
|
+
title: Dialog window title
|
189
|
+
label: Text label above the input field
|
190
|
+
default: Default text in the input field
|
191
|
+
|
192
|
+
Returns:
|
193
|
+
str: Entered text or None if canceled
|
194
|
+
"""
|
195
|
+
try:
|
196
|
+
text, ok = QInputDialog.getMultiLineText(
|
197
|
+
None,
|
198
|
+
title,
|
199
|
+
label,
|
200
|
+
default,
|
201
|
+
Qt.WindowType.Dialog | Qt.WindowType.WindowCloseButtonHint,
|
202
|
+
)
|
203
|
+
return text if ok else None
|
204
|
+
except Exception as e:
|
205
|
+
self.console.error(f"Error in multiline text input dialog: {e}")
|
206
|
+
return None
|
207
|
+
|
208
|
+
|
209
|
+
def get_text(
|
210
|
+
title: str = "Input",
|
211
|
+
label: str = "Enter text:",
|
212
|
+
default: str = "",
|
213
|
+
echo_mode: QLineEdit.EchoMode = QLineEdit.EchoMode.Normal,
|
214
|
+
) -> str | None:
|
215
|
+
"""Displays a text input dialog and returns the text entered by the user."""
|
216
|
+
qt_app = InputDialog()
|
217
|
+
return qt_app.get_text(title, label, default, echo_mode)
|
218
|
+
|
219
|
+
|
220
|
+
def get_password(title: str = "Password", label: str = "Enter password:", default: str = "") -> str | None:
|
221
|
+
"""Displays a password input dialog with masked text."""
|
222
|
+
qt_app = InputDialog()
|
223
|
+
return qt_app.get_password(title, label, default)
|
224
|
+
|
225
|
+
|
226
|
+
def get_api_key(
|
227
|
+
title: str = "API Key Required",
|
228
|
+
label: str = "Enter API key:",
|
229
|
+
default: str = "",
|
230
|
+
service_name: str = "",
|
231
|
+
) -> str | None:
|
232
|
+
"""
|
233
|
+
Shows a secure input dialog optimized for entering API keys.
|
234
|
+
|
235
|
+
Args:
|
236
|
+
title: Dialog window title
|
237
|
+
label: Text label above the input field
|
238
|
+
default: Default API key (rarely used, but available)
|
239
|
+
service_name: Name of the service requiring the API key
|
240
|
+
|
241
|
+
Returns:
|
242
|
+
str: Entered API key or None if canceled
|
243
|
+
"""
|
244
|
+
qt_app = InputDialog()
|
245
|
+
|
246
|
+
# Customize the label if service name is provided
|
247
|
+
if service_name:
|
248
|
+
label = f"Enter API key for {service_name}:"
|
249
|
+
title = f"{service_name} API Key"
|
250
|
+
|
251
|
+
return qt_app.get_text(title=title, label=label, default=default, echo_mode=QLineEdit.EchoMode.Password)
|
252
|
+
|
253
|
+
|
254
|
+
def get_int(
|
255
|
+
title: str = "Input",
|
256
|
+
label: str = "Enter number:",
|
257
|
+
default: int = 0,
|
258
|
+
min_value: int = -2147483647,
|
259
|
+
max_value: int = 2147483647,
|
260
|
+
step: int = 1,
|
261
|
+
) -> int | None:
|
262
|
+
"""Displays an integer input dialog with spinner buttons."""
|
263
|
+
qt_app = InputDialog()
|
264
|
+
return qt_app.get_int(title, label, default, min_value, max_value, step)
|
265
|
+
|
266
|
+
|
267
|
+
def get_double(
|
268
|
+
title: str = "Input",
|
269
|
+
label: str = "Enter number:",
|
270
|
+
default: float = 0.0,
|
271
|
+
min_value: float = -2147483647.0,
|
272
|
+
max_value: float = 2147483647.0,
|
273
|
+
decimals: int = 2,
|
274
|
+
) -> float | None:
|
275
|
+
"""Displays a floating-point input dialog with spinner buttons."""
|
276
|
+
qt_app = InputDialog()
|
277
|
+
return qt_app.get_double(title, label, default, min_value, max_value, decimals)
|
278
|
+
|
279
|
+
|
280
|
+
def get_item(
|
281
|
+
title: str = "Select",
|
282
|
+
label: str = "Select an item:",
|
283
|
+
items: list[str] | None = None,
|
284
|
+
current: int = 0,
|
285
|
+
editable: bool = False,
|
286
|
+
) -> str | None:
|
287
|
+
"""Displays a dropdown selection dialog."""
|
288
|
+
qt_app = InputDialog()
|
289
|
+
return qt_app.get_item(title, label, items, current, editable)
|
290
|
+
|
291
|
+
|
292
|
+
def get_multiline_text(title: str = "Input", label: str = "Enter text:", default: str = "") -> str | None:
|
293
|
+
"""Displays a multi-line text input dialog."""
|
294
|
+
qt_app = InputDialog()
|
295
|
+
return qt_app.get_multiline_text(title, label, default)
|
296
|
+
|
297
|
+
|
298
|
+
if __name__ == "__main__":
|
299
|
+
# Example usage
|
300
|
+
api_key = get_api_key(
|
301
|
+
title="API Key Required",
|
302
|
+
label="Enter your API key:",
|
303
|
+
default="",
|
304
|
+
service_name="MyService",
|
305
|
+
)
|
306
|
+
print(f"API Key: {api_key}")
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from .logger_manager._common import VERBOSE_CONSOLE_FORMAT
|
2
|
+
from .logger_manager._styles import VERBOSE
|
3
|
+
from .loggers import (
|
4
|
+
BaseLogger,
|
5
|
+
BufferLogger,
|
6
|
+
ConsoleLogger,
|
7
|
+
FileLogger,
|
8
|
+
SubConsoleLogger,
|
9
|
+
get_console,
|
10
|
+
get_logger,
|
11
|
+
get_sub_logger,
|
12
|
+
)
|
13
|
+
|
14
|
+
__all__ = [
|
15
|
+
"BaseLogger",
|
16
|
+
"ConsoleLogger",
|
17
|
+
"BufferLogger",
|
18
|
+
"SubConsoleLogger",
|
19
|
+
"FileLogger",
|
20
|
+
"get_console",
|
21
|
+
"get_logger",
|
22
|
+
"get_sub_logger",
|
23
|
+
"VERBOSE",
|
24
|
+
"VERBOSE_CONSOLE_FORMAT",
|
25
|
+
]
|
File without changes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import inspect
|
2
|
+
from types import TracebackType
|
3
|
+
from typing import Required, TypedDict
|
4
|
+
|
5
|
+
|
6
|
+
class ExecValues(TypedDict, total=True):
|
7
|
+
|
8
|
+
exc_type: Required[type[BaseException]]
|
9
|
+
exc_value: Required[BaseException]
|
10
|
+
exc_traceback: Required[TracebackType]
|
11
|
+
|
12
|
+
|
13
|
+
VERBOSE_FORMAT = "%(asctime)s |%(levelname)s| {%(module)s|%(funcName)s|%(lineno)d} %(message)s"
|
14
|
+
VERBOSE_CONSOLE_FORMAT = "%(asctime)s <[{}]{}[/{}]> %(message)s"
|
15
|
+
SIMPLE_FORMAT = "%(message)s"
|
16
|
+
FIVE_MEGABYTES = 1024 * 1024 * 5
|
17
|
+
|
18
|
+
|
19
|
+
class StackLevelTracker:
|
20
|
+
STACK_LEVEL_OFFSET = 1
|
21
|
+
|
22
|
+
def __init__(self) -> None:
|
23
|
+
self.start_depth: int | None = None
|
24
|
+
self.end_depth: int | None = None
|
25
|
+
|
26
|
+
@property
|
27
|
+
def not_set(self) -> bool:
|
28
|
+
"""Check if the start depth is not set."""
|
29
|
+
return self.start_depth is None
|
30
|
+
|
31
|
+
def record_start(self) -> None:
|
32
|
+
"""Record the current stack depth as the start depth."""
|
33
|
+
self.start_depth = len(inspect.stack())
|
34
|
+
|
35
|
+
def record_end(self) -> int:
|
36
|
+
"""Record the current stack depth as the end depth and then return the calculated stack level.
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
int: The calculated stack level based on the difference between start and end depths.
|
40
|
+
"""
|
41
|
+
self.end_depth = len(inspect.stack())
|
42
|
+
return self.calculate_stacklevel()
|
43
|
+
|
44
|
+
def calculate_stacklevel(self) -> int:
|
45
|
+
if self.start_depth is None or self.end_depth is None:
|
46
|
+
raise ValueError("Start and end depths must be recorded before calculating stack level.")
|
47
|
+
return self.end_depth - (self.start_depth + self.STACK_LEVEL_OFFSET)
|