summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYouri Ackx <varia@ackx.net>2020-10-02 16:57:28 +0200
committerYouri Ackx <varia@ackx.net>2020-10-02 16:57:28 +0200
commit74df4c141934c01b3b2f7e27f8438b07b1c12b63 (patch)
tree2692b8685d133018c07daa5d2cdfb877f7464e8b
parentd841e82241a209573a1da638aa64921c7e65b811 (diff)
parentbf5f8f0968552670744fee7960419b8aea27c5b5 (diff)
downloadblinker-74df4c141934c01b3b2f7e27f8438b07b1c12b63.tar.gz
Merge branch 'master' into feature/send-async
# Conflicts: # CHANGES
-rw-r--r--.travis.yml33
-rw-r--r--CHANGES5
-rw-r--r--README.md42
-rw-r--r--blinker/_saferef.py2
-rw-r--r--blinker/_utilities.py14
-rw-r--r--blinker/base.py27
-rw-r--r--docs/source/index.rst4
-rw-r--r--setup.cfg3
-rw-r--r--setup.py15
-rw-r--r--tests/test_signals.py21
-rw-r--r--tox.ini2
11 files changed, 92 insertions, 76 deletions
diff --git a/.travis.yml b/.travis.yml
index 952e3d6..995721e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,31 @@
language: python
-python:
- - "2.6"
- - "2.7"
- - "3.2"
- - "3.3"
- - "3.4"
+
+matrix:
+ include:
+ - python: 2.7
+ os: linux
+ dist: trusty
+ env: TOXENV=py27
+ - python: pypy
+ os: linux
+ dist: trusty
+ env: TOXENV=pypy
+ - python: 3.5
+ os: linux
+ dist: trusty
+ env: TOXENV=py35
+ - python: 3.6
+ os: linux
+ dist: trusty
+ env: TOXENV=py36
+ - python: 3.7
+ os: linux
+ dist: xenial
+ env: TOXENV=py37
+ - python: 3.8
+ os: linux
+ dist: xenial
+ env: TOXENV=py38
# command to install dependencies
install:
diff --git a/CHANGES b/CHANGES
index 880c314..75f790e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -5,6 +5,11 @@ Blinker Changelog
Version 1.5dev
--------------
+Not yet released.
+
+- Verified Python 3.7 support (no changes needed).
+- Verified Python 3.6 support (no changes needed).
+- Verified Python 3.5 support (no changes needed).
- Added Signal.send_async, dispatching to an arbitrary mix of connected
coroutines and receiver functions.
diff --git a/README.md b/README.md
index fcdccdc..907a3ec 100644
--- a/README.md
+++ b/README.md
@@ -9,31 +9,33 @@ interested parties to subscribe to events, or "signals".
Signal receivers can subscribe to specific senders or receive signals
sent by any sender.
- >>> from blinker import signal
- >>> started = signal('round-started')
- >>> def each(round):
- ... print "Round %s!" % round
- ...
- >>> started.connect(each)
-
- >>> def round_two(round):
- ... print "This is round two."
- ...
- >>> started.connect(round_two, sender=2)
-
- >>> for round in range(1, 4):
- ... started.send(round)
- ...
- Round 1!
- Round 2!
- This is round two.
- Round 3!
+```python
+>>> from blinker import signal
+>>> started = signal('round-started')
+>>> def each(round):
+... print "Round %s!" % round
+...
+>>> started.connect(each)
+
+>>> def round_two(round):
+... print "This is round two."
+...
+>>> started.connect(round_two, sender=2)
+
+>>> for round in range(1, 4):
+... started.send(round)
+...
+Round 1!
+Round 2!
+This is round two.
+Round 3!
+```
See the [Blinker documentation](https://pythonhosted.org/blinker/) for more information.
## Requirements
-Blinker requires Python 2.4 or higher, Python 3.0 or higher, or Jython 2.5 or higher.
+Blinker requires Python 2.7, Python 3.4 or higher, or Jython 2.7 or higher.
## Changelog Summary
diff --git a/blinker/_saferef.py b/blinker/_saferef.py
index 269e362..081173d 100644
--- a/blinker/_saferef.py
+++ b/blinker/_saferef.py
@@ -198,7 +198,7 @@ class BoundMethodWeakref(object):
def __str__(self):
"""Give a friendly representation of the object."""
- return "%s(%s.%s)" % (
+ return "{}({}.{})".format(
self.__class__.__name__,
self.self_name,
self.func_name,
diff --git a/blinker/_utilities.py b/blinker/_utilities.py
index 056270d..133c57a 100644
--- a/blinker/_utilities.py
+++ b/blinker/_utilities.py
@@ -36,7 +36,7 @@ except:
def __reduce__(self):
if self.default_factory is None:
- args = tuple()
+ args = ()
else:
args = self.default_factory,
return type(self), args, None, None, self.items()
@@ -53,20 +53,10 @@ except:
copy.deepcopy(self.items()))
def __repr__(self):
- return 'defaultdict(%s, %s)' % (self.default_factory,
+ return 'defaultdict({}, {})'.format(self.default_factory,
dict.__repr__(self))
-try:
- from contextlib import contextmanager
-except ImportError:
- def contextmanager(fn):
- def oops(*args, **kw):
- raise RuntimeError("Python 2.5 or above is required to use "
- "context managers.")
- oops.__name__ = fn.__name__
- return oops
-
class _symbol(object):
def __init__(self, name):
diff --git a/blinker/base.py b/blinker/base.py
index 67aa41d..3ff0984 100644
--- a/blinker/base.py
+++ b/blinker/base.py
@@ -8,12 +8,12 @@ each manages its own receivers and message emission.
The :func:`signal` function provides singleton behavior for named signals.
"""
+from contextlib import contextmanager
from warnings import warn
from weakref import WeakValueDictionary
from blinker._utilities import (
WeakTypes,
- contextmanager,
defaultdict,
hashable_identity,
lazy_property,
@@ -250,6 +250,14 @@ class Signal(object):
:param \*\*kwargs: Data to be sent to receivers.
"""
+ if not self.receivers:
+ # Ensure correct signature even on no-op sends, disable with -O
+ # for lowest possible cost.
+ if __debug__ and sender and len(sender) > 1:
+ raise TypeError('send() accepts only one positional '
+ 'argument, %s given' % len(sender))
+ return []
+
# Using '*sender' rather than 'sender=None' allows 'sender' to be
# used as a keyword argument- i.e. it's an invisible name in the
# function signature.
@@ -260,11 +268,8 @@ class Signal(object):
'%s given' % len(sender))
else:
sender = sender[0]
- if not self.receivers:
- return []
- else:
- return [(receiver, receiver(sender, **kwargs))
- for receiver in self.receivers_for(sender)]
+ return [(receiver, receiver(sender, **kwargs))
+ for receiver in self.receivers_for(sender)]
def send_async(self, *sender, **kwargs):
"""Send and collect results from connected functions and coroutines.
@@ -360,9 +365,9 @@ class Signal(object):
self._by_receiver[receiver_id].discard(sender_id)
def _cleanup_bookkeeping(self):
- """Prune unused sender/receiver bookeeping. Not threadsafe.
+ """Prune unused sender/receiver bookkeeping. Not threadsafe.
- Connecting & disconnecting leave behind a small amount of bookeeping
+ Connecting & disconnecting leave behind a small amount of bookkeeping
for the receiver and sender values. Typical workloads using Blinker,
for example in most web apps, Flask, CLI scripts, etc., are not
adversely affected by this bookkeeping.
@@ -370,10 +375,10 @@ class Signal(object):
With a long-running Python process performing dynamic signal routing
with high volume- e.g. connecting to function closures, "senders" are
all unique object instances, and doing all of this over and over- you
- may see memory usage will grow due to extraneous bookeeping. (An empty
+ may see memory usage will grow due to extraneous bookkeeping. (An empty
set() for each stale sender/receiver pair.)
- This method will prune that bookeeping away, with the caveat that such
+ This method will prune that bookkeeping away, with the caveat that such
pruning is not threadsafe. The risk is that cleanup of a fully
disconnected receiver/sender pair occurs while another thread is
connecting that same pair. If you are in the highly dynamic, unique
@@ -422,7 +427,7 @@ class NamedSignal(Signal):
def __repr__(self):
base = Signal.__repr__(self)
- return "%s; %r>" % (base[:-1], self.name)
+ return "{}; {!r}>".format(base[:-1], self.name)
class Namespace(dict):
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 28976d8..bdb40ef 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -16,8 +16,8 @@ The core of Blinker is quite small but provides powerful features:
- thread safety
Blinker was written by Jason Kirtand and is provided under the MIT
-License. The library supports Python 2.4 or later; Python 3.0 or later;
-or Jython 2.5 or later; or PyPy 1.6 or later.
+License. The library supports Python 2.7 and Python 3.5 or later;
+or Jython 2.7 or later; or PyPy 2.7 or later.
Decoupling With Named Signals
diff --git a/setup.cfg b/setup.cfg
index a0af19a..d47317b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,5 @@
[upload_docs]
upload-dir = docs/html
+
+[bdist_wheel]
+universal = 1
diff --git a/setup.py b/setup.py
index 8655223..ccfd67a 100644
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,8 @@ setup(name="blinker",
keywords='signal emit events broadcast',
long_description=readme,
license='MIT License',
- url='http://pythonhosted.org/blinker/',
+ url='https://pythonhosted.org/blinker/',
+ python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
@@ -24,16 +25,12 @@ setup(name="blinker",
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.4',
- 'Programming Language :: Python :: 2.5',
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.0',
- 'Programming Language :: Python :: 3.1',
- 'Programming Language :: Python :: 3.2',
- 'Programming Language :: Python :: 3.3',
- 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
'Topic :: Software Development :: Libraries',
'Topic :: Utilities',
],
diff --git a/tests/test_signals.py b/tests/test_signals.py
index e651465..9771e40 100644
--- a/tests/test_signals.py
+++ b/tests/test_signals.py
@@ -53,10 +53,10 @@ def test_meta_connect():
sig = blinker.Signal()
sig.connect(receiver)
- assert sentinel == [dict(sender=sig,
- receiver_arg=receiver,
- sender_arg=blinker.ANY,
- weak_arg=True)]
+ assert sentinel == [{'sender': sig,
+ 'receiver_arg': receiver,
+ 'sender_arg': blinker.ANY,
+ 'weak_arg': True}]
blinker.receiver_connected._clear_state()
@@ -83,7 +83,7 @@ def _test_signal_signals(sender):
expected = ('receiver_connected',
sig,
- dict(receiver=receiver, sender=sender, weak=weak))
+ {'receiver': receiver, 'sender': sender, 'weak': weak})
assert sentinel[-1] == expected
@@ -92,14 +92,14 @@ def _test_signal_signals(sender):
expected = ('receiver_disconnected',
sig,
- dict(receiver=receiver1, sender=sender))
+ {'receiver': receiver1, 'sender': sender})
assert sentinel[-1] == expected
# disconnect from ANY and all senders (implicit disconnect signature)
sig.disconnect(receiver2)
assert sentinel[-1] == ('receiver_disconnected',
sig,
- dict(receiver=receiver2, sender=blinker.ANY))
+ {'receiver': receiver2, 'sender': blinker.ANY})
def test_signal_signals_any_sender():
@@ -491,10 +491,3 @@ def test_named_blinker():
def values_are_empty_sets_(dictionary):
for val in dictionary.values():
assert val == set()
-
-if sys.version_info < (2, 5):
- def test_context_manager_warning():
- sig = blinker.Signal()
- receiver = lambda sender: None
-
- assert_raises(RuntimeError, sig.connected_to, receiver)
diff --git a/tox.ini b/tox.ini
index 0f9a8c5..a6e07ae 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py25,py26,py27,py30,py31,py32,py33,py34,jython
+envlist = py27,py35,py36,py37,py38,jython
[testenv]
deps=nose