PrEditor 1.0.0__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 PrEditor might be problematic. Click here for more details.
- preditor/__init__.py +322 -0
- preditor/__main__.py +13 -0
- preditor/about_module.py +161 -0
- preditor/cli.py +192 -0
- preditor/config.py +302 -0
- preditor/contexts.py +119 -0
- preditor/cores/__init__.py +0 -0
- preditor/cores/core.py +20 -0
- preditor/dccs/maya/PrEditor_maya.mod +2 -0
- preditor/dccs/maya/plug-ins/PrEditor_maya.py +110 -0
- preditor/debug.py +144 -0
- preditor/delayable_engine/__init__.py +302 -0
- preditor/delayable_engine/delayables.py +85 -0
- preditor/enum.py +728 -0
- preditor/excepthooks.py +131 -0
- preditor/gui/__init__.py +93 -0
- preditor/gui/app.py +160 -0
- preditor/gui/codehighlighter.py +209 -0
- preditor/gui/completer.py +226 -0
- preditor/gui/console.py +867 -0
- preditor/gui/dialog.py +178 -0
- preditor/gui/drag_tab_bar.py +190 -0
- preditor/gui/editor_chooser.py +57 -0
- preditor/gui/errordialog.py +68 -0
- preditor/gui/find_files.py +125 -0
- preditor/gui/fuzzy_search/__init__.py +0 -0
- preditor/gui/fuzzy_search/fuzzy_search.py +93 -0
- preditor/gui/group_tab_widget/__init__.py +325 -0
- preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
- preditor/gui/group_tab_widget/grouped_tab_models.py +108 -0
- preditor/gui/group_tab_widget/grouped_tab_widget.py +78 -0
- preditor/gui/group_tab_widget/one_tab_widget.py +54 -0
- preditor/gui/level_buttons.py +343 -0
- preditor/gui/logger_window_handler.py +48 -0
- preditor/gui/logger_window_plugin.py +32 -0
- preditor/gui/loggerwindow.py +1385 -0
- preditor/gui/newtabwidget.py +69 -0
- preditor/gui/set_text_editor_path_dialog.py +59 -0
- preditor/gui/status_label.py +99 -0
- preditor/gui/suggest_path_quotes_dialog.py +50 -0
- preditor/gui/ui/editor_chooser.ui +93 -0
- preditor/gui/ui/errordialog.ui +74 -0
- preditor/gui/ui/find_files.ui +140 -0
- preditor/gui/ui/loggerwindow.ui +1105 -0
- preditor/gui/ui/set_text_editor_path_dialog.ui +189 -0
- preditor/gui/ui/suggest_path_quotes_dialog.ui +225 -0
- preditor/gui/window.py +161 -0
- preditor/gui/workbox_mixin.py +389 -0
- preditor/gui/workbox_text_edit.py +137 -0
- preditor/gui/workboxwidget.py +298 -0
- preditor/logging_config.py +52 -0
- preditor/osystem.py +401 -0
- preditor/plugins.py +118 -0
- preditor/prefs.py +74 -0
- preditor/resource/environment_variables.html +26 -0
- preditor/resource/error_mail.html +85 -0
- preditor/resource/error_mail_inline.html +41 -0
- preditor/resource/img/README.md +17 -0
- preditor/resource/img/arrow_forward.png +0 -0
- preditor/resource/img/check-bold.png +0 -0
- preditor/resource/img/chevron-down.png +0 -0
- preditor/resource/img/chevron-up.png +0 -0
- preditor/resource/img/close-thick.png +0 -0
- preditor/resource/img/comment-edit.png +0 -0
- preditor/resource/img/content-copy.png +0 -0
- preditor/resource/img/content-cut.png +0 -0
- preditor/resource/img/content-duplicate.png +0 -0
- preditor/resource/img/content-paste.png +0 -0
- preditor/resource/img/content-save.png +0 -0
- preditor/resource/img/debug_disabled.png +0 -0
- preditor/resource/img/eye-check.png +0 -0
- preditor/resource/img/file-plus.png +0 -0
- preditor/resource/img/file-remove.png +0 -0
- preditor/resource/img/format-align-left.png +0 -0
- preditor/resource/img/format-letter-case-lower.png +0 -0
- preditor/resource/img/format-letter-case-upper.png +0 -0
- preditor/resource/img/format-letter-case.svg +1 -0
- preditor/resource/img/information.png +0 -0
- preditor/resource/img/logging_critical.png +0 -0
- preditor/resource/img/logging_custom.png +0 -0
- preditor/resource/img/logging_debug.png +0 -0
- preditor/resource/img/logging_error.png +0 -0
- preditor/resource/img/logging_info.png +0 -0
- preditor/resource/img/logging_not_set.png +0 -0
- preditor/resource/img/logging_warning.png +0 -0
- preditor/resource/img/marker.png +0 -0
- preditor/resource/img/play.png +0 -0
- preditor/resource/img/playlist-play.png +0 -0
- preditor/resource/img/plus-minus-variant.png +0 -0
- preditor/resource/img/preditor.ico +0 -0
- preditor/resource/img/preditor.png +0 -0
- preditor/resource/img/preditor.psd +0 -0
- preditor/resource/img/preditor.svg +44 -0
- preditor/resource/img/regex.svg +1 -0
- preditor/resource/img/restart.svg +1 -0
- preditor/resource/img/skip-forward-outline.png +0 -0
- preditor/resource/img/skip-next-outline.png +0 -0
- preditor/resource/img/skip-next.png +0 -0
- preditor/resource/img/skip-previous.png +0 -0
- preditor/resource/img/subdirectory-arrow-right.png +0 -0
- preditor/resource/img/text-search-variant.png +0 -0
- preditor/resource/img/warning-big.png +0 -0
- preditor/resource/lang/python.json +30 -0
- preditor/resource/settings.ini +25 -0
- preditor/resource/stylesheet/Bright.css +65 -0
- preditor/resource/stylesheet/Dark.css +199 -0
- preditor/scintilla/__init__.py +22 -0
- preditor/scintilla/delayables/__init__.py +11 -0
- preditor/scintilla/delayables/smart_highlight.py +94 -0
- preditor/scintilla/delayables/spell_check.py +173 -0
- preditor/scintilla/documenteditor.py +2038 -0
- preditor/scintilla/finddialog.py +68 -0
- preditor/scintilla/lang/__init__.py +80 -0
- preditor/scintilla/lang/config/bash.ini +15 -0
- preditor/scintilla/lang/config/batch.ini +14 -0
- preditor/scintilla/lang/config/cpp.ini +19 -0
- preditor/scintilla/lang/config/css.ini +19 -0
- preditor/scintilla/lang/config/eyeonscript.ini +17 -0
- preditor/scintilla/lang/config/html.ini +21 -0
- preditor/scintilla/lang/config/javascript.ini +24 -0
- preditor/scintilla/lang/config/lua.ini +16 -0
- preditor/scintilla/lang/config/maxscript.ini +20 -0
- preditor/scintilla/lang/config/mel.ini +18 -0
- preditor/scintilla/lang/config/mu.ini +22 -0
- preditor/scintilla/lang/config/nsi.ini +19 -0
- preditor/scintilla/lang/config/perl.ini +19 -0
- preditor/scintilla/lang/config/puppet.ini +19 -0
- preditor/scintilla/lang/config/python.ini +28 -0
- preditor/scintilla/lang/config/ruby.ini +19 -0
- preditor/scintilla/lang/config/sql.ini +7 -0
- preditor/scintilla/lang/config/xml.ini +21 -0
- preditor/scintilla/lang/config/yaml.ini +18 -0
- preditor/scintilla/lang/language.py +240 -0
- preditor/scintilla/lexers/__init__.py +0 -0
- preditor/scintilla/lexers/cpplexer.py +21 -0
- preditor/scintilla/lexers/javascriptlexer.py +25 -0
- preditor/scintilla/lexers/maxscriptlexer.py +234 -0
- preditor/scintilla/lexers/mellexer.py +368 -0
- preditor/scintilla/lexers/mulexer.py +32 -0
- preditor/scintilla/lexers/pythonlexer.py +41 -0
- preditor/scintilla/ui/finddialog.ui +160 -0
- preditor/settings.py +71 -0
- preditor/stream/__init__.py +80 -0
- preditor/stream/director.py +73 -0
- preditor/stream/manager.py +74 -0
- preditor/streamhandler_helper.py +46 -0
- preditor/utils/__init__.py +0 -0
- preditor/utils/cute.py +30 -0
- preditor/utils/stylesheets.py +54 -0
- preditor/utils/text_search.py +342 -0
- preditor/version.py +21 -0
- preditor/weakref.py +363 -0
- preditor-1.0.0.dist-info/METADATA +224 -0
- preditor-1.0.0.dist-info/RECORD +158 -0
- preditor-1.0.0.dist-info/WHEEL +5 -0
- preditor-1.0.0.dist-info/entry_points.txt +18 -0
- preditor-1.0.0.dist-info/licenses/LICENSE +165 -0
- preditor-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import types
|
|
5
|
+
from functools import partial
|
|
6
|
+
|
|
7
|
+
from Qt.QtGui import QIcon
|
|
8
|
+
from Qt.QtWidgets import QAction, QMenu, QToolButton
|
|
9
|
+
|
|
10
|
+
from .. import plugins, resourcePath
|
|
11
|
+
from ..enum import Enum, EnumGroup
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Level(Enum):
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
Custom `Enum` representing an information level.
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
cached_icon(None): Used to cache the created icon from `get_icon` for
|
|
21
|
+
future use.
|
|
22
|
+
icon_name(str): Name of source icon file to use when creating icon via
|
|
23
|
+
`get_icon`.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
cached_icon = None
|
|
27
|
+
icon_name = "dot"
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def name(self):
|
|
31
|
+
"""
|
|
32
|
+
Override of `name` property allowing for the return of a "friendly
|
|
33
|
+
name" to be used in place of the inferred name from the `Enum` instance
|
|
34
|
+
name.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
str: Name of `Enum` instance.
|
|
38
|
+
"""
|
|
39
|
+
return getattr(self, "friendly_name", super(Level, self).name)
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def icon(self):
|
|
43
|
+
"""
|
|
44
|
+
Icon representing the level. On first access, the icon is created via
|
|
45
|
+
the `get_icon`-method and cached for later use.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
QIcon:
|
|
49
|
+
"""
|
|
50
|
+
if not self.cached_icon:
|
|
51
|
+
self.cached_icon = self.get_icon(self.icon_name, self.level)
|
|
52
|
+
return self.cached_icon
|
|
53
|
+
|
|
54
|
+
def get_icon(self, name, level):
|
|
55
|
+
"""
|
|
56
|
+
Retrieves the icon of `name` and level.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
name (str): Icon to retrieve QIcon for.
|
|
60
|
+
level (str): Level name to apply.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
QIcon: Correct instantiated QIcon.
|
|
64
|
+
"""
|
|
65
|
+
return QIcon(
|
|
66
|
+
resourcePath('img/{name}_{level}.png'.format(name=name, level=level))
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class LoggerLevel(Level):
|
|
71
|
+
"""A Logger level `Enum` using the 'format_align_left' icon."""
|
|
72
|
+
|
|
73
|
+
icon_name = "logging"
|
|
74
|
+
|
|
75
|
+
def is_current(self, logger):
|
|
76
|
+
"""Returns if the current logging level matches this label."""
|
|
77
|
+
return logging.getLevelName(logger.level) == self.label
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class LoggerLevels(EnumGroup):
|
|
81
|
+
"""
|
|
82
|
+
Logger levels with their implementation level name and number & custom
|
|
83
|
+
icon level.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
Disabled = LoggerLevel(
|
|
87
|
+
friendly_name="Not Set / Inherited", label="NOTSET", number=0, level="not_set"
|
|
88
|
+
)
|
|
89
|
+
Critical = LoggerLevel(label="CRITICAL", number=50, level="critical")
|
|
90
|
+
Error = LoggerLevel(label="ERROR", number=40, level="error")
|
|
91
|
+
Warning = LoggerLevel(label="WARNING", number=30, level="warning")
|
|
92
|
+
Info = LoggerLevel(label="INFO", number=20, level="info")
|
|
93
|
+
Debug = LoggerLevel(label="DEBUG", number=10, level="debug")
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def fromLabel(cls, label, default=None, logger=None):
|
|
97
|
+
try:
|
|
98
|
+
return super(LoggerLevels, cls).fromLabel(label, default=default)
|
|
99
|
+
except ValueError:
|
|
100
|
+
# This is not be a standard level, generate a custom level to use
|
|
101
|
+
if logger is None:
|
|
102
|
+
logger = logging.getLogger()
|
|
103
|
+
effective_level = logger.getEffectiveLevel()
|
|
104
|
+
effective_level_name = logging.getLevelName(effective_level)
|
|
105
|
+
|
|
106
|
+
enum = LoggerLevel(
|
|
107
|
+
label=effective_level_name,
|
|
108
|
+
number=effective_level,
|
|
109
|
+
level=effective_level_name,
|
|
110
|
+
)
|
|
111
|
+
# Force the custom icon as this enum's name won't match
|
|
112
|
+
enum.cached_icon = enum.get_icon(enum.icon_name, "custom")
|
|
113
|
+
# Add it to the enum
|
|
114
|
+
LoggerLevels.append(enum)
|
|
115
|
+
return enum
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class LoggingLevelButton(QToolButton):
|
|
119
|
+
|
|
120
|
+
"""
|
|
121
|
+
A drop down button to set logger levels for all loggers known to Python's
|
|
122
|
+
native logging implementation.
|
|
123
|
+
|
|
124
|
+
The logger menus present in the tool bar button have level-changing actions
|
|
125
|
+
as well a sub-menus for any descendant loggers.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def __init__(self, parent=None):
|
|
129
|
+
"""
|
|
130
|
+
Creates the root logger menu this button displays when clicked.
|
|
131
|
+
Additionally, any pre-existing loggers and their menus are added.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
parent (QWidget, optional): The parent widget for this button.
|
|
135
|
+
"""
|
|
136
|
+
super(LoggingLevelButton, self).__init__(parent=parent)
|
|
137
|
+
self.setPopupMode(QToolButton.InstantPopup)
|
|
138
|
+
|
|
139
|
+
# create root logger menu
|
|
140
|
+
root = logging.getLogger("")
|
|
141
|
+
root_menu = LoggingLevelMenu(name="root", logger=root, parent=self)
|
|
142
|
+
self.setMenu(root_menu)
|
|
143
|
+
|
|
144
|
+
# TODO: Hook refresh up to a root logger signal
|
|
145
|
+
# Monkey patch root.setLogger to emit signal we connect to
|
|
146
|
+
root = self.patched_root_logger().level_changed.connect(self.refresh)
|
|
147
|
+
|
|
148
|
+
@staticmethod
|
|
149
|
+
def patched_root_logger():
|
|
150
|
+
"""Returns `logging.getLogger("")`. This will have the level_changed
|
|
151
|
+
signal added if it wasn't already.
|
|
152
|
+
|
|
153
|
+
The level_changed signal is emitted any time something changes the
|
|
154
|
+
root logger level. PrEditor uses this to update the logging level button
|
|
155
|
+
icon any time the root logger's level is changed. The rest of the loggers
|
|
156
|
+
don't need this as the menu is built on demand with the correct icons indicated.
|
|
157
|
+
"""
|
|
158
|
+
root = logging.getLogger("")
|
|
159
|
+
if hasattr(root, "level_changed"):
|
|
160
|
+
# Already patched, nothing to do
|
|
161
|
+
return root
|
|
162
|
+
|
|
163
|
+
# Need to patch the root logger
|
|
164
|
+
from signalslot import Signal
|
|
165
|
+
|
|
166
|
+
root.level_changed = Signal(args=["level"], name="level_changed")
|
|
167
|
+
|
|
168
|
+
# Store the current setLevel, so we can call it in our method
|
|
169
|
+
root._setLevel = root.setLevel
|
|
170
|
+
|
|
171
|
+
def setLevel(self, level):
|
|
172
|
+
"""
|
|
173
|
+
Sets the threshold for this logger to `level`. Also emits the
|
|
174
|
+
instance's `level_changed`-signal with the level number as its payload.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
level (int): Numeric level value.
|
|
178
|
+
"""
|
|
179
|
+
# Call the original setLevel method
|
|
180
|
+
self._setLevel(level)
|
|
181
|
+
# Emit our signal
|
|
182
|
+
self.level_changed.emit(level=level)
|
|
183
|
+
|
|
184
|
+
root.setLevel = types.MethodType(setLevel, root)
|
|
185
|
+
|
|
186
|
+
return root
|
|
187
|
+
|
|
188
|
+
def refresh(self, **kwargs):
|
|
189
|
+
effective_level = logging.getLogger("").getEffectiveLevel()
|
|
190
|
+
effective_level_name = logging.getLevelName(effective_level)
|
|
191
|
+
level_enum = LoggerLevels.fromLabel(effective_level_name)
|
|
192
|
+
|
|
193
|
+
self.setIcon(level_enum.icon)
|
|
194
|
+
self.setToolTip("Logger 'root' current level: {}".format(level_enum.name))
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class LazyMenu(QMenu):
|
|
198
|
+
"""A menu class that only calls self.refresh when it is about to be shown."""
|
|
199
|
+
|
|
200
|
+
def __init__(self, *args, **kwargs):
|
|
201
|
+
super(LazyMenu, self).__init__(*args, **kwargs)
|
|
202
|
+
self.aboutToShow.connect(self.refresh)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class HandlerMenu(LazyMenu):
|
|
206
|
+
def __init__(self, logger, parent=None):
|
|
207
|
+
super(HandlerMenu, self).__init__(title="Handlers", parent=parent)
|
|
208
|
+
self.logger = logger
|
|
209
|
+
|
|
210
|
+
def install_handler(self, name):
|
|
211
|
+
plugins.add_logging_handler(self.logger, name)
|
|
212
|
+
|
|
213
|
+
def refresh(self):
|
|
214
|
+
self.clear()
|
|
215
|
+
# Add the Install sub menu showing all logging_handler plugins
|
|
216
|
+
handler_install = self.addMenu('Install')
|
|
217
|
+
for name, cls in plugins.logging_handlers():
|
|
218
|
+
act = handler_install.addAction(name)
|
|
219
|
+
act.triggered.connect(partial(self.install_handler, name))
|
|
220
|
+
for h in self.logger.handlers:
|
|
221
|
+
if type(h) is cls:
|
|
222
|
+
act.setEnabled(False)
|
|
223
|
+
act.setToolTip('Already installed for this logger.')
|
|
224
|
+
break
|
|
225
|
+
|
|
226
|
+
# Add a visual indication of all of the existing handlers
|
|
227
|
+
# TODO: Add ability to modify the formatters and auto-creation on startup
|
|
228
|
+
self.addSeparator()
|
|
229
|
+
for handler in self.logger.handlers:
|
|
230
|
+
act = self.addAction(repr(handler))
|
|
231
|
+
act.setEnabled(False)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class LoggingLevelMenu(LazyMenu):
|
|
235
|
+
|
|
236
|
+
"""
|
|
237
|
+
Custom menu for Python Loggers.
|
|
238
|
+
|
|
239
|
+
Provides an interface for changing logger levels via menu actions. Also
|
|
240
|
+
displays the presently set level by highlighting the relevant menu action
|
|
241
|
+
and via the menu's icon (which displays the logger's effective level,
|
|
242
|
+
potentially inherited from its ancestor).
|
|
243
|
+
"""
|
|
244
|
+
|
|
245
|
+
def __init__(self, name, logger, parent=None):
|
|
246
|
+
"""
|
|
247
|
+
Creates the default level menu actions for updating the logger's level.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
name (str): Name of Logger this menu will represent.
|
|
251
|
+
logger (logging.Logger): Logger this menu will represent and control
|
|
252
|
+
via actions that modify the logger's set level.
|
|
253
|
+
parent (QToolButton/QMenu): `QMenu` or `QToolButton` this menu will
|
|
254
|
+
be parented to.
|
|
255
|
+
|
|
256
|
+
Note: If the logger is merely a placeholder it will be initialized so
|
|
257
|
+
it can be added to the menu hierarchy. This ensures all ancestors
|
|
258
|
+
exist for appropriate parenting when descendants are added.
|
|
259
|
+
"""
|
|
260
|
+
super(LoggingLevelMenu, self).__init__(title=name.split(".")[-1], parent=parent)
|
|
261
|
+
|
|
262
|
+
if isinstance(logger, logging.PlaceHolder):
|
|
263
|
+
logger = logging.getLogger(name)
|
|
264
|
+
|
|
265
|
+
self.logger = logger
|
|
266
|
+
self.name = name
|
|
267
|
+
self.update_ui()
|
|
268
|
+
|
|
269
|
+
def children(self):
|
|
270
|
+
"""The direct sub-loggers of this logging object."""
|
|
271
|
+
parent = self.name
|
|
272
|
+
if parent == "root":
|
|
273
|
+
parent = ""
|
|
274
|
+
for name, logger in sorted(
|
|
275
|
+
logging.root.manager.loggerDict.items(), key=lambda x: x[0].lower()
|
|
276
|
+
):
|
|
277
|
+
if name.startswith(parent):
|
|
278
|
+
remaining = name.lstrip(parent).lstrip(".")
|
|
279
|
+
if remaining and "." not in remaining:
|
|
280
|
+
yield name, logger
|
|
281
|
+
|
|
282
|
+
def level(self):
|
|
283
|
+
"""Returns the current effective LoggerLevel for self.logger."""
|
|
284
|
+
effective_level = self.logger.getEffectiveLevel()
|
|
285
|
+
effective_level_name = logging.getLevelName(effective_level)
|
|
286
|
+
return LoggerLevels.fromLabel(effective_level_name, logger=self.logger)
|
|
287
|
+
|
|
288
|
+
def refresh(self):
|
|
289
|
+
self.clear()
|
|
290
|
+
|
|
291
|
+
self.addMenu(HandlerMenu(self.logger, self))
|
|
292
|
+
self.addSeparator()
|
|
293
|
+
|
|
294
|
+
for logger_level in LoggerLevels:
|
|
295
|
+
is_current = logger_level.is_current(self.logger)
|
|
296
|
+
|
|
297
|
+
action = QAction(logger_level.icon, logger_level.name, self)
|
|
298
|
+
action.setCheckable(True)
|
|
299
|
+
action.setChecked(is_current)
|
|
300
|
+
|
|
301
|
+
# tooltip example: "Set 'preditor.debug' to level Warning")
|
|
302
|
+
action.setToolTip(
|
|
303
|
+
"Set '{}' to level {}".format(self.name, logger_level.name)
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# when clicked/activated set associated loggers level
|
|
307
|
+
action.triggered.connect(partial(self.setLevel, logger_level.number))
|
|
308
|
+
self.addAction(action)
|
|
309
|
+
|
|
310
|
+
self.addSeparator()
|
|
311
|
+
|
|
312
|
+
for name, child in self.children():
|
|
313
|
+
self.addMenu(LoggingLevelMenu(name, child, self))
|
|
314
|
+
|
|
315
|
+
def setLevel(self, level):
|
|
316
|
+
"""
|
|
317
|
+
Sets the logger this menu object represents to the level supplied.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
level (str): Logging level to set logger to.
|
|
321
|
+
"""
|
|
322
|
+
self.logger.setLevel(level)
|
|
323
|
+
self.update_ui()
|
|
324
|
+
|
|
325
|
+
def update_ui(self):
|
|
326
|
+
"""Set the menu icon to this LoggerLevel's icon.
|
|
327
|
+
|
|
328
|
+
If the updated logger is the root logger, the logging level toolbar
|
|
329
|
+
button's icon is updated instead.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
level (LoggerLevel): Logging level to change icon to represent.
|
|
333
|
+
"""
|
|
334
|
+
|
|
335
|
+
level_enum = self.level()
|
|
336
|
+
act = self.menuAction()
|
|
337
|
+
act.setIcon(level_enum.icon)
|
|
338
|
+
act.setToolTip(
|
|
339
|
+
"Logger '{}' current level: {}".format(self.logger.name, level_enum.name)
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
if self.name == "root":
|
|
343
|
+
self.parent().refresh()
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from .. import instance
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LoggerWindowHandler(logging.Handler):
|
|
9
|
+
"""A logging handler that writes directly to the PrEditor instance.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
error (bool, optional): Write the output as if it were written
|
|
13
|
+
to sys.stderr and not sys.stdout. Ie in red text.
|
|
14
|
+
formatter (str or logging.Formatter, optional): If specified,
|
|
15
|
+
this is passed to setFormatter.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
default_format = (
|
|
19
|
+
'%(levelname)s %(module)s.%(funcName)s line:%(lineno)d - %(message)s'
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
def __init__(self, error=True, formatter=default_format):
|
|
23
|
+
super(LoggerWindowHandler, self).__init__()
|
|
24
|
+
self.error = error
|
|
25
|
+
if formatter is not None:
|
|
26
|
+
if not isinstance(formatter, logging.Formatter):
|
|
27
|
+
formatter = logging.Formatter(formatter)
|
|
28
|
+
self.setFormatter(formatter)
|
|
29
|
+
|
|
30
|
+
def emit(self, record):
|
|
31
|
+
_instance = instance(create=False)
|
|
32
|
+
if _instance is None:
|
|
33
|
+
# No gui has been created yet, so nothing to do
|
|
34
|
+
return
|
|
35
|
+
try:
|
|
36
|
+
# If the python logger was closed and garbage collected,
|
|
37
|
+
# there is nothing to do, simply exit the call
|
|
38
|
+
console = _instance.console()
|
|
39
|
+
if not console:
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
msg = self.format(record)
|
|
43
|
+
msg = u'{}\n'.format(msg)
|
|
44
|
+
console.write(msg, self.error)
|
|
45
|
+
except (KeyboardInterrupt, SystemExit):
|
|
46
|
+
raise
|
|
47
|
+
except Exception:
|
|
48
|
+
self.handleError(record)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class LoggerWindowPlugin:
|
|
2
|
+
"""Base class for LoggerWindow plugins.
|
|
3
|
+
|
|
4
|
+
These plugins are loaded using the `preditor.plug.loggerwindow` entry point.
|
|
5
|
+
This entry point is loaded when `LoggerWindow` is initialized. For each entry
|
|
6
|
+
point defined a single instance of the plugin is created per instance of
|
|
7
|
+
a LoggerWindow.
|
|
8
|
+
|
|
9
|
+
To save preferences override `record_prefs` and `restore_prefs` methods. These
|
|
10
|
+
are used to save and load preferences any time the PrEditor save/loads prefs.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, parent):
|
|
14
|
+
self.parent = parent
|
|
15
|
+
|
|
16
|
+
def record_prefs(self, name):
|
|
17
|
+
"""Returns any prefs to save with the PrEditor's preferences.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
dict: A dictionary that will be saved using json or None.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def restore_prefs(self, name, prefs):
|
|
24
|
+
"""Restore the preferences saved from a previous launch.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
name(str): The name specified by the `preditor.plug.loggerwindow`
|
|
28
|
+
entry point.
|
|
29
|
+
prefs(dict or None): The prefs returned by a previous call to
|
|
30
|
+
`record_prefs()` from the last preference save. None is passed
|
|
31
|
+
if no prefs were recorded.
|
|
32
|
+
"""
|