Skip to content

Instantly share code, notes, and snippets.

@sprin
Last active August 29, 2015 13:56
Show Gist options
  • Save sprin/8887860 to your computer and use it in GitHub Desktop.
Save sprin/8887860 to your computer and use it in GitHub Desktop.
Thread Locals Abuse
from threading import local
threadlocal = local()
# foo takes a as an arg, but we can also see it is dependent on x from
# threadlocal if we look in the body.
def foo(a):
return a + threadlocal.x
# bar takes a as an arg, and calls foo on it. Unless we read through the
# body of bar, then trace it to foo, and read the body of foo, we have no
# way of knowing that bar is dependent on x.
def bar(a):
return foo(a)
# A naive test of bar will fail with
# AttributeError: 'thread._local' object has no attribute 'x'
# At least since we are "unsafely" dereferencing the variable, we get an error
# which indicates the dependence on the threadlocal.
def test_bar():
assert bar(1) == 3
# Assuming the test author has read through the entire chain of calls and
# identified all the references to threadlocals, a passing test might be
# written as:
def test_bar2():
# Inject x=2 into foo via threadlocals before calling bar
threadlocal.x = 2
assert bar(1) == 3
# Let's try test_bar again
# That's right! It passes now!
def test_bar3():
assert bar(1) == 3
# Now let's be clever and "safely" get our threadlocals, since
# we wouldn't want to throw an error if a variable in threadlocals is
# missing, would we?
def get_attr(name, default=None):
return getattr(threadlocal, name, default)
def baz():
return get_attr('y')
# Now instead of getting an error to implicate the threadlocal, we get
# an AssertionError! Now we get to hunt for the missing dependency
# without any clues.
def test_baz():
assert baz() == 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment