-------------------------------------------- On Thu, 1/16/14, Peter Otten <__pete...@web.de> wrote:
Subject: Re: Is it possible to get string from function? To: python-list@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() -- https://mail.python.org/mailman/listinfo/python-list