[Python-checkins] CVS: python/dist/src/Lib doctest.py,1.17,1.18

Tim Peters tim_one@users.sourceforge.net
Mon, 01 Oct 2001 20:53:43 -0700


Update of /cvsroot/python/python/dist/src/Lib
In directory usw-pr-cvs1:/tmp/cvs-serv5055/python/Lib

Modified Files:
	doctest.py 
Log Message:
SF patch [#466616] Exclude imported items from doctest,
from Tim Hochberg.  Also mucho fiddling to change the way doctest
determines whether a thing is a function, module or class.  Under 2.2,
this really requires the functions in inspect.py (e.g., types.ClassType
is close to meaningless now, if not outright misleading).


Index: doctest.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/doctest.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -C2 -d -r1.17 -r1.18
*** doctest.py	2001/08/18 00:05:50	1.17
--- doctest.py	2001/10/02 03:53:41	1.18
***************
*** 49,56 ****
  
  + f.__doc__ for all functions f in M.__dict__.values(), except those
!   with private names.
  
  + C.__doc__ for all classes C in M.__dict__.values(), except those with
!   private names.
  
  + If M.__test__ exists and "is true", it must be a dict, and
--- 49,56 ----
  
  + f.__doc__ for all functions f in M.__dict__.values(), except those
!   with private names and those defined in other modules.
  
  + C.__doc__ for all classes C in M.__dict__.values(), except those with
!   private names and those defined in other modules.
  
  + If M.__test__ exists and "is true", it must be a dict, and
***************
*** 76,101 ****
  of a Tester instance).
  
- Warning:  imports can cause trouble; e.g., if you do
- 
- from XYZ import XYZclass
- 
- then XYZclass is a name in M.__dict__ too, and doctest has no way to know
- that XYZclass wasn't *defined* in M.  So it may try to execute the examples
- in XYZclass's docstring, and those in turn may require a different set of
- globals to work correctly.  I prefer to do "import *"- friendly imports,
- a la
- 
- import XYY
- _XYZclass = XYZ.XYZclass
- del XYZ
- 
- or (Python 2.0)
- 
- from XYZ import XYZclass as _XYZclass
- 
- and then the leading underscore stops testmod from going nuts.  You may
- prefer the method in the next section.
- 
- 
  WHAT'S THE EXECUTION CONTEXT?
  
--- 76,79 ----
***************
*** 304,314 ****
  import __future__
  
- import types
- _FunctionType = types.FunctionType
- _ClassType    = types.ClassType
- _ModuleType   = types.ModuleType
- _StringType   = types.StringType
- del types
- 
  import re
  PS1 = ">>>"
--- 282,285 ----
***************
*** 320,323 ****
--- 291,300 ----
  del re
  
+ from types import StringTypes as _StringTypes
+ 
+ from inspect import isclass    as _isclass
+ from inspect import isfunction as _isfunction
+ from inspect import ismodule   as _ismodule
+ 
  # Extract interactive examples from a string.  Return a list of triples,
  # (source, outcome, lineno).  "source" is the source code, and ends
***************
*** 575,578 ****
--- 552,564 ----
      return base[:1] == "_" and not base[:2] == "__" == base[-2:]
  
+ # Determine if a class of function was defined in the given module.
+ 
+ def _from_module(module, object):
+     if _isfunction(object):
+         return module.__dict__ is object.func_globals
+     if _isclass(object):
+         return module.__name__ == object.__module__
+     raise ValueError("object must be a class or function")
+ 
  class Tester:
      """Class Tester -- runs docstring examples and accumulates stats.
***************
*** 591,597 ****
          object.__name__) for logging.  Return (#failures, #tries).
  
!     rundict(d, name)
          Search for examples in docstrings in all of d.values(); use name
!         for logging.  Return (#failures, #tries).
  
      run__test__(d, name)
--- 577,584 ----
          object.__name__) for logging.  Return (#failures, #tries).
  
!     rundict(d, name, module=None)
          Search for examples in docstrings in all of d.values(); use name
!         for logging.  Exclude functions and classes not defined in module
!         if specified.  Return (#failures, #tries).
  
      run__test__(d, name)
***************
*** 665,669 ****
          if mod is None and globs is None:
              raise TypeError("Tester.__init__: must specify mod or globs")
!         if mod is not None and type(mod) is not _ModuleType:
              raise TypeError("Tester.__init__: mod must be a module; " +
                              `mod`)
--- 652,656 ----
          if mod is None and globs is None:
              raise TypeError("Tester.__init__: must specify mod or globs")
!         if mod is not None and not _ismodule(mod):
              raise TypeError("Tester.__init__: mod must be a module; " +
                              `mod`)
***************
*** 760,764 ****
              print f, "of", t, "examples failed in", name + ".__doc__"
          self.__record_outcome(name, f, t)
!         if type(object) is _ClassType:
              f2, t2 = self.rundict(object.__dict__, name)
              f = f + f2
--- 747,751 ----
              print f, "of", t, "examples failed in", name + ".__doc__"
          self.__record_outcome(name, f, t)
!         if _isclass(object):
              f2, t2 = self.rundict(object.__dict__, name)
              f = f + f2
***************
*** 766,792 ****
          return f, t
  
!     def rundict(self, d, name):
          """
