From 46fcc461b6d50b0be42754ac1801b16002f76c94 Mon Sep 17 00:00:00 2001 From: Morgan Fainberg Date: Fri, 27 May 2016 17:11:53 -0700 Subject: [PATCH] Do not change object size when iterating In `gear.Server._lostConnection()` the jobs list pulls .values() from `conn.related_jobs`, in `gear.server._removeJob()` it is possible to change the conn.related_jobs dictionary which will cause a `RuntimeError: dictionary changed size during iteration` exception to be raised in python 3 since .values() is an iterator instead of a rendered list() like in python 2. This RuntimeError is eliminated by forcing the python 2 behavior by wrapping the `.values()` call to be wrapped into an explicit list. Change-Id: I730473f3200a427cce774df534f1ff4958866dac --- gear/__init__.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gear/__init__.py b/gear/__init__.py index 7fccc34..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: @@ -2683,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: