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,298 @@
|
|
|
1
|
+
from __future__ import absolute_import, print_function
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import re
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
from Qt.QtCore import Qt
|
|
8
|
+
from Qt.QtGui import QIcon
|
|
9
|
+
from Qt.QtWidgets import QAction
|
|
10
|
+
|
|
11
|
+
from .. import core, resourcePath
|
|
12
|
+
from ..gui.workbox_mixin import WorkboxMixin
|
|
13
|
+
from ..scintilla.documenteditor import DocumentEditor, SearchOptions
|
|
14
|
+
from ..scintilla.finddialog import FindDialog
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class WorkboxWidget(WorkboxMixin, DocumentEditor):
|
|
18
|
+
def __init__(
|
|
19
|
+
self, parent=None, console=None, delayable_engine='default', core_name=None
|
|
20
|
+
):
|
|
21
|
+
self.__set_console__(console)
|
|
22
|
+
self._searchFlags = 0
|
|
23
|
+
self._searchText = ''
|
|
24
|
+
self._searchDialog = None
|
|
25
|
+
|
|
26
|
+
# initialize the super class
|
|
27
|
+
super(WorkboxWidget, self).__init__(
|
|
28
|
+
parent, delayable_engine=delayable_engine, core_name=core_name
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Store the software name so we can handle custom keyboard shortcuts based on
|
|
32
|
+
# software
|
|
33
|
+
self._software = core.objectName()
|
|
34
|
+
# Used to remove any trailing whitespace when running selected text
|
|
35
|
+
self.regex = re.compile(r'\s+$')
|
|
36
|
+
self.initShortcuts()
|
|
37
|
+
self.setLanguage('Python')
|
|
38
|
+
# Default to unix newlines
|
|
39
|
+
self.setEolMode(self.EolUnix)
|
|
40
|
+
if hasattr(self.window(), "setWorkboxFontBasedOnConsole"):
|
|
41
|
+
self.window().setWorkboxFontBasedOnConsole()
|
|
42
|
+
|
|
43
|
+
def __auto_complete_enabled__(self):
|
|
44
|
+
return self.autoCompletionSource() == self.AcsAll
|
|
45
|
+
|
|
46
|
+
def __set_auto_complete_enabled__(self, state):
|
|
47
|
+
state = self.AcsAll if state else self.AcsNone
|
|
48
|
+
self.setAutoCompletionSource(state)
|
|
49
|
+
|
|
50
|
+
def __clear__(self):
|
|
51
|
+
self.clear()
|
|
52
|
+
|
|
53
|
+
def __comment_toggle__(self):
|
|
54
|
+
self.commentToggle()
|
|
55
|
+
|
|
56
|
+
def __copy_indents_as_spaces__(self):
|
|
57
|
+
return self.copyIndentsAsSpaces
|
|
58
|
+
|
|
59
|
+
def __set_copy_indents_as_spaces__(self, state):
|
|
60
|
+
self.copyIndentsAsSpaces = state
|
|
61
|
+
|
|
62
|
+
def __cursor_position__(self):
|
|
63
|
+
"""Returns the line and index of the cursor."""
|
|
64
|
+
return self.getCursorPosition()
|
|
65
|
+
|
|
66
|
+
def __set_cursor_position__(self, line, index):
|
|
67
|
+
"""Set the cursor to this line number and index"""
|
|
68
|
+
self.setCursorPosition(line, index)
|
|
69
|
+
|
|
70
|
+
def __exec_all__(self):
|
|
71
|
+
txt = self.__unix_end_lines__(self.text()).rstrip()
|
|
72
|
+
filename = self.__workbox_filename__()
|
|
73
|
+
self.__console__().executeString(txt, filename=filename)
|
|
74
|
+
|
|
75
|
+
def __file_monitoring_enabled__(self):
|
|
76
|
+
return self._fileMonitoringActive
|
|
77
|
+
|
|
78
|
+
def __set_file_monitoring_enabled__(self, state):
|
|
79
|
+
self.setAutoReloadOnChange(state)
|
|
80
|
+
self.enableFileWatching(state)
|
|
81
|
+
|
|
82
|
+
def __filename__(self):
|
|
83
|
+
return self.filename()
|
|
84
|
+
|
|
85
|
+
def __font__(self):
|
|
86
|
+
if self.lexer():
|
|
87
|
+
return self.lexer().font(0)
|
|
88
|
+
else:
|
|
89
|
+
self.font()
|
|
90
|
+
|
|
91
|
+
def __set_font__(self, font):
|
|
92
|
+
self.documentFont = font
|
|
93
|
+
if self.lexer():
|
|
94
|
+
self.lexer().setFont(font)
|
|
95
|
+
else:
|
|
96
|
+
self.setFont(font)
|
|
97
|
+
|
|
98
|
+
def __goto_line__(self, line):
|
|
99
|
+
self.goToLine(line)
|
|
100
|
+
|
|
101
|
+
def __indentations_use_tabs__(self):
|
|
102
|
+
return self.indentationsUseTabs()
|
|
103
|
+
|
|
104
|
+
def __set_indentations_use_tabs__(self, state):
|
|
105
|
+
self.setIndentationsUseTabs(state)
|
|
106
|
+
|
|
107
|
+
def __insert_text__(self, txt):
|
|
108
|
+
self.insert(txt)
|
|
109
|
+
|
|
110
|
+
def __load__(self, filename):
|
|
111
|
+
self.load(filename)
|
|
112
|
+
|
|
113
|
+
def __margins_font__(self):
|
|
114
|
+
return self.marginsFont()
|
|
115
|
+
|
|
116
|
+
def __set_margins_font__(self, font):
|
|
117
|
+
self.setMarginsFont(font)
|
|
118
|
+
|
|
119
|
+
def __marker_add__(self, line):
|
|
120
|
+
try:
|
|
121
|
+
marker = self._marker
|
|
122
|
+
except AttributeError:
|
|
123
|
+
self._marker = self.markerDefine(self.Circle)
|
|
124
|
+
marker = self._marker
|
|
125
|
+
self.markerAdd(line, marker)
|
|
126
|
+
|
|
127
|
+
def __marker_clear_all__(self):
|
|
128
|
+
try:
|
|
129
|
+
self.markerDeleteAll(self._marker)
|
|
130
|
+
except AttributeError:
|
|
131
|
+
# self._marker has not been created yet
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
def __reload_file__(self):
|
|
135
|
+
# loading the file too quickly misses any changes
|
|
136
|
+
time.sleep(0.1)
|
|
137
|
+
font = self.__font__()
|
|
138
|
+
self.reloadChange()
|
|
139
|
+
self.__set_font__(font)
|
|
140
|
+
|
|
141
|
+
def __remove_selected_text__(self):
|
|
142
|
+
self.removeSelectedText()
|
|
143
|
+
|
|
144
|
+
def __save__(self):
|
|
145
|
+
self.save()
|
|
146
|
+
|
|
147
|
+
def __selected_text__(self, start_of_line=False, selectText=False):
|
|
148
|
+
line, s, end, e = self.getSelection()
|
|
149
|
+
if line == -1:
|
|
150
|
+
# Nothing is selected, return the current line of text
|
|
151
|
+
line, index = self.getCursorPosition()
|
|
152
|
+
txt = self.text(line)
|
|
153
|
+
|
|
154
|
+
lineLength = len(self.text(line).rstrip())
|
|
155
|
+
selectText = self.window().uiSelectTextACT.isChecked() or selectText
|
|
156
|
+
|
|
157
|
+
if selectText:
|
|
158
|
+
self.setSelection(line, 0, line, lineLength)
|
|
159
|
+
|
|
160
|
+
elif start_of_line:
|
|
161
|
+
ss = self.positionFromLineIndex(line, 0)
|
|
162
|
+
ee = self.positionFromLineIndex(end, e)
|
|
163
|
+
txt = self.text(ss, ee)
|
|
164
|
+
else:
|
|
165
|
+
txt = self.selectedText()
|
|
166
|
+
return self.regex.split(txt)[0], line
|
|
167
|
+
|
|
168
|
+
def __tab_width__(self):
|
|
169
|
+
return self.tabWidth()
|
|
170
|
+
|
|
171
|
+
def __set_tab_width__(self, width):
|
|
172
|
+
self.setTabWidth(width)
|
|
173
|
+
|
|
174
|
+
def __text__(self, line=None, start=None, end=None):
|
|
175
|
+
"""Returns the text in this widget, possibly limited in scope.
|
|
176
|
+
|
|
177
|
+
Note: Only pass line, or (start and end) to this method.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
line (int, optional): Limit the returned scope to just this line number.
|
|
181
|
+
start (int, optional): Limit the scope to text between this and end.
|
|
182
|
+
end (int, optional): Limit the scope to text between start and this.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
str: The requested text.
|
|
186
|
+
"""
|
|
187
|
+
if line:
|
|
188
|
+
return self.text(line)
|
|
189
|
+
elif (start is None) != (end is None):
|
|
190
|
+
raise ValueError('You must pass start and end if you pass either.')
|
|
191
|
+
elif start is not None:
|
|
192
|
+
self.text(start, end)
|
|
193
|
+
return self.text()
|
|
194
|
+
|
|
195
|
+
def __set_text__(self, txt):
|
|
196
|
+
"""Replace all of the current text with txt."""
|
|
197
|
+
self.setText(txt)
|
|
198
|
+
|
|
199
|
+
@classmethod
|
|
200
|
+
def __write_file__(cls, filename, txt):
|
|
201
|
+
with io.open(filename, 'w', newline='\n') as fle:
|
|
202
|
+
# Save unix newlines for simplicity
|
|
203
|
+
fle.write(cls.__unix_end_lines__(txt))
|
|
204
|
+
|
|
205
|
+
def keyPressEvent(self, event):
|
|
206
|
+
"""Check for certain keyboard shortcuts, and handle them as needed,
|
|
207
|
+
otherwise pass the keyPress to the superclass.
|
|
208
|
+
|
|
209
|
+
NOTE! We handle the "shift+return" shortcut here, rather than the
|
|
210
|
+
QAction's shortcut, because the workbox will always intercept that
|
|
211
|
+
shortcut. So, we handle it here, and call the main window's
|
|
212
|
+
execSelected, which ultimately calls this workbox's __exec_selected__.
|
|
213
|
+
|
|
214
|
+
Also note, it would make sense to have ctrl+Enter also execute without
|
|
215
|
+
truncation, but no modifiers are registered when Enter is pressed (unlike
|
|
216
|
+
when Return is pressed), so this combination is not detectable.
|
|
217
|
+
"""
|
|
218
|
+
if self._software == 'softimage':
|
|
219
|
+
DocumentEditor.keyPressEvent(self, event)
|
|
220
|
+
else:
|
|
221
|
+
if self.process_shortcut(event):
|
|
222
|
+
return
|
|
223
|
+
else:
|
|
224
|
+
# Send regular keystroke
|
|
225
|
+
DocumentEditor.keyPressEvent(self, event)
|
|
226
|
+
|
|
227
|
+
def initShortcuts(self):
|
|
228
|
+
"""Use this to set up shortcuts when the DocumentEditor"""
|
|
229
|
+
icon = QIcon(resourcePath('img/text-search-variant.png'))
|
|
230
|
+
self.uiFindACT = QAction(icon, 'Find...', self)
|
|
231
|
+
self.uiFindACT.setShortcut("Ctrl+F")
|
|
232
|
+
self.addAction(self.uiFindACT)
|
|
233
|
+
|
|
234
|
+
icon = QIcon(resourcePath('img/skip-previous.png'))
|
|
235
|
+
self.uiFindPrevACT = QAction(icon, 'Find Prev', self)
|
|
236
|
+
self.uiFindPrevACT.setShortcut("Ctrl+F3")
|
|
237
|
+
self.addAction(self.uiFindPrevACT)
|
|
238
|
+
|
|
239
|
+
icon = QIcon(resourcePath('img/skip-next.png'))
|
|
240
|
+
self.uiFindNextACT = QAction(icon, 'Find Next', self)
|
|
241
|
+
self.uiFindNextACT.setShortcut("F3")
|
|
242
|
+
self.addAction(self.uiFindNextACT)
|
|
243
|
+
|
|
244
|
+
self.uiSelectCurrentLineACT = QAction(icon, 'Select Line', self)
|
|
245
|
+
self.uiSelectCurrentLineACT.triggered.connect(self.expandCursorToLineSelection)
|
|
246
|
+
self.uiSelectCurrentLineACT.setShortcut('Ctrl+L')
|
|
247
|
+
self.addAction(self.uiSelectCurrentLineACT)
|
|
248
|
+
|
|
249
|
+
# create the search dialog and connect actions
|
|
250
|
+
self._searchDialog = FindDialog(self)
|
|
251
|
+
self._searchDialog.setAttribute(Qt.WA_DeleteOnClose, False)
|
|
252
|
+
self.uiFindACT.triggered.connect(
|
|
253
|
+
lambda: self._searchDialog.search(self.searchText())
|
|
254
|
+
)
|
|
255
|
+
self.uiFindPrevACT.triggered.connect(
|
|
256
|
+
lambda: self.findPrev(self.searchText(), self.searchFlags())
|
|
257
|
+
)
|
|
258
|
+
self.uiFindNextACT.triggered.connect(
|
|
259
|
+
lambda: self.findNext(self.searchText(), self.searchFlags())
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
def searchFlags(self):
|
|
263
|
+
return self._searchFlags
|
|
264
|
+
|
|
265
|
+
def searchText(self):
|
|
266
|
+
if not self._searchDialog:
|
|
267
|
+
return ''
|
|
268
|
+
# refresh the search text unless we are using regular expressions
|
|
269
|
+
if (
|
|
270
|
+
not self._searchDialog.isVisible()
|
|
271
|
+
and not self._searchFlags & SearchOptions.QRegExp
|
|
272
|
+
):
|
|
273
|
+
txt = self.selectedText()
|
|
274
|
+
if txt:
|
|
275
|
+
self._searchText = txt
|
|
276
|
+
return self._searchText
|
|
277
|
+
|
|
278
|
+
def setSearchFlags(self, flags):
|
|
279
|
+
self._searchFlags = flags
|
|
280
|
+
|
|
281
|
+
def setSearchText(self, txt):
|
|
282
|
+
self._searchText = txt
|
|
283
|
+
|
|
284
|
+
def showMenu(self, pos):
|
|
285
|
+
menu = super(WorkboxWidget, self).showMenu(pos, popup=False)
|
|
286
|
+
menu.addSeparator()
|
|
287
|
+
submenu = menu.addMenu('Options')
|
|
288
|
+
act = submenu.addAction('Toggle end line visibility')
|
|
289
|
+
act.setCheckable(True)
|
|
290
|
+
act.setChecked(self.eolVisibility())
|
|
291
|
+
act.triggered.connect(self.setEolVisibility)
|
|
292
|
+
|
|
293
|
+
act = submenu.addAction('Show Whitespace')
|
|
294
|
+
act.setCheckable(True)
|
|
295
|
+
act.setChecked(self.showWhitespaces())
|
|
296
|
+
act.triggered.connect(self.setShowWhitespaces)
|
|
297
|
+
|
|
298
|
+
menu.popup(self._clickPos)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import logging.config
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
from .prefs import prefs_path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LoggingConfig(object):
|
|
12
|
+
def __init__(self, core_name, version=1):
|
|
13
|
+
self._filename = None
|
|
14
|
+
self.cfg = {'version': version}
|
|
15
|
+
self.core_name = core_name
|
|
16
|
+
|
|
17
|
+
def add_logger(self, name, logger):
|
|
18
|
+
if not logger.level:
|
|
19
|
+
# No need to record a logger that is inheriting its logging level
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
# Build the required dictionaries
|
|
23
|
+
loggers = self.cfg.setdefault('loggers', {})
|
|
24
|
+
log = loggers.setdefault(name, {})
|
|
25
|
+
log['level'] = logger.level
|
|
26
|
+
|
|
27
|
+
def build(self):
|
|
28
|
+
self.add_logger("", logging.root)
|
|
29
|
+
for name, logger in logging.root.manager.loggerDict.items():
|
|
30
|
+
if not isinstance(logger, logging.PlaceHolder):
|
|
31
|
+
self.add_logger(name, logger)
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def filename(self):
|
|
35
|
+
if self._filename:
|
|
36
|
+
return self._filename
|
|
37
|
+
|
|
38
|
+
self._filename = prefs_path('logging_prefs.json', core_name=self.core_name)
|
|
39
|
+
return self._filename
|
|
40
|
+
|
|
41
|
+
def load(self):
|
|
42
|
+
if not os.path.exists(self.filename):
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
with open(self.filename) as fle:
|
|
46
|
+
self.cfg = json.load(fle)
|
|
47
|
+
logging.config.dictConfig(self.cfg)
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
def save(self):
|
|
51
|
+
with open(self.filename, 'w') as fle:
|
|
52
|
+
json.dump(self.cfg, fle, indent=4)
|