shinestacker 0.3.2__py3-none-any.whl → 0.3.4__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.
Potentially problematic release.
This version of shinestacker might be problematic. Click here for more details.
- shinestacker/__init__.py +2 -1
- shinestacker/_version.py +1 -1
- shinestacker/algorithms/__init__.py +3 -2
- shinestacker/algorithms/align.py +102 -64
- shinestacker/algorithms/balance.py +89 -42
- shinestacker/algorithms/base_stack_algo.py +42 -0
- shinestacker/algorithms/core_utils.py +6 -6
- shinestacker/algorithms/denoise.py +4 -1
- shinestacker/algorithms/depth_map.py +28 -39
- shinestacker/algorithms/exif.py +43 -38
- shinestacker/algorithms/multilayer.py +48 -28
- shinestacker/algorithms/noise_detection.py +34 -23
- shinestacker/algorithms/pyramid.py +42 -42
- shinestacker/algorithms/sharpen.py +1 -0
- shinestacker/algorithms/stack.py +42 -41
- shinestacker/algorithms/stack_framework.py +111 -65
- shinestacker/algorithms/utils.py +12 -11
- shinestacker/algorithms/vignetting.py +48 -22
- shinestacker/algorithms/white_balance.py +1 -0
- shinestacker/app/about_dialog.py +6 -2
- shinestacker/app/app_config.py +1 -0
- shinestacker/app/gui_utils.py +20 -0
- shinestacker/app/help_menu.py +1 -0
- shinestacker/app/main.py +9 -18
- shinestacker/app/open_frames.py +5 -4
- shinestacker/app/project.py +5 -16
- shinestacker/app/retouch.py +5 -17
- shinestacker/core/colors.py +4 -4
- shinestacker/core/core_utils.py +1 -1
- shinestacker/core/exceptions.py +2 -1
- shinestacker/core/framework.py +46 -33
- shinestacker/core/logging.py +9 -10
- shinestacker/gui/action_config.py +253 -197
- shinestacker/gui/actions_window.py +32 -28
- shinestacker/gui/colors.py +1 -0
- shinestacker/gui/gui_images.py +7 -3
- shinestacker/gui/gui_logging.py +3 -2
- shinestacker/gui/gui_run.py +53 -38
- shinestacker/gui/main_window.py +69 -25
- shinestacker/gui/new_project.py +35 -2
- shinestacker/gui/project_converter.py +21 -20
- shinestacker/gui/project_editor.py +45 -52
- shinestacker/gui/project_model.py +15 -23
- shinestacker/retouch/{filter_base.py → base_filter.py} +7 -4
- shinestacker/retouch/brush.py +1 -0
- shinestacker/retouch/brush_gradient.py +17 -3
- shinestacker/retouch/brush_preview.py +14 -10
- shinestacker/retouch/brush_tool.py +28 -19
- shinestacker/retouch/denoise_filter.py +3 -2
- shinestacker/retouch/display_manager.py +11 -5
- shinestacker/retouch/exif_data.py +1 -0
- shinestacker/retouch/file_loader.py +13 -9
- shinestacker/retouch/filter_manager.py +1 -0
- shinestacker/retouch/image_editor.py +14 -48
- shinestacker/retouch/image_editor_ui.py +10 -5
- shinestacker/retouch/image_filters.py +4 -2
- shinestacker/retouch/image_viewer.py +33 -31
- shinestacker/retouch/io_gui_handler.py +25 -13
- shinestacker/retouch/io_manager.py +3 -2
- shinestacker/retouch/layer_collection.py +79 -23
- shinestacker/retouch/shortcuts_help.py +1 -0
- shinestacker/retouch/undo_manager.py +7 -0
- shinestacker/retouch/unsharp_mask_filter.py +3 -2
- shinestacker/retouch/white_balance_filter.py +11 -6
- {shinestacker-0.3.2.dist-info → shinestacker-0.3.4.dist-info}/METADATA +10 -4
- shinestacker-0.3.4.dist-info/RECORD +86 -0
- shinestacker-0.3.2.dist-info/RECORD +0 -85
- {shinestacker-0.3.2.dist-info → shinestacker-0.3.4.dist-info}/WHEEL +0 -0
- {shinestacker-0.3.2.dist-info → shinestacker-0.3.4.dist-info}/entry_points.txt +0 -0
- {shinestacker-0.3.2.dist-info → shinestacker-0.3.4.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-0.3.2.dist-info → shinestacker-0.3.4.dist-info}/top_level.txt +0 -0
shinestacker/app/main.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, C0413, E0611, R0903, E1121, W0201
|
|
1
2
|
import sys
|
|
2
3
|
import os
|
|
3
4
|
import logging
|
|
@@ -14,9 +15,8 @@ from shinestacker.config.constants import constants
|
|
|
14
15
|
from shinestacker.core.logging import setup_logging
|
|
15
16
|
from shinestacker.gui.main_window import MainWindow
|
|
16
17
|
from shinestacker.retouch.image_editor_ui import ImageEditorUI
|
|
17
|
-
from shinestacker.app.gui_utils import disable_macos_special_menu_items
|
|
18
|
+
from shinestacker.app.gui_utils import disable_macos_special_menu_items, fill_app_menu
|
|
18
19
|
from shinestacker.app.help_menu import add_help_action
|
|
19
|
-
from shinestacker.app.about_dialog import show_about_dialog
|
|
20
20
|
from shinestacker.app.open_frames import open_frames
|
|
21
21
|
|
|
22
22
|
|
|
@@ -35,8 +35,10 @@ class MainApp(QMainWindow):
|
|
|
35
35
|
self.stacked_widget.addWidget(self.project_window)
|
|
36
36
|
self.stacked_widget.addWidget(self.retouch_window)
|
|
37
37
|
self.app_menu = self.create_menu()
|
|
38
|
-
self.project_window.menuBar().insertMenu(
|
|
39
|
-
|
|
38
|
+
self.project_window.menuBar().insertMenu(
|
|
39
|
+
self.project_window.menuBar().actions()[0], self.app_menu)
|
|
40
|
+
self.retouch_window.menuBar().insertMenu(
|
|
41
|
+
self.retouch_window.menuBar().actions()[0], self.app_menu)
|
|
40
42
|
add_help_action(self.project_window)
|
|
41
43
|
add_help_action(self.retouch_window)
|
|
42
44
|
|
|
@@ -71,18 +73,7 @@ class MainApp(QMainWindow):
|
|
|
71
73
|
app_menu.addAction(self.switch_to_project_action)
|
|
72
74
|
app_menu.addAction(self.switch_to_retouch_action)
|
|
73
75
|
app_menu.addSeparator()
|
|
74
|
-
|
|
75
|
-
about_action.triggered.connect(show_about_dialog)
|
|
76
|
-
app_menu.addAction(about_action)
|
|
77
|
-
app_menu.addSeparator()
|
|
78
|
-
if config.DONT_USE_NATIVE_MENU:
|
|
79
|
-
quit_txt, quit_short = "&Quit", "Ctrl+Q"
|
|
80
|
-
else:
|
|
81
|
-
quit_txt, quit_short = "Shut dw&wn", "Ctrl+Q"
|
|
82
|
-
exit_action = QAction(quit_txt, self)
|
|
83
|
-
exit_action.setShortcut(quit_short)
|
|
84
|
-
exit_action.triggered.connect(self.quit)
|
|
85
|
-
app_menu.addAction(exit_action)
|
|
76
|
+
fill_app_menu(self, app_menu)
|
|
86
77
|
return app_menu
|
|
87
78
|
|
|
88
79
|
def quit(self):
|
|
@@ -161,8 +152,8 @@ expert options are visible by default.
|
|
|
161
152
|
main_app.switch_to_retouch()
|
|
162
153
|
else:
|
|
163
154
|
main_app.switch_to_project()
|
|
164
|
-
QTimer.singleShot(100,
|
|
165
|
-
QTimer.singleShot(100,
|
|
155
|
+
QTimer.singleShot(100, main_app.project_window.new_project)
|
|
156
|
+
QTimer.singleShot(100, main_app.setFocus)
|
|
166
157
|
sys.exit(app.exec())
|
|
167
158
|
|
|
168
159
|
|
shinestacker/app/open_frames.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=C0114, C0116, E0611
|
|
1
2
|
import os
|
|
2
3
|
import sys
|
|
3
4
|
from PySide6.QtCore import QTimer
|
|
@@ -20,13 +21,13 @@ def open_files(editor, filenames):
|
|
|
20
21
|
))
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
def open_frames(editor, filename,
|
|
24
|
+
def open_frames(editor, filename, path_list):
|
|
24
25
|
if filename:
|
|
25
26
|
filenames = filename.split(';')
|
|
26
27
|
open_files(editor, filenames)
|
|
27
|
-
elif
|
|
28
|
+
elif path_list:
|
|
28
29
|
reverse = False
|
|
29
|
-
paths =
|
|
30
|
+
paths = path_list.split(';')
|
|
30
31
|
filenames = []
|
|
31
32
|
for path in paths:
|
|
32
33
|
if os.path.exists(path) and os.path.isdir(path):
|
|
@@ -37,5 +38,5 @@ def open_frames(editor, filename, path):
|
|
|
37
38
|
filenames += full_paths
|
|
38
39
|
else:
|
|
39
40
|
print(f"path {path} is invalid", file=sys.stderr)
|
|
40
|
-
exit(1)
|
|
41
|
+
sys.exit(1)
|
|
41
42
|
open_files(editor, filenames)
|
shinestacker/app/project.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, C0413, E0611, R0903, E1121, W0201
|
|
1
2
|
import os
|
|
2
3
|
import sys
|
|
3
4
|
import logging
|
|
@@ -6,16 +7,15 @@ import matplotlib
|
|
|
6
7
|
import matplotlib.backends.backend_pdf
|
|
7
8
|
matplotlib.use('agg')
|
|
8
9
|
from PySide6.QtWidgets import QApplication, QMenu
|
|
9
|
-
from PySide6.QtGui import QIcon
|
|
10
|
+
from PySide6.QtGui import QIcon
|
|
10
11
|
from PySide6.QtCore import Qt, QTimer, QEvent
|
|
11
12
|
from shinestacker.config.config import config
|
|
12
13
|
config.init(DISABLE_TQDM=True, DONT_USE_NATIVE_MENU=True)
|
|
13
14
|
from shinestacker.config.constants import constants
|
|
14
15
|
from shinestacker.core.logging import setup_logging
|
|
15
16
|
from shinestacker.gui.main_window import MainWindow
|
|
16
|
-
from shinestacker.app.gui_utils import disable_macos_special_menu_items
|
|
17
|
+
from shinestacker.app.gui_utils import disable_macos_special_menu_items, fill_app_menu
|
|
17
18
|
from shinestacker.app.help_menu import add_help_action
|
|
18
|
-
from shinestacker.app.about_dialog import show_about_dialog
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class ProjectApp(MainWindow):
|
|
@@ -28,18 +28,7 @@ class ProjectApp(MainWindow):
|
|
|
28
28
|
|
|
29
29
|
def create_menu(self):
|
|
30
30
|
app_menu = QMenu(constants.APP_STRING)
|
|
31
|
-
|
|
32
|
-
about_action.triggered.connect(show_about_dialog)
|
|
33
|
-
app_menu.addAction(about_action)
|
|
34
|
-
app_menu.addSeparator()
|
|
35
|
-
if config.DONT_USE_NATIVE_MENU:
|
|
36
|
-
quit_txt, quit_short = "&Quit", "Ctrl+Q"
|
|
37
|
-
else:
|
|
38
|
-
quit_txt, quit_short = "Shut dw&wn", "Ctrl+Q"
|
|
39
|
-
exit_action = QAction(quit_txt, self)
|
|
40
|
-
exit_action.setShortcut(quit_short)
|
|
41
|
-
exit_action.triggered.connect(self.quit)
|
|
42
|
-
app_menu.addAction(exit_action)
|
|
31
|
+
fill_app_menu(self, app_menu)
|
|
43
32
|
return app_menu
|
|
44
33
|
|
|
45
34
|
def _retouch_callback(self, filename):
|
|
@@ -83,7 +72,7 @@ expert options are visible by default.
|
|
|
83
72
|
if filename:
|
|
84
73
|
QTimer.singleShot(100, lambda: window.open_project(filename))
|
|
85
74
|
else:
|
|
86
|
-
QTimer.singleShot(100,
|
|
75
|
+
QTimer.singleShot(100, window.new_project)
|
|
87
76
|
sys.exit(app.exec())
|
|
88
77
|
|
|
89
78
|
|
shinestacker/app/retouch.py
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, C0413, E0611, R0903, E1121, W0201
|
|
1
2
|
import os
|
|
2
3
|
import sys
|
|
3
4
|
import argparse
|
|
4
5
|
from PySide6.QtWidgets import QApplication, QMenu
|
|
5
|
-
from PySide6.QtGui import QIcon
|
|
6
|
+
from PySide6.QtGui import QIcon
|
|
6
7
|
from PySide6.QtCore import Qt, QEvent
|
|
7
8
|
from shinestacker.config.config import config
|
|
8
9
|
config.init(DISABLE_TQDM=True, DONT_USE_NATIVE_MENU=True)
|
|
9
|
-
from shinestacker.config.config import config
|
|
10
10
|
from shinestacker.config.constants import constants
|
|
11
11
|
from shinestacker.retouch.image_editor_ui import ImageEditorUI
|
|
12
|
-
from shinestacker.app.gui_utils import disable_macos_special_menu_items
|
|
12
|
+
from shinestacker.app.gui_utils import disable_macos_special_menu_items, fill_app_menu
|
|
13
13
|
from shinestacker.app.help_menu import add_help_action
|
|
14
|
-
from shinestacker.app.about_dialog import show_about_dialog
|
|
15
14
|
from shinestacker.app.open_frames import open_frames
|
|
16
15
|
|
|
17
16
|
|
|
@@ -24,18 +23,7 @@ class RetouchApp(ImageEditorUI):
|
|
|
24
23
|
|
|
25
24
|
def create_menu(self):
|
|
26
25
|
app_menu = QMenu(constants.APP_STRING)
|
|
27
|
-
|
|
28
|
-
about_action.triggered.connect(show_about_dialog)
|
|
29
|
-
app_menu.addAction(about_action)
|
|
30
|
-
app_menu.addSeparator()
|
|
31
|
-
if config.DONT_USE_NATIVE_MENU:
|
|
32
|
-
quit_txt, quit_short = "&Quit", "Ctrl+Q"
|
|
33
|
-
else:
|
|
34
|
-
quit_txt, quit_short = "Shut dw&wn", "Ctrl+Q"
|
|
35
|
-
exit_action = QAction(quit_txt, self)
|
|
36
|
-
exit_action.setShortcut(quit_short)
|
|
37
|
-
exit_action.triggered.connect(self.quit)
|
|
38
|
-
app_menu.addAction(exit_action)
|
|
26
|
+
fill_app_menu(self, app_menu)
|
|
39
27
|
return app_menu
|
|
40
28
|
|
|
41
29
|
|
|
@@ -64,7 +52,7 @@ Multiple directories can be specified separated by ';'.
|
|
|
64
52
|
path = args['path']
|
|
65
53
|
if filename and path:
|
|
66
54
|
print("can't specify both arguments --filename and --path", file=sys.stderr)
|
|
67
|
-
exit(1)
|
|
55
|
+
sys.exit(1)
|
|
68
56
|
app = Application(sys.argv)
|
|
69
57
|
if config.DONT_USE_NATIVE_MENU:
|
|
70
58
|
app.setAttribute(Qt.AA_DontUseNativeMenuBar)
|
shinestacker/core/colors.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint: disable=C0114, C0116
|
|
1
|
+
# pylint: disable=C0114, C0116
|
|
2
2
|
COLORS = {
|
|
3
3
|
"black": 30,
|
|
4
4
|
"red": 31,
|
|
@@ -50,11 +50,11 @@ EFFECTS = {
|
|
|
50
50
|
def color_str(text, *args):
|
|
51
51
|
text_colored = text
|
|
52
52
|
for arg in args:
|
|
53
|
-
if arg in COLORS
|
|
53
|
+
if arg in COLORS:
|
|
54
54
|
text_colored = f"\033[{COLORS[arg]}m{text_colored}"
|
|
55
|
-
elif arg in BG_COLORS
|
|
55
|
+
elif arg in BG_COLORS:
|
|
56
56
|
text_colored = f"\033[{BG_COLORS[arg]}m{text_colored}"
|
|
57
|
-
elif arg in EFFECTS
|
|
57
|
+
elif arg in EFFECTS:
|
|
58
58
|
text_colored = f"\033[{EFFECTS[arg]}m{text_colored}"
|
|
59
59
|
else:
|
|
60
60
|
raise ValueError(f"Color or effect not supported: {arg}")
|
shinestacker/core/core_utils.py
CHANGED
shinestacker/core/exceptions.py
CHANGED
|
@@ -8,7 +8,8 @@ class InvalidOptionError(FocusStackError):
|
|
|
8
8
|
self.option = option
|
|
9
9
|
self.value = value
|
|
10
10
|
self.details = details
|
|
11
|
-
super().__init__(f"Invalid option {option} = {value}" +
|
|
11
|
+
super().__init__(f"Invalid option {option} = {value}" +
|
|
12
|
+
("" if details == "" else f": {details}"))
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class ImageLoadError(FocusStackError):
|
shinestacker/core/framework.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint: disable=C0114, C0115, C0116
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, R0917, R0913, R0902
|
|
2
2
|
import time
|
|
3
3
|
import logging
|
|
4
4
|
from .. config.config import config
|
|
@@ -8,7 +8,7 @@ from .core_utils import make_tqdm_bar
|
|
|
8
8
|
from .exceptions import RunStopException
|
|
9
9
|
|
|
10
10
|
LINE_UP = "\r\033[A"
|
|
11
|
-
|
|
11
|
+
TRAILING_SPACES = " " * 30
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class TqdmCallbacks:
|
|
@@ -17,12 +17,12 @@ class TqdmCallbacks:
|
|
|
17
17
|
callbacks = {
|
|
18
18
|
'step_counts': lambda id, name, counts: TqdmCallbacks.instance().step_counts(name, counts),
|
|
19
19
|
'begin_steps': lambda id, name: TqdmCallbacks.instance().begin_steps(name),
|
|
20
|
-
'end_steps': lambda id, name: TqdmCallbacks.instance().end_steps(
|
|
21
|
-
'after_step': lambda id, name, steps: TqdmCallbacks.instance().after_step(
|
|
20
|
+
'end_steps': lambda id, name: TqdmCallbacks.instance().end_steps(),
|
|
21
|
+
'after_step': lambda id, name, steps: TqdmCallbacks.instance().after_step()
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
def __init__(self):
|
|
25
|
-
self.
|
|
25
|
+
self.tbar = None
|
|
26
26
|
self.counts = -1
|
|
27
27
|
|
|
28
28
|
@classmethod
|
|
@@ -33,20 +33,20 @@ class TqdmCallbacks:
|
|
|
33
33
|
|
|
34
34
|
def step_counts(self, name, counts):
|
|
35
35
|
self.counts = counts
|
|
36
|
-
self.
|
|
36
|
+
self.tbar = make_tqdm_bar(name, self.counts)
|
|
37
37
|
|
|
38
38
|
def begin_steps(self, name):
|
|
39
39
|
pass
|
|
40
40
|
|
|
41
|
-
def end_steps(self
|
|
42
|
-
if self.
|
|
41
|
+
def end_steps(self):
|
|
42
|
+
if self.tbar is None:
|
|
43
43
|
raise RuntimeError("tqdm bar not initialized")
|
|
44
|
-
self.
|
|
45
|
-
self.
|
|
44
|
+
self.tbar.close()
|
|
45
|
+
self.tbar = None
|
|
46
46
|
|
|
47
|
-
def after_step(self
|
|
48
|
-
self.
|
|
49
|
-
self.
|
|
47
|
+
def after_step(self):
|
|
48
|
+
self.tbar.write("")
|
|
49
|
+
self.tbar.update(1)
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
tqdm_callbacks = TqdmCallbacks()
|
|
@@ -58,7 +58,7 @@ def elapsed_time_str(start):
|
|
|
58
58
|
ss = dt - mm * 60
|
|
59
59
|
hh = mm // 60
|
|
60
60
|
mm -= hh * 60
|
|
61
|
-
return "{:02d}:{:02d}:{:05.2f}s"
|
|
61
|
+
return f"{hh:02d}:{mm:02d}:{ss:05.2f}s"
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
class JobBase:
|
|
@@ -67,8 +67,11 @@ class JobBase:
|
|
|
67
67
|
self.name = name
|
|
68
68
|
self.enabled = enabled
|
|
69
69
|
self.base_message = ''
|
|
70
|
+
self.logger = None
|
|
71
|
+
self._t0 = None
|
|
72
|
+
self.callbacks = None
|
|
70
73
|
if config.JUPYTER_NOTEBOOK:
|
|
71
|
-
self.begin_r, self.end_r = "", "\r"
|
|
74
|
+
self.begin_r, self.end_r = "", "\r"
|
|
72
75
|
else:
|
|
73
76
|
self.begin_r, self.end_r = LINE_UP, None
|
|
74
77
|
|
|
@@ -80,29 +83,28 @@ class JobBase:
|
|
|
80
83
|
return callback(*args)
|
|
81
84
|
return None
|
|
82
85
|
|
|
86
|
+
def run_core(self):
|
|
87
|
+
pass
|
|
88
|
+
|
|
83
89
|
def run(self):
|
|
84
|
-
self.
|
|
90
|
+
self._t0 = time.time()
|
|
85
91
|
if not self.enabled:
|
|
86
92
|
self.get_logger().warning(color_str(self.name + ": entire job disabled", 'red'))
|
|
87
93
|
self.callback('before_action', self.id, self.name)
|
|
88
94
|
self.run_core()
|
|
89
95
|
self.callback('after_action', self.id, self.name)
|
|
90
|
-
self.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
self.get_logger().info(
|
|
96
|
-
color_str(self.name + ": ",
|
|
97
|
-
"green", "bold") + color_str("completed", "green") + trailing_spaces)
|
|
96
|
+
msg_name = color_str(self.name + ":", "green", "bold")
|
|
97
|
+
msg_time = color_str(f"elapsed time: {elapsed_time_str(self._t0)}", "green")
|
|
98
|
+
msg_completed = color_str("completed", "green")
|
|
99
|
+
self.get_logger().info(msg=f"{msg_name} {msg_time}{TRAILING_SPACES}")
|
|
100
|
+
self.get_logger().info(msg=f"{msg_name} {msg_completed}{TRAILING_SPACES}")
|
|
98
101
|
|
|
99
102
|
def get_logger(self, tqdm=False):
|
|
100
103
|
if config.DISABLE_TQDM:
|
|
101
104
|
tqdm = False
|
|
102
105
|
if self.logger is None:
|
|
103
106
|
return logging.getLogger("tqdm" if tqdm else __name__)
|
|
104
|
-
|
|
105
|
-
return self.logger
|
|
107
|
+
return self.logger
|
|
106
108
|
|
|
107
109
|
def set_terminator(self, tqdm=False, end='\n'):
|
|
108
110
|
if config.DISABLE_TQDM:
|
|
@@ -117,14 +119,20 @@ class JobBase:
|
|
|
117
119
|
if msg != '':
|
|
118
120
|
self.base_message += (': ' + msg)
|
|
119
121
|
self.set_terminator(tqdm, end)
|
|
120
|
-
self.get_logger(tqdm).log(
|
|
122
|
+
self.get_logger(tqdm).log(
|
|
123
|
+
level=level,
|
|
124
|
+
msg=f"{begin}{color_str(self.base_message, 'blue', 'bold')}{TRAILING_SPACES}"
|
|
125
|
+
)
|
|
121
126
|
self.set_terminator(tqdm)
|
|
122
127
|
|
|
123
128
|
def sub_message(self, msg, level=logging.INFO, end=None, begin='', tqdm=False):
|
|
124
129
|
if config.DISABLE_TQDM:
|
|
125
130
|
tqdm = False
|
|
126
131
|
self.set_terminator(tqdm, end)
|
|
127
|
-
self.get_logger(tqdm).log(
|
|
132
|
+
self.get_logger(tqdm).log(
|
|
133
|
+
level=level,
|
|
134
|
+
msg=f"{begin}{self.base_message}{msg}{TRAILING_SPACES}"
|
|
135
|
+
)
|
|
128
136
|
self.set_terminator(tqdm)
|
|
129
137
|
|
|
130
138
|
def print_message_r(self, msg='', level=logging.INFO):
|
|
@@ -141,11 +149,12 @@ class Job(JobBase):
|
|
|
141
149
|
self.__actions = []
|
|
142
150
|
if logger_name is None:
|
|
143
151
|
setup_logging(log_file=log_file)
|
|
144
|
-
|
|
152
|
+
if logger_name is not None:
|
|
153
|
+
self.logger = logging.getLogger(logger_name)
|
|
145
154
|
self.callbacks = TqdmCallbacks.callbacks if callbacks == 'tqdm' else callbacks
|
|
146
155
|
|
|
147
156
|
def time(self):
|
|
148
|
-
return time.time() - self.
|
|
157
|
+
return time.time() - self._t0
|
|
149
158
|
|
|
150
159
|
def init(self, a):
|
|
151
160
|
pass
|
|
@@ -177,6 +186,8 @@ class Job(JobBase):
|
|
|
177
186
|
class ActionList(JobBase):
|
|
178
187
|
def __init__(self, name, enabled=True, **kwargs):
|
|
179
188
|
JobBase.__init__(self, name, enabled, **kwargs)
|
|
189
|
+
self.counts = None
|
|
190
|
+
self.count = None
|
|
180
191
|
|
|
181
192
|
def set_counts(self, counts):
|
|
182
193
|
self.counts = counts
|
|
@@ -192,19 +203,21 @@ class ActionList(JobBase):
|
|
|
192
203
|
self.count = 1
|
|
193
204
|
return self
|
|
194
205
|
|
|
206
|
+
def run_step(self):
|
|
207
|
+
pass
|
|
208
|
+
|
|
195
209
|
def __next__(self):
|
|
196
210
|
if self.count <= self.counts:
|
|
197
211
|
self.run_step()
|
|
198
212
|
x = self.count
|
|
199
213
|
self.count += 1
|
|
200
214
|
return x
|
|
201
|
-
|
|
202
|
-
raise StopIteration
|
|
215
|
+
raise StopIteration
|
|
203
216
|
|
|
204
217
|
def run_core(self):
|
|
205
218
|
self.print_message('begin run', end='\n')
|
|
206
219
|
self.begin()
|
|
207
|
-
for
|
|
220
|
+
for _ in iter(self):
|
|
208
221
|
self.callback('after_step', self.id, self.name, self.count)
|
|
209
222
|
if self.callback('check_running', self.id, self.name) is False:
|
|
210
223
|
raise RunStopException(self.name)
|
shinestacker/core/logging.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116
|
|
1
2
|
import logging
|
|
2
3
|
import sys
|
|
3
4
|
from pathlib import Path
|
|
@@ -26,28 +27,26 @@ class ConsoleFormatter(logging.Formatter):
|
|
|
26
27
|
|
|
27
28
|
class FileFormatter(logging.Formatter):
|
|
28
29
|
def format(self, record):
|
|
29
|
-
fmt =
|
|
30
|
-
return constants.ANSI_ESCAPE.sub(
|
|
30
|
+
fmt = "[%(levelname).3s %(asctime)s] %(message)s"
|
|
31
|
+
return constants.ANSI_ESCAPE.sub(
|
|
32
|
+
'',
|
|
33
|
+
logging.Formatter(fmt).format(record).replace("\r", "").rstrip()
|
|
34
|
+
)
|
|
31
35
|
|
|
32
36
|
|
|
33
37
|
class TqdmLoggingHandler(logging.StreamHandler):
|
|
34
38
|
def emit(self, record):
|
|
35
39
|
if not config.DISABLE_TQDM:
|
|
36
|
-
|
|
37
|
-
tqdm.write(self.format(record), end=self.terminator)
|
|
38
|
-
except RecursionError:
|
|
39
|
-
raise
|
|
40
|
-
except Exception:
|
|
41
|
-
self.handleError(record)
|
|
40
|
+
tqdm.write(self.format(record), end=self.terminator)
|
|
42
41
|
else:
|
|
43
42
|
logging.StreamHandler.emit(self, record)
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
def setup_logging(console_level=logging.INFO, file_level=logging.DEBUG, log_file='',
|
|
47
46
|
disable_console=False):
|
|
48
|
-
if hasattr(setup_logging, '
|
|
47
|
+
if hasattr(setup_logging, 'called'):
|
|
49
48
|
return
|
|
50
|
-
setup_logging.
|
|
49
|
+
setup_logging.called = True
|
|
51
50
|
root_logger = logging.getLogger()
|
|
52
51
|
root_logger.setLevel(logging.DEBUG)
|
|
53
52
|
if not disable_console:
|