Last active
August 29, 2015 13:56
-
-
Save sprin/8887860 to your computer and use it in GitHub Desktop.
Thread Locals Abuse
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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