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.

Files changed (71) hide show
  1. shinestacker/__init__.py +2 -1
  2. shinestacker/_version.py +1 -1
  3. shinestacker/algorithms/__init__.py +3 -2
  4. shinestacker/algorithms/align.py +102 -64
  5. shinestacker/algorithms/balance.py +89 -42
  6. shinestacker/algorithms/base_stack_algo.py +42 -0
  7. shinestacker/algorithms/core_utils.py +6 -6
  8. shinestacker/algorithms/denoise.py +4 -1
  9. shinestacker/algorithms/depth_map.py +28 -39
  10. shinestacker/algorithms/exif.py +43 -38
  11. shinestacker/algorithms/multilayer.py +48 -28
  12. shinestacker/algorithms/noise_detection.py +34 -23
  13. shinestacker/algorithms/pyramid.py +42 -42
  14. shinestacker/algorithms/sharpen.py +1 -0
  15. shinestacker/algorithms/stack.py +42 -41
  16. shinestacker/algorithms/stack_framework.py +111 -65
  17. shinestacker/algorithms/utils.py +12 -11
  18. shinestacker/algorithms/vignetting.py +48 -22
  19. shinestacker/algorithms/white_balance.py +1 -0
  20. shinestacker/app/about_dialog.py +6 -2
  21. shinestacker/app/app_config.py +1 -0
  22. shinestacker/app/gui_utils.py +20 -0
  23. shinestacker/app/help_menu.py +1 -0
  24. shinestacker/app/main.py +9 -18
  25. shinestacker/app/open_frames.py +5 -4
  26. shinestacker/app/project.py +5 -16
  27. shinestacker/app/retouch.py +5 -17
  28. shinestacker/core/colors.py +4 -4
  29. shinestacker/core/core_utils.py +1 -1
  30. shinestacker/core/exceptions.py +2 -1
  31. shinestacker/core/framework.py +46 -33
  32. shinestacker/core/logging.py +9 -10
  33. shinestacker/gui/action_config.py +253 -197
  34. shinestacker/gui/actions_window.py +32 -28
  35. shinestacker/gui/colors.py +1 -0
  36. shinestacker/gui/gui_images.py +7 -3
  37. shinestacker/gui/gui_logging.py +3 -2
  38. shinestacker/gui/gui_run.py +53 -38
  39. shinestacker/gui/main_window.py +69 -25
  40. shinestacker/gui/new_project.py +35 -2
  41. shinestacker/gui/project_converter.py +21 -20
  42. shinestacker/gui/project_editor.py +45 -52
  43. shinestacker/gui/project_model.py +15 -23
  44. shinestacker/retouch/{filter_base.py → base_filter.py} +7 -4
  45. shinestacker/retouch/brush.py +1 -0
  46. shinestacker/retouch/brush_gradient.py +17 -3
  47. shinestacker/retouch/brush_preview.py +14 -10
  48. shinestacker/retouch/brush_tool.py +28 -19
  49. shinestacker/retouch/denoise_filter.py +3 -2
  50. shinestacker/retouch/display_manager.py +11 -5
  51. shinestacker/retouch/exif_data.py +1 -0
  52. shinestacker/retouch/file_loader.py +13 -9
  53. shinestacker/retouch/filter_manager.py +1 -0
  54. shinestacker/retouch/image_editor.py +14 -48
  55. shinestacker/retouch/image_editor_ui.py +10 -5
  56. shinestacker/retouch/image_filters.py +4 -2
  57. shinestacker/retouch/image_viewer.py +33 -31
  58. shinestacker/retouch/io_gui_handler.py +25 -13
  59. shinestacker/retouch/io_manager.py +3 -2
  60. shinestacker/retouch/layer_collection.py +79 -23
  61. shinestacker/retouch/shortcuts_help.py +1 -0
  62. shinestacker/retouch/undo_manager.py +7 -0
  63. shinestacker/retouch/unsharp_mask_filter.py +3 -2
  64. shinestacker/retouch/white_balance_filter.py +11 -6
  65. {shinestacker-0.3.2.dist-info → shinestacker-0.3.4.dist-info}/METADATA +10 -4
  66. shinestacker-0.3.4.dist-info/RECORD +86 -0
  67. shinestacker-0.3.2.dist-info/RECORD +0 -85
  68. {shinestacker-0.3.2.dist-info → shinestacker-0.3.4.dist-info}/WHEEL +0 -0
  69. {shinestacker-0.3.2.dist-info → shinestacker-0.3.4.dist-info}/entry_points.txt +0 -0
  70. {shinestacker-0.3.2.dist-info → shinestacker-0.3.4.dist-info}/licenses/LICENSE +0 -0
  71. {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(self.project_window.menuBar().actions()[0], self.app_menu)
39
- self.retouch_window.menuBar().insertMenu(self.retouch_window.menuBar().actions()[0], self.app_menu)
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
- about_action = QAction(f"About {constants.APP_STRING}", self)
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, lambda: main_app.project_window.new_project())
165
- QTimer.singleShot(100, lambda: main_app.setFocus())
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
 
