Is it possible to get string from function?
Albert-Jan Roskam
fomcl at yahoo.com
Thu Jan 16 05:59:42 EST 2014
--------------------------------------------
On Thu, 1/16/14, Peter Otten <__peter__ at web.de> wrote:
Subject: Re: Is it possible to get string from function?
To: python-list at python.org
Date: Thursday, January 16, 2014, 9:52 AM
Roy Smith wrote:
> I realize the subject line is kind of meaningless, so
let me explain :-)
>
> I've got some unit tests that look like:
>
> class Foo(TestCase):
> def test_t1(self):
> RECEIPT = "some string"
>
> def test_t2(self):
> RECEIPT = "some other string"
>
> def test_t3(self):
> RECEIPT = "yet a third string"
>
> and so on. It's important that the strings be
mutually unique. In the
> example above, it's trivial to look at them and observe
that they're all
> different, but in real life, the strings are about 2500
characters long,
> hex-encoded. It even turns out that a couple of
the strings are
> identical in the first 1000 or so characters, so it's
not trivial to do
> by visual inspection.
>
> So, I figured I would write a meta-test, which used
introspection to
> find all the methods in the class, extract the strings
from them (they
> are all assigned to a variable named RECEIPT), and
check to make sure
> they're all different.
>
> Is it possible to do that? It is straight-forward
using the inspect
> module to discover the methods, but I don't see any way
to find what
> strings are assigned to a variable with a given
name. Of course, that
> assignment doesn't even happen until the function is
executed, so
> perhaps what I want just isn't possible?
>
> It turns out, I solved the problem with more mundane
tools:
>
> grep 'RECEIPT = ' test.py | sort | uniq -c
>
> and I could have also solved the problem by putting all
the strings in a
> dict and having the functions pull them out of
there. But, I'm still
> interested in exploring if there is any way to do this
with
> introspection, as an academic exercise.
Instead of using introspection you could make it explicit
with a decorator:
$ cat unique_receipt.py
import functools
import sys
import unittest
_receipts = {}
def unique_receipt(receipt):
def deco(f):
if receipt in _receipts:
raise ValueError(
"Duplicate receipt {!r} in \n {} and \n
{}".format(
receipt, _receipts[receipt], f))
_receipts[receipt] = f
@functools.wraps(f)
def g(self):
return f(self,
receipt)
return g
return deco
class Foo(unittest.TestCase):
@unique_receipt("foo")
def test_t1(self, RECEIPT):
pass
@unique_receipt("bar")
def test_t2(self, RECEIPT):
pass
@unique_receipt("foo")
def test_t3(self, RECEIPT):
pass
if __name__ == "__main__":
unittest.main()
$ python unique_receipt.py
Traceback (most recent call last):
File "unique_receipt.py", line 19, in <module>
class Foo(unittest.TestCase):
File "unique_receipt.py", line 28, in Foo
@unique_receipt("foo")
File "unique_receipt.py", line 11, in deco
receipt, _receipts[receipt], f))
ValueError: Duplicate receipt 'foo' in
<function test_t1 at 0x7fc8714af5f0> and
<function test_t3 at 0x7fc8714af7d0>
============> Very cool approach. Question, though: what would be wrong with the following approach:
import unittest
class Test(unittest.TestCase):
receipts = {}
def unique_value(self, k, v):
assert Test.receipts.get(k) is None, "Duplicate: %s" % v
Test.receipts[k] = v
def test_a(self):
self.unique_value("large_value", "foo")
def test_b(self):
self.unique_value("large_value", "bar") # oh no, a duplicate!
def test_c(self):
self.unique_value("another_large_value", "blah")
unittest.main()
More information about the Python-list
mailing list