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