@@ -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, path):
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 path:
28
+ elif path_list:
28
29
  reverse = False
29
- paths = path.split(';')
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)
@@ -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, QAction
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
- about_action = QAction(f"About {constants.APP_STRING}", self)
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, lambda: window.new_project())
75
+ QTimer.singleShot(100, window.new_project)
87
76
  sys.exit(app.exec())
88
77
 
89
78
 
@@ -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, QAction
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
- about_action = QAction(f"About {constants.APP_STRING}", self)
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)
@@ -1,4 +1,4 @@
1
- # pylint: disable=C0114, C0116, C0201
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.keys():
53
+ if arg in COLORS:
54
54
  text_colored = f"\033[{COLORS[arg]}m{text_colored}"
55
- elif arg in BG_COLORS.keys():
55
+ elif arg in BG_COLORS:
56
56
  text_colored = f"\033[{BG_COLORS[arg]}m{text_colored}"
57
- elif arg in EFFECTS.keys():
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}")
@@ -1,4 +1,4 @@
1
- # pylint: disable=C0114, C0116, C0201
1
+ # pylint: disable=C0114, C0116
2
2
  import os
3
3
  import sys
4
4
  import platform
@@ -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}" + ("" if details == "" else f": {details}"))
11
+ super().__init__(f"Invalid option {option} = {value}" +
12
+ ("" if details == "" else f": {details}"))
12
13
 
13
14
 
14
15
  class ImageLoadError(FocusStackError):
@@ -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
- trailing_spaces = " " * 30
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(name),
21
- 'after_step': lambda id, name, steps: TqdmCallbacks.instance().after_step(name)
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.bar = None
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.bar = make_tqdm_bar(name, self.counts)
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, name):
42
- if self.bar is None:
41
+ def end_steps(self):
42
+ if self.tbar is None:
43
43
  raise RuntimeError("tqdm bar not initialized")
44
- self.bar.close()
45
- self.bar = None
44
+ self.tbar.close()
45
+ self.tbar = None
46
46
 
47
- def after_step(self, name):
48
- self.bar.write("")
49
- self.bar.update(1)
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".format(hh, mm, ss)
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.__t0 = time.time()
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.get_logger().info(
91
- color_str(self.name + ": ",
92
- "green", "bold") + color_str("elapsed "
93
- "time: {}".format(elapsed_time_str(self.__t0)),
94
- "green") + trailing_spaces)
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
- else:
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(level, begin + color_str(self.base_message, 'blue', 'bold') + trailing_spaces)
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(level, begin + self.base_message + msg + trailing_spaces)
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
- self.logger = None if logger_name is None else logging.getLogger(logger_name)
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.__t0
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
- else:
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 x in iter(self):
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)
@@ -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 = f"[%(levelname).3s %(asctime)s] %(message)s" # noqa
30
- return constants.ANSI_ESCAPE.sub('', logging.Formatter(fmt).format(record).replace("\r", "").rstrip())
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
- try:
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, '_called'):
47
+ if hasattr(setup_logging, 'called'):
49
48
  return
50
- setup_logging._called = True
49
+ setup_logging.called = True
51
50
  root_logger = logging.getLogger()
52
51
  root_logger.setLevel(logging.DEBUG)
53
52
  if not disable_console: