gntplib 0.5__py3-none-any.whl → 0.66__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 gntplib might be problematic. Click here for more details.

gntplib/__version__.py ADDED
@@ -0,0 +1 @@
1
+ version = 0.63
gntplib/async.py CHANGED
@@ -1,193 +1,193 @@
1
- """This module provides support for asynchronous processing built on Tornado_.
2
-
3
- .. _Tornado: http://www.tornadoweb.org/
4
- """
5
-
6
- from __future__ import unicode_literals
7
- import logging
8
- import socket
9
-
10
- from tornado import gen, httpclient, ioloop, iostream
11
-
12
- import gntplib
13
-
14
-
15
- __all__ = ['AsyncIcon', 'AsyncNotifier', 'AsyncPublisher', 'AsyncResource',
16
- 'AsyncSubscriber']
17
-
18
-
19
- logger = logging.getLogger(__name__)
20
-
21
-
22
- class AsyncPublisher(gntplib.Publisher):
23
- """Asynchronous Publisher of Growl Notification Transport Protocol (GNTP).
24
-
25
- Same as :class:`~gntplib.Publisher` except the following:
26
-
27
- * uses :class:`AsyncGNTPClient` as `gntp_client_class`.
28
- * accepts :class:`tornado.ioloop.IOLoop` instance by additional
29
- `io_loop` keyword argument.
30
-
31
- :param name: the name of the application.
32
- :param event_defs: the definitions of the notifications.
33
- :param icon: url string or an instance of :class:`Resource` for the icon of
34
- the application. Defaults to `None`.
35
- :param io_loop: :class:`tornado.ioloop.IOLoop` instance.
36
- :param custom_headers: the list of key-value tuples for Custom Headers.
37
- :param app_specific_headers: the list of key-value tuples for App-Specific
38
- Headers.
39
- """
40
-
41
- def __init__(self, name, event_defs, icon=None, io_loop=None, **kwargs):
42
- io_loop = io_loop or ioloop.IOLoop.instance()
43
- gntplib.Publisher.__init__(self, name, event_defs, icon,
44
- gntp_client_class=AsyncGNTPClient,
45
- io_loop=io_loop, **kwargs)
46
-
47
-
48
- class AsyncNotifier(AsyncPublisher, gntplib.Notifier):
49
- """Deprecated Asynchronous Notifier of Growl Notification Transport
50
- Protocol (GNTP)."""
51
-
52
- def __init__(self, name, event_defs, icon=None, io_loop=None, **kwargs):
53
- import warnings
54
- warnings.warn('AsyncNotifier is deprecated, use AsyncPublisher'
55
- ' instead', DeprecationWarning, stacklevel=2)
56
- AsyncPublisher.__init__(self, name, event_defs, icon, io_loop,
57
- **kwargs)
58
-
59
-
60
- class AsyncSubscriber(gntplib.Subscriber):
61
- """Asynchronous Subscriber of Growl Notification Transport Protocol (GNTP).
62
-
63
- Same as :class:`~gntplib.Subscriber` except the following:
64
-
65
- * uses :class:`AsyncGNTPClient` as `gntp_client_class`.
66
- * accepts :class:`tornado.ioloop.IOLoop` instance by additional
67
- `io_loop` keyword argument.
68
-
69
- :param name: the name of the subscriber.
70
- :param hub: the subscribed-to machine. If a string is given, it is used as
71
- a host of the hub and default port number `23053` is used.
72
- If host-port tuple is given, it is used directly.
73
- :param password: the password of the subscribed-to machine.
74
- :param id_: the unique id of the subscriber. If not set, randomly
75
- generated UUID is used.
76
- :param port: the port number of the subscriber. Defaults to `23053`.
77
- :param io_loop: :class:`tornado.ioloop.IOLoop` instance.
78
- :param custom_headers: the list of key-value tuples for Custom Headers.
79
- :param app_specific_headers: the list of key-value tuples for App-Specific
80
- Headers.
81
- """
82
-
83
- def __init__(self, id_, name, hub, password, port=gntplib.DEFAULT_PORT,
84
- io_loop=None, **kwargs):
85
- io_loop = io_loop or ioloop.IOLoop.instance()
86
- gntplib.Subscriber.__init__(self, id_, name, hub, password, port=port,
87
- gntp_client_class=AsyncGNTPClient,
88
- io_loop=io_loop, **kwargs)
89
-
90
-
91
- class AsyncGNTPConnection(gntplib.BaseGNTPConnection):
92
- """Asynchronous GNTP connection built on Tornado."""
93
-
94
- def __init__(self, address, timeout, final_callback, socket_callback=None,
95
- io_loop=None):
96
- gntplib.BaseGNTPConnection.__init__(self, final_callback,
97
- socket_callback)
98
- sock = socket.create_connection(address, timeout=timeout)
99
- self.stream = iostream.IOStream(sock, io_loop=io_loop)
100
-
101
- def write_message(self, message):
102
- """Send the request to the GNTP server."""
103
- self.stream.write(message)
104
-
105
- def read_message(self, callback):
106
- """Read a message from opened stream and run callback with it."""
107
- self.stream.read_until(gntplib.MESSAGE_DELIMITER, callback)
108
-
109
- def close(self):
110
- """Close the stream."""
111
- self.stream.close()
112
- self.stream = None
113
-
114
-
115
- class AsyncGNTPClient(gntplib.GNTPClient):
116
- """Asynchronous GNTP client built on Tornado.
117
-
118
- :param io_loop: :class:`tornado.ioloop.IOLoop` instance.
119
- """
120
-
121
- def __init__(self, io_loop=None, **kwargs):
122
- gntplib.GNTPClient.__init__(self, connection_class=AsyncGNTPConnection,
123
- **kwargs)
124
- self.io_loop = io_loop
125
-
126
- @gen.engine
127
- def process_request(self, request, callback, **kwargs):
128
- """Process a request.
129
-
130
- If the request contains :class:`AsyncResource` instances, the
131
- connection to the GNTP server will be established after all their
132
- fetches are completed asynchronously.
133
- """
134
- async_resources = collect_async_resources(request)
135
- if async_resources:
136
- yield gen.Task(fetch_async_resources_in_parallel,
137
- async_resources,
138
- self.io_loop)
139
- gntplib.GNTPClient.process_request(self, request, callback,
140
- io_loop=self.io_loop, **kwargs)
141
-
142
-
143
- class AsyncResource(gntplib.Resource):
144
- """Class for asynchronous resource.
145
-
146
- :param url: url string of the resource.
147
- """
148
- def __init__(self, url):
149
- gntplib.Resource.__init__(self, None)
150
- self.url = url
151
-
152
-
153
- class AsyncIcon(AsyncResource):
154
- """Deprecated asynchronous icon class."""
155
-
156
- def __init__(self, url):
157
- import warnings
158
- warnings.warn('AsyncIcon is deprecated, use AsyncResource instead',
159
- DeprecationWarning, stacklevel=2)
160
- AsyncResource.__init__(self, url)
161
-
162
-
163
- @gen.engine
164
- def fetch_async_resources_in_parallel(async_resources, io_loop, callback):
165
- """Fetch :class:`AsyncResource`'s url in parallel."""
166
- http_client = httpclient.AsyncHTTPClient(io_loop=io_loop)
167
- responses = yield [gen.Task(http_client.fetch, resource.url)
168
- for resource in async_resources]
169
- for resource, response in zip(async_resources, responses):
170
- if response.error:
171
- logger.warning('failed to fetch %r: %s', resource.url,
172
- response.error)
173
- resource.data = None
174
- else:
175
- resource.data = response.body
176
- callback(async_resources)
177
-
178
-
179
- def collect_async_resources(request):
180
- """Collect :class:`AsyncResource` instances from given request."""
181
- resources = []
182
-
183
- if isinstance(request, gntplib.RegisterRequest):
184
- resources = [request.app_icon] + [e.icon for e in request.events]
185
- elif isinstance(request, gntplib.NotifyRequest):
186
- resources = [request.notification.icon]
187
-
188
- resources.extend([value for _, value in request.custom_headers
189
- if isinstance(value, AsyncResource)])
190
- resources.extend([value for _, value in request.app_specific_headers
191
- if isinstance(value, AsyncResource)])
192
-
193
- return list(set(r for r in resources if isinstance(r, AsyncResource)))
1
+ """This module provides support for asynchronous processing built on Tornado_.
2
+
3
+ .. _Tornado: http://www.tornadoweb.org/
4
+ """
5
+
6
+ from __future__ import unicode_literals
7
+ import logging
8
+ import socket
9
+
10
+ from tornado import gen, httpclient, ioloop, iostream
11
+
12
+ import gntplib
13
+
14
+
15
+ __all__ = ['AsyncIcon', 'AsyncNotifier', 'AsyncPublisher', 'AsyncResource',
16
+ 'AsyncSubscriber']
17
+
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class AsyncPublisher(gntplib.Publisher):
23
+ """Asynchronous Publisher of Growl Notification Transport Protocol (GNTP).
24
+
25
+ Same as :class:`~gntplib.Publisher` except the following:
26
+
27
+ * uses :class:`AsyncGNTPClient` as `gntp_client_class`.
28
+ * accepts :class:`tornado.ioloop.IOLoop` instance by additional
29
+ `io_loop` keyword argument.
30
+
31
+ :param name: the name of the application.
32
+ :param event_defs: the definitions of the notifications.
33
+ :param icon: url string or an instance of :class:`Resource` for the icon of
34
+ the application. Defaults to `None`.
35
+ :param io_loop: :class:`tornado.ioloop.IOLoop` instance.
36
+ :param custom_headers: the list of key-value tuples for Custom Headers.
37
+ :param app_specific_headers: the list of key-value tuples for App-Specific
38
+ Headers.
39
+ """
40
+
41
+ def __init__(self, name, event_defs, icon=None, io_loop=None, **kwargs):
42
+ io_loop = io_loop or ioloop.IOLoop.instance()
43
+ gntplib.Publisher.__init__(self, name, event_defs, icon,
44
+ gntp_client_class=AsyncGNTPClient,
45
+ io_loop=io_loop, **kwargs)
46
+
47
+
48
+ class AsyncNotifier(AsyncPublisher, gntplib.Notifier):
49
+ """Deprecated Asynchronous Notifier of Growl Notification Transport
50
+ Protocol (GNTP)."""
51
+
52
+ def __init__(self, name, event_defs, icon=None, io_loop=None, **kwargs):
53
+ import warnings
54
+ warnings.warn('AsyncNotifier is deprecated, use AsyncPublisher'
55
+ ' instead', DeprecationWarning, stacklevel=2)
56
+ AsyncPublisher.__init__(self, name, event_defs, icon, io_loop,
57
+ **kwargs)
58
+
59
+
60
+ class AsyncSubscriber(gntplib.Subscriber):
61
+ """Asynchronous Subscriber of Growl Notification Transport Protocol (GNTP).
62
+
63
+ Same as :class:`~gntplib.Subscriber` except the following:
64
+
65
+ * uses :class:`AsyncGNTPClient` as `gntp_client_class`.
66
+ * accepts :class:`tornado.ioloop.IOLoop` instance by additional
67
+ `io_loop` keyword argument.
68
+
69
+ :param name: the name of the subscriber.
70
+ :param hub: the subscribed-to machine. If a string is given, it is used as
71
+ a host of the hub and default port number `23053` is used.
72
+ If host-port tuple is given, it is used directly.
73
+ :param password: the password of the subscribed-to machine.
74
+ :param id_: the unique id of the subscriber. If not set, randomly
75
+ generated UUID is used.
76
+ :param port: the port number of the subscriber. Defaults to `23053`.
77
+ :param io_loop: :class:`tornado.ioloop.IOLoop` instance.
78
+ :param custom_headers: the list of key-value tuples for Custom Headers.
79
+ :param app_specific_headers: the list of key-value tuples for App-Specific
80
+ Headers.
81
+ """
82
+
83
+ def __init__(self, id_, name, hub, password, port=gntplib.DEFAULT_PORT,
84
+ io_loop=None, **kwargs):
85
+ io_loop = io_loop or ioloop.IOLoop.instance()
86
+ gntplib.Subscriber.__init__(self, id_, name, hub, password, port=port,
87
+ gntp_client_class=AsyncGNTPClient,
88
+ io_loop=io_loop, **kwargs)
89
+
90
+
91
+ class AsyncGNTPConnection(gntplib.BaseGNTPConnection):
92
+ """Asynchronous GNTP connection built on Tornado."""
93
+
94
+ def __init__(self, address, timeout, final_callback, socket_callback=None,
95
+ io_loop=None):
96
+ gntplib.BaseGNTPConnection.__init__(self, final_callback,
97
+ socket_callback)
98
+ sock = socket.create_connection(address, timeout=timeout)
99
+ self.stream = iostream.IOStream(sock, io_loop=io_loop)
100
+
101
+ def write_message(self, message):
102
+ """Send the request to the GNTP server."""
103
+ self.stream.write(message)
104
+
105
+ def read_message(self, callback):
106
+ """Read a message from opened stream and run callback with it."""
107
+ self.stream.read_until(gntplib.MESSAGE_DELIMITER, callback)
108
+
109
+ def close(self):
110
+ """Close the stream."""
111
+ self.stream.close()
112
+ self.stream = None
113
+
114
+
115
+ class AsyncGNTPClient(gntplib.GNTPClient):
116
+ """Asynchronous GNTP client built on Tornado.
117
+
118
+ :param io_loop: :class:`tornado.ioloop.IOLoop` instance.
119
+ """
120
+
121
+ def __init__(self, io_loop=None, **kwargs):
122
+ gntplib.GNTPClient.__init__(self, connection_class=AsyncGNTPConnection,
123
+ **kwargs)
124
+ self.io_loop = io_loop
125
+
126
+ @gen.engine
127
+ def process_request(self, request, callback, **kwargs):
128
+ """Process a request.
129
+
130
+ If the request contains :class:`AsyncResource` instances, the
131
+ connection to the GNTP server will be established after all their
132
+ fetches are completed asynchronously.
133
+ """
134
+ async_resources = collect_async_resources(request)
135
+ if async_resources:
136
+ yield gen.Task(fetch_async_resources_in_parallel,
137
+ async_resources,
138
+ self.io_loop)
139
+ gntplib.GNTPClient.process_request(self, request, callback,
140
+ io_loop=self.io_loop, **kwargs)
141
+
142
+
143
+ class AsyncResource(gntplib.Resource):
144
+ """Class for asynchronous resource.
145
+
146
+ :param url: url string of the resource.
147
+ """
148
+ def __init__(self, url):
149
+ gntplib.Resource.__init__(self, None)
150
+ self.url = url
151
+
152
+
153
+ class AsyncIcon(AsyncResource):
154
+ """Deprecated asynchronous icon class."""
155
+
156
+ def __init__(self, url):
157
+ import warnings
158
+ warnings.warn('AsyncIcon is deprecated, use AsyncResource instead',
159
+ DeprecationWarning, stacklevel=2)
160
+ AsyncResource.__init__(self, url)
161
+
162
+
163
+ @gen.engine
164
+ def fetch_async_resources_in_parallel(async_resources, io_loop, callback):
165
+ """Fetch :class:`AsyncResource`'s url in parallel."""
166
+ http_client = httpclient.AsyncHTTPClient(io_loop=io_loop)
167
+ responses = yield [gen.Task(http_client.fetch, resource.url)
168
+ for resource in async_resources]
169
+ for resource, response in zip(async_resources, responses):
170
+ if response.error:
171
+ logger.warning('failed to fetch %r: %s', resource.url,
172
+ response.error)
173
+ resource.data = None
174
+ else:
175
+ resource.data = response.body
176
+ callback(async_resources)
177
+
178
+
179
+ def collect_async_resources(request):
180
+ """Collect :class:`AsyncResource` instances from given request."""
181
+ resources = []
182
+
183
+ if isinstance(request, gntplib.RegisterRequest):
184
+ resources = [request.app_icon] + [e.icon for e in request.events]
185
+ elif isinstance(request, gntplib.NotifyRequest):
186
+ resources = [request.notification.icon]
187
+
188
+ resources.extend([value for _, value in request.custom_headers
189
+ if isinstance(value, AsyncResource)])
190
+ resources.extend([value for _, value in request.app_specific_headers
191
+ if isinstance(value, AsyncResource)])
192
+
193
+ return list(set(r for r in resources if isinstance(r, AsyncResource)))
gntplib/ciphers.py CHANGED
@@ -1,97 +1,97 @@
1
- """This module provides the encryption of messages built on PyCrypto_.
2
-
3
- .. _PyCrypto: http://pycrypto.org/
4
- """
5
-
6
- from __future__ import unicode_literals
7
- import binascii
8
- import struct
9
-
10
- import Crypto.Cipher.AES
11
- import Crypto.Cipher.DES
12
- import Crypto.Cipher.DES3
13
-
14
- from .utils import random_bytes
15
-
16
-
17
- __all__ = ['AES', 'DES', 'DES3']
18
-
19
-
20
- class _Algorithm(object):
21
- """The factory class of ciphers."""
22
-
23
- def __init__(self, algorithm_id, key_size):
24
- self.algorithm_id = algorithm_id
25
- self.key_size = key_size
26
-
27
- def cipher(self, key):
28
- """Return an instance of :class:`Cipher`."""
29
- return Cipher(key, self.algorithm_id)
30
-
31
-
32
- #: key length: 24 bytes (192 bit), block size: 16 byte (128 bit), iv size: 16
33
- #: byte (128 bit)
34
- AES = _Algorithm('AES', 24)
35
- #: key length: 8 bytes (64 bit), block size: 8 byte (64 bit), iv size: 8 byte
36
- #: (64 bit)
37
- DES = _Algorithm('DES', 8)
38
- #: key length: 24 bytes (192 bit), block size: 8 byte (64 bit), iv size: 8 byte
39
- #: (64 bit)
40
- DES3 = _Algorithm('3DES', 24)
41
-
42
- ALGORITHM_MAP = {
43
- 'AES': Crypto.Cipher.AES,
44
- 'DES': Crypto.Cipher.DES,
45
- '3DES': Crypto.Cipher.DES3,
46
- }
47
- KEY_SIZE_MAP = {
48
- 'AES': 24,
49
- 'DES': 8,
50
- '3DES': 24,
51
- }
52
-
53
-
54
- class Cipher(object):
55
- """The encryption of messages.
56
-
57
- :param key: the key of the encryption.
58
- :param algorithm_id: the algorithm of the encryption. Specify `'AES'`,
59
- `'DES'` or `'3DES'`.
60
- :param iv: the initial value.
61
- """
62
-
63
- def __init__(self, key, algorithm_id='DES', iv=None):
64
- self.key = key
65
- self.key_size = KEY_SIZE_MAP[algorithm_id]
66
- self.algorithm = ALGORITHM_MAP[algorithm_id]
67
- self.algorithm_id = algorithm_id
68
- self.iv = iv or self._random_iv()
69
-
70
- @property
71
- def iv_hex(self):
72
- """The hex-encoded iv."""
73
- return binascii.hexlify(self.iv)
74
-
75
- def encrypt(self, text):
76
- return self._cipher().encrypt(self._padding(text))
77
-
78
- def decrypt(self, text):
79
- return self._unpadding(self._cipher().decrypt(text))
80
-
81
- def _cipher(self):
82
- return self.algorithm.new(self.key.key[:self.key_size],
83
- self.algorithm.MODE_CBC,
84
- self.iv)
85
-
86
- def _padding(self, text):
87
- """PKCS5 (PKCS7) padding."""
88
- num = self.algorithm.block_size - len(text) % self.algorithm.block_size
89
- return text + struct.pack(b'B' * num, *([num] * num))
90
-
91
- def _unpadding(self, text):
92
- """Reverse PKCS5 (PKCS7) padding."""
93
- num = ord(text[-1:])
94
- return text[:-num]
95
-
96
- def _random_iv(self):
97
- return random_bytes(self.algorithm.block_size)
1
+ """This module provides the encryption of messages built on PyCrypto_.
2
+
3
+ .. _PyCrypto: http://pycrypto.org/
4
+ """
5
+
6
+ from __future__ import unicode_literals
7
+ import binascii
8
+ import struct
9
+
10
+ import Crypto.Cipher.AES
11
+ import Crypto.Cipher.DES
12
+ import Crypto.Cipher.DES3
13
+
14
+ from .utils import random_bytes
15
+
16
+
17
+ __all__ = ['AES', 'DES', 'DES3']
18
+
19
+
20
+ class _Algorithm(object):
21
+ """The factory class of ciphers."""
22
+
23
+ def __init__(self, algorithm_id, key_size):
24
+ self.algorithm_id = algorithm_id
25
+ self.key_size = key_size
26
+
27
+ def cipher(self, key):
28
+ """Return an instance of :class:`Cipher`."""
29
+ return Cipher(key, self.algorithm_id)
30
+
31
+
32
+ #: key length: 24 bytes (192 bit), block size: 16 byte (128 bit), iv size: 16
33
+ #: byte (128 bit)
34
+ AES = _Algorithm('AES', 24)
35
+ #: key length: 8 bytes (64 bit), block size: 8 byte (64 bit), iv size: 8 byte
36
+ #: (64 bit)
37
+ DES = _Algorithm('DES', 8)
38
+ #: key length: 24 bytes (192 bit), block size: 8 byte (64 bit), iv size: 8 byte
39
+ #: (64 bit)
40
+ DES3 = _Algorithm('3DES', 24)
41
+
42
+ ALGORITHM_MAP = {
43
+ 'AES': Crypto.Cipher.AES,
44
+ 'DES': Crypto.Cipher.DES,
45
+ '3DES': Crypto.Cipher.DES3,
46
+ }
47
+ KEY_SIZE_MAP = {
48
+ 'AES': 24,
49
+ 'DES': 8,
50
+ '3DES': 24,
51
+ }
52
+
53
+
54
+ class Cipher(object):
55
+ """The encryption of messages.
56
+
57
+ :param key: the key of the encryption.
58
+ :param algorithm_id: the algorithm of the encryption. Specify `'AES'`,
59
+ `'DES'` or `'3DES'`.
60
+ :param iv: the initial value.
61
+ """
62
+
63
+ def __init__(self, key, algorithm_id='DES', iv=None):
64
+ self.key = key
65
+ self.key_size = KEY_SIZE_MAP[algorithm_id]
66
+ self.algorithm = ALGORITHM_MAP[algorithm_id]
67
+ self.algorithm_id = algorithm_id
68
+ self.iv = iv or self._random_iv()
69
+
70
+ @property
71
+ def iv_hex(self):
72
+ """The hex-encoded iv."""
73
+ return binascii.hexlify(self.iv)
74
+
75
+ def encrypt(self, text):
76
+ return self._cipher().encrypt(self._padding(text))
77
+
78
+ def decrypt(self, text):
79
+ return self._unpadding(self._cipher().decrypt(text))
80
+
81
+ def _cipher(self):
82
+ return self.algorithm.new(self.key.key[:self.key_size],
83
+ self.algorithm.MODE_CBC,
84
+ self.iv)
85
+
86
+ def _padding(self, text):
87
+ """PKCS5 (PKCS7) padding."""
88
+ num = self.algorithm.block_size - len(text) % self.algorithm.block_size
89
+ return text + struct.pack(b'B' * num, *([num] * num))
90
+
91
+ def _unpadding(self, text):
92
+ """Reverse PKCS5 (PKCS7) padding."""
93
+ num = ord(text[-1:])
94
+ return text[:-num]
95
+
96
+ def _random_iv(self):
97
+ return random_bytes(self.algorithm.block_size)
gntplib/compat.py CHANGED
@@ -1,9 +1,9 @@
1
- """This module makes gntplib compatible with Python 2 and 3."""
2
-
3
- import sys
4
-
5
-
6
- if sys.version_info[0] == 3:
7
- text_type = str
8
- else:
9
- text_type = unicode
1
+ """This module makes gntplib compatible with Python 2 and 3."""
2
+
3
+ import sys
4
+
5
+
6
+ if sys.version_info[0] == 3:
7
+ text_type = str
8
+ else:
9
+ text_type = unicode
gntplib/exceptions.py CHANGED
@@ -1,5 +1,5 @@
1
- """This module provides a number of exceptions."""
2
-
3
-
4
- class GNTPError(Exception):
5
- """Base class for GNTP exception."""
1
+ """This module provides a number of exceptions."""
2
+
3
+
4
+ class GNTPError(Exception):
5
+ """Base class for GNTP exception."""