Hello community,
here is the log from the commit of package python-system_hotkey for
openSUSE:Factory checked in at 2020-10-23 12:22:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-system_hotkey (Old)
and /work/SRC/openSUSE:Factory/.python-system_hotkey.new.3463 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-system_hotkey"
Fri Oct 23 12:22:25 2020 rev:2 rq:843483 version:1.0.3
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-system_hotkey/python-system_hotkey.changes
2020-05-26 17:21:57.700315511 +0200
+++
/work/SRC/openSUSE:Factory/.python-system_hotkey.new.3463/python-system_hotkey.changes
2020-10-23 12:23:55.940750595 +0200
@@ -1,0 +2,8 @@
+Thu Oct 22 16:48:44 UTC 2020 - andy great <[email protected]>
+
+- Update to version 1.0.3.
+ * Fix a typo in Readme
+ * Documented the fact that xlib shouldn't really be used
+- Cleanup spec file.
+
+-------------------------------------------------------------------
Old:
----
system_hotkey-1.0.2.tar.gz
New:
----
system_hotkey-1.0.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-system_hotkey.spec ++++++
--- /var/tmp/diff_new_pack.3mL1cI/_old 2020-10-23 12:23:57.776755861 +0200
+++ /var/tmp/diff_new_pack.3mL1cI/_new 2020-10-23 12:23:57.780755872 +0200
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-system_hotkey
-Version: 1.0.2
+Version: 1.0.3
Release: 0
Summary: System wide hotkeys
License: BSD-3-Clause
@@ -44,8 +44,6 @@
%prep
%setup -q -n system_hotkey-%{version}
-# version was not bumped
-sed -i -e 's:1\.0\.1:1.0.2:g' setup.py
%build
%python_build
@@ -61,10 +59,7 @@
%files %{python_files}
%license LICENSE
%doc HISTORY.rst README.rst
-%dir %{python_sitelib}/system_hotkey/
-%dir %{python_sitelib}/system_hotkey/__pycache__/
-%{python_sitelib}/system_hotkey-%{version}-py%{python_version}.egg-info/
-%{python_sitelib}/system_hotkey/*.py
-%pycache_only %{python_sitelib}/system_hotkey/__pycache__/*.pyc
+%{python_sitelib}/system_hotkey
+%{python_sitelib}/*egg-info
%changelog
++++++ system_hotkey-1.0.2.tar.gz -> system_hotkey-1.0.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/system_hotkey-1.0.2/.gitignore
new/system_hotkey-1.0.3/.gitignore
--- old/system_hotkey-1.0.2/.gitignore 2016-07-28 22:29:56.000000000 +0200
+++ new/system_hotkey-1.0.3/.gitignore 2019-05-15 14:53:03.000000000 +0200
@@ -6,5 +6,5 @@
*egg-info/
*.bat
.cache/
-
+tags
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/system_hotkey-1.0.2/HISTORY.rst
new/system_hotkey-1.0.3/HISTORY.rst
--- old/system_hotkey-1.0.2/HISTORY.rst 2016-07-28 22:29:56.000000000 +0200
+++ new/system_hotkey-1.0.3/HISTORY.rst 2019-05-15 14:53:03.000000000 +0200
@@ -4,11 +4,22 @@
Mac support
-eta > 9 months
+eta > 8 months
Version Release Notes
=====================
+1.0.4
+-----
+* Exceptions are now run in main
+
+1.0.3
+-----
+* Documented the fact that xlib shouldn't really be used
+
+1.0.2
+-----
+* Fixed a linux bug where spurious events got passed through
1.0.0
-----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/system_hotkey-1.0.2/README.rst
new/system_hotkey-1.0.3/README.rst
--- old/system_hotkey-1.0.2/README.rst 2016-07-28 22:29:56.000000000 +0200
+++ new/system_hotkey-1.0.3/README.rst 2019-05-15 14:53:03.000000000 +0200
@@ -5,8 +5,6 @@
Currently no mac or python2 support :(
-Mac support is coming in a few years i would say!
-
Installation
------------
@@ -15,7 +13,7 @@
.. code-block:: bash
- pip3 install system_hotkey
+ pip3 install system_hotkey
should do the trick
@@ -25,9 +23,9 @@
Linux
^^^^^
-For x11 you will can either use `xcffib <https://github.com/tych0/xcffib>`_
(bsd license),
-or you may use the python xlib bindings (gpl license)
+For x11 you should use `xcffib <https://github.com/tych0/xcffib>`_ (bsd
license),
+If for some reason you have to use the python xlib bindings (gpl license), a
few fixes need be added first. See `here
<https://github.com/timeyyy/system_hotkey/issues/6#issuecomment-265410255>`_
Usage
@@ -46,16 +44,16 @@
- control
- shift
-- super (win key)
+- super (windows key)
- alt
-A InvalidKeyError will be raised if a key was not understood
+InvalidKeyError will be raised if a key was not understood
.. code-block:: python
from system_hotkey import SystemHotkey
- hk = SystemHotkeys()
- hk.register(('control', 'shift', 'h'), callback=lambda:print("Easy!"))
+ hk = SystemHotkey()
+ hk.register(('control', 'shift', 'h'), callback=lambda x: print("Easy!"))
A SystemRegisterError will be raised if a hotkey is already in use.
@@ -76,7 +74,7 @@
def some_func(self, event, hotkey, args):
pass
- hk = SystemHotkeys(consumer=some_func)
+ hk = SystemHotkey(consumer=some_func)
hk.register(hotkey, arg1, arg2, arg3)
So you have a master function that receives all hotkey presses and can
delegate as desired.
@@ -93,3 +91,5 @@
- I have only mapped most common keys, i have not experimented with
Unicode/Japanese characters etc. It's only a matter of mapping a name to the
keysym on Linux and virtual key code on windows.
- binding to kp_left (key pad left) will also bind to kp_4, there is a flag
(unite_kp) to toggle this behaviour but it is experimental
+
+- Requires an xserver (x11)...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/system_hotkey-1.0.2/setup.py
new/system_hotkey-1.0.3/setup.py
--- old/system_hotkey-1.0.2/setup.py 2016-07-28 22:29:56.000000000 +0200
+++ new/system_hotkey-1.0.3/setup.py 2019-05-15 14:53:03.000000000 +0200
@@ -1,5 +1,5 @@
from setuptools import setup, find_packages
-from codecs import open
+from codecs import open
import os
here = os.path.abspath(os.path.dirname(__file__))
@@ -8,88 +8,32 @@
with open(os.path.join(*paths), 'r') as f:
return f.read()
-#if os.name == 'nt':
-# REQUIRED = ['pywin32']
-#else:
-REQUIRED = []
-
setup(
name = 'system_hotkey',
-
- version='1.0.1',
-
+ version='1.0.3',
description = 'System wide hotkeys',
long_description = (read('README.rst') + '\n\n' +
read('HISTORY.rst') + '\n\n' +
read('AUTHORS.rst')),
-
url = 'https://github.com/timeyyy/system_hotkey',
-
author='timothy eichler',
author_email='[email protected]',
-
license='BSD3',
-
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
# How mature is this project? Common values are
#~ 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
- 'Development Status :: 3 - Alpha',
+ 'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Operating System :: OS Independent',
'License :: OSI Approved :: BSD License',
- # Specify the Python versions you support here. In particular,
ensure
- # that you indicate whether you support Python 2, Python 3 or
both.
#~ 'Programming Language :: Python :: 2',
- #~ 'Programming Language :: Python :: 2.6',
- #~ 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.2',
- 'Programming Language :: Python :: 3.3',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
],
# What does your project relate to?
keywords = 'hotkeys python3 shortcutkeys shortuct x11 windows',
-
- # You can just specify the packages manually here if your project is
- # simple. Or you can use find_packages().
packages=find_packages(exclude=['contrib', 'docs', 'tests*']),
-
- # List run-time dependencies here. These will be installed by pip when
your
- # project is installed. For an analysis of "install_requires" vs pip's
- # requirements files see:
- # https://packaging.python.org/en/latest/requirements.html
- install_requires = REQUIRED,
-
- # List additional groups of dependencies here (e.g. development
dependencies).
- # You can install these using the following syntax, for example:
- # $ pip install -e .[dev,test]
- #~ extras_require = {
- #~ 'dev': ['check-manifest'],
- #~ 'test': ['coverage'],
- #~ },
-
- # If there are data files included in your packages that need to be
- # installed, specify them here. If using Python 2.6 or less, then these
- # have to be included in MANIFEST.in as well.
- #~ package_data={
- #~ 'sample': ['package_data.dat'],
- #~ },
-
- # Although 'package_data' is the preferred approach, in some case you
may
- # need to place data files outside of your packages.
- # see
http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files
- # In this case, 'data_file' will be installed into
'<sys.prefix>/my_data'
- #~ data_files=[('my_data', ['data/data_file'])],
-
- # To provide executable scripts, use entry points in preference to the
- # "scripts" keyword. Entry points provide cross-platform support and
allow
- # pip to create the appropriate form of executable for the target
platform.
- #~ entry_points = {
- #~ 'console_scripts': [
- #~ 'sample=sample:main',],},
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/system_hotkey-1.0.2/system_hotkey/system_hotkey.py
new/system_hotkey-1.0.3/system_hotkey/system_hotkey.py
--- old/system_hotkey-1.0.2/system_hotkey/system_hotkey.py 2016-07-28
22:29:56.000000000 +0200
+++ new/system_hotkey-1.0.3/system_hotkey/system_hotkey.py 2019-05-15
14:53:03.000000000 +0200
@@ -137,16 +137,18 @@
# win32con.NUMLOCK_ON,
# win32con.NUMLOCK_ON | win32con.CAPSLOCK_ON
)
+# Linux
else:
try:
from . import xpybutil_keybind as keybind
except SystemError:
import xpybutil_keybind as keybind
+ # Xcb
try:
- import xcffib # the xproto con will not work unlesss you
inport this first
+ # Xproto con will not work unlesss you inport this first
+ import xcffib
from xcffib import xproto
- from xpybutil import keybind
xcb_modifiers = {
'control' : xproto.ModMask.Control,
@@ -161,105 +163,69 @@
xproto.ModMask.Lock | xproto.ModMask._2)
except ImportError:
pass
- try:
- from Xlib import X
- from Xlib import XK
- from Xlib.display import Display
- special_X_keysyms = { # these couldn't be gotten from the
xlib keycode function
- ' ' : "space",
- '\t' : "Tab",
- '\n' : "Return",
- '\r' : "Return",
- '\e' : "Escape",
- '!' : "exclam",
- '#' : "numbersign",
- '%' : "percent",
- '$' : "dollar",
- '&' : "ampersand",
- '"' : "quotedbl",
- '\'' : "apostrophe",
- '(' : "parenleft",
- ')' : "parenright",
- '*' : "asterisk",
- '=' : "equal",
- '+' : "plus",
- ',' : "comma",
- '-' : "minus",
- '.' : "period",
- '/' : "slash",
- ':' : "colon",
- ';' : "semicolon",
- '<' : "less",
- '>' : "greater",
- '?' : "question",
- '@' : "at",
- '[' : "bracketleft",
- ']' : "bracketright",
- '\\' : "backslash",
- '^' : "asciicircum",
- '_' : "underscore",
- '`' : "grave",
- '{' : "braceleft",
- '|' : "bar",
- '}' : "braceright",
- '~' : "asciitilde"
- }
-
- xlib_modifiers = {
- 'control' : X.ControlMask,
- 'shift' : X.ShiftMask,
- 'alt' : X.Mod1Mask,
- 'super' : X.Mod4Mask
- }
-
- xlib_trivial_mods = ( # only working for scrollock
- 0,
- X.LockMask,
- X.Mod2Mask,
- X.LockMask | X.Mod2Mask)
- except ImportError:
- pass
+ # Xlib
+ else:
+ try:
+ from Xlib import X
+ from Xlib import XK
+ from Xlib.display import Display
+ # These couldn't be gotten from the xlib keycode function
+ special_X_keysyms = {
+ ' ' : "space",
+ '\t' : "tab",
+ '\n' : "return",
+ '\r' : "return",
+ '\e' : "escape",
+ '!' : "exclam",
+ '#' : "numbersign",
+ '%' : "percent",
+ '$' : "dollar",
+ '&' : "ampersand",
+ '"' : "quotedbl",
+ '\'' : "apostrophe",
+ '(' : "parenleft",
+ ')' : "parenright",
+ '*' : "asterisk",
+ '=' : "equal",
+ '+' : "plus",
+ ',' : "comma",
+ '-' : "minus",
+ '.' : "period",
+ '/' : "slash",
+ ':' : "colon",
+ ';' : "semicolon",
+ '<' : "less",
+ '>' : "greater",
+ '?' : "question",
+ '@' : "at",
+ '[' : "bracketleft",
+ ']' : "bracketright",
+ '\\' : "backslash",
+ '^' : "asciicircum",
+ '_' : "underscore",
+ '`' : "grave",
+ '{' : "braceleft",
+ '|' : "bar",
+ '}' : "braceright",
+ '~' : "asciitilde"
+ }
+
+ xlib_modifiers = {
+ 'control' : X.ControlMask,
+ 'shift' : X.ShiftMask,
+ 'alt' : X.Mod1Mask,
+ 'super' : X.Mod4Mask
+ }
+
+ xlib_trivial_mods = ( # only working for scrollock
+ 0,
+ X.LockMask,
+ X.Mod2Mask,
+ X.LockMask | X.Mod2Mask)
+ except ImportError:
+ pass
-special_X_keysyms = {
- ' ' : "space",
- '\t' : "Tab",
- '\n' : "Return",
- '\r' : "Return",
- '\e' : "Escape",
- '!' : "exclam",
- '#' : "numbersign",
- '%' : "percent",
- '$' : "dollar",
- '&' : "ampersand",
- '"' : "quotedbl",
- '\'' : "apostrophe",
- '(' : "parenleft",
- ')' : "parenright",
- '*' : "asterisk",
- '=' : "equal",
- '+' : "plus",
- ',' : "comma",
- '-' : "minus",
- '.' : "period",
- '/' : "slash",
- ':' : "colon",
- ';' : "semicolon",
- '<' : "less",
- '>' : "greater",
- '?' : "question",
- '@' : "at",
- '[' : "bracketleft",
- ']' : "bracketright",
- '\\' : "backslash",
- '^' : "asciicircum",
- '_' : "underscore",
- '`' : "grave",
- '{' : "braceleft",
- '|' : "bar",
- '}' : "braceright",
- '~' : "asciitilde"
- }
class Aliases():
'''
@@ -291,7 +257,7 @@
thread_safe = util.CallSerializer()
class MixIn():
- @thread_safe.serialize_call
+ @thread_safe.serialize_call(0.5)
def register(self, hotkey, *args, callback=None, overwrite=False):
'''
Add a system wide hotkey,
@@ -328,7 +294,6 @@
else:
msg = 'existing bind detected... unregister or set overwrite
to True'
raise SystemRegisterError(msg, *hotkey)
- return
if os.name == 'nt':
def nt_register():
@@ -367,11 +332,14 @@
#~ copy[-1] = 'keyrelease'
#~ self.keybinds[tuple(copy)].append(callback)
- @thread_safe.serialize_call
+ @thread_safe.serialize_call(0.5)
def unregister(self, hotkey):
'''
Remove the System wide hotkey,
the order of the modifier keys is irrelevant
+
+ InvalidKeyError raised if key not understood
+ UnregisterError raiesd if key doesn't exist
'''
keycode, masks = self.parse_hotkeylist(hotkey)
if os.name == 'nt':
@@ -392,9 +360,12 @@
try:
for mod in self.trivial_mods:
self.conn.core.UngrabKeyChecked(keycode, self.root,
masks | mod).check()
- except xproto.BadAccess:
- raise UnregisterError("Failed unregs")
- del self.keybinds[tuple(self.order_hotkey(hotkey))]
+ except xproto.BadAccess as e:
+ raise UnregisterError("Failed to unregister") from e
+ try:
+ del self.keybinds[tuple(self.order_hotkey(hotkey))]
+ except KeyError as err:
+ raise UnregisterError from err
def order_hotkey(self, hotkey):
# Order doesn't matter for modifiers, so we force an order here
@@ -437,7 +408,7 @@
try:
masks.append(self.modders[item])
except KeyError:
- raise SystemRegisterError('Modifier: %s not supported' %
item) #TBD rmeove how the keyerror gets displayed as well
+ raise SystemRegisterError('Modifier: %s not supported' %
item) from None
masks = self.or_modifiers_together(masks)
else:
masks = 0
@@ -463,7 +434,7 @@
if self.verbose:
print('MFERROR', hotkey)
# Possible numpad key? The keysym can change if shift is pressed
(only tested on linux)
- # Todo test numpad bindings on a non english system
+ # TODO test numpad bindings on a non english system
aliases = NUMPAD_ALIASES.get(hotkey[-1])
if aliases:
for key in aliases:
@@ -532,7 +503,7 @@
'''
given a keycode returns a keysym
'''
- # Todo
+ # TODO
# --quirks--
# linux:
# numpad keys with multiple keysyms are currently undistinguishable
@@ -550,7 +521,7 @@
hk_ref = {}
keybinds = {}
- def __init__(self, consumer='callback', check_queue_interval=0.01,
use_xlib=False, conn=None, verbose=False, unite_kp=True):
+ def __init__(self, consumer='callback', check_queue_interval=0.0001,
use_xlib=False, conn=None, verbose=False, unite_kp=True):
'''
if the consumer param = 'callback', -> All hotkeys will require
a callback function
@@ -672,7 +643,7 @@
if event.event_type == 'keypress':
if self.verbose:
print('calling ', repr(cb))
- cb(event) # TBD either throw these up in a
thread, or pass in a queue to be put onto
+ cb(event) # TODO either throw these up in a
thread, or pass in a queue to be put onto
thread.start_new_thread(thread_me,(),)
elif callable(consumer):
@@ -773,7 +744,7 @@
return keybind.keysym_strings.get(keysym, [None])[0]
def _xlib_the_grab(self, keycode, masks):
- # Todo error handlig
http://tronche.com/gui/x/xlib/event-handling/protocol-errors/default-handlers.html
+ # TODO error handlig
http://tronche.com/gui/x/xlib/event-handling/protocol-errors/default-handlers.html
# try:
for triv_mod in self.trivial_mods:
self.xRoot.grab_key(keycode, triv_mod | masks, 1, X.GrabModeAsync,
X.GrabModeAsync)
@@ -788,13 +759,13 @@
True,
self.root, triv_mod | masks, keycode,
xproto.GrabMode.Async, xproto.GrabMode.Async).check()
- except struct.error:
+ except struct.error as e:
msg = 'Unable to Register, Key not understood by
systemhotkey'
- raise InvalidKeyError(msg)
- except xproto.AccessError:
+ raise InvalidKeyError(msg) from e
+ except xproto.AccessError as e:
keysym = self._xcb_get_keysym(keycode)
msg = 'The bind could be in use elsewhere: ' + keysym
- raise SystemRegisterError(msg)
+ raise SystemRegisterError(msg) from e
def _xcb_get_keycode(self, key):
return keybind.lookup_string(key)
@@ -806,7 +777,7 @@
if __name__ == '__main__':
# hk = SystemHotkey(use_xlib=True, verbose=1, unite_kp=1)
# hk = SystemHotkey(use_xlib=False, verbose=0) # xcb
- #hk.register(('a',), callback=lambda e: print('hi'))
+ # hk.register(('a',), callback=lambda e: print('hi'))
# hk.register(('kp_3',), callback=lambda e: print('hi'))
#hk.register(('left',), callback=lambda e: print('hi'))
@@ -825,20 +796,21 @@
# hk.register(('control','shift', 'k'), callback=lambda e: print('i am con
shift k2'))
def consumer(event, hotkey, args):
if hotkey != ["f4"]:
- import pdb;pdb.set_trace()
+ print(1)
+ # import pdb;pdb.set_trace()
else:
print(1)
- hk = SystemHotkey(use_xlib=False, consumer=consumer, verbose=1,
+ hk = SystemHotkey(use_xlib=False, consumer=consumer, verbose=0,
check_queue_interval=0.001)
- hk.register(('f4',), callback=lambda e: print('hi'))
+ hk.register(('escape',), callback=lambda e: print('hi'))
while 1:
pass
# Refernces #
#https://wiki.python.org/moin/AppsWithPythonScripting
-#~ http://msdn.microsoft.com/en-us/library/ms927178.aspx
-#http://www.kbdedit.com/manual/low_level_vk_list.html
-#http://stackoverflow.com/questions/14076207/simulating-a-key-press-event-in-python-2-7
#TBD WINDOWS KEY UP /DOWN ?
+#vk codes http://msdn.microsoft.com/en-us/library/ms927178.aspx
+#vk codes http://www.kbdedit.com/manual/low_level_vk_list.html
+#http://stackoverflow.com/questions/14076207/simulating-a-key-press-event-in-python-2-7
#TODO WINDOWS KEY UP /DOWN ?
#https://github.com/Tzbob/python-windows-tiler/blob/master/pwt/hotkey.py
-# Tbd how to keep the lisetning alive if a n error is encounterd? how to
recover?
+#TODO how to keep the lisetning alive if an error is encounterd? how to
recover?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/system_hotkey-1.0.2/system_hotkey/tests/test_system_hotkey.py
new/system_hotkey-1.0.3/system_hotkey/tests/test_system_hotkey.py
--- old/system_hotkey-1.0.2/system_hotkey/tests/test_system_hotkey.py
1970-01-01 01:00:00.000000000 +0100
+++ new/system_hotkey-1.0.3/system_hotkey/tests/test_system_hotkey.py
2019-05-15 14:53:03.000000000 +0200
@@ -0,0 +1,44 @@
+from system_hotkey import SystemHotkey, \
+ SystemRegisterError, \
+ UnregisterError, \
+ InvalidKeyError
+
+def test_errors_raised_in_main():
+ hk = SystemHotkey()
+ key = ('5',)
+ cb = lambda e: print('hi')
+
+ hk.register(key, callback=cb)
+ try:
+ hk.register(key, callback=cb)
+ except SystemRegisterError:
+ pass
+ else:
+ raise Exception('fail')
+
+ hk.unregister(key)
+ try:
+ hk.unregister(key)
+ except UnregisterError:
+ pass
+ else:
+ raise Exception('fail')
+
+ bad_key = ('badkey ..',)
+ try:
+ hk.register(bad_key, callback=cb)
+ except InvalidKeyError:
+ pass
+ else:
+ raise Exception('fail')
+
+ try:
+ hk.unregister(bad_key)
+ except:
+ pass
+ else:
+ raise Exception('fail')
+
+ # input() # Hold program open until you press enter
+
+test_errors_raised_in_main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/system_hotkey-1.0.2/system_hotkey/util.py
new/system_hotkey-1.0.3/system_hotkey/util.py
--- old/system_hotkey-1.0.2/system_hotkey/util.py 2016-07-28
22:29:56.000000000 +0200
+++ new/system_hotkey-1.0.3/system_hotkey/util.py 2019-05-15
14:53:03.000000000 +0200
@@ -4,8 +4,11 @@
general utilites..
'''
import _thread as thread
+import threading
from queue import Queue
+import queue
from functools import wraps
+import time
def unique_int(values):
@@ -26,22 +29,93 @@
return last
+class ExceptionSerializer():
+ def __init__(self):
+ self.queue = queue.Queue()
+
+ def catch_and_raise(self, func, timeout=0.5):
+ '''
+ wait for a function to finish and raise any errors'''
+ self.wait_event(func, timeout)
+ self._check_for_errors(func)
+
+ def mark_done(self, function):
+ '''Wrap functions so that we can monitor when they are done'''
+ self.init_wrap(function)
+ @wraps(function)
+ def decorator(*args, **kwargs):
+ # Function has started running
+ self.clear_event(function)
+ try:
+ results = function(*args, **kwargs)
+ except Exception as err:
+ self.queue.put(err)
+ else:
+ return results
+ finally:
+ # Function has finished running
+ self.set_event(function)
+
+ return decorator
+
+ def put(self, x):
+ self.queue.put(x)
+
+ def init_wrap(self, func):
+ name = self._make_event_name(func)
+ event = threading.Event()
+ setattr(self, name, event)
+
+ def _check_for_errors(self, func):
+ try:
+ error = self.queue.get(block=False)
+ except queue.Empty:
+ pass
+ else:
+ raise error
+
+ def _make_event_name(self, func):
+ return '_event_' + func.__name__
+
+ def get_event(self, func):
+ return getattr(self, self._make_event_name(func))
+
+ def set_event(self, func):
+ self.get_event(func).set()
+
+ def clear_event(self, func):
+ self.get_event(func).clear()
+
+ def wait_event(self, func, *args):
+ self.get_event(func).wait(*args)
+
+
class CallSerializer():
def __init__(self):
self.queue = Queue()
thread.start_new_thread(self.call_functions, (),)
+ self.bug_catcher = ExceptionSerializer()
def call_functions(self):
while 1:
func, args, kwargs = self.queue.get(block=True)
func(*args, **kwargs)
- def serialize_call(self, function):
+ def serialize_call(self, timeout=0.5):
'''
a call to a function decorated will not have
overlapping calls, i.e thread safe
'''
- @wraps(function)
- def decorator(*args, **kwargs):
- self.queue.put((function, args, kwargs))
- return decorator
+ def state(function):
+ @wraps(function)
+ def decorator(*args, **kwargs):
+ # Function will let us know when it is done running
+ # This is done so we can catch exceptions raised
+ # in functions that are run within threads
+ mark_func = self.bug_catcher.mark_done(function)
+ self.queue.put((mark_func, args, kwargs))
+ # wait for the function to finish and raise errors
+ self.bug_catcher.catch_and_raise(function, timeout)
+ return decorator
+ return state
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/system_hotkey-1.0.2/tests/test_hotkeys.py
new/system_hotkey-1.0.3/tests/test_hotkeys.py
--- old/system_hotkey-1.0.2/tests/test_hotkeys.py 2016-07-28
22:29:56.000000000 +0200
+++ new/system_hotkey-1.0.3/tests/test_hotkeys.py 1970-01-01
01:00:00.000000000 +0100
@@ -1,55 +0,0 @@
-import os
-import time
-
-import system_hotkey
-hk = system_hotkey.SystemHotkey()
-
-CALLBACK_RESULT = []
-
-def append_callback(key):
- print('APPENDING ',key)
- CALLBACK_RESULT.append(key)
-
-if os.name == 'nt':
- from win32api import keybd_event
- def send_event(key): # note if we change the time on checking our
queue this sleep time will have to be changed
- time.sleep(0.03)
- keybd_event(int(hk.get_keycode(key)) , 0, 1, 0)
- time.sleep(0.03)
-
-
-keys_to_test = [('k',),
- ('control','k'),
- ('control','shift','k'),
- ('control','shift','alt','k'),
- ('control','shift','alt','super', 'k')]
-
-def test_register_args():
- '''If in callback mode the register function requires a callback for
all hotkeys regiersted,
- an error needs to be raised'''
- _hk = system_hotkey.SystemHotkey()
- try:
- _hk.register((keys_to_test[0]),)
- except TypeError:
- pass
- else:
- assert("hk register with no callback worked when it shouldn't
have")
-
-def test_register_1():
- '''
- Registers a hotkey without any modifiers, tests that the callback
- was run
- '''
- hk.register(keys_to_test[0], callback=lambda e:
append_callback(keys_to_test[0])) # THIS IS THREADED SO TBD DOCUMENT just
need to wait a bit before sending the first key or after pressing a key getting
the result
- send_event(keys_to_test[0][0])
- assert CALLBACK_RESULT[0] == keys_to_test[0]
-
-
-def register_2():
- '''testing with one modifier'''
- hk.register(keys_to_test[1], lambda msg:
CALLBACK_RESULT[0].append(keys_to_test[0]))
- send_event(keys_to_test[1])
-
-#~ test_register_1()
-#~ register_2()
-