PrEditor 2.1.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.
- preditor/__init__.py +315 -0
- preditor/__main__.py +13 -0
- preditor/about_module.py +165 -0
- preditor/cli.py +192 -0
- preditor/config.py +318 -0
- preditor/constants.py +13 -0
- preditor/contexts.py +210 -0
- preditor/cores/__init__.py +0 -0
- preditor/cores/core.py +20 -0
- preditor/dccs/.hab.json +10 -0
- preditor/dccs/maya/PrEditor_maya.mod +1 -0
- preditor/dccs/maya/README.md +22 -0
- preditor/dccs/maya/plug-ins/PrEditor_maya.py +141 -0
- preditor/dccs/studiomax/PackageContents.xml +32 -0
- preditor/dccs/studiomax/PrEditor-PrEditor_Show.mcr +8 -0
- preditor/dccs/studiomax/README.md +17 -0
- preditor/dccs/studiomax/preditor.ms +16 -0
- preditor/dccs/studiomax/preditor_menu.mnx +7 -0
- preditor/debug.py +149 -0
- preditor/delayable_engine/__init__.py +302 -0
- preditor/delayable_engine/delayables.py +85 -0
- preditor/enum.py +728 -0
- preditor/excepthooks.py +165 -0
- preditor/gui/__init__.py +56 -0
- preditor/gui/app.py +163 -0
- preditor/gui/codehighlighter.py +289 -0
- preditor/gui/completer.py +237 -0
- preditor/gui/console.py +605 -0
- preditor/gui/console_base.py +911 -0
- preditor/gui/dialog.py +181 -0
- preditor/gui/drag_tab_bar.py +625 -0
- preditor/gui/editor_chooser.py +57 -0
- preditor/gui/errordialog.py +69 -0
- preditor/gui/find_files.py +137 -0
- preditor/gui/fuzzy_search/__init__.py +0 -0
- preditor/gui/fuzzy_search/fuzzy_search.py +97 -0
- preditor/gui/group_tab_widget/__init__.py +0 -0
- preditor/gui/group_tab_widget/group_tab_widget.py +528 -0
- preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
- preditor/gui/group_tab_widget/grouped_tab_models.py +107 -0
- preditor/gui/group_tab_widget/grouped_tab_widget.py +223 -0
- preditor/gui/group_tab_widget/one_tab_widget.py +96 -0
- preditor/gui/level_buttons.py +358 -0
- preditor/gui/logger_window_handler.py +77 -0
- preditor/gui/logger_window_plugin.py +35 -0
- preditor/gui/loggerwindow.py +2405 -0
- preditor/gui/newtabwidget.py +69 -0
- preditor/gui/output_console.py +11 -0
- preditor/gui/qtdesigner/__init__.py +21 -0
- preditor/gui/qtdesigner/_log_plugin.py +29 -0
- preditor/gui/qtdesigner/console_base_plugin.py +48 -0
- preditor/gui/qtdesigner/console_predit_plugin.py +48 -0
- preditor/gui/set_text_editor_path_dialog.py +61 -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 +1909 -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 +1139 -0
- preditor/gui/workbox_text_edit.py +136 -0
- preditor/gui/workboxwidget.py +315 -0
- preditor/logging_config.py +55 -0
- preditor/osystem.py +401 -0
- preditor/plugins.py +118 -0
- preditor/prefs.py +381 -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/pref_updates/pref_updates.json +17 -0
- preditor/resource/settings.ini +25 -0
- preditor/resource/stylesheet/Bright.css +76 -0
- preditor/resource/stylesheet/Dark.css +210 -0
- preditor/scintilla/__init__.py +40 -0
- preditor/scintilla/delayables/__init__.py +11 -0
- preditor/scintilla/delayables/smart_highlight.py +97 -0
- preditor/scintilla/delayables/spell_check.py +174 -0
- preditor/scintilla/documenteditor.py +1924 -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 +22 -0
- preditor/scintilla/lexers/javascriptlexer.py +27 -0
- preditor/scintilla/lexers/maxscriptlexer.py +235 -0
- preditor/scintilla/lexers/mellexer.py +369 -0
- preditor/scintilla/lexers/mulexer.py +33 -0
- preditor/scintilla/lexers/pythonlexer.py +42 -0
- preditor/scintilla/ui/finddialog.ui +160 -0
- preditor/settings.py +71 -0
- preditor/stream/__init__.py +72 -0
- preditor/stream/console_handler.py +169 -0
- preditor/stream/director.py +144 -0
- preditor/stream/manager.py +97 -0
- preditor/streamhandler_helper.py +46 -0
- preditor/utils/__init__.py +191 -0
- preditor/utils/call_stack.py +86 -0
- preditor/utils/cute.py +106 -0
- preditor/utils/stylesheets.py +54 -0
- preditor/utils/text_search.py +338 -0
- preditor/version.py +34 -0
- preditor/weakref.py +363 -0
- preditor-2.1.0.dist-info/METADATA +308 -0
- preditor-2.1.0.dist-info/RECORD +179 -0
- preditor-2.1.0.dist-info/WHEEL +5 -0
- preditor-2.1.0.dist-info/entry_points.txt +19 -0
- preditor-2.1.0.dist-info/licenses/LICENSE +165 -0
- preditor-2.1.0.dist-info/top_level.txt +3 -0
- tests/encodings/test_ecoding.py +33 -0
- tests/find_files/test_find_files.py +74 -0
- tests/ide/test_delayable_engine.py +171 -0
preditor/osystem.py
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides additional methods that aren't easily found in existing
|
|
3
|
+
python or Qt modules for cross-platform usage.
|
|
4
|
+
|
|
5
|
+
The osystem module provides a number of functions to make dealing with
|
|
6
|
+
paths and other platform-specific things in a more abstract platform-agnostic
|
|
7
|
+
way.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import absolute_import, print_function
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import subprocess
|
|
13
|
+
import sys
|
|
14
|
+
from builtins import str as text
|
|
15
|
+
|
|
16
|
+
import preditor
|
|
17
|
+
|
|
18
|
+
from . import settings
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def getPointerSize():
|
|
22
|
+
import struct
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
size = struct.calcsize('P')
|
|
26
|
+
except struct.error:
|
|
27
|
+
# Older installations can only query longs
|
|
28
|
+
size = struct.calcsize('l')
|
|
29
|
+
size *= 8
|
|
30
|
+
global getPointerSize
|
|
31
|
+
|
|
32
|
+
def getPointerSize():
|
|
33
|
+
return size
|
|
34
|
+
|
|
35
|
+
return size
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Get the active version of python, not a hard coded value.
|
|
39
|
+
def pythonPath(pyw=False, architecture=None):
|
|
40
|
+
if settings.OS_TYPE != 'Windows':
|
|
41
|
+
return 'python'
|
|
42
|
+
from distutils.sysconfig import get_python_inc
|
|
43
|
+
|
|
44
|
+
# Unable to pull the path from the registry just use the current python path
|
|
45
|
+
basepath = os.path.split(get_python_inc())[0]
|
|
46
|
+
# build the path to the python executable. If requested use pythonw instead of
|
|
47
|
+
# python
|
|
48
|
+
return os.path.join(basepath, 'python{w}.exe'.format(w=pyw and 'w' or ''))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def defaultLogFile(filename='preditorProtocol.log'):
|
|
52
|
+
"""Returns a default log file path often used for redirecting stdout/err to.
|
|
53
|
+
Uses the `BDEV_PATH_BLUR` environment variable as the basepath.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
filename (str, optional): filename to log to.
|
|
57
|
+
"""
|
|
58
|
+
basepath = expandvars(os.environ['BDEV_PATH_BLUR'])
|
|
59
|
+
return os.path.join(basepath, filename)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def expandvars(text, cache=None):
|
|
63
|
+
"""
|
|
64
|
+
Recursively expands the text variables, vs. the os.path.expandvars
|
|
65
|
+
method which only works at one level.
|
|
66
|
+
|
|
67
|
+
:param text: text string to expand
|
|
68
|
+
:type text: str
|
|
69
|
+
:param cache: used internally during recursion to prevent infinite loop
|
|
70
|
+
:type cache: dict
|
|
71
|
+
:rtype: str
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
# make sure we have data
|
|
75
|
+
if not text:
|
|
76
|
+
return ''
|
|
77
|
+
|
|
78
|
+
import re
|
|
79
|
+
|
|
80
|
+
# check for circular dependencies
|
|
81
|
+
if cache is None:
|
|
82
|
+
cache = {}
|
|
83
|
+
|
|
84
|
+
# return the cleaned variable
|
|
85
|
+
output = str(text)
|
|
86
|
+
keys = re.findall(r'\$(\w+)|\${(\w+)\}|\%(\w+)\%', text)
|
|
87
|
+
|
|
88
|
+
for first, second, third in keys:
|
|
89
|
+
repl = ''
|
|
90
|
+
key = ''
|
|
91
|
+
if first:
|
|
92
|
+
repl = '$%s' % first
|
|
93
|
+
key = first
|
|
94
|
+
elif second:
|
|
95
|
+
repl = '${%s}' % second
|
|
96
|
+
key = second
|
|
97
|
+
elif third:
|
|
98
|
+
repl = '%%%s%%' % third
|
|
99
|
+
key = third
|
|
100
|
+
else:
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
value = os.environ.get(key)
|
|
104
|
+
if value:
|
|
105
|
+
if key not in cache:
|
|
106
|
+
cache[key] = value
|
|
107
|
+
value = expandvars(value, cache)
|
|
108
|
+
else:
|
|
109
|
+
print(
|
|
110
|
+
'WARNING! %s environ variable contains a circular dependency' % key
|
|
111
|
+
)
|
|
112
|
+
value = cache[key]
|
|
113
|
+
else:
|
|
114
|
+
value = repl
|
|
115
|
+
|
|
116
|
+
output = output.replace(repl, value)
|
|
117
|
+
|
|
118
|
+
return output
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def explore(filename, dirFallback=False):
|
|
122
|
+
"""Launches the provided filename in the prefered editor for the specific platform.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
filename (str): The file path to explore to.
|
|
126
|
+
dirFallback (bool): If True, and the file path does not exist, explore to
|
|
127
|
+
the deepest folder that does exist.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
bool: If it was able to explore the filename.
|
|
131
|
+
"""
|
|
132
|
+
# pull the file path from the inputed filename
|
|
133
|
+
fpath = os.path.normpath(filename)
|
|
134
|
+
|
|
135
|
+
if dirFallback:
|
|
136
|
+
# If the provided filename does not exist, recursively check each parent folder
|
|
137
|
+
# for existence.
|
|
138
|
+
while not os.path.exists(fpath) and not os.path.ismount(fpath):
|
|
139
|
+
fpath = os.path.split(fpath)[0]
|
|
140
|
+
|
|
141
|
+
# run the file in windows
|
|
142
|
+
if settings.OS_TYPE == 'Windows':
|
|
143
|
+
env = subprocessEnvironment()
|
|
144
|
+
if os.path.isfile(fpath):
|
|
145
|
+
subprocess.Popen(r'explorer.exe /select, "{}"'.format(fpath), env=env)
|
|
146
|
+
return True
|
|
147
|
+
subprocess.Popen(r'explorer.exe "{}"'.format(fpath), env=env)
|
|
148
|
+
return True
|
|
149
|
+
|
|
150
|
+
# run the file in linux
|
|
151
|
+
elif settings.OS_TYPE == 'Linux':
|
|
152
|
+
cmd = expandvars(os.environ.get('BDEV_CMD_BROWSE', ''))
|
|
153
|
+
if not cmd:
|
|
154
|
+
return False
|
|
155
|
+
subprocess.Popen(cmd % {'filepath': fpath}, shell=True)
|
|
156
|
+
return True
|
|
157
|
+
return False
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def subprocessEnvironment(env=None):
|
|
161
|
+
"""Returns a copy of the environment that will restore a new python instance to
|
|
162
|
+
current state.
|
|
163
|
+
|
|
164
|
+
Provides a environment dict that can be passed to subprocess.Popen that will restore
|
|
165
|
+
the current treegrunt environment settings, and blurdev stylesheet. It also resets
|
|
166
|
+
any environment variables set by a dcc that may cause problems when running a
|
|
167
|
+
subprocess.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
|
|
171
|
+
env (dict, Optional): The base dictionary that is modified with blurdev
|
|
172
|
+
variables. if None(default) it will be populated with a copy of os.environ.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
dict: A list of environment variables to be passed to subprocess's env argument.
|
|
176
|
+
"""
|
|
177
|
+
if env is None:
|
|
178
|
+
env = os.environ.copy()
|
|
179
|
+
|
|
180
|
+
# By default libstone adds "C:\Windows\System32\blur64" or "C:\blur\common" to
|
|
181
|
+
# QApplication.libraryPaths(), setting this env var to a invalid path disables that.
|
|
182
|
+
# Leaving this set likely will cause the subprocess to not be configured correctly.
|
|
183
|
+
# The subprocess should be responsible for setting this variable
|
|
184
|
+
if 'LIBSTONE_QT_LIBRARY_PATH' in env:
|
|
185
|
+
del env['LIBSTONE_QT_LIBRARY_PATH']
|
|
186
|
+
|
|
187
|
+
# If PYTHONPATH is being used, attempt to reset it to the system value.
|
|
188
|
+
# Applications like maya add PYTHONPATH, and this breaks subprocesses.
|
|
189
|
+
if env.get('PYTHONPATH'):
|
|
190
|
+
if settings.OS_TYPE == 'Windows':
|
|
191
|
+
try:
|
|
192
|
+
# Store the 'PYTHONPATH' from the system registry if set
|
|
193
|
+
env['PYTHONPATH'] = getEnvironmentVariable('PYTHONPATH')
|
|
194
|
+
except WindowsError:
|
|
195
|
+
# If the registry is not set, then remove the variable
|
|
196
|
+
del env['PYTHONPATH']
|
|
197
|
+
|
|
198
|
+
# If PYTHONHOME is used, just remove it. This variable is supposed to point
|
|
199
|
+
# to a folder relative to the python stdlib
|
|
200
|
+
# Applications like Houdini add PYTHONHOME, and it breaks the subprocesses
|
|
201
|
+
if env.get('PYTHONHOME'):
|
|
202
|
+
if settings.OS_TYPE == 'Windows':
|
|
203
|
+
try:
|
|
204
|
+
# Store the 'PYTHONHOME' from the system registry if set
|
|
205
|
+
env['PYTHONHOME'] = getEnvironmentVariable('PYTHONHOME')
|
|
206
|
+
except WindowsError:
|
|
207
|
+
# If the registry is not set, then remove the variable
|
|
208
|
+
del env['PYTHONHOME']
|
|
209
|
+
|
|
210
|
+
# Some DCC's require inserting or appending path variables. When using subprocess
|
|
211
|
+
# these path variables may cause problems with the target application. This allows
|
|
212
|
+
# removing those path variables from the environment being passed to subprocess.
|
|
213
|
+
def normalize(i):
|
|
214
|
+
return os.path.normpath(os.path.normcase(i))
|
|
215
|
+
|
|
216
|
+
removePaths = set([normalize(x) for x in preditor.core._removeFromPATHEnv])
|
|
217
|
+
|
|
218
|
+
# blurpath records any paths it adds to the PATH variable and other env variable
|
|
219
|
+
# modifications it makes, revert these changes.
|
|
220
|
+
try:
|
|
221
|
+
import blurpath
|
|
222
|
+
|
|
223
|
+
# Restore the original environment variables stored by blurpath.
|
|
224
|
+
blurpath.resetEnvVars(env) # blurpath v0.0.16 or newer
|
|
225
|
+
except ImportError:
|
|
226
|
+
pass
|
|
227
|
+
except AttributeError:
|
|
228
|
+
# TODO: Once blurpath v0.0.16 or newer is passed out, remove the
|
|
229
|
+
# outter AttributeError except block. Its just for backwards compatibility.
|
|
230
|
+
try:
|
|
231
|
+
removePaths.update([normalize(x) for x in blurpath.addedToPathEnv])
|
|
232
|
+
except AttributeError:
|
|
233
|
+
pass
|
|
234
|
+
|
|
235
|
+
path = env.get('PATH')
|
|
236
|
+
if path:
|
|
237
|
+
paths = [
|
|
238
|
+
x for x in path.split(os.path.pathsep) if normalize(x) not in removePaths
|
|
239
|
+
]
|
|
240
|
+
path = os.path.pathsep.join(paths)
|
|
241
|
+
# subprocess does not accept unicode in python 2
|
|
242
|
+
if sys.version_info[0] == 2 and isinstance(path, text):
|
|
243
|
+
path = path.encode('utf8')
|
|
244
|
+
env['PATH'] = path
|
|
245
|
+
|
|
246
|
+
# settings.environStr does nothing in python3, so this code only needs
|
|
247
|
+
# to run in python2
|
|
248
|
+
if sys.version_info[0] < 3:
|
|
249
|
+
# subprocess explodes if it receives unicode in Python2 and in Python3,
|
|
250
|
+
# it explodes if it *doesn't* receive unicode.
|
|
251
|
+
temp = {}
|
|
252
|
+
for k, v in env.items():
|
|
253
|
+
# Attempt to remove any unicode objects. Ignore any conversion failures
|
|
254
|
+
try:
|
|
255
|
+
k = settings.environStr(k)
|
|
256
|
+
except Exception:
|
|
257
|
+
pass
|
|
258
|
+
try:
|
|
259
|
+
v = settings.environStr(v)
|
|
260
|
+
except AttributeError:
|
|
261
|
+
pass
|
|
262
|
+
temp[k] = v
|
|
263
|
+
env = temp
|
|
264
|
+
|
|
265
|
+
return env
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
# --------------------------------------------------------------------------------
|
|
269
|
+
# Read registy values
|
|
270
|
+
# --------------------------------------------------------------------------------
|
|
271
|
+
def getRegKey(registry, key, architecture=None, write=False):
|
|
272
|
+
"""Returns a winreg hkey or none.
|
|
273
|
+
|
|
274
|
+
Args: registry (str): The registry to look in. 'HKEY_LOCAL_MACHINE' for example
|
|
275
|
+
|
|
276
|
+
key (str): The key to open. r'Software\\Autodesk\\Softimage\\InstallPaths' for
|
|
277
|
+
example
|
|
278
|
+
|
|
279
|
+
architecture (int | None): 32 or 64 bit. If None use system default.
|
|
280
|
+
Defaults to None
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
A winreg handle object
|
|
284
|
+
"""
|
|
285
|
+
# Do not want to import winreg unless it is neccissary
|
|
286
|
+
regKey = None
|
|
287
|
+
import winreg
|
|
288
|
+
|
|
289
|
+
aReg = winreg.ConnectRegistry(None, getattr(winreg, registry))
|
|
290
|
+
if architecture == 32:
|
|
291
|
+
sam = winreg.KEY_WOW64_32KEY
|
|
292
|
+
elif architecture == 64:
|
|
293
|
+
sam = winreg.KEY_WOW64_64KEY
|
|
294
|
+
else:
|
|
295
|
+
sam = 0
|
|
296
|
+
access = winreg.KEY_READ
|
|
297
|
+
if write:
|
|
298
|
+
access = winreg.KEY_WRITE
|
|
299
|
+
try:
|
|
300
|
+
regKey = winreg.OpenKey(aReg, key, 0, access | sam)
|
|
301
|
+
except WindowsError:
|
|
302
|
+
pass
|
|
303
|
+
return regKey
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def registryValue(registry, key, value_name, architecture=None):
|
|
307
|
+
"""Returns the value and type of the provided registry key's value name.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
|
|
311
|
+
registry (str): The registry to look in. 'HKEY_LOCAL_MACHINE' for example
|
|
312
|
+
|
|
313
|
+
key (str): The key to open. r'Software\\Autodesk\\Softimage\\InstallPaths' for
|
|
314
|
+
example
|
|
315
|
+
|
|
316
|
+
value_name (str): The name of the value to read. To read the '(Default)' key
|
|
317
|
+
pass a empty string.
|
|
318
|
+
|
|
319
|
+
architecture (int | None): 32 or 64 bit. If None use system default.
|
|
320
|
+
Defaults to None.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
object: Value stored in key
|
|
324
|
+
int: registry type for value. See winreg's Value Types
|
|
325
|
+
"""
|
|
326
|
+
# Do not want to import winreg unless it is neccissary
|
|
327
|
+
regKey = getRegKey(registry, key, architecture=architecture)
|
|
328
|
+
if regKey:
|
|
329
|
+
import winreg
|
|
330
|
+
|
|
331
|
+
return winreg.QueryValueEx(regKey, value_name)
|
|
332
|
+
return '', 0
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def getEnvironmentRegKey(machine=False):
|
|
336
|
+
"""Get the Registry Path and Key for the environment, either of the current
|
|
337
|
+
user or the system.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
machine (bool, optional): If True, the system Environment location will
|
|
341
|
+
be returned. Otherwise, the Environment location for the current
|
|
342
|
+
user will be returned. Defaults to False.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
tuple: Returns a tuple of two strings (registry path, key).
|
|
346
|
+
"""
|
|
347
|
+
registry = 'HKEY_CURRENT_USER'
|
|
348
|
+
key = r'Environment'
|
|
349
|
+
# Replace {PATH} with the existing path variable.
|
|
350
|
+
if machine:
|
|
351
|
+
registry = 'HKEY_LOCAL_MACHINE'
|
|
352
|
+
key = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
|
|
353
|
+
return registry, key
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def getEnvironmentVariable(value_name, system=None, default=None, architecture=None):
|
|
357
|
+
"""Returns the environment variable stored in the windows registry.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
value_name (str): The name of the environment variable to get the value of.
|
|
361
|
+
system (bool or None, optional): If True, then only look in the system
|
|
362
|
+
environment variables. If False, then only look at the user
|
|
363
|
+
environment variables. If None(default), then return the user value
|
|
364
|
+
if set, otherwise return the system value.
|
|
365
|
+
default: If the variable is not set, return this value.
|
|
366
|
+
If None(default) then a WindowsError is raised.
|
|
367
|
+
architecture (int or None): 32 or 64 bit. If None use system default.
|
|
368
|
+
Defaults to None.
|
|
369
|
+
|
|
370
|
+
Raises:
|
|
371
|
+
WindowsError: [Error 2] is returned if the environment variable is not
|
|
372
|
+
stored in the requested registry. If you pass a default value other
|
|
373
|
+
than None this will not be raised.
|
|
374
|
+
"""
|
|
375
|
+
if system is None and value_name.lower() == 'path':
|
|
376
|
+
msg = "PATH is a special environment variable, set system to True or False."
|
|
377
|
+
raise ValueError(msg)
|
|
378
|
+
|
|
379
|
+
if not system:
|
|
380
|
+
# system is None or False, so check user variables.
|
|
381
|
+
registry, key = getEnvironmentRegKey(False)
|
|
382
|
+
try:
|
|
383
|
+
return registryValue(registry, key, value_name, architecture=architecture)[
|
|
384
|
+
0
|
|
385
|
+
]
|
|
386
|
+
except WindowsError:
|
|
387
|
+
pass
|
|
388
|
+
if system is False:
|
|
389
|
+
# If system is False, then return the default.
|
|
390
|
+
# If None, then check the system.
|
|
391
|
+
if default is None:
|
|
392
|
+
raise
|
|
393
|
+
return default
|
|
394
|
+
|
|
395
|
+
registry, key = getEnvironmentRegKey(True)
|
|
396
|
+
try:
|
|
397
|
+
return registryValue(registry, key, value_name, architecture=architecture)[0]
|
|
398
|
+
except WindowsError:
|
|
399
|
+
if default is None:
|
|
400
|
+
raise
|
|
401
|
+
return default
|
preditor/plugins.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from importlib_metadata import EntryPoint, entry_points
|
|
6
|
+
|
|
7
|
+
_logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Plugins(object):
|
|
11
|
+
def about_module(self):
|
|
12
|
+
plugs = {}
|
|
13
|
+
for ep in self.iterator("preditor.plug.about_module"):
|
|
14
|
+
name = ep.name
|
|
15
|
+
if name in plugs:
|
|
16
|
+
_logger.warning(
|
|
17
|
+
'Duplicate "preditor.plug.about_module" plugin found with '
|
|
18
|
+
'name "{}"'.format(name)
|
|
19
|
+
)
|
|
20
|
+
else:
|
|
21
|
+
plugs[name] = ep
|
|
22
|
+
|
|
23
|
+
# Sort the plugins alphabetically
|
|
24
|
+
for name in sorted(plugs.keys(), key=lambda i: i.lower()):
|
|
25
|
+
ep = plugs[name]
|
|
26
|
+
try:
|
|
27
|
+
result = ep.load()
|
|
28
|
+
except Exception as error:
|
|
29
|
+
result = "Error processing: {}".format(error)
|
|
30
|
+
|
|
31
|
+
yield name, result
|
|
32
|
+
|
|
33
|
+
def add_logging_handler(self, logger, handler_cls, *args, **kwargs):
|
|
34
|
+
"""Add a logging handler to a logger if not already installed.
|
|
35
|
+
|
|
36
|
+
Checks for an existing handler on logger for the specific class(does not
|
|
37
|
+
use isinstance). If not then it will create an instance of the handler
|
|
38
|
+
and add it to the logger.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
logger (logging.RootLogger): The logger instance to add the handler.
|
|
42
|
+
handler_cls (logging.Handler or str): If a string is passed it will
|
|
43
|
+
use `self.logging_handlers` to get the class. If not found then
|
|
44
|
+
exits with success marked as False. Other values are treated as
|
|
45
|
+
the handler class to add to the logger.
|
|
46
|
+
*args: Passed to the handler_cls if a new instance is created.
|
|
47
|
+
**kargs: Passed to the handler_cls if a new instance is created.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
logging.Handler or None: The handler instance that was added, already
|
|
51
|
+
has been added, or None if the handler name isn't a valid plugin.
|
|
52
|
+
bool: True only if the handler_cls was not already added to this logger.
|
|
53
|
+
"""
|
|
54
|
+
if isinstance(handler_cls, str):
|
|
55
|
+
handlers = dict(self.logging_handlers(handler_cls))
|
|
56
|
+
if not handlers:
|
|
57
|
+
# No handler to add for this name
|
|
58
|
+
return None, False
|
|
59
|
+
handler_cls = handlers[handler_cls]
|
|
60
|
+
|
|
61
|
+
# Attempt to find an existing handler instance and return it
|
|
62
|
+
for h in logger.handlers:
|
|
63
|
+
if type(h) is handler_cls:
|
|
64
|
+
return h, False
|
|
65
|
+
|
|
66
|
+
# No handler installed create and install it
|
|
67
|
+
handler = handler_cls(*args, **kwargs)
|
|
68
|
+
logger.addHandler(handler)
|
|
69
|
+
return handler, True
|
|
70
|
+
|
|
71
|
+
def editor(self, name):
|
|
72
|
+
for plug_name, ep in self.editors(name):
|
|
73
|
+
return plug_name, ep.load()
|
|
74
|
+
return None, None
|
|
75
|
+
|
|
76
|
+
def editors(self, name=None):
|
|
77
|
+
for ep in self.iterator(group="preditor.plug.editors"):
|
|
78
|
+
if name and ep.name != name:
|
|
79
|
+
continue
|
|
80
|
+
yield ep.name, ep
|
|
81
|
+
|
|
82
|
+
def initialize(self, name=None):
|
|
83
|
+
for ep in self.iterator(group="preditor.plug.initialize"):
|
|
84
|
+
yield ep.load()
|
|
85
|
+
|
|
86
|
+
def loggerwindow(self, name=None):
|
|
87
|
+
"""Returns instances of "preditor.plug.loggerwindow" plugins.
|
|
88
|
+
|
|
89
|
+
These plugins are used by the LoggerWindow to extend its interface. For
|
|
90
|
+
example it can be used to add a toolbar or update the menus.
|
|
91
|
+
|
|
92
|
+
When using this plugin, make sure the returned class is a subclass of
|
|
93
|
+
`preditor.gui.logger_window_plugin.LoggerWindowPlugin`.
|
|
94
|
+
"""
|
|
95
|
+
for ep in self.iterator(group="preditor.plug.loggerwindow"):
|
|
96
|
+
if name and ep.name != name:
|
|
97
|
+
continue
|
|
98
|
+
yield ep.name, ep.load()
|
|
99
|
+
|
|
100
|
+
def logging_handlers(self, name=None):
|
|
101
|
+
for ep in self.iterator(group="preditor.plug.logging_handlers"):
|
|
102
|
+
yield ep.name, ep.load()
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
def iterator(cls, group=None, name=None):
|
|
106
|
+
"""Iterates over the requested entry point yielding results."""
|
|
107
|
+
for ep in entry_points().select(group=group):
|
|
108
|
+
yield ep
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def from_string(cls, value, name="", group=""):
|
|
112
|
+
"""Resolve an EntryPoint string into its object.
|
|
113
|
+
|
|
114
|
+
Example:
|
|
115
|
+
cls = from_string("preditor.gui.errordialog:ErrorDialog")
|
|
116
|
+
"""
|
|
117
|
+
ep = EntryPoint(name=name, value=value, group=group)
|
|
118
|
+
return ep.load()
|