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
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()
|
preditor/prefs.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for handling user interface preferences
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
from __future__ import absolute_import
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
# cache of all the preferences
|
|
11
|
+
_cache = {}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def backup():
|
|
15
|
+
"""Saves a copy of the current preferences to a zip archive."""
|
|
16
|
+
import glob
|
|
17
|
+
import shutil
|
|
18
|
+
|
|
19
|
+
archive_base = "preditor_backup_"
|
|
20
|
+
# Save all prefs not just the current core_name.
|
|
21
|
+
prefs = prefs_path()
|
|
22
|
+
# Note: Using parent dir of prefs so we can use shutil.make_archive without
|
|
23
|
+
# backing up the previous backups.
|
|
24
|
+
parent_dir = os.path.join(os.path.dirname(prefs), "_backups")
|
|
25
|
+
|
|
26
|
+
# Get the next backup version number to use.
|
|
27
|
+
filenames = glob.glob(os.path.join(parent_dir, "{}*.zip".format(archive_base)))
|
|
28
|
+
version = 1
|
|
29
|
+
if filenames:
|
|
30
|
+
# Add one to the largest version that exists on disk.
|
|
31
|
+
version = int(os.path.splitext(max(filenames))[0].split(archive_base)[-1])
|
|
32
|
+
version += 1
|
|
33
|
+
|
|
34
|
+
# Build the file path to save the archive to.
|
|
35
|
+
archive_base = os.path.join(parent_dir, archive_base + "{:04}".format(version))
|
|
36
|
+
|
|
37
|
+
# Save the preferences to the given archive name.
|
|
38
|
+
zip_path = shutil.make_archive(archive_base, "zip", prefs)
|
|
39
|
+
|
|
40
|
+
return zip_path
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def browse(core_name):
|
|
44
|
+
from . import osystem
|
|
45
|
+
|
|
46
|
+
path = prefs_path(core_name)
|
|
47
|
+
osystem.explore(path)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def existing():
|
|
51
|
+
"""Returns a list of PrEditor preference path names that exist on disk."""
|
|
52
|
+
root = prefs_path()
|
|
53
|
+
return sorted(next(os.walk(root))[1], key=lambda i: i.lower())
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def prefs_path(filename=None, core_name=None):
|
|
57
|
+
"""The path PrEditor's preferences are saved as a json file.
|
|
58
|
+
|
|
59
|
+
The enviroment variable `PREDITOR_PREF_PATH` is used if set, otherwise
|
|
60
|
+
it is saved in one of the user folders.
|
|
61
|
+
"""
|
|
62
|
+
if "PREDITOR_PREF_PATH" in os.environ:
|
|
63
|
+
ret = os.environ["PREDITOR_PREF_PATH"]
|
|
64
|
+
else:
|
|
65
|
+
if sys.platform == "win32":
|
|
66
|
+
ret = "%appdata%/blur/preditor"
|
|
67
|
+
else:
|
|
68
|
+
ret = "$HOME/.blur/preditor"
|
|
69
|
+
ret = os.path.normpath(os.path.expandvars(os.path.expanduser(ret)))
|
|
70
|
+
if core_name:
|
|
71
|
+
ret = os.path.join(ret, core_name)
|
|
72
|
+
if filename:
|
|
73
|
+
ret = os.path.join(ret, filename)
|
|
74
|
+
return ret
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head/>
|
|
3
|
+
<body>
|
|
4
|
+
<h1>blurdev</h1>
|
|
5
|
+
<hr>
|
|
6
|
+
<h2>blurdev Site variables:</h2>
|
|
7
|
+
<p><span style=" font-style:italic;">These variables should be defined at a user or system level to configure blurdev.</span></p>
|
|
8
|
+
<p><span style=" font-weight:bold;">BDEV_DESIGNERPLUG_*:</span> Used to add a collection of designer plugins to QDesigner. Should be set to "XMLPATH,MODULE_DIR". XMLPATH is the full path to a xml file listing plugins to load. MODULE_DIR is a path that needs added to sys.path so the modules in XMLPATH are importable. You can use environment variables in these strings, they will be expanded. This is used by QDesigner, nothing else.</p>
|
|
9
|
+
<p><span style=" font-weight:bold;">BDEV_OFFLINE:</span> If set to 1, this indicates that blurdev is not running on the "Blur" network. This causes the [* Offline] section of blurdev/resource/settings.ini to override the [Default] and [*] sections. When blurdev is imported it adds all env vars defined in settings.ini for the current operating system and Default if they are not already defined in os.environ.</p>
|
|
10
|
+
<p><span style=" font-weight:bold;">BDEV_PATH_PREFS:</span> This environment variable points to where per-computer user prefs are stored.</p>
|
|
11
|
+
<p><span style=" font-weight:bold;">BDEV_PATH_PREFS_SHARED:</span> This environment variable points to where shared user prefs are stored. This is often on the network and includes the os's logged in username in the path. If BDEV_OFFLINE is set to 1 this may point to the BDEV_PATH_PREFS location.</p>
|
|
12
|
+
<p></p>
|
|
13
|
+
<h2>blurdev Temp variables:</h2>
|
|
14
|
+
<p><span style=" font-style:italic;">These variables should not be defined all the time.</span></p>
|
|
15
|
+
<p><span style=" font-weight:bold;">BDEV_DISABLE_AUTORUN:</span> Set to "true" to disable the autorun.bat script used at blur. If this is not set when Maya shuts down, maya takes minutes to close. Maya uses several subprocess calls when closing and for some reason the doskey calls in the script take much longer than normal.</p>
|
|
16
|
+
<p><span style=" font-weight:bold;">BDEV_STYLESHEET:</span> Used to override the stylesheet when initalizing blurdev.</p>
|
|
17
|
+
<p><span style=" font-weight:bold;">BDEV_TOOL_ENVIRONMENT:</span> Forces blurdev to initialize with this treegrunt environment name. When saving prefs, this environment name change will not be saved. This is mostly used to ensure that launching a subprocess or farm job happens on the same treegrunt environment.</p>
|
|
18
|
+
<p></p>
|
|
19
|
+
<h1>trax</h1>
|
|
20
|
+
<hr>
|
|
21
|
+
<p><span style=" font-weight:bold;">TRAX_SPOOL_DIRECTORY_OVERRIDE:</span> If defined, all messages will be stored the directory of this variable. Each message filename will have a "[mapping.mount()]_" prefix added giving you a hint to which server it would have ended up on. Defining this variable effectively disables all spool messages, and gives you a way to see what each spool message would look like. If your code depends on trax.api.spool.waitForCompletion, it will never complete.</p>
|
|
22
|
+
<h1>Notes</h1>
|
|
23
|
+
<hr>
|
|
24
|
+
<p>Any variable names containing a * are wildcards. This allows you to add as many instances of that environment variable type as needed.</p>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|