!         d. name -> search for docstring examples in all of d.values().
  
          For k, v in d.items() such that v is a function or class,
          do self.rundoc(v, name + "." + k).  Whether this includes
          objects with private names depends on the constructor's
!         "isprivate" argument.
          Return aggregate (#failures, #examples).
  
!         >>> def _f():
!         ...    '''>>> assert 1 == 1
!         ...    '''
!         >>> def g():
          ...    '''>>> assert 2 != 1
          ...    '''
!         >>> d = {"_f": _f, "g": g}
          >>> t = Tester(globs={}, verbose=0)
!         >>> t.rundict(d, "rundict_test")  # _f is skipped
!         (0, 1)
          >>> t = Tester(globs={}, verbose=0, isprivate=lambda x,y: 0)
!         >>> t.rundict(d, "rundict_test_pvt")  # both are searched
!         (0, 2)
          """
  
--- 753,809 ----
          return f, t
  
!     def rundict(self, d, name, module=None):
          """
!         d, name, module=None -> search for docstring examples in d.values().
  
          For k, v in d.items() such that v is a function or class,
          do self.rundoc(v, name + "." + k).  Whether this includes
          objects with private names depends on the constructor's
!         "isprivate" argument.  If module is specified, functions and
!         classes that are not defined in module are excluded.
          Return aggregate (#failures, #examples).
  
!         Build and populate two modules with sample functions to test that
!         exclusion of external functions and classes works.
! 
!         >>> import new
!         >>> m1 = new.module('_m1')
!         >>> m2 = new.module('_m2')
!         >>> test_data = \"""
!         ... def f():
!         ...     '''>>> assert 1 == 1
!         ...     '''
!         ... def g():
          ...    '''>>> assert 2 != 1
          ...    '''
!         ... class H:
!         ...    '''>>> assert 2 > 1
!         ...    '''
!         ...    def bar(self):
!         ...        '''>>> assert 1 < 2
!         ...        '''
!         ... \"""
!         >>> exec test_data in m1.__dict__
!         >>> exec test_data in m2.__dict__
! 
!         Tests that objects outside m1 are excluded:
! 
!         >>> d = {"_f": m1.f,  "g": m1.g,  "h": m1.H,
!         ...      "f2": m2.f, "g2": m2.g, "h2": m2.H}
          >>> t = Tester(globs={}, verbose=0)
!         >>> t.rundict(d, "rundict_test", m1)  # _f, f2 and g2 and h2 skipped
!         (0, 3)
! 
!         Again, but with a custom isprivate function allowing _f:
! 
          >>> t = Tester(globs={}, verbose=0, isprivate=lambda x,y: 0)
!         >>> t.rundict(d, "rundict_test_pvt", m1)  # Only f2, g2 and h2 skipped
!         (0, 4)
! 
!         And once more, not excluding stuff outside m1:
! 
!         >>> t = Tester(globs={}, verbose=0, isprivate=lambda x,y: 0)
!         >>> t.rundict(d, "rundict_test_pvt")  # None are skipped.
!         (0, 8)
          """
  
***************
*** 801,805 ****
          for thisname in names:
              value = d[thisname]
!             if type(value) in (_FunctionType, _ClassType):
                  f2, t2 = self.__runone(value, name + "." + thisname)
                  f = f + f2
--- 818,824 ----
          for thisname in names:
              value = d[thisname]
!             if _isfunction(value) or _isclass(value):
!                 if module and not _from_module(module, value):
!                     continue
                  f2, t2 = self.__runone(value, name + "." + thisname)
                  f = f + f2
***************
*** 826,832 ****
                  v = d[k]
                  thisname = prefix + k
!                 if type(v) is _StringType:
                      f, t = self.runstring(v, thisname)
!                 elif type(v) in (_FunctionType, _ClassType):
                      f, t = self.rundoc(v, thisname)
                  else:
--- 845,851 ----
                  v = d[k]
                  thisname = prefix + k
!                 if type(v) in _StringTypes:
                      f, t = self.runstring(v, thisname)
!                 elif _isfunction(v) or _isclass(v):
                      f, t = self.rundoc(v, thisname)
                  else:
***************
*** 1013,1017 ****
      global master
  
!     if type(m) is not _ModuleType:
          raise TypeError("testmod: module required; " + `m`)
      if name is None:
--- 1032,1036 ----
      global master
  
!     if not _ismodule(m):
          raise TypeError("testmod: module required; " + `m`)
      if name is None: