summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gear/__init__.py30
-rw-r--r--gear/tests/test_gear.py5
-rw-r--r--tox.ini3
3 files changed, 27 insertions, 11 deletions
diff --git a/gear/__init__.py b/gear/__init__.py
index 51c0c91..c561a86 100644
--- a/gear/__init__.py
+++ b/gear/__init__.py
@@ -797,7 +797,11 @@ class BaseClientServer(object):
self.log.debug("Marking %s as disconnected" % conn)
self.connections_condition.acquire()
try:
- jobs = conn.related_jobs.values()
+ # NOTE(notmorgan): In the loop below it is possible to change the
+ # jobs list on the connection. In python 3 .values() is an iter not
+ # a static list, meaning that a change will break the for loop
+ # as the object being iterated on will have changed in size.
+ jobs = list(conn.related_jobs.values())
if conn in self.active_connections:
self.active_connections.remove(conn)
if conn not in self.inactive_connections:
@@ -1105,11 +1109,15 @@ class BaseClientServer(object):
The object may no longer be used after shutdown is called.
"""
- self.log.debug("Beginning shutdown")
- self._shutdown()
- self.log.debug("Beginning cleanup")
- self._cleanup()
- self.log.debug("Finished shutdown")
+ if self.running:
+ self.log.debug("Beginning shutdown")
+ self._shutdown()
+ self.log.debug("Beginning cleanup")
+ self._cleanup()
+ self.log.debug("Finished shutdown")
+ else:
+ self.log.warning("Shutdown called when not currently running. "
+ "Ignoring.")
def _shutdown(self):
# The first part of the shutdown process where all threads
@@ -2346,8 +2354,8 @@ class NonBlockingConnection(Connection):
if e.errno == errno.EAGAIN:
self.log.debug("Write operation on %s would block"
% self)
- raise RetryIOError()
- raise
+ else:
+ raise
finally:
data = data[r:]
if data:
@@ -2679,7 +2687,11 @@ class Server(BaseClientServer):
self.connections_condition.acquire()
self._unregisterConnection(conn)
try:
- jobs = conn.related_jobs.values()
+ # NOTE(notmorgan): In the loop below it is possible to change the
+ # jobs list on the connection. In python 3 .values() is an iter not
+ # a static list, meaning that a change will break the for loop
+ # as the object being iterated on will have changed in size.
+ jobs = list(conn.related_jobs.values())
if conn in self.active_connections:
self.active_connections.remove(conn)
finally:
diff --git a/gear/tests/test_gear.py b/gear/tests/test_gear.py
index d90d99e..6398b9e 100644
--- a/gear/tests/test_gear.py
+++ b/gear/tests/test_gear.py
@@ -287,6 +287,11 @@ class TestClient(tests.BaseTestCase):
acl.revokeGrant('manager')
self.assertFalse(acl.canGrant('manager'))
+ def test_double_shutdown(self):
+ client = gear.Client()
+ client.shutdown()
+ client.shutdown()
+
def load_tests(loader, in_tests, pattern):
return testscenarios.load_tests_apply_scenarios(loader, in_tests, pattern)
diff --git a/tox.ini b/tox.ini
index daf5cc5..34e0e0f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,7 @@
[tox]
minversion = 1.6
skipsdist = True
-envlist = py26,py27,pep8
+envlist = py26,py27,py34,pep8
[testenv]
setenv = VIRTUAL_ENV={envdir}
@@ -14,7 +14,6 @@ commands =
[tox:jenkins]
sitepackages = True
-downloadcache = ~/cache/pip
[testenv:pep8]
commands = flake8