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/settings.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
from __future__ import absolute_import, print_function
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import configparser
|
|
9
|
+
except Exception:
|
|
10
|
+
import ConfigParser as configparser # noqa: N813
|
|
11
|
+
|
|
12
|
+
# define the default environment variables
|
|
13
|
+
OS_TYPE = ''
|
|
14
|
+
if os.name == 'posix':
|
|
15
|
+
OS_TYPE = 'Linux'
|
|
16
|
+
elif os.name == 'nt':
|
|
17
|
+
OS_TYPE = 'Windows'
|
|
18
|
+
elif os.name == 'osx':
|
|
19
|
+
OS_TYPE = 'MacOS'
|
|
20
|
+
|
|
21
|
+
# The sections to add from settings.ini
|
|
22
|
+
# The order matters. Add from most specific to least specific.
|
|
23
|
+
# Example: Add Windows Offline, then Windows, then Default.
|
|
24
|
+
# Environment variables that exist in os.environ will not be added.
|
|
25
|
+
_SECTIONS_TO_ADD = []
|
|
26
|
+
if os.getenv('BDEV_OFFLINE') == '1':
|
|
27
|
+
_SECTIONS_TO_ADD.append('{} Offline'.format(OS_TYPE))
|
|
28
|
+
_SECTIONS_TO_ADD += [OS_TYPE, 'Default']
|
|
29
|
+
|
|
30
|
+
_currentEnv = ''
|
|
31
|
+
defaults = {}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def environStr(value):
|
|
35
|
+
if sys.version_info[0] > 2:
|
|
36
|
+
# Python 3 requires a unicode value. aka str(), which these values already are
|
|
37
|
+
return value
|
|
38
|
+
# Python 2 requires str object, not unicode
|
|
39
|
+
return value.encode('utf8')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def addConfigSection(config_parser, section):
|
|
43
|
+
"""
|
|
44
|
+
Add a config section to os.environ for a section.
|
|
45
|
+
|
|
46
|
+
Does not add options that already exist in os.environ.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
config_parser (configparser.RawConfigParser): The parser to read from.
|
|
50
|
+
Must already be read.
|
|
51
|
+
section (str): The section name to add.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
for option in config_parser.options(section):
|
|
55
|
+
if option.upper() not in os.environ:
|
|
56
|
+
value = config_parser.get(section, option)
|
|
57
|
+
if value == 'None':
|
|
58
|
+
value = ''
|
|
59
|
+
# In python2.7 on windows you can't pass unicode values to
|
|
60
|
+
# subprocess.Popen's env argument. This is the reason we are calling str()
|
|
61
|
+
os.environ[environStr(option.upper())] = environStr(value)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# load the default environment from the settings INI
|
|
65
|
+
config = configparser.RawConfigParser()
|
|
66
|
+
config.read(os.path.join(os.path.dirname(__file__), 'resource', 'settings.ini'))
|
|
67
|
+
for section in _SECTIONS_TO_ADD:
|
|
68
|
+
addConfigSection(config, section)
|
|
69
|
+
|
|
70
|
+
# store the blurdev path in the environment
|
|
71
|
+
os.environ['BDEV_PATH'] = environStr(os.path.dirname(__file__))
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
""" A system for capturing stream output and later inserting the captured output into a
|
|
2
|
+
gui, and allowing that GUI to directly capture any new output written to the streams.
|
|
3
|
+
|
|
4
|
+
A use case for this is to attach a Manager's as early as possible to ``sys.stdout``
|
|
5
|
+
and ``sys.stderr`` process, before any GUI's are created. Then later you initialize a
|
|
6
|
+
GUI python console that should show all python output that has already been written.
|
|
7
|
+
Any future writes are delivered directly to the gui using a callback mechanism.
|
|
8
|
+
|
|
9
|
+
Example::
|
|
10
|
+
|
|
11
|
+
# Startup script or plugin for DCC runs this as early as possible.
|
|
12
|
+
from preditor.stream import install_to_std
|
|
13
|
+
|
|
14
|
+
manager = install_to_std()
|
|
15
|
+
# Startup script exits and DCC continues to load eventually creating the main gui.
|
|
16
|
+
|
|
17
|
+
# From a menu a user chooses to show a custom console(A gui that replicates a
|
|
18
|
+
# python interactive console inside the DCC).
|
|
19
|
+
console = PythonConsole()
|
|
20
|
+
|
|
21
|
+
# We will want to see all the previous writes made by python, so replay them
|
|
22
|
+
# in the console so it can properly handle stdout and stderr writes.
|
|
23
|
+
for msg, state in manager:
|
|
24
|
+
console.write(msg, state)
|
|
25
|
+
|
|
26
|
+
# Make it so any future writes are automatically added to the console.
|
|
27
|
+
manager.add_callback(console.write)
|
|
28
|
+
|
|
29
|
+
# Optionally, disable storing data in the buffer. buffer.write calls will now
|
|
30
|
+
# directly write to console so there is no reason to duplicate the data to the
|
|
31
|
+
# buffer.
|
|
32
|
+
manager.append_writes = False
|
|
33
|
+
"""
|
|
34
|
+
from __future__ import absolute_import, print_function
|
|
35
|
+
|
|
36
|
+
import sys
|
|
37
|
+
|
|
38
|
+
STDERR = 1
|
|
39
|
+
STDIN = 2
|
|
40
|
+
STDOUT = 3
|
|
41
|
+
|
|
42
|
+
from .director import Director # noqa: E402
|
|
43
|
+
from .manager import Manager # noqa: E402
|
|
44
|
+
|
|
45
|
+
"""Set when :py:attr:``install_to_std`` is called. This stores the installed Manager
|
|
46
|
+
so it can be accessed to install callbacks.
|
|
47
|
+
"""
|
|
48
|
+
active = None
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
"active",
|
|
52
|
+
"Director",
|
|
53
|
+
"install_to_std",
|
|
54
|
+
"Manager",
|
|
55
|
+
"STDERR",
|
|
56
|
+
"STDIN",
|
|
57
|
+
"STDOUT",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def install_to_std(out=True, err=True):
|
|
62
|
+
"""Replaces ``sys.stdout`` and ``sys.stderr`` with :py:class:`Director`'s
|
|
63
|
+
using the returned :py:class:`Manager`. This manager is stored as the ``active``
|
|
64
|
+
variable and can be accessed later. This can be called more than once, and it will
|
|
65
|
+
simply return the already installed Manager.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
out (bool, optional): Enables replacement of ``sys.stdout`` on first call.
|
|
69
|
+
err (bool, optional): Enables replacement of ``sys.stderr`` on first call.
|
|
70
|
+
"""
|
|
71
|
+
global active
|
|
72
|
+
|
|
73
|
+
if active is None:
|
|
74
|
+
active = Manager()
|
|
75
|
+
if out:
|
|
76
|
+
sys.stdout = Director(active, STDOUT)
|
|
77
|
+
if err:
|
|
78
|
+
sys.stderr = Director(active, STDERR)
|
|
79
|
+
|
|
80
|
+
return active
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from __future__ import absolute_import, print_function
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from . import STDERR, STDOUT
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Director(io.TextIOBase):
|
|
10
|
+
"""A file like object that stores the text written to it in a manager.
|
|
11
|
+
This manager can be shared between multiple Directors to build a single
|
|
12
|
+
continuous history of all writes.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
manager (Manager): The manager that writes are stored in.
|
|
16
|
+
state: The state passed to the manager. This is often ``preditor.stream.STDOUT``
|
|
17
|
+
or ``preditor.stream.STDERR``.
|
|
18
|
+
old_stream: A second stream that will be written to every time this stream
|
|
19
|
+
is written to. This allows this object to replace sys.stdout and still
|
|
20
|
+
send that output to the original stdout, which is useful for not breaking
|
|
21
|
+
DCC's script editors. Pass False to disable this feature. If you pass None
|
|
22
|
+
and state is set to ``preditor.stream.STDOUT`` or ``preditor.stream.STDERR``
|
|
23
|
+
this will automatically be set to the current sys.stdout or sys.stderr.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, manager, state, old_stream=None, *args, **kwargs):
|
|
27
|
+
super(Director, self).__init__(*args, **kwargs)
|
|
28
|
+
self.manager = manager
|
|
29
|
+
self.state = state
|
|
30
|
+
|
|
31
|
+
# Keep track of whether we wrapped a std stream
|
|
32
|
+
# that way we don't .close() any streams that we don't control
|
|
33
|
+
self.std_stream_wrapped = False
|
|
34
|
+
|
|
35
|
+
if old_stream is False:
|
|
36
|
+
old_stream = None
|
|
37
|
+
elif old_stream is None:
|
|
38
|
+
if state == STDOUT:
|
|
39
|
+
# On Windows if we're in pythonw.exe, then sys.stdout is named "nul"
|
|
40
|
+
# And it uses cp1252 encoding (which breaks with unicode)
|
|
41
|
+
# So if we find this nul TextIOWrapper, it's safe to just skip it
|
|
42
|
+
if getattr(sys.stdout, 'name', '') != 'nul':
|
|
43
|
+
self.std_stream_wrapped = True
|
|
44
|
+
old_stream = sys.stdout
|
|
45
|
+
elif state == STDERR:
|
|
46
|
+
if getattr(sys.stderr, 'name', '') != 'nul':
|
|
47
|
+
self.std_stream_wrapped = True
|
|
48
|
+
old_stream = sys.stderr
|
|
49
|
+
|
|
50
|
+
self.old_stream = old_stream
|
|
51
|
+
|
|
52
|
+
def close(self):
|
|
53
|
+
if (
|
|
54
|
+
self.old_stream
|
|
55
|
+
and not self.std_stream_wrapped
|
|
56
|
+
and self.old_stream is not sys.__stdout__
|
|
57
|
+
and self.old_stream is not sys.__stderr__
|
|
58
|
+
):
|
|
59
|
+
self.old_stream.close()
|
|
60
|
+
|
|
61
|
+
super(Director, self).close()
|
|
62
|
+
|
|
63
|
+
def flush(self):
|
|
64
|
+
if self.old_stream:
|
|
65
|
+
self.old_stream.flush()
|
|
66
|
+
|
|
67
|
+
super(Director, self).flush()
|
|
68
|
+
|
|
69
|
+
def write(self, msg):
|
|
70
|
+
self.manager.write(msg, self.state)
|
|
71
|
+
|
|
72
|
+
if self.old_stream:
|
|
73
|
+
self.old_stream.write(msg)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from __future__ import absolute_import, print_function
|
|
2
|
+
|
|
3
|
+
import collections
|
|
4
|
+
|
|
5
|
+
from ..weakref import WeakList
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Manager(collections.deque):
|
|
9
|
+
"""Stores all of the data from the stdout/stderr writes. You can iterate over this
|
|
10
|
+
object to see all of the (msg, state) calls that have been written to it up to the
|
|
11
|
+
maxlen specified when constructing it.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
maxlen (int, optional): The maximum number of raw writes to store. If this is
|
|
15
|
+
exceeded, the oldest writes are discarded.
|
|
16
|
+
|
|
17
|
+
Properties:
|
|
18
|
+
store_writes (bool): Set this to False if you no longer want write calls to
|
|
19
|
+
store on the manager.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, maxlen=10000):
|
|
23
|
+
super(Manager, self).__init__(maxlen=maxlen)
|
|
24
|
+
self.callbacks = WeakList()
|
|
25
|
+
self.store_writes = True
|
|
26
|
+
|
|
27
|
+
def add_callback(self, callback, replay=False, disable_writes=False, clear=False):
|
|
28
|
+
"""Add a callable that will be called every time write is called.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
callback (callable): A callable object that takes two arguments. It must
|
|
32
|
+
take two arguments (msg, state). See write for more details.
|
|
33
|
+
replay (bool, optional): If True, then iterate over all the stored writes
|
|
34
|
+
and pass them to callback. This is useful for when you are initializing
|
|
35
|
+
a gui and want to include all previous prints.
|
|
36
|
+
disable_writes (bool, optional): Set store_writes to False if this is True.
|
|
37
|
+
clear (bool, optional): Clear the stored history on this object.
|
|
38
|
+
"""
|
|
39
|
+
self.callbacks.append(callback)
|
|
40
|
+
|
|
41
|
+
if replay:
|
|
42
|
+
# Replay the existing prints into the console.
|
|
43
|
+
for msg, state in self:
|
|
44
|
+
callback(msg, state)
|
|
45
|
+
|
|
46
|
+
if disable_writes:
|
|
47
|
+
# Disable storing data in the buffer. buffer.write calls will now
|
|
48
|
+
# directly write to console so there is no reason to duplicate the
|
|
49
|
+
# data to the buffer.
|
|
50
|
+
self.store_writes = False
|
|
51
|
+
|
|
52
|
+
if clear:
|
|
53
|
+
self.clear()
|
|
54
|
+
|
|
55
|
+
def remove_callback(self, callback):
|
|
56
|
+
self.callbacks.remove(callback)
|
|
57
|
+
|
|
58
|
+
def get_value(self, fmt="[{state}:{msg}]"):
|
|
59
|
+
return ''.join([fmt.format(msg=d[0], state=d[1]) for d in self])
|
|
60
|
+
|
|
61
|
+
def write(self, msg, state):
|
|
62
|
+
"""Adds the written text to the manager and passes it to any attached callbacks.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
msg (str): The text to be written.
|
|
66
|
+
state: A identifier for how the text is to be written. For example if this
|
|
67
|
+
write is coming from sys.stderr this will likely be set to
|
|
68
|
+
``preditor.stream.STDERR``.
|
|
69
|
+
"""
|
|
70
|
+
if self.store_writes:
|
|
71
|
+
self.append((msg, state))
|
|
72
|
+
|
|
73
|
+
for callback in self.callbacks:
|
|
74
|
+
callback(msg, state)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class StreamHandlerHelper(object):
|
|
8
|
+
"""A collection of functions for manipulating ``logging.StreamHandler`` objects."""
|
|
9
|
+
|
|
10
|
+
@classmethod
|
|
11
|
+
def set_stream(cls, handler, stream):
|
|
12
|
+
"""For the given StreamHandler, set its stream. This works around
|
|
13
|
+
python 2's lack of StreamHandler.setStream by replicating python 3.
|
|
14
|
+
"""
|
|
15
|
+
# TODO: once python 2 is no longer supported, replace any uses of this
|
|
16
|
+
# function with `handler.setStream(stream)`
|
|
17
|
+
if sys.version_info[0] > 2:
|
|
18
|
+
handler.setStream(stream)
|
|
19
|
+
else:
|
|
20
|
+
# Copied from python 3's logging's setStream to work in python 2
|
|
21
|
+
handler.acquire()
|
|
22
|
+
try:
|
|
23
|
+
handler.flush()
|
|
24
|
+
handler.stream = stream
|
|
25
|
+
finally:
|
|
26
|
+
handler.release()
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def replace_stream(cls, old, new, logger=None):
|
|
30
|
+
"""Replaces the stream of StreamHandlers by checking all
|
|
31
|
+
`logging.StreamHandler`'s attached to the provided logger. If any of them are
|
|
32
|
+
using old for their stream, update that stream to new.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
old (stream): Only StreamHandlers using this stream will be updated to new.
|
|
36
|
+
new (stream): A file stream object like `sys.stderr` that will replace old.
|
|
37
|
+
logger (logging.Logger, optional): The logger to update streams for. If
|
|
38
|
+
None, the root logger(`logging.getLogger()`) will be used.
|
|
39
|
+
"""
|
|
40
|
+
if logger is None:
|
|
41
|
+
logger = logging.getLogger()
|
|
42
|
+
|
|
43
|
+
for handler in logger.handlers:
|
|
44
|
+
if isinstance(handler, logging.StreamHandler):
|
|
45
|
+
if handler.stream == old:
|
|
46
|
+
cls.set_stream(handler, new)
|
|
File without changes
|
preditor/utils/cute.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
__all__ = ["ensureWindowIsVisible"]
|
|
4
|
+
from Qt.QtWidgets import QApplication
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def ensureWindowIsVisible(widget):
|
|
8
|
+
"""
|
|
9
|
+
Checks the widget's geometry against all of the system's screens. If it does
|
|
10
|
+
not intersect it will reposition it to the top left corner of the highest
|
|
11
|
+
numbered desktop. Returns a boolean indicating if it had to move the
|
|
12
|
+
widget.
|
|
13
|
+
"""
|
|
14
|
+
desktop = QApplication.desktop()
|
|
15
|
+
geo = widget.geometry()
|
|
16
|
+
for screen in range(desktop.screenCount()):
|
|
17
|
+
monGeo = desktop.screenGeometry(screen)
|
|
18
|
+
if monGeo.intersects(geo):
|
|
19
|
+
break
|
|
20
|
+
else:
|
|
21
|
+
geo.moveTo(monGeo.x() + 7, monGeo.y() + 30)
|
|
22
|
+
# setting the geometry may trigger a second check if setGeometry is overridden
|
|
23
|
+
disable = hasattr(widget, 'checkScreenGeo') and widget.checkScreenGeo
|
|
24
|
+
if disable:
|
|
25
|
+
widget.checkScreenGeo = False
|
|
26
|
+
widget.setGeometry(geo)
|
|
27
|
+
if disable:
|
|
28
|
+
widget.checkScreenGeo = True
|
|
29
|
+
return True
|
|
30
|
+
return False
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import absolute_import
|
|
2
|
+
|
|
3
|
+
import glob
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def read_stylesheet(stylesheet='', path=None):
|
|
8
|
+
"""Returns the contents of the requested stylesheet.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
|
|
12
|
+
stylesheet (str): the name of the stylesheet. Attempt to load stylesheet.css
|
|
13
|
+
shipped with preditor. Ignored if path is provided.
|
|
14
|
+
|
|
15
|
+
path (str): Return the contents of this file path.
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
str: The contents of stylesheet or blank if stylesheet was not found.
|
|
19
|
+
valid: A stylesheet was found and loaded.
|
|
20
|
+
"""
|
|
21
|
+
if path is None:
|
|
22
|
+
path = os.path.join(
|
|
23
|
+
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
|
24
|
+
'resource',
|
|
25
|
+
'stylesheet',
|
|
26
|
+
'{}.css'.format(stylesheet),
|
|
27
|
+
)
|
|
28
|
+
if os.path.isfile(path):
|
|
29
|
+
with open(path) as f:
|
|
30
|
+
return f.read(), True
|
|
31
|
+
return '', False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def stylesheets(subFolder=None):
|
|
35
|
+
"""Returns a list of installed stylesheet names.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
subFolder (str or None, optional): Use this to access sub-folders of
|
|
39
|
+
the stylesheet resource directory.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
list: A list .css file paths in the target directory.
|
|
43
|
+
"""
|
|
44
|
+
components = [
|
|
45
|
+
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
|
46
|
+
'resource',
|
|
47
|
+
'stylesheet',
|
|
48
|
+
]
|
|
49
|
+
if subFolder is not None:
|
|
50
|
+
components.append(subFolder)
|
|
51
|
+
cssdir = os.path.join(*components)
|
|
52
|
+
cssfiles = sorted(glob.glob(os.path.join(cssdir, '*.css')))
|
|
53
|
+
# Only return the filename without the .css extension
|
|
54
|
+
return [os.path.splitext(os.path.basename(fp))[0] for fp in cssfiles]
|