[Python-checkins] python/dist/src/Lib/test pyclbr_input.py, NONE, 1.1 test_decorators.py, NONE, 1.1 test_parser.py, 1.18, 1.19 test_pyclbr.py, 1.21, 1.22 tokenize_tests.txt, 1.1, 1.2

anthonybaxter at users.sourceforge.net anthonybaxter at users.sourceforge.net
Mon Aug 2 08:10:27 CEST 2004


Update of /cvsroot/python/python/dist/src/Lib/test
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6086/Lib/test

Modified Files:
	test_parser.py test_pyclbr.py tokenize_tests.txt 
Added Files:
	pyclbr_input.py test_decorators.py 
Log Message:
PEP-0318, @decorator-style. In Guido's words:
"@ seems the syntax that everybody can hate equally"
Implementation by Mark Russell, from SF #979728.


--- NEW FILE: pyclbr_input.py ---
"""Test cases for test_pyclbr.py"""

def f(): pass

class Other(object):
    @classmethod
    def foo(c): pass

    def om(self): pass

class B (object):
    def bm(self): pass
    
class C (B):
    foo = Other().foo
    om = Other.om
    
    d = 10

    # XXX: This causes test_pyclbr.py to fail, but only because the
    #      introspection-based is_method() code in the test can't
    #      distinguish between this and a geniune method function like m().
    #      The pyclbr.py module gets this right as it parses the text.
    #
    #f = f
    
    def m(self): pass
    
    @staticmethod
    def sm(self): pass

    @classmethod
    def cm(self): pass

--- NEW FILE: test_decorators.py ---
import unittest
from test import test_support

def funcattrs(**kwds):
    def decorate(func):
        func.__dict__.update(kwds)
        return func
    return decorate

class MiscDecorators (object):
    @staticmethod
    def author(name):
        def decorate(func):
            func.__dict__['author'] = name
            return func
        return decorate

# -----------------------------------------------

class DbcheckError (Exception):
    def __init__(self, exprstr, func, args, kwds):
        # A real version of this would set attributes here
        Exception.__init__(self, "dbcheck %r failed (func=%s args=%s kwds=%s)" %
                           (exprstr, func, args, kwds))
    
    
def dbcheck(exprstr, globals=None, locals=None):
    "Decorator to implement debugging assertions"
    def decorate(func):
        expr = compile(exprstr, "dbcheck-%s" % func.func_name, "eval")
        def check(*args, **kwds):
            if not eval(expr, globals, locals):
                raise DbcheckError(exprstr, func, args, kwds)
            return func(*args, **kwds)
        return check
    return decorate

# -----------------------------------------------

def countcalls(counts):
    "Decorator to count calls to a function"
    def decorate(func):
        name = func.func_name
        counts[name] = 0
        def call(*args, **kwds):
            counts[name] += 1
            return func(*args, **kwds)
        # XXX: Would like to say: call.func_name = func.func_name here
        #      to make nested decorators work in any order, but func_name
        #      is a readonly attribute
        return call
    return decorate

# -----------------------------------------------

def memoize(func):
    saved = {}
    def call(*args):
        try:
            return saved[args]
        except KeyError:
            res = func(*args)
            saved[args] = res
            return res
        except TypeError:
            # Unhashable argument
            return func(*args)
    return call
            
# -----------------------------------------------

class TestDecorators(unittest.TestCase):

    def test_single(self):
        class C(object):
            @staticmethod
            def foo(): return 42
        self.assertEqual(C.foo(), 42)
        self.assertEqual(C().foo(), 42)

    def test_dotted(self):
        decorators = MiscDecorators()
        @decorators.author('Cleese')
        def foo(): return 42
        self.assertEqual(foo(), 42)
        self.assertEqual(foo.author, 'Cleese')

    def test_argforms(self):
        # A few tests of argument passing, as we use restricted form
        # of expressions for decorators.
        
        def noteargs(*args, **kwds):
            def decorate(func):
                setattr(func, 'dbval', (args, kwds))
                return func
            return decorate

        args = ( 'Now', 'is', 'the', 'time' )
        kwds = dict(one=1, two=2)
        @noteargs(*args, **kwds)
        def f1(): return 42
        self.assertEqual(f1(), 42)
        self.assertEqual(f1.dbval, (args, kwds))

        @noteargs('terry', 'gilliam', eric='idle', john='cleese')
        def f2(): return 84
        self.assertEqual(f2(), 84)
        self.assertEqual(f2.dbval, (('terry', 'gilliam'),
                                     dict(eric='idle', john='cleese')))

        @noteargs(1, 2,)
        def f3(): pass
        self.assertEqual(f3.dbval, ((1, 2), {}))

    def test_dbcheck(self):
        @dbcheck('args[1] is not None')
        def f(a, b):
            return a + b
        self.assertEqual(f(1, 2), 3)
        self.assertRaises(DbcheckError, f, 1, None)

    def test_memoize(self):
        # XXX: This doesn't work unless memoize is the last decorator -
        #      see the comment in countcalls.
        counts = {}
        @countcalls(counts) @memoize 
        def double(x):
            return x * 2

        self.assertEqual(counts, dict(double=0))

        # Only the first call with a given argument bumps the call count:
        #
        self.assertEqual(double(2), 4)
        self.assertEqual(counts['double'], 1)
        self.assertEqual(double(2), 4)
        self.assertEqual(counts['double'], 1)
        self.assertEqual(double(3), 6)
        self.assertEqual(counts['double'], 2)

        # Unhashable arguments do not get memoized:
        #
        self.assertEqual(double([10]), [10, 10])
        self.assertEqual(counts['double'], 3)
        self.assertEqual(double([10]), [10, 10])
        self.assertEqual(counts['double'], 4)

    def test_errors(self):
        # Test syntax restrictions - these are all compile-time errors:
        #
        for expr in [ "1+2", "x[3]", "(1, 2)" ]:
            # Sanity check: is expr is a valid expression by itself?
            compile(expr, "testexpr", "exec")
            
            codestr = "@%s\ndef f(): pass" % expr
            self.assertRaises(SyntaxError, compile, codestr, "test", "exec")

        # Test runtime errors

        def unimp(func):
            raise NotImplementedError
        context = dict(nullval=None, unimp=unimp)
        
        for expr, exc in [ ("undef", NameError),
                           ("nullval", TypeError),
                           ("nullval.attr", AttributeError),
                           ("unimp", NotImplementedError)]:
            codestr = "@%s\ndef f(): pass\nassert f() is None" % expr
            code = compile(codestr, "test", "exec")
            self.assertRaises(exc, eval, code, context)

    def test_double(self):
        class C(object):
            @funcattrs(abc=1, xyz="haha")
            @funcattrs(booh=42)
            def foo(self): return 42
        self.assertEqual(C().foo(), 42)
        self.assertEqual(C.foo.abc, 1)
        self.assertEqual(C.foo.xyz, "haha")
        self.assertEqual(C.foo.booh, 42)

    def test_order(self):
        class C(object):
            @funcattrs(abc=1) @staticmethod
            def foo(): return 42
        # This wouldn't work if staticmethod was called first
        self.assertEqual(C.foo(), 42)
        self.assertEqual(C().foo(), 42)

def test_main():
    test_support.run_unittest(TestDecorators)

if __name__=="__main__":
    test_main()

Index: test_parser.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_parser.py,v
retrieving revision 1.18
retrieving revision 1.19
diff -C2 -d -r1.18 -r1.19
*** test_parser.py	19 May 2004 08:20:09 -0000	1.18
--- test_parser.py	2 Aug 2004 06:09:54 -0000	1.19
***************
*** 16,21 ****
          try:
              st2 = parser.sequence2st(t)
!         except parser.ParserError:
!             self.fail("could not roundtrip %r" % s)
  
          self.assertEquals(t, st2.totuple(),
--- 16,21 ----
          try:
              st2 = parser.sequence2st(t)
!         except parser.ParserError, why:
!             self.fail("could not roundtrip %r: %s" % (s, why))
  
          self.assertEquals(t, st2.totuple(),
***************
*** 120,123 ****
--- 120,131 ----
          self.check_suite("def f(a, b, foo=bar, **kw): pass")
  
+         self.check_suite("@staticmethod\n"
+                          "def f(): pass")
+         self.check_suite("@staticmethod\n"
+                          "@funcattrs(x, y)\n"
+                          "def f(): pass")
+         self.check_suite("@funcattrs()\n"
+                          "def f(): pass")
+ 
      def test_import_from_statement(self):
          self.check_suite("from sys.path import *")

Index: test_pyclbr.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_pyclbr.py,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -d -r1.21 -r1.22
*** test_pyclbr.py	18 Jul 2004 00:08:11 -0000	1.21
--- test_pyclbr.py	2 Aug 2004 06:09:54 -0000	1.22
***************
*** 9,12 ****
--- 9,15 ----
  from unittest import TestCase
  
+ StaticMethodType = type(staticmethod(lambda: None))
+ ClassMethodType = type(classmethod(lambda c: None))
+ 
  # This next line triggers an error on old versions of pyclbr.
  
***************
*** 44,52 ****
          self.failUnless(obj.has_key(key))
  
!     def assertEquals(self, a, b, ignore=None):
          ''' succeed iff a == b or a in ignore or b in ignore '''
!         if (ignore == None) or (a in ignore) or (b in ignore): return
! 
!         unittest.TestCase.assertEquals(self, a, b)
  
      def checkModule(self, moduleName, module=None, ignore=()):
--- 47,54 ----
          self.failUnless(obj.has_key(key))
  
!     def assertEqualsOrIgnored(self, a, b, ignore):
          ''' succeed iff a == b or a in ignore or b in ignore '''
!         if a not in ignore and b not in ignore:
!             self.assertEquals(a, b)
  
      def checkModule(self, moduleName, module=None, ignore=()):
***************
*** 63,71 ****
          dict = pyclbr.readmodule_ex(moduleName)
  
!         def ismethod(obj, name):
!             if not  isinstance(obj, MethodType):
!                 return False
!             if obj.im_self is not None:
!                 return False
              objname = obj.__name__
              if objname.startswith("__") and not objname.endswith("__"):
--- 65,84 ----
          dict = pyclbr.readmodule_ex(moduleName)
  
!         def ismethod(oclass, obj, name):
!             classdict = oclass.__dict__
!             if isinstance(obj, FunctionType):
!                 if not isinstance(classdict[name], StaticMethodType):
!                     return False
!             else:
!                 if not  isinstance(obj, MethodType):
!                     return False
!                 if obj.im_self is not None:
!                     if (not isinstance(classdict[name], ClassMethodType) or
!                         obj.im_self is not oclass):
!                         return False
!                 else:
!                     if not isinstance(classdict[name], FunctionType):
!                         return False
! 
              objname = obj.__name__
              if objname.startswith("__") and not objname.endswith("__"):
***************
*** 82,86 ****
                  self.assertEquals(type(py_item), FunctionType)
              else:
!                 self.assertEquals(type(py_item), ClassType)
                  real_bases = [base.__name__ for base in py_item.__bases__]
                  pyclbr_bases = [ getattr(base, 'name', base)
--- 95,99 ----
                  self.assertEquals(type(py_item), FunctionType)
              else:
!                 self.failUnless(isinstance(py_item, (ClassType, type)))
                  real_bases = [base.__name__ for base in py_item.__bases__]
                  pyclbr_bases = [ getattr(base, 'name', base)
***************
*** 95,99 ****
                  actualMethods = []
                  for m in py_item.__dict__.keys():
!                     if ismethod(getattr(py_item, m), m):
                          actualMethods.append(m)
                  foundMethods = []
--- 108,112 ----
                  actualMethods = []
                  for m in py_item.__dict__.keys():
!                     if ismethod(py_item, getattr(py_item, m), m):
                          actualMethods.append(m)
                  foundMethods = []
***************
*** 108,112 ****
                      self.assertEquals(py_item.__module__, value.module)
  
!                     self.assertEquals(py_item.__name__, value.name, ignore)
                      # can't check file or lineno
                  except:
--- 121,126 ----
                      self.assertEquals(py_item.__module__, value.module)
  
!                     self.assertEqualsOrIgnored(py_item.__name__, value.name,
!                                                ignore)
                      # can't check file or lineno
                  except:
***************
*** 133,136 ****
--- 147,156 ----
          self.checkModule('difflib')
  
+     def test_decorators(self):
+         # XXX: See comment in pyclbr_input.py for a test that would fail
+         #      if it were not commented out.
+         #
+         self.checkModule('test.pyclbr_input')
+         
      def test_others(self):
          cm = self.checkModule

Index: tokenize_tests.txt
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/tokenize_tests.txt,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** tokenize_tests.txt	12 May 2003 19:42:04 -0000	1.1
--- tokenize_tests.txt	2 Aug 2004 06:09:54 -0000	1.2
***************
*** 174,175 ****
--- 174,178 ----
  x = sys.modules['time'].time()
  
+ @staticmethod
+ def foo(): pass
+ 



More information about the Python-checkins mailing list