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.

Files changed (158) hide show
  1. preditor/__init__.py +322 -0
  2. preditor/__main__.py +13 -0
  3. preditor/about_module.py +161 -0
  4. preditor/cli.py +192 -0
  5. preditor/config.py +302 -0
  6. preditor/contexts.py +119 -0
  7. preditor/cores/__init__.py +0 -0
  8. preditor/cores/core.py +20 -0
  9. preditor/dccs/maya/PrEditor_maya.mod +2 -0
  10. preditor/dccs/maya/plug-ins/PrEditor_maya.py +110 -0
  11. preditor/debug.py +144 -0
  12. preditor/delayable_engine/__init__.py +302 -0
  13. preditor/delayable_engine/delayables.py +85 -0
  14. preditor/enum.py +728 -0
  15. preditor/excepthooks.py +131 -0
  16. preditor/gui/__init__.py +93 -0
  17. preditor/gui/app.py +160 -0
  18. preditor/gui/codehighlighter.py +209 -0
  19. preditor/gui/completer.py +226 -0
  20. preditor/gui/console.py +867 -0
  21. preditor/gui/dialog.py +178 -0
  22. preditor/gui/drag_tab_bar.py +190 -0
  23. preditor/gui/editor_chooser.py +57 -0
  24. preditor/gui/errordialog.py +68 -0
  25. preditor/gui/find_files.py +125 -0
  26. preditor/gui/fuzzy_search/__init__.py +0 -0
  27. preditor/gui/fuzzy_search/fuzzy_search.py +93 -0
  28. preditor/gui/group_tab_widget/__init__.py +325 -0
  29. preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
  30. preditor/gui/group_tab_widget/grouped_tab_models.py +108 -0
  31. preditor/gui/group_tab_widget/grouped_tab_widget.py +78 -0
  32. preditor/gui/group_tab_widget/one_tab_widget.py +54 -0
  33. preditor/gui/level_buttons.py +343 -0
  34. preditor/gui/logger_window_handler.py +48 -0
  35. preditor/gui/logger_window_plugin.py +32 -0
  36. preditor/gui/loggerwindow.py +1385 -0
  37. preditor/gui/newtabwidget.py +69 -0
  38. preditor/gui/set_text_editor_path_dialog.py +59 -0
  39. preditor/gui/status_label.py +99 -0
  40. preditor/gui/suggest_path_quotes_dialog.py +50 -0
  41. preditor/gui/ui/editor_chooser.ui +93 -0
  42. preditor/gui/ui/errordialog.ui +74 -0
  43. preditor/gui/ui/find_files.ui +140 -0
  44. preditor/gui/ui/loggerwindow.ui +1105 -0
  45. preditor/gui/ui/set_text_editor_path_dialog.ui +189 -0
  46. preditor/gui/ui/suggest_path_quotes_dialog.ui +225 -0
  47. preditor/gui/window.py +161 -0
  48. preditor/gui/workbox_mixin.py +389 -0
  49. preditor/gui/workbox_text_edit.py +137 -0
  50. preditor/gui/workboxwidget.py +298 -0
  51. preditor/logging_config.py +52 -0
  52. preditor/osystem.py +401 -0
  53. preditor/plugins.py +118 -0
  54. preditor/prefs.py +74 -0
  55. preditor/resource/environment_variables.html +26 -0
  56. preditor/resource/error_mail.html +85 -0
  57. preditor/resource/error_mail_inline.html +41 -0
  58. preditor/resource/img/README.md +17 -0
  59. preditor/resource/img/arrow_forward.png +0 -0
  60. preditor/resource/img/check-bold.png +0 -0
  61. preditor/resource/img/chevron-down.png +0 -0
  62. preditor/resource/img/chevron-up.png +0 -0
  63. preditor/resource/img/close-thick.png +0 -0
  64. preditor/resource/img/comment-edit.png +0 -0
  65. preditor/resource/img/content-copy.png +0 -0
  66. preditor/resource/img/content-cut.png +0 -0
  67. preditor/resource/img/content-duplicate.png +0 -0
  68. preditor/resource/img/content-paste.png +0 -0
  69. preditor/resource/img/content-save.png +0 -0
  70. preditor/resource/img/debug_disabled.png +0 -0
  71. preditor/resource/img/eye-check.png +0 -0
  72. preditor/resource/img/file-plus.png +0 -0
  73. preditor/resource/img/file-remove.png +0 -0
  74. preditor/resource/img/format-align-left.png +0 -0
  75. preditor/resource/img/format-letter-case-lower.png +0 -0
  76. preditor/resource/img/format-letter-case-upper.png +0 -0
  77. preditor/resource/img/format-letter-case.svg +1 -0
  78. preditor/resource/img/information.png +0 -0
  79. preditor/resource/img/logging_critical.png +0 -0
  80. preditor/resource/img/logging_custom.png +0 -0
  81. preditor/resource/img/logging_debug.png +0 -0
  82. preditor/resource/img/logging_error.png +0 -0
  83. preditor/resource/img/logging_info.png +0 -0
  84. preditor/resource/img/logging_not_set.png +0 -0
  85. preditor/resource/img/logging_warning.png +0 -0
  86. preditor/resource/img/marker.png +0 -0
  87. preditor/resource/img/play.png +0 -0
  88. preditor/resource/img/playlist-play.png +0 -0
  89. preditor/resource/img/plus-minus-variant.png +0 -0
  90. preditor/resource/img/preditor.ico +0 -0
  91. preditor/resource/img/preditor.png +0 -0
  92. preditor/resource/img/preditor.psd +0 -0
  93. preditor/resource/img/preditor.svg +44 -0
  94. preditor/resource/img/regex.svg +1 -0
  95. preditor/resource/img/restart.svg +1 -0
  96. preditor/resource/img/skip-forward-outline.png +0 -0
  97. preditor/resource/img/skip-next-outline.png +0 -0
  98. preditor/resource/img/skip-next.png +0 -0
  99. preditor/resource/img/skip-previous.png +0 -0
  100. preditor/resource/img/subdirectory-arrow-right.png +0 -0
  101. preditor/resource/img/text-search-variant.png +0 -0
  102. preditor/resource/img/warning-big.png +0 -0
  103. preditor/resource/lang/python.json +30 -0
  104. preditor/resource/settings.ini +25 -0
  105. preditor/resource/stylesheet/Bright.css +65 -0
  106. preditor/resource/stylesheet/Dark.css +199 -0
  107. preditor/scintilla/__init__.py +22 -0
  108. preditor/scintilla/delayables/__init__.py +11 -0
  109. preditor/scintilla/delayables/smart_highlight.py +94 -0
  110. preditor/scintilla/delayables/spell_check.py +173 -0
  111. preditor/scintilla/documenteditor.py +2038 -0
  112. preditor/scintilla/finddialog.py +68 -0
  113. preditor/scintilla/lang/__init__.py +80 -0
  114. preditor/scintilla/lang/config/bash.ini +15 -0
  115. preditor/scintilla/lang/config/batch.ini +14 -0
  116. preditor/scintilla/lang/config/cpp.ini +19 -0
  117. preditor/scintilla/lang/config/css.ini +19 -0
  118. preditor/scintilla/lang/config/eyeonscript.ini +17 -0
  119. preditor/scintilla/lang/config/html.ini +21 -0
  120. preditor/scintilla/lang/config/javascript.ini +24 -0
  121. preditor/scintilla/lang/config/lua.ini +16 -0
  122. preditor/scintilla/lang/config/maxscript.ini +20 -0
  123. preditor/scintilla/lang/config/mel.ini +18 -0
  124. preditor/scintilla/lang/config/mu.ini +22 -0
  125. preditor/scintilla/lang/config/nsi.ini +19 -0
  126. preditor/scintilla/lang/config/perl.ini +19 -0
  127. preditor/scintilla/lang/config/puppet.ini +19 -0
  128. preditor/scintilla/lang/config/python.ini +28 -0
  129. preditor/scintilla/lang/config/ruby.ini +19 -0
  130. preditor/scintilla/lang/config/sql.ini +7 -0
  131. preditor/scintilla/lang/config/xml.ini +21 -0
  132. preditor/scintilla/lang/config/yaml.ini +18 -0
  133. preditor/scintilla/lang/language.py +240 -0
  134. preditor/scintilla/lexers/__init__.py +0 -0
  135. preditor/scintilla/lexers/cpplexer.py +21 -0
  136. preditor/scintilla/lexers/javascriptlexer.py +25 -0
  137. preditor/scintilla/lexers/maxscriptlexer.py +234 -0
  138. preditor/scintilla/lexers/mellexer.py +368 -0
  139. preditor/scintilla/lexers/mulexer.py +32 -0
  140. preditor/scintilla/lexers/pythonlexer.py +41 -0
  141. preditor/scintilla/ui/finddialog.ui +160 -0
  142. preditor/settings.py +71 -0
  143. preditor/stream/__init__.py +80 -0
  144. preditor/stream/director.py +73 -0
  145. preditor/stream/manager.py +74 -0
  146. preditor/streamhandler_helper.py +46 -0
  147. preditor/utils/__init__.py +0 -0
  148. preditor/utils/cute.py +30 -0
  149. preditor/utils/stylesheets.py +54 -0
  150. preditor/utils/text_search.py +342 -0
  151. preditor/version.py +21 -0
  152. preditor/weakref.py +363 -0
  153. preditor-1.0.0.dist-info/METADATA +224 -0
  154. preditor-1.0.0.dist-info/RECORD +158 -0
  155. preditor-1.0.0.dist-info/WHEEL +5 -0
  156. preditor-1.0.0.dist-info/entry_points.txt +18 -0
  157. preditor-1.0.0.dist-info/licenses/LICENSE +165 -0
  158. 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>