You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have never (knowingly) been tripped up by it, but I noticed this while reviewing #137...
gapipy.client.default_config is basically used as a default argument to client initialization and some of its content are (mutable) dicts. Because of that it's possible to accidentally "share" data there -- you might have some surprises if you instantiate multiple clients in the same process with different configs.
To demonstrate...
>>>fromgapipyimportClient>>># Let's make a client and enable connection pooling>>>c1=Client(connection_pool_options={"enable": True})
>>>c1.connection_pool_options["enable"]
True>>># Ok, let's make another WITHOUT connection pooling>>>c2=Client(connection_pool_options={"enable": False})
>>>c2.connection_pool_options["enable"]
False>>># Cool, now let's see what that first client is up to, it was True to begin with...>>>c1.connection_pool_options["enable"]
False>>>c1.connection_pool_optionsisc2.connection_pool_optionsTrue
I suspect the crux of the issue is probably twofold:
new client instances get direct references to stuff in default_config and some of those things are mutable
Client.__init__ explicitly mutates the default connection_pool_options dict when some extra connection pool configs have been passed
I bet you could have a similar issue with the global http headers config, except that Client.__init__ doesn't mutate that one you'd have to have a series of events like:
instantiate a client
instantiate another client
mutate one of their client.global_http_headers and the other client is affected because they both shared the same default value
(Pretty sure I had a hand in both of those connection-pool-options and global-http-headers things 🤦 oops)
I haven't taken a run at writing tests for it yet, but I wonder if the fix is simply:
update get_config to copy.deepcopy (or similar) the value it gets from default_config before returning it, and
use get_config (instead of direct dict access) when getting "connection_pool_options" out of default_config
We could also take other approaches like:
Client.__init__ should deepcopy the default dict before yanking stuff out, or
the default dict should be returned from a function instead of existing at at module level, or
something else entirely 🤷
The text was updated successfully, but these errors were encountered:
jonprindiville
changed the title
Client instances can share config because default_config is essentially a mutable default arg to __init__
Client instances can share config because default_config contains mutable values
Oct 20, 2021
I have never (knowingly) been tripped up by it, but I noticed this while reviewing #137...
gapipy.client.default_config
is basically used as a default argument to client initialization and some of its content are (mutable) dicts. Because of that it's possible to accidentally "share" data there -- you might have some surprises if you instantiate multiple clients in the same process with different configs.To demonstrate...
I suspect the crux of the issue is probably twofold:
Client.__init__
explicitly mutates the defaultconnection_pool_options
dict when some extra connection pool configs have been passedI bet you could have a similar issue with the global http headers config, except that
Client.__init__
doesn't mutate that one you'd have to have a series of events like:client.global_http_headers
and the other client is affected because they both shared the same default value(Pretty sure I had a hand in both of those connection-pool-options and global-http-headers things 🤦 oops)
I haven't taken a run at writing tests for it yet, but I wonder if the fix is simply:
get_config
tocopy.deepcopy
(or similar) the value it gets fromdefault_config
before returning it, andget_config
(instead of direct dict access) when getting"connection_pool_options"
out ofdefault_config
We could also take other approaches like:
Client.__init__
should deepcopy the default dict before yanking stuff out, orThe text was updated successfully, but these errors were encountered: