diff options
-rw-r--r-- | gear/__init__.py | 30 | ||||
-rw-r--r-- | gear/tests/test_gear.py | 5 | ||||
-rw-r--r-- | tox.ini | 3 |
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) @@ -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 |