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/weakref.py ADDED
@@ -0,0 +1,363 @@
1
+ # coding: utf-8
2
+ # /*##########################################################################
3
+ #
4
+ # Copyright (c) 2016-2018 European Synchrotron Radiation Facility
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #
24
+ # ###########################################################################*/
25
+ # Code pulled from the silx codebase
26
+ # https://github.com/silx-kit/silx/blob/master/src/silx/utils/weakref.py
27
+ """Weakref utils for compatibility between Python 2 and Python 3 or for
28
+ extended features.
29
+ """
30
+ from __future__ import absolute_import
31
+
32
+ __authors__ = ["V. Valls"]
33
+ __license__ = "MIT"
34
+ __date__ = "15/09/2016"
35
+
36
+
37
+ import inspect
38
+ import types
39
+ import weakref
40
+
41
+
42
+ def ref(object, callback=None):
43
+ """Returns a weak reference to object. The original object can be retrieved
44
+ by calling the reference object if the referent is still alive. If the
45
+ referent is no longer alive, calling the reference object will cause None
46
+ to be returned.
47
+
48
+ The signature is the same as the standard `weakref` library, but it returns
49
+ `WeakMethod` if the object is a bound method.
50
+
51
+ :param object: An object
52
+ :param func callback: If provided, and the returned weakref object is
53
+ still alive, the callback will be called when the object is about to
54
+ be finalized. The weak reference object will be passed as the only
55
+ parameter to the callback. Then the referent will no longer be
56
+ available.
57
+ :return: A weak reference to the object
58
+ """
59
+ if inspect.ismethod(object):
60
+ return WeakMethod(object, callback)
61
+ else:
62
+ return weakref.ref(object, callback)
63
+
64
+
65
+ def proxy(object, callback=None):
66
+ """Return a proxy to object which uses a weak reference. This supports use
67
+ of the proxy in most contexts instead of requiring the explicit
68
+ dereferencing used with weak reference objects.
69
+
70
+ The signature is the same as the standard `weakref` library, but it returns
71
+ `WeakMethodProxy` if the object is a bound method.
72
+
73
+ :param object: An object
74
+ :param func callback: If provided, and the returned weakref object is
75
+ still alive, the callback will be called when the object is about to
76
+ be finalized. The weak reference object will be passed as the only
77
+ parameter to the callback. Then the referent will no longer be
78
+ available.
79
+ :return: A proxy to a weak reference of the object
80
+ """
81
+ if inspect.ismethod(object):
82
+ return WeakMethodProxy(object, callback)
83
+ else:
84
+ return weakref.proxy(object, callback)
85
+
86
+
87
+ class WeakMethod(object):
88
+ """Wraps a callable object like a function or a bound method.
89
+ Feature callback when the object is about to be finalized.
90
+ Provids the same interface as a normal weak reference.
91
+ """
92
+
93
+ def __init__(self, function, callback=None):
94
+ """
95
+ Constructor
96
+ :param function: Function/method to be called
97
+ :param callback: If callback is provided and not None,
98
+ and the returned weakref object is still alive, the
99
+ callback will be called when the object is about to
100
+ be finalized; the weak reference object will be passed
101
+ as the only parameter to the callback; the referent will
102
+ no longer be available
103
+ """
104
+ self.__callback = callback
105
+
106
+ if inspect.ismethod(function):
107
+ # it is a bound method
108
+ self.__obj = weakref.ref(function.__self__, self.__call_callback)
109
+ self.__method = weakref.ref(function.__func__, self.__call_callback)
110
+ else:
111
+ self.__obj = None
112
+ self.__method = weakref.ref(function, self.__call_callback)
113
+
114
+ def __call_callback(self, ref):
115
+ """Called when the object is about to be finalized"""
116
+ if not self.is_alive():
117
+ return
118
+ self.__obj = None
119
+ self.__method = None
120
+ if self.__callback is not None:
121
+ self.__callback(self)
122
+
123
+ def __call__(self):
124
+ """Return a callable function or None if the WeakMethod is dead."""
125
+ if self.__obj is not None:
126
+ method = self.__method()
127
+ obj = self.__obj()
128
+ if method is None or obj is None:
129
+ return None
130
+ return types.MethodType(method, obj)
131
+ elif self.__method is not None:
132
+ return self.__method()
133
+ else:
134
+ return None
135
+
136
+ def is_alive(self):
137
+ """True if the WeakMethod is still alive"""
138
+ return self.__method is not None
139
+
140
+ def __eq__(self, other):
141
+ """Check it another obect is equal to this.
142
+
143
+ :param object other: Object to compare with
144
+ """
145
+ if isinstance(other, WeakMethod):
146
+ if not self.is_alive():
147
+ return False
148
+ return self.__obj == other.__obj and self.__method == other.__method
149
+ return False
150
+
151
+ def __ne__(self, other):
152
+ """Check it another obect is not equal to this.
153
+
154
+ :param object other: Object to compare with
155
+ """
156
+ if isinstance(other, WeakMethod):
157
+ if not self.is_alive():
158
+ return False
159
+ return self.__obj != other.__obj or self.__method != other.__method
160
+ return True
161
+
162
+ def __hash__(self):
163
+ """Returns the hash for the object."""
164
+ return self.__obj.__hash__() ^ self.__method.__hash__()
165
+
166
+
167
+ class WeakMethodProxy(WeakMethod):
168
+ """Wraps a callable object like a function or a bound method
169
+ with a weakref proxy.
170
+ """
171
+
172
+ def __call__(self, *args, **kwargs):
173
+ """Dereference the method and call it if the method is still alive.
174
+ Else raises an ReferenceError.
175
+
176
+ :raises: ReferenceError, if the method is not alive
177
+ """
178
+ fn = super(WeakMethodProxy, self).__call__()
179
+ if fn is None:
180
+ raise ReferenceError("weakly-referenced object no longer exists")
181
+ return fn(*args, **kwargs)
182
+
183
+
184
+ class WeakList(list):
185
+ """Manage a list of weaked references.
186
+ When an object is dead, the list is flaged as invalid.
187
+ If expected the list is cleaned up to remove dead objects.
188
+ """
189
+
190
+ def __init__(self, enumerator=()):
191
+ """Create a WeakList
192
+
193
+ :param iterator enumerator: A list of object to initialize the
194
+ list
195
+ """
196
+ list.__init__(self)
197
+ self.__list = []
198
+ self.__is_valid = True
199
+ for obj in enumerator:
200
+ self.append(obj)
201
+
202
+ def __invalidate(self, ref):
203
+ """Flag the list as invalidated. The list contains dead references."""
204
+ self.__is_valid = False
205
+
206
+ def __create_ref(self, obj):
207
+ """Create a weakref from an object. It uses the `ref` module function."""
208
+ return ref(obj, self.__invalidate)
209
+
210
+ def __clean(self):
211
+ """Clean the list from dead references"""
212
+ if self.__is_valid:
213
+ return
214
+ self.__list = [ref for ref in self.__list if ref() is not None]
215
+ self.__is_valid = True
216
+
217
+ def __iter__(self):
218
+ """Iterate over objects of the list"""
219
+ for ref in self.__list:
220
+ obj = ref()
221
+ if obj is not None:
222
+ yield obj
223
+
224
+ def __len__(self):
225
+ """Count item on the list"""
226
+ self.__clean()
227
+ return len(self.__list)
228
+
229
+ def __getitem__(self, key):
230
+ """Returns the object at the requested index
231
+
232
+ :param key: Indexes to get
233
+ :type key: int or slice
234
+ """
235
+ self.__clean()
236
+ data = self.__list[key]
237
+ if isinstance(data, list):
238
+ result = [ref() for ref in data]
239
+ else:
240
+ result = data()
241
+ return result
242
+
243
+ def __setitem__(self, key, obj):
244
+ """Set an item at an index
245
+
246
+ :param key: Indexes to set
247
+ :type key: int or slice
248
+ """
249
+ self.__clean()
250
+ if isinstance(key, slice):
251
+ objs = [self.__create_ref(o) for o in obj]
252
+ self.__list[key] = objs
253
+ else:
254
+ obj_ref = self.__create_ref(obj)
255
+ self.__list[key] = obj_ref
256
+
257
+ def __delitem__(self, key):
258
+ """Delete an Indexes item of this list
259
+
260
+ :param key: Index to delete
261
+ :type key: int or slice
262
+ """
263
+ self.__clean()
264
+ del self.__list[key]
265
+
266
+ def __delslice__(self, i, j):
267
+ """Looks to be used in Python 2.7"""
268
+ self.__delitem__(slice(i, j, None))
269
+
270
+ def __setslice__(self, i, j, sequence):
271
+ """Looks to be used in Python 2.7"""
272
+ self.__setitem__(slice(i, j, None), sequence)
273
+
274
+ def __getslice__(self, i, j):
275
+ """Looks to be used in Python 2.7"""
276
+ return self.__getitem__(slice(i, j, None))
277
+
278
+ def __reversed__(self):
279
+ """Returns a copy of the reverted list"""
280
+ reversed_list = reversed(list(self))
281
+ return WeakList(reversed_list)
282
+
283
+ def __contains__(self, obj):
284
+ """Returns true if the object is in the list"""
285
+ ref = self.__create_ref(obj)
286
+ return ref in self.__list
287
+
288
+ def __add__(self, other):
289
+ """Returns a WeakList containing this list an the other"""
290
+ l = WeakList(self) # noqa: E741
291
+ l.extend(other)
292
+ return l
293
+
294
+ def __iadd__(self, other):
295
+ """Add objects to this list inplace"""
296
+ self.extend(other)
297
+ return self
298
+
299
+ def __mul__(self, n):
300
+ """Returns a WeakList containing n-duplication object of this list"""
301
+ return WeakList(list(self) * n)
302
+
303
+ def __imul__(self, n):
304
+ """N-duplication of the objects to this list inplace"""
305
+ self.__list *= n
306
+ return self
307
+
308
+ def append(self, obj):
309
+ """Add an object at the end of the list"""
310
+ ref = self.__create_ref(obj)
311
+ self.__list.append(ref)
312
+
313
+ def count(self, obj):
314
+ """Returns the number of occurencies of an object"""
315
+ ref = self.__create_ref(obj)
316
+ return self.__list.count(ref)
317
+
318
+ def extend(self, other):
319
+ """Append the list with all objects from another list"""
320
+ for obj in other:
321
+ self.append(obj)
322
+
323
+ def index(self, obj):
324
+ """Returns the index of an object"""
325
+ ref = self.__create_ref(obj)
326
+ return self.__list.index(ref)
327
+
328
+ def insert(self, index, obj):
329
+ """Insert an object at the requested index"""
330
+ ref = self.__create_ref(obj)
331
+ self.__list.insert(index, ref)
332
+
333
+ def pop(self, index=-1):
334
+ """Remove and return an object at the requested index"""
335
+ self.__clean()
336
+ obj = self.__list.pop(index)()
337
+ return obj
338
+
339
+ def remove(self, obj):
340
+ """Remove an object from the list"""
341
+ ref = self.__create_ref(obj)
342
+ self.__list.remove(ref)
343
+
344
+ def reverse(self):
345
+ """Reverse the list inplace"""
346
+ self.__list.reverse()
347
+
348
+ def sort(self, key=None, reverse=False):
349
+ """Sort the list inplace.
350
+ Not very efficient.
351
+ """
352
+ sorted_list = list(self)
353
+ sorted_list.sort(key=key, reverse=reverse)
354
+ self.__list = []
355
+ self.extend(sorted_list)
356
+
357
+ def __str__(self):
358
+ unref_list = list(self)
359
+ return "WeakList(%s)" % str(unref_list)
360
+
361
+ def __repr__(self):
362
+ unref_list = list(self)
363
+ return "WeakList(%s)" % repr(unref_list)
@@ -0,0 +1,224 @@
1
+ Metadata-Version: 2.4
2
+ Name: PrEditor
3
+ Version: 1.0.0
4
+ Summary: A python REPL and Editor and console based on Qt.
5
+ Author-email: Blur Studio <opensource@blur.com>
6
+ License: LGPL-3.0
7
+ Project-URL: Homepage, https://github.com/blurstudio/PrEditor
8
+ Project-URL: Source, https://github.com/blurstudio/PrEditor
9
+ Project-URL: Tracker, https://github.com/blurstudio/PrEditor/issues
10
+ Platform: any
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: Implementation :: CPython
18
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
19
+ Requires-Python: >=3.7
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: Qt.py
23
+ Requires-Dist: configparser>=4.0.2
24
+ Requires-Dist: future>=0.18.2
25
+ Requires-Dist: signalslot>=0.1.2
26
+ Requires-Dist: importlib-metadata>=4.8.3
27
+ Provides-Extra: cli
28
+ Requires-Dist: click>=7.1.2; extra == "cli"
29
+ Requires-Dist: click-default-group; extra == "cli"
30
+ Provides-Extra: dev
31
+ Requires-Dist: black; extra == "dev"
32
+ Requires-Dist: build; extra == "dev"
33
+ Requires-Dist: covdefaults; extra == "dev"
34
+ Requires-Dist: coverage; extra == "dev"
35
+ Requires-Dist: flake8; extra == "dev"
36
+ Requires-Dist: flake8-bugbear; extra == "dev"
37
+ Requires-Dist: Flake8-pyproject; extra == "dev"
38
+ Requires-Dist: pep8-naming; extra == "dev"
39
+ Requires-Dist: pytest; extra == "dev"
40
+ Requires-Dist: tox; extra == "dev"
41
+ Provides-Extra: shortcut
42
+ Requires-Dist: casement>=0.1.0; platform_system == "Windows" and extra == "shortcut"
43
+ Dynamic: license-file
44
+
45
+ # PrEditor
46
+
47
+ A python REPL, editor and console based on Qt. It allows you to interact
48
+ directly with the current python session and write/run complex code in workbox's.
49
+ It also has an interface for configuring python logging.
50
+
51
+ # Use and Features
52
+
53
+ ![preview](https://github.com/blurstudio/PrEditor/assets/2424292/5425aa5f-0f9b-4b04-8e98-5a58546eb93c)
54
+
55
+ * **Console:** The top section is a python REPL allowing you to run code like you
56
+ are in the python interactive shell. However, you can't use code
57
+ blocks([...](https://docs.python.org/3/glossary.html#term-...)), use the workbox instead.
58
+ * Python's stdout and stderr are written here including exceptions.
59
+ * If the cursor is at the very end of the last line, and that line starts with
60
+ a prompt (`>>> ` this includes 1 space) the code is executed when you press return.
61
+ Pressing return on any other prompt line copies that line to the end ready to
62
+ execute.
63
+ * Pressing `Ctrl + Up/Down` will cycle through previous command history.
64
+ * The console is a text edit and you can edit any of the text so you can fix
65
+ your mistakes as you make them
66
+ * **Workbox:** The workbox is a place to write complex multi-line code. The contents
67
+ of all workboxes are saved when PrEditor is closed or pressing `Ctrl + S`.
68
+ * Workboxes are grouped into tabs of workboxes. You can drag and drop
69
+ individual workboxes between groups and re-order them.
70
+ * `Ctrl + Return` runs all code inside of the current workbox.
71
+ * `Shift + Return` or the `Number-pad Return` executes the selected text or
72
+ the line the cursor is on.
73
+ * `run_workbox("group/tab")` This command is added allowing you to run the
74
+ contents of a workbox. Pass the name of the group and workbox tabs separated
75
+ by a forward slash.
76
+ * **Logging Level button:** Tools for managing python loggers.
77
+ * This button shows all known python loggers and lets you view/change their
78
+ logging levels.
79
+ * You can install logging handlers that have had PrEditor plugins written for them.
80
+ * Known python logger levels are saved and restored.
81
+ * All code is run in `__main__`. In code you can add objects to it for inspection in PrEditor.
82
+ * `Ctrl + Shift + PgUp/PgDown` changes focus between the console and workbox.
83
+ * `Ctrl + Alt + Shift + PgUp/PgDown` changes focus and copies the current prompt
84
+ line of the console, or the current line of the workbox to the other.
85
+
86
+
87
+ # Examples
88
+
89
+ See [examples](examples) for more complete examples of using PrEditor.
90
+
91
+ For simple standalone applications that only exist for the life of the main window
92
+ you can simply call `connect_preditor` in your class `__init__` and optionally add
93
+ the created QAction into your GUI's menu. All `sys.stdout` and `sys.stderr` output
94
+ written after `connect_preditor` is called, will be shown in the PrEditor window
95
+ if it shown. If a exception is raised, and PrEditor is not visible, the user will
96
+ be notified and can easily show PrEditor.
97
+ ```py
98
+ import preditor
99
+
100
+ # Create a keyboard shortcut(F2) to launch PrEditor and start capturing sys.stdout
101
+ # and sys.stderr writes. The name argument makes this instance use it for prefs
102
+ action = preditor.connect_preditor(window, name="Example")
103
+
104
+ # Add the newly created action to a menu
105
+ window.menuBar().actions()[0].menu.addAction(action)
106
+ ```
107
+
108
+ Steps for initialization of a more complex application where you don't have
109
+ control over the initialization of the Gui(like Maya).
110
+ See [examples/add_to_app.py](examples/add_to_app.py) for a simple implementation.
111
+
112
+
113
+ ```py
114
+ # Step 1: Capture sys.stdout and sys.stderr output to a buffer as early as
115
+ # possible without creating the gui. Add this code to a plugin that gets loaded
116
+ # as early as possible. This can even be run before the gui is created.
117
+ import preditor
118
+ # The name "maya" specifies the core_name that will be used to load/save prefs.
119
+ preditor.configure("maya")
120
+
121
+ # Step 2: Add a way for the user to trigger calling launch to show the PrEditor
122
+ # gui. This is the first time the PrEditor GUI is initialized.
123
+ preditor.launch()
124
+
125
+ # Step 3: When closing the application, calling this will ensure that the
126
+ # current PrEditor gui's state is saved. It's safe and fast to call this even
127
+ # if the gui was never created.
128
+ preditor.shutdown()
129
+ ```
130
+
131
+ Up to the point where the PrEditor instance is created you can update the config
132
+ data set by `preditor.configure`. For example you can change the name(used to load
133
+ a set of user prefs) by calling `preditor.config.name = 'NewName'`. This is useful
134
+ for configuring PrEditor before you import your specific setup code that implements
135
+ a better `parent_callback`.
136
+
137
+ # Installing
138
+
139
+ `pip install preditor`
140
+
141
+ ## Installing Qt
142
+
143
+ PrEditor is built on Qt, but uses [Qt.py](https://github.com/mottosso/Qt.py) so
144
+ you can choose to use PySide2 or PyQt5. We have elected to not directly depend
145
+ on either of these packages as if you want to use PrEditor inside of a an existing
146
+ application like Maya or Houdini, they already come with PySide2 installed. If
147
+ you are using it externally, add them to your pip install command.
148
+
149
+ - PySide2: `pip install preditor PySide2`
150
+ - PyQt5: `pip install preditor PyQt5`
151
+
152
+ ## Cli
153
+
154
+ PrEditor is intended to be installed inside existing applications like Maya,
155
+ Houdini, Nuke etc, so it doesn't make sense to require installing packages like
156
+ click for those installs. If you are setting up a system wide install and want
157
+ to use the cli interface, you will need to install the cli optional dependencies.
158
+
159
+ `pip install preditor[cli]`
160
+
161
+ ### Creating shortcuts
162
+
163
+ If you want to be able to create desktop shortcuts from the cli to launch
164
+ PrEditor, you will also need to include the `shortcut` dependencies. Currently
165
+ this is only useful for windows.
166
+
167
+ - `pip install preditor[cli,shortcut]`
168
+
169
+ ## QScintilla workbox
170
+
171
+ The more mature QScintilla workbox requires a few extra dependencies that must
172
+ be passed manually. It hasn't been added to `extras_require` because we plan to
173
+ split it into its own pip module due to it requiring PyQt5 which is a little hard
174
+ to get working inside of DCC's that ship with PySide2 by default. Here is the
175
+ python 3 pip install command.
176
+
177
+ - `pip install preditor PyQt5, QScintilla>=2.11.4 aspell-python-py3`
178
+
179
+ The aspell-python-py3 requirement is optional to enable spell check.
180
+
181
+
182
+ # DCC Integration
183
+
184
+ ## Maya
185
+
186
+ PrEditor is pre-setup to use as a Maya module. To use it, create a virtualenv
187
+ with the same python as maya, or install it using mayapy.
188
+
189
+ ```
190
+ virtualenv venv_preditor
191
+ venv_preditor\Scripts\activate
192
+ pip install PrEditor
193
+ set MAYA_MODULE_PATH=c:\path\to\venv_preditor\Lib\site-packages\preditor\dccs
194
+ ```
195
+ Note: Due to how maya .mod files works if you are using development installs you
196
+ can't use pip editable installs. This is due to the relative path used
197
+ `PYTHONPATH +:= ../..` in `PrEditor_maya.mod`. You can modify that to use a hard
198
+ coded file path for testing, or add a second .mod file to add the virtualenv's
199
+ `site-packages` file path as a hard coded file path.
200
+
201
+
202
+ # Plugins
203
+
204
+ PrEditor is can be extended using entry point plugins defined by other pip packages.
205
+
206
+ * `preditor.plug.about_module`: Used to add information about various packages
207
+ like version and install location to the output of `preditor.about_preditor()`.
208
+ This is what generates the text shown by Help menu -> About PrEditor. See
209
+ sub-classes of `AboutModule` in `preditor.about_module` and how those are
210
+ added in [setup.cfg](setup.cfg).
211
+
212
+ * `preditor.plug.editors`: Used to add new workbox editors to PrEditor. See
213
+ [workbox_text_edit.py](preditor/gui/workbox_text_edit.py) for an example of
214
+ implementing a workbox. See [workbox_mixin.py](preditor/gui/workbox_mixin.py)
215
+ for the full interface to implement all features of an editor.
216
+
217
+ * `preditor.plug.loggerwindow`: Used to customize the LoggerWindow instance when
218
+ the LoggerWindow is created. For example, this can be used to create extra Toolbars
219
+ or add menu items. When using this plugin, make sure to use the
220
+ `preditor.gui.logger_window_plugin.LoggerWindowPlugin` class for your base class.
221
+
222
+ * `preditor.plug.logging_handlers`: Used to add custom python logging handlers
223
+ to the LoggingLevelButton's handlers sub-menus. This allows you to install a
224
+ handler instance on a specific logging object.