From: <fwi...@us...> - 2009-01-08 00:32:26
|
Revision: 5873 http://jython.svn.sourceforge.net/jython/?rev=5873&view=rev Author: fwierzbicki Date: 2009-01-08 00:32:17 +0000 (Thu, 08 Jan 2009) Log Message: ----------- Merged revisions 5842-5847,5854,5857-5859,5863-5865,5869 via svnmerge from https://jython.svn.sourceforge.net/svnroot/jython/trunk/jython ........ r5842 | cgroves | 2009-01-04 17:15:09 -0500 (Sun, 04 Jan 2009) | 5 lines Split java subclassing tests out of test_java_integration into test_java_subclasses, move unduplicated bits of test_jsubclass into test_java_subclasses. ........ r5843 | cgroves | 2009-01-04 18:06:27 -0500 (Sun, 04 Jan 2009) | 1 line Add tests that have been failing or skipping for the past few months to the expected lists ........ r5844 | cgroves | 2009-01-04 18:20:34 -0500 (Sun, 04 Jan 2009) | 1 line One more longstanding skip ........ r5845 | cgroves | 2009-01-04 22:56:25 -0500 (Sun, 04 Jan 2009) | 17 lines test292 - Moved to test_java_integration test293 - Importing no longer auto-imports submodules; deleted test294 - Moved to test_java_subclasses test295 - Moved to test_traceback test296 - Moved to test_import_jy test297,301,310,313,314,315,317 - Testing jythonc; deleted test298 - Moved to test_import_jy test299,300 - Tested by test_file test303 - Moved to test_java_visibility test307,308 - Moved to test_zipimport_jy test309 - Tested by test_scope test311 - Already disabled; deleted test312 - Moved to test_sax_jy test316 - Moved to test_java_integration test318 - Tested by test_syntax test319 - Moved to test_java_visibility ........ r5846 | cgroves | 2009-01-05 02:08:51 -0500 (Mon, 05 Jan 2009) | 1 line From http://svn.python.org/projects/python/branches/release25-maint/Lib/test/test_doctest.py@59127 ........ r5847 | cgroves | 2009-01-05 02:12:43 -0500 (Mon, 05 Jan 2009) | 10 lines test302 - Move to test_pep263_jy This adds a check for the encoding declared by the source file actually matching up with what we were getting out of it, and switches the default encoding to ascii to follow CPython. CPython assumes utf-8 in some single compilation contexts, and this uses the same parser algorithm everywhere, so I made a small change to test_doctest since Jython is throwing a SyntaxError on utf-8 strings to a single compilation. ........ r5854 | amak | 2009-01-05 14:47:25 -0500 (Mon, 05 Jan 2009) | 2 lines Fixed a bug where connect timeouts were not being honoured when set through socket.setdefaulttimeout() http://bugs.jython.org/issue1218 ........ r5857 | fwierzbicki | 2009-01-05 21:11:04 -0500 (Mon, 05 Jan 2009) | 2 lines Remove some unused methods. ........ r5858 | fwierzbicki | 2009-01-06 15:57:41 -0500 (Tue, 06 Jan 2009) | 4 lines Making the package names point to the raw original package names in source and making the jarjar step process everything in one step so the package mangling happens on our source as well as the included jars for jython-complete.jar. ........ r5859 | otmarhumbel | 2009-01-06 16:58:40 -0500 (Tue, 06 Jan 2009) | 2 lines - using ${dist.dir} for both jython.jar and jython-complete.jar - no unjar of jarjar.jar (since it does not exist any more) ........ r5863 | otmarhumbel | 2009-01-07 02:35:05 -0500 (Wed, 07 Jan 2009) | 2 lines - added asm and constantine .jar files to the eclipse build path - jarjar directory is not needed any more ........ r5864 | otmarhumbel | 2009-01-07 03:08:00 -0500 (Wed, 07 Jan 2009) | 5 lines 1) exlude jython.jar from the installation this makes the installer autotests pass again 2) do not include the /Lib files into jython-complete.jar once issue #1214 is fixed, 'java -jar jython-complete.jar' will run for all installation types (for now, set the -Dpython.home variable if not in standalone mode) ........ r5865 | otmarhumbel | 2009-01-07 03:28:57 -0500 (Wed, 07 Jan 2009) | 1 line preparation for an easy rename of the jython .jar files ........ r5869 | cgroves | 2009-01-07 13:12:46 -0500 (Wed, 07 Jan 2009) | 1 line Use the path to the imported item as __file__, not the package path ........ Modified Paths: -------------- branches/jy3k/.classpath branches/jy3k/Lib/os.py branches/jy3k/Lib/socket.py branches/jy3k/Lib/test/regrtest.py branches/jy3k/Lib/test/test_classpathimporter.py branches/jy3k/Lib/test/test_import_jy.py branches/jy3k/Lib/test/test_java_integration.py branches/jy3k/Lib/test/test_java_visibility.py branches/jy3k/Lib/test/test_socket.py branches/jy3k/Lib/test/test_traceback.py branches/jy3k/Lib/test/test_traceback_jy.py branches/jy3k/build.xml branches/jy3k/src/org/python/antlr/GrammarActions.java branches/jy3k/src/org/python/compiler/AdapterMaker.java branches/jy3k/src/org/python/compiler/ClassFile.java branches/jy3k/src/org/python/compiler/Code.java branches/jy3k/src/org/python/compiler/CodeCompiler.java branches/jy3k/src/org/python/compiler/Constant.java branches/jy3k/src/org/python/compiler/Module.java branches/jy3k/src/org/python/compiler/ProxyMaker.java branches/jy3k/src/org/python/core/APIReader.java branches/jy3k/src/org/python/core/BytecodeLoader.java branches/jy3k/src/org/python/core/ClasspathPyImporter.java branches/jy3k/src/org/python/core/ParserFacade.java branches/jy3k/src/org/python/core/Py.java branches/jy3k/src/org/python/core/PyReflectedConstructor.java branches/jy3k/src/org/python/core/imp.java branches/jy3k/src/org/python/core/io/FileIO.java branches/jy3k/src/org/python/core/io/IOBase.java branches/jy3k/src/org/python/core/io/ServerSocketIO.java branches/jy3k/src/org/python/core/util/importer.java branches/jy3k/src/org/python/expose/generate/ClassMethodExposer.java branches/jy3k/src/org/python/expose/generate/DescriptorExposer.java branches/jy3k/src/org/python/expose/generate/ExposeTask.java branches/jy3k/src/org/python/expose/generate/ExposedFieldFinder.java branches/jy3k/src/org/python/expose/generate/ExposedMethodFinder.java branches/jy3k/src/org/python/expose/generate/ExposedTypeProcessor.java branches/jy3k/src/org/python/expose/generate/ExposedTypeVisitor.java branches/jy3k/src/org/python/expose/generate/Exposer.java branches/jy3k/src/org/python/expose/generate/InstanceMethodExposer.java branches/jy3k/src/org/python/expose/generate/MethodExposer.java branches/jy3k/src/org/python/expose/generate/NewExposer.java branches/jy3k/src/org/python/expose/generate/OverridableNewExposer.java branches/jy3k/src/org/python/expose/generate/PyTypes.java branches/jy3k/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java branches/jy3k/src/org/python/expose/generate/TypeExposer.java branches/jy3k/src/org/python/modules/_py_compile.java branches/jy3k/src/org/python/modules/errno.java branches/jy3k/src/org/python/modules/zipimport/zipimporter.java branches/jy3k/tests/java/org/python/expose/generate/DescriptorExposerTest.java branches/jy3k/tests/java/org/python/expose/generate/ExposeMethodFinderTest.java branches/jy3k/tests/java/org/python/expose/generate/ExposedTypeVisitorTest.java branches/jy3k/tests/java/org/python/expose/generate/MethodExposerTest.java branches/jy3k/tests/java/org/python/expose/generate/NewExposerTest.java branches/jy3k/tests/java/org/python/expose/generate/OverridableNewExposerTest.java branches/jy3k/tests/java/org/python/expose/generate/TypeExposerTest.java branches/jy3k/tests/java/org/python/tests/BeanInterface.java branches/jy3k/tests/java/org/python/tests/Coercions.java Added Paths: ----------- branches/jy3k/Lib/test/anygui.py branches/jy3k/Lib/test/import_nonexistent.py branches/jy3k/Lib/test/invalid_utf_8_declared_encoding.py branches/jy3k/Lib/test/latin1_no_encoding.py branches/jy3k/Lib/test/python_home.policy branches/jy3k/Lib/test/syspath_import.jar branches/jy3k/Lib/test/test_doctest.py branches/jy3k/Lib/test/test_java_subclasses.py branches/jy3k/Lib/test/test_pep263_jy.py branches/jy3k/Lib/test/test_sax_jy.py branches/jy3k/Lib/test/test_zipimport_jy.py branches/jy3k/tests/java/org/python/tests/Matryoshka.java Removed Paths: ------------- branches/jy3k/Lib/test/test_jsubclass.py branches/jy3k/bugtests/classes/test288i.java branches/jy3k/bugtests/classes/test288j.java branches/jy3k/bugtests/test290.py branches/jy3k/bugtests/test291.py branches/jy3k/bugtests/test292.policy branches/jy3k/bugtests/test292.py branches/jy3k/bugtests/test293.py branches/jy3k/bugtests/test293p/ branches/jy3k/bugtests/test294.py branches/jy3k/bugtests/test294j.java branches/jy3k/bugtests/test295.py branches/jy3k/bugtests/test296.py branches/jy3k/bugtests/test296p/ branches/jy3k/bugtests/test297.py branches/jy3k/bugtests/test297c.py branches/jy3k/bugtests/test298.py branches/jy3k/bugtests/test298m1.py branches/jy3k/bugtests/test299.py branches/jy3k/bugtests/test300.py branches/jy3k/bugtests/test301.py branches/jy3k/bugtests/test301c.py branches/jy3k/bugtests/test302.py branches/jy3k/bugtests/test303.py branches/jy3k/bugtests/test303j.java branches/jy3k/bugtests/test307.py branches/jy3k/bugtests/test307foobar.template branches/jy3k/bugtests/test307m.template branches/jy3k/bugtests/test307p.template branches/jy3k/bugtests/test308.py branches/jy3k/bugtests/test308d/ branches/jy3k/bugtests/test309.py branches/jy3k/bugtests/test310.py branches/jy3k/bugtests/test310c.py branches/jy3k/bugtests/test311.py branches/jy3k/bugtests/test312.py branches/jy3k/bugtests/test313.py branches/jy3k/bugtests/test313c.py branches/jy3k/bugtests/test314.py branches/jy3k/bugtests/test314c.py branches/jy3k/bugtests/test315.py branches/jy3k/bugtests/test315c.py branches/jy3k/bugtests/test316.py branches/jy3k/bugtests/test317.py branches/jy3k/bugtests/test317c.py branches/jy3k/bugtests/test318.py branches/jy3k/bugtests/test319.py branches/jy3k/bugtests/test319j.java branches/jy3k/tests/java/javatests/MethodInvokationTest.java Property Changed: ---------------- branches/jy3k/ Property changes on: branches/jy3k ___________________________________________________________________ Modified: svnmerge-integrated - /trunk/jython:1-5840 + /trunk/jython:1-5872 Modified: branches/jy3k/.classpath =================================================================== --- branches/jy3k/.classpath 2009-01-07 23:59:24 UTC (rev 5872) +++ branches/jy3k/.classpath 2009-01-08 00:32:17 UTC (rev 5873) @@ -12,8 +12,10 @@ <classpathentry kind="lib" path="extlibs/mysql-connector-java-5.1.6.jar"/> <classpathentry kind="lib" path="extlibs/postgresql-8.3-603.jdbc4.jar"/> <classpathentry kind="lib" path="extlibs/servlet-api-2.5.jar"/> - <classpathentry kind="lib" path="build/jarjar"/> <classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/> <classpathentry kind="lib" path="extlibs/antlr-3.1.1-runtime.jar"/> + <classpathentry kind="lib" path="extlibs/asm-3.1.jar"/> + <classpathentry kind="lib" path="extlibs/asm-commons-3.1.jar"/> + <classpathentry kind="lib" path="extlibs/constantine-0.4.jar"/> <classpathentry kind="output" path="bugtests/classes"/> </classpath> Modified: branches/jy3k/Lib/os.py =================================================================== --- branches/jy3k/Lib/os.py 2009-01-07 23:59:24 UTC (rev 5872) +++ branches/jy3k/Lib/os.py 2009-01-08 00:32:17 UTC (rev 5873) @@ -47,10 +47,14 @@ import stat as _stat import sys from java.io import File -from org.python.constantine.platform import Errno from org.python.core.io import FileDescriptors, FileIO, IOBase from org.python.core.Py import newString as asPyString +try: + from org.python.constantine.platform import Errno +except ImportError: + from com.kenai.constantine.platform import Errno + # Mapping of: os._name: [name list, shell command list] _os_map = dict(nt=[ ['Windows 95', 'Windows 98', 'Windows ME', 'Windows NT', @@ -96,7 +100,10 @@ # should *NOT* use it _name = get_os_type() -from org.python.posix import JavaPOSIX, POSIXHandler, POSIXFactory +try: + from org.python.posix import JavaPOSIX, POSIXHandler, POSIXFactory +except ImportError: + from org.jruby.ext.posix import JavaPOSIX, POSIXHandler, POSIXFactory class PythonPOSIXHandler(POSIXHandler): def error(self, error, msg): @@ -420,7 +427,10 @@ if constant.name() == constant.description(): # XXX: have constantine handle this fallback # Fake constant or just lacks a description, fallback to Linux's - from org.python.constantine.platform.linux import Errno as LinuxErrno + try: + from org.python.constantine.platform.linux import Errno as LinuxErrno + except ImportError: + from com.kenai.constantine.platform.linux import Errno as LinuxErrno constant = getattr(LinuxErrno, constant.name(), None) if not constant: return 'Unknown error: %d' % code @@ -558,7 +568,10 @@ global _time_t if _time_t is None: from java.lang import Integer, Long - from org.python.posix.util import Platform + try: + from org.python.posix import Platform + except ImportError: + from org.jruby.ext.posix.util import Platform _time_t = Integer if Platform.IS_32_BIT else Long try: Modified: branches/jy3k/Lib/socket.py =================================================================== --- branches/jy3k/Lib/socket.py 2009-01-07 23:59:24 UTC (rev 5872) +++ branches/jy3k/Lib/socket.py 2009-01-08 00:32:17 UTC (rev 5873) @@ -632,12 +632,14 @@ class _nonblocking_api_mixin: - timeout = _defaulttimeout mode = MODE_BLOCKING reference_count = 0 close_lock = threading.Lock() def __init__(self): + self.timeout = _defaulttimeout + if self.timeout is not None: + self.mode = MODE_TIMEOUT self.pending_options = { SO_REUSEADDR: 0, } @@ -791,7 +793,7 @@ self.sock_impl.bind(bind_host, bind_port, self.pending_options[SO_REUSEADDR]) self._config() # Configure timeouts, etc, now that the socket exists self.sock_impl.connect(host, port) - except java.lang.Exception, jlx: + except java.lang.Exception, jlx: raise _map_exception(jlx) def connect(self, addr): Copied: branches/jy3k/Lib/test/anygui.py (from rev 5869, trunk/jython/Lib/test/anygui.py) =================================================================== --- branches/jy3k/Lib/test/anygui.py (rev 0) +++ branches/jy3k/Lib/test/anygui.py 2009-01-08 00:32:17 UTC (rev 5873) @@ -0,0 +1,40 @@ +'''Used by test_import_jy/test_getattr_module''' +import sys + +class anygui: + __all__ = ['Window'] # Etc... + + def __init__(self): + self.__backend = None + self.__backends = ['msw', 'x', 'mac', 'wx', 'tk', 'java'] + + def __try_to_get(self, modulename): + import imp + try: + module = imp.find_module(modulename) + except (IOError, ImportError, AttributeError, AssertionError): + return None + else: + return module + + def __import_backend(self, wishlist): + candidates = self.__backends[:] + for wish in wishlist: + if wish in candidates: + candidates.remove(wish) + else: + wishlist.remove(wish) + candidates = wishlist + candidates + + for name in candidates: + backend = self.__try_to_get('%sgui' % name) + if not backend: + raise Exception, 'not able to import any GUI backends' + self.__backend = backend + + def __getattr__(self, name): + if not self.__backend: + self.__import_backend(self.__dict__.get('wishlist', [])) + return self.__backend.__dict__[name] + +sys.modules[__name__] = anygui() Copied: branches/jy3k/Lib/test/import_nonexistent.py (from rev 5869, trunk/jython/Lib/test/import_nonexistent.py) =================================================================== --- branches/jy3k/Lib/test/import_nonexistent.py (rev 0) +++ branches/jy3k/Lib/test/import_nonexistent.py 2009-01-08 00:32:17 UTC (rev 5873) @@ -0,0 +1,7 @@ +try: + import nonexistent_module +except ImportError: + pass # This should cause an import error, but as there's a security manager in place it hasn't + # always done so +else: + raise Error("Should've caused an import error!") Copied: branches/jy3k/Lib/test/invalid_utf_8_declared_encoding.py (from rev 5869, trunk/jython/Lib/test/invalid_utf_8_declared_encoding.py) =================================================================== (Binary files differ) Copied: branches/jy3k/Lib/test/latin1_no_encoding.py (from rev 5869, trunk/jython/Lib/test/latin1_no_encoding.py) =================================================================== (Binary files differ) Copied: branches/jy3k/Lib/test/python_home.policy (from rev 5869, trunk/jython/Lib/test/python_home.policy) =================================================================== --- branches/jy3k/Lib/test/python_home.policy (rev 0) +++ branches/jy3k/Lib/test/python_home.policy 2009-01-08 00:32:17 UTC (rev 5873) @@ -0,0 +1,5 @@ +grant codeBase "file:${python.home}/-" { + permission java.util.PropertyPermission "*", "read,write"; + permission java.io.FilePermission "<<ALL FILES>>", "read,write"; +}; + Modified: branches/jy3k/Lib/test/regrtest.py =================================================================== --- branches/jy3k/Lib/test/regrtest.py 2009-01-07 23:59:24 UTC (rev 5872) +++ branches/jy3k/Lib/test/regrtest.py 2009-01-08 00:32:17 UTC (rev 5873) @@ -1380,6 +1380,7 @@ 'java': """ test__locale + test__rawffi test_aepack test_al test_applesingle @@ -1449,6 +1450,7 @@ test_winreg test_winsound test_xml_etree_c + test_zipfile64 """ } _expectations['freebsd5'] = _expectations['freebsd4'] @@ -1475,11 +1477,16 @@ test_gc test_iterlen test_marshal + test_multibytecodec + test_multibytecodec_support test_peepholer test_profile test_pyclbr + test_stringprep test_transformer test_ucn + test_unicode + test_unicodedata test_xml_etree test_zipimport """, Copied: branches/jy3k/Lib/test/syspath_import.jar (from rev 5869, trunk/jython/Lib/test/syspath_import.jar) =================================================================== (Binary files differ) Modified: branches/jy3k/Lib/test/test_classpathimporter.py =================================================================== --- branches/jy3k/Lib/test/test_classpathimporter.py 2009-01-07 23:59:24 UTC (rev 5872) +++ branches/jy3k/Lib/test/test_classpathimporter.py 2009-01-08 00:32:17 UTC (rev 5873) @@ -18,22 +18,24 @@ except KeyError: pass - def setClassLoaderAndCheck(self, jar): + def setClassLoaderAndCheck(self, jar, prefix): Thread.currentThread().contextClassLoader = test_support.make_jar_classloader(jar) import flat_in_jar self.assertEquals(flat_in_jar.value, 7) import jar_pkg + self.assertEquals(prefix + '/jar_pkg/__init__$py.class', jar_pkg.__file__) from jar_pkg import prefer_compiled + self.assertEquals(prefix + '/jar_pkg/prefer_compiled$py.class', prefer_compiled.__file__) self.assert_(prefer_compiled.compiled) self.assertRaises(NameError, __import__, 'flat_bad') self.assertRaises(NameError, __import__, 'jar_pkg.bad') def test_default_pyclasspath(self): - self.setClassLoaderAndCheck("classimport.jar") + self.setClassLoaderAndCheck("classimport.jar", "__pyclasspath__") def test_path_in_pyclasspath(self): sys.path = ['__pyclasspath__/Lib'] - self.setClassLoaderAndCheck("classimport_Lib.jar") + self.setClassLoaderAndCheck("classimport_Lib.jar", "__pyclasspath__/Lib") def test_main(): test_support.run_unittest(ClasspathImporterTestCase) Copied: branches/jy3k/Lib/test/test_doctest.py (from rev 5869, trunk/jython/Lib/test/test_doctest.py) =================================================================== --- branches/jy3k/Lib/test/test_doctest.py (rev 0) +++ branches/jy3k/Lib/test/test_doctest.py 2009-01-08 00:32:17 UTC (rev 5873) @@ -0,0 +1,2438 @@ +""" +Test script for doctest. +""" + +from test import test_support +import doctest +import warnings + +###################################################################### +## Sample Objects (used by test cases) +###################################################################### + +def sample_func(v): + """ + Blah blah + + >>> print sample_func(22) + 44 + + Yee ha! + """ + return v+v + +class SampleClass: + """ + >>> print 1 + 1 + + >>> # comments get ignored. so are empty PS1 and PS2 prompts: + >>> + ... + + Multiline example: + >>> sc = SampleClass(3) + >>> for i in range(10): + ... sc = sc.double() + ... print sc.get(), + 6 12 24 48 96 192 384 768 1536 3072 + """ + def __init__(self, val): + """ + >>> print SampleClass(12).get() + 12 + """ + self.val = val + + def double(self): + """ + >>> print SampleClass(12).double().get() + 24 + """ + return SampleClass(self.val + self.val) + + def get(self): + """ + >>> print SampleClass(-5).get() + -5 + """ + return self.val + + def a_staticmethod(v): + """ + >>> print SampleClass.a_staticmethod(10) + 11 + """ + return v+1 + a_staticmethod = staticmethod(a_staticmethod) + + def a_classmethod(cls, v): + """ + >>> print SampleClass.a_classmethod(10) + 12 + >>> print SampleClass(0).a_classmethod(10) + 12 + """ + return v+2 + a_classmethod = classmethod(a_classmethod) + + a_property = property(get, doc=""" + >>> print SampleClass(22).a_property + 22 + """) + + class NestedClass: + """ + >>> x = SampleClass.NestedClass(5) + >>> y = x.square() + >>> print y.get() + 25 + """ + def __init__(self, val=0): + """ + >>> print SampleClass.NestedClass().get() + 0 + """ + self.val = val + def square(self): + return SampleClass.NestedClass(self.val*self.val) + def get(self): + return self.val + +class SampleNewStyleClass(object): + r""" + >>> print '1\n2\n3' + 1 + 2 + 3 + """ + def __init__(self, val): + """ + >>> print SampleNewStyleClass(12).get() + 12 + """ + self.val = val + + def double(self): + """ + >>> print SampleNewStyleClass(12).double().get() + 24 + """ + return SampleNewStyleClass(self.val + self.val) + + def get(self): + """ + >>> print SampleNewStyleClass(-5).get() + -5 + """ + return self.val + +###################################################################### +## Fake stdin (for testing interactive debugging) +###################################################################### + +class _FakeInput: + """ + A fake input stream for pdb's interactive debugger. Whenever a + line is read, print it (to simulate the user typing it), and then + return it. The set of lines to return is specified in the + constructor; they should not have trailing newlines. + """ + def __init__(self, lines): + self.lines = lines + + def readline(self): + line = self.lines.pop(0) + print line + return line+'\n' + +###################################################################### +## Test Cases +###################################################################### + +def test_Example(): r""" +Unit tests for the `Example` class. + +Example is a simple container class that holds: + - `source`: A source string. + - `want`: An expected output string. + - `exc_msg`: An expected exception message string (or None if no + exception is expected). + - `lineno`: A line number (within the docstring). + - `indent`: The example's indentation in the input string. + - `options`: An option dictionary, mapping option flags to True or + False. + +These attributes are set by the constructor. `source` and `want` are +required; the other attributes all have default values: + + >>> example = doctest.Example('print 1', '1\n') + >>> (example.source, example.want, example.exc_msg, + ... example.lineno, example.indent, example.options) + ('print 1\n', '1\n', None, 0, 0, {}) + +The first three attributes (`source`, `want`, and `exc_msg`) may be +specified positionally; the remaining arguments should be specified as +keyword arguments: + + >>> exc_msg = 'IndexError: pop from an empty list' + >>> example = doctest.Example('[].pop()', '', exc_msg, + ... lineno=5, indent=4, + ... options={doctest.ELLIPSIS: True}) + >>> (example.source, example.want, example.exc_msg, + ... example.lineno, example.indent, example.options) + ('[].pop()\n', '', 'IndexError: pop from an empty list\n', 5, 4, {8: True}) + +The constructor normalizes the `source` string to end in a newline: + + Source spans a single line: no terminating newline. + >>> e = doctest.Example('print 1', '1\n') + >>> e.source, e.want + ('print 1\n', '1\n') + + >>> e = doctest.Example('print 1\n', '1\n') + >>> e.source, e.want + ('print 1\n', '1\n') + + Source spans multiple lines: require terminating newline. + >>> e = doctest.Example('print 1;\nprint 2\n', '1\n2\n') + >>> e.source, e.want + ('print 1;\nprint 2\n', '1\n2\n') + + >>> e = doctest.Example('print 1;\nprint 2', '1\n2\n') + >>> e.source, e.want + ('print 1;\nprint 2\n', '1\n2\n') + + Empty source string (which should never appear in real examples) + >>> e = doctest.Example('', '') + >>> e.source, e.want + ('\n', '') + +The constructor normalizes the `want` string to end in a newline, +unless it's the empty string: + + >>> e = doctest.Example('print 1', '1\n') + >>> e.source, e.want + ('print 1\n', '1\n') + + >>> e = doctest.Example('print 1', '1') + >>> e.source, e.want + ('print 1\n', '1\n') + + >>> e = doctest.Example('print', '') + >>> e.source, e.want + ('print\n', '') + +The constructor normalizes the `exc_msg` string to end in a newline, +unless it's `None`: + + Message spans one line + >>> exc_msg = 'IndexError: pop from an empty list' + >>> e = doctest.Example('[].pop()', '', exc_msg) + >>> e.exc_msg + 'IndexError: pop from an empty list\n' + + >>> exc_msg = 'IndexError: pop from an empty list\n' + >>> e = doctest.Example('[].pop()', '', exc_msg) + >>> e.exc_msg + 'IndexError: pop from an empty list\n' + + Message spans multiple lines + >>> exc_msg = 'ValueError: 1\n 2' + >>> e = doctest.Example('raise ValueError("1\n 2")', '', exc_msg) + >>> e.exc_msg + 'ValueError: 1\n 2\n' + + >>> exc_msg = 'ValueError: 1\n 2\n' + >>> e = doctest.Example('raise ValueError("1\n 2")', '', exc_msg) + >>> e.exc_msg + 'ValueError: 1\n 2\n' + + Empty (but non-None) exception message (which should never appear + in real examples) + >>> exc_msg = '' + >>> e = doctest.Example('raise X()', '', exc_msg) + >>> e.exc_msg + '\n' +""" + +def test_DocTest(): r""" +Unit tests for the `DocTest` class. + +DocTest is a collection of examples, extracted from a docstring, along +with information about where the docstring comes from (a name, +filename, and line number). The docstring is parsed by the `DocTest` +constructor: + + >>> docstring = ''' + ... >>> print 12 + ... 12 + ... + ... Non-example text. + ... + ... >>> print 'another\example' + ... another + ... example + ... ''' + >>> globs = {} # globals to run the test in. + >>> parser = doctest.DocTestParser() + >>> test = parser.get_doctest(docstring, globs, 'some_test', + ... 'some_file', 20) + >>> print test + <DocTest some_test from some_file:20 (2 examples)> + >>> len(test.examples) + 2 + >>> e1, e2 = test.examples + >>> (e1.source, e1.want, e1.lineno) + ('print 12\n', '12\n', 1) + >>> (e2.source, e2.want, e2.lineno) + ("print 'another\\example'\n", 'another\nexample\n', 6) + +Source information (name, filename, and line number) is available as +attributes on the doctest object: + + >>> (test.name, test.filename, test.lineno) + ('some_test', 'some_file', 20) + +The line number of an example within its containing file is found by +adding the line number of the example and the line number of its +containing test: + + >>> test.lineno + e1.lineno + 21 + >>> test.lineno + e2.lineno + 26 + +If the docstring contains inconsistant leading whitespace in the +expected output of an example, then `DocTest` will raise a ValueError: + + >>> docstring = r''' + ... >>> print 'bad\nindentation' + ... bad + ... indentation + ... ''' + >>> parser.get_doctest(docstring, globs, 'some_test', 'filename', 0) + Traceback (most recent call last): + ValueError: line 4 of the docstring for some_test has inconsistent leading whitespace: 'indentation' + +If the docstring contains inconsistent leading whitespace on +continuation lines, then `DocTest` will raise a ValueError: + + >>> docstring = r''' + ... >>> print ('bad indentation', + ... ... 2) + ... ('bad', 'indentation') + ... ''' + >>> parser.get_doctest(docstring, globs, 'some_test', 'filename', 0) + Traceback (most recent call last): + ValueError: line 2 of the docstring for some_test has inconsistent leading whitespace: '... 2)' + +If there's no blank space after a PS1 prompt ('>>>'), then `DocTest` +will raise a ValueError: + + >>> docstring = '>>>print 1\n1' + >>> parser.get_doctest(docstring, globs, 'some_test', 'filename', 0) + Traceback (most recent call last): + ValueError: line 1 of the docstring for some_test lacks blank after >>>: '>>>print 1' + +If there's no blank space after a PS2 prompt ('...'), then `DocTest` +will raise a ValueError: + + >>> docstring = '>>> if 1:\n...print 1\n1' + >>> parser.get_doctest(docstring, globs, 'some_test', 'filename', 0) + Traceback (most recent call last): + ValueError: line 2 of the docstring for some_test lacks blank after ...: '...print 1' + +""" + +def test_DocTestFinder(): r""" +Unit tests for the `DocTestFinder` class. + +DocTestFinder is used to extract DocTests from an object's docstring +and the docstrings of its contained objects. It can be used with +modules, functions, classes, methods, staticmethods, classmethods, and +properties. + +Finding Tests in Functions +~~~~~~~~~~~~~~~~~~~~~~~~~~ +For a function whose docstring contains examples, DocTestFinder.find() +will return a single test (for that function's docstring): + + >>> finder = doctest.DocTestFinder() + +We'll simulate a __file__ attr that ends in pyc: + + >>> import test.test_doctest + >>> old = test.test_doctest.__file__ + >>> test.test_doctest.__file__ = 'test_doctest.pyc' + + >>> tests = finder.find(sample_func) + + >>> print tests # doctest: +ELLIPSIS + [<DocTest sample_func from ...:13 (1 example)>] + +The exact name depends on how test_doctest was invoked, so allow for +leading path components. + + >>> tests[0].filename # doctest: +ELLIPSIS + '...test_doctest.py' + + >>> test.test_doctest.__file__ = old + + + >>> e = tests[0].examples[0] + >>> (e.source, e.want, e.lineno) + ('print sample_func(22)\n', '44\n', 3) + +By default, tests are created for objects with no docstring: + + >>> def no_docstring(v): + ... pass + >>> finder.find(no_docstring) + [] + +However, the optional argument `exclude_empty` to the DocTestFinder +constructor can be used to exclude tests for objects with empty +docstrings: + + >>> def no_docstring(v): + ... pass + >>> excl_empty_finder = doctest.DocTestFinder(exclude_empty=True) + >>> excl_empty_finder.find(no_docstring) + [] + +If the function has a docstring with no examples, then a test with no +examples is returned. (This lets `DocTestRunner` collect statistics +about which functions have no tests -- but is that useful? And should +an empty test also be created when there's no docstring?) + + >>> def no_examples(v): + ... ''' no doctest examples ''' + >>> finder.find(no_examples) # doctest: +ELLIPSIS + [<DocTest no_examples from ...:1 (no examples)>] + +Finding Tests in Classes +~~~~~~~~~~~~~~~~~~~~~~~~ +For a class, DocTestFinder will create a test for the class's +docstring, and will recursively explore its contents, including +methods, classmethods, staticmethods, properties, and nested classes. + + >>> finder = doctest.DocTestFinder() + >>> tests = finder.find(SampleClass) + >>> for t in tests: + ... print '%2s %s' % (len(t.examples), t.name) + 3 SampleClass + 3 SampleClass.NestedClass + 1 SampleClass.NestedClass.__init__ + 1 SampleClass.__init__ + 2 SampleClass.a_classmethod + 1 SampleClass.a_property + 1 SampleClass.a_staticmethod + 1 SampleClass.double + 1 SampleClass.get + +New-style classes are also supported: + + >>> tests = finder.find(SampleNewStyleClass) + >>> for t in tests: + ... print '%2s %s' % (len(t.examples), t.name) + 1 SampleNewStyleClass + 1 SampleNewStyleClass.__init__ + 1 SampleNewStyleClass.double + 1 SampleNewStyleClass.get + +Finding Tests in Modules +~~~~~~~~~~~~~~~~~~~~~~~~ +For a module, DocTestFinder will create a test for the class's +docstring, and will recursively explore its contents, including +functions, classes, and the `__test__` dictionary, if it exists: + + >>> # A module + >>> import new + >>> m = new.module('some_module') + >>> def triple(val): + ... ''' + ... >>> print triple(11) + ... 33 + ... ''' + ... return val*3 + >>> m.__dict__.update({ + ... 'sample_func': sample_func, + ... 'SampleClass': SampleClass, + ... '__doc__': ''' + ... Module docstring. + ... >>> print 'module' + ... module + ... ''', + ... '__test__': { + ... 'd': '>>> print 6\n6\n>>> print 7\n7\n', + ... 'c': triple}}) + + >>> finder = doctest.DocTestFinder() + >>> # Use module=test.test_doctest, to prevent doctest from + >>> # ignoring the objects since they weren't defined in m. + >>> import test.test_doctest + >>> tests = finder.find(m, module=test.test_doctest) + >>> for t in tests: + ... print '%2s %s' % (len(t.examples), t.name) + 1 some_module + 3 some_module.SampleClass + 3 some_module.SampleClass.NestedClass + 1 some_module.SampleClass.NestedClass.__init__ + 1 some_module.SampleClass.__init__ + 2 some_module.SampleClass.a_classmethod + 1 some_module.SampleClass.a_property + 1 some_module.SampleClass.a_staticmethod + 1 some_module.SampleClass.double + 1 some_module.SampleClass.get + 1 some_module.__test__.c + 2 some_module.__test__.d + 1 some_module.sample_func + +Duplicate Removal +~~~~~~~~~~~~~~~~~ +If a single object is listed twice (under different names), then tests +will only be generated for it once: + + >>> from test import doctest_aliases + >>> tests = excl_empty_finder.find(doctest_aliases) + >>> print len(tests) + 2 + >>> print tests[0].name + test.doctest_aliases.TwoNames + + TwoNames.f and TwoNames.g are bound to the same object. + We can't guess which will be found in doctest's traversal of + TwoNames.__dict__ first, so we have to allow for either. + + >>> tests[1].name.split('.')[-1] in ['f', 'g'] + True + +Empty Tests +~~~~~~~~~~~ +By default, an object with no doctests doesn't create any tests: + + >>> tests = doctest.DocTestFinder().find(SampleClass) + >>> for t in tests: + ... print '%2s %s' % (len(t.examples), t.name) + 3 SampleClass + 3 SampleClass.NestedClass + 1 SampleClass.NestedClass.__init__ + 1 SampleClass.__init__ + 2 SampleClass.a_classmethod + 1 SampleClass.a_property + 1 SampleClass.a_staticmethod + 1 SampleClass.double + 1 SampleClass.get + +By default, that excluded objects with no doctests. exclude_empty=False +tells it to include (empty) tests for objects with no doctests. This feature +is really to support backward compatibility in what doctest.master.summarize() +displays. + + >>> tests = doctest.DocTestFinder(exclude_empty=False).find(SampleClass) + >>> for t in tests: + ... print '%2s %s' % (len(t.examples), t.name) + 3 SampleClass + 3 SampleClass.NestedClass + 1 SampleClass.NestedClass.__init__ + 0 SampleClass.NestedClass.get + 0 SampleClass.NestedClass.square + 1 SampleClass.__init__ + 2 SampleClass.a_classmethod + 1 SampleClass.a_property + 1 SampleClass.a_staticmethod + 1 SampleClass.double + 1 SampleClass.get + +Turning off Recursion +~~~~~~~~~~~~~~~~~~~~~ +DocTestFinder can be told not to look for tests in contained objects +using the `recurse` flag: + + >>> tests = doctest.DocTestFinder(recurse=False).find(SampleClass) + >>> for t in tests: + ... print '%2s %s' % (len(t.examples), t.name) + 3 SampleClass + +Line numbers +~~~~~~~~~~~~ +DocTestFinder finds the line number of each example: + + >>> def f(x): + ... ''' + ... >>> x = 12 + ... + ... some text + ... + ... >>> # examples are not created for comments & bare prompts. + ... >>> + ... ... + ... + ... >>> for x in range(10): + ... ... print x, + ... 0 1 2 3 4 5 6 7 8 9 + ... >>> x//2 + ... 6 + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> [e.lineno for e in test.examples] + [1, 9, 12] +""" + +def test_DocTestParser(): r""" +Unit tests for the `DocTestParser` class. + +DocTestParser is used to parse docstrings containing doctest examples. + +The `parse` method divides a docstring into examples and intervening +text: + + >>> s = ''' + ... >>> x, y = 2, 3 # no output expected + ... >>> if 1: + ... ... print x + ... ... print y + ... 2 + ... 3 + ... + ... Some text. + ... >>> x+y + ... 5 + ... ''' + >>> parser = doctest.DocTestParser() + >>> for piece in parser.parse(s): + ... if isinstance(piece, doctest.Example): + ... print 'Example:', (piece.source, piece.want, piece.lineno) + ... else: + ... print ' Text:', `piece` + Text: '\n' + Example: ('x, y = 2, 3 # no output expected\n', '', 1) + Text: '' + Example: ('if 1:\n print x\n print y\n', '2\n3\n', 2) + Text: '\nSome text.\n' + Example: ('x+y\n', '5\n', 9) + Text: '' + +The `get_examples` method returns just the examples: + + >>> for piece in parser.get_examples(s): + ... print (piece.source, piece.want, piece.lineno) + ('x, y = 2, 3 # no output expected\n', '', 1) + ('if 1:\n print x\n print y\n', '2\n3\n', 2) + ('x+y\n', '5\n', 9) + +The `get_doctest` method creates a Test from the examples, along with the +given arguments: + + >>> test = parser.get_doctest(s, {}, 'name', 'filename', lineno=5) + >>> (test.name, test.filename, test.lineno) + ('name', 'filename', 5) + >>> for piece in test.examples: + ... print (piece.source, piece.want, piece.lineno) + ('x, y = 2, 3 # no output expected\n', '', 1) + ('if 1:\n print x\n print y\n', '2\n3\n', 2) + ('x+y\n', '5\n', 9) +""" + +class test_DocTestRunner: + def basics(): r""" +Unit tests for the `DocTestRunner` class. + +DocTestRunner is used to run DocTest test cases, and to accumulate +statistics. Here's a simple DocTest case we can use: + + >>> def f(x): + ... ''' + ... >>> x = 12 + ... >>> print x + ... 12 + ... >>> x//2 + ... 6 + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + +The main DocTestRunner interface is the `run` method, which runs a +given DocTest case in a given namespace (globs). It returns a tuple +`(f,t)`, where `f` is the number of failed tests and `t` is the number +of tried tests. + + >>> doctest.DocTestRunner(verbose=False).run(test) + (0, 3) + +If any example produces incorrect output, then the test runner reports +the failure and proceeds to the next example: + + >>> def f(x): + ... ''' + ... >>> x = 12 + ... >>> print x + ... 14 + ... >>> x//2 + ... 6 + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=True).run(test) + ... # doctest: +ELLIPSIS + Trying: + x = 12 + Expecting nothing + ok + Trying: + print x + Expecting: + 14 + ********************************************************************** + File ..., line 4, in f + Failed example: + print x + Expected: + 14 + Got: + 12 + Trying: + x//2 + Expecting: + 6 + ok + (1, 3) +""" + def verbose_flag(): r""" +The `verbose` flag makes the test runner generate more detailed +output: + + >>> def f(x): + ... ''' + ... >>> x = 12 + ... >>> print x + ... 12 + ... >>> x//2 + ... 6 + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + + >>> doctest.DocTestRunner(verbose=True).run(test) + Trying: + x = 12 + Expecting nothing + ok + Trying: + print x + Expecting: + 12 + ok + Trying: + x//2 + Expecting: + 6 + ok + (0, 3) + +If the `verbose` flag is unspecified, then the output will be verbose +iff `-v` appears in sys.argv: + + >>> # Save the real sys.argv list. + >>> old_argv = sys.argv + + >>> # If -v does not appear in sys.argv, then output isn't verbose. + >>> sys.argv = ['test'] + >>> doctest.DocTestRunner().run(test) + (0, 3) + + >>> # If -v does appear in sys.argv, then output is verbose. + >>> sys.argv = ['test', '-v'] + >>> doctest.DocTestRunner().run(test) + Trying: + x = 12 + Expecting nothing + ok + Trying: + print x + Expecting: + 12 + ok + Trying: + x//2 + Expecting: + 6 + ok + (0, 3) + + >>> # Restore sys.argv + >>> sys.argv = old_argv + +In the remaining examples, the test runner's verbosity will be +explicitly set, to ensure that the test behavior is consistent. + """ + def exceptions(): r""" +Tests of `DocTestRunner`'s exception handling. + +An expected exception is specified with a traceback message. The +lines between the first line and the type/value may be omitted or +replaced with any other string: + + >>> def f(x): + ... ''' + ... >>> x = 12 + ... >>> print x//0 + ... Traceback (most recent call last): + ... ZeroDivisionError: integer division or modulo by zero + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + (0, 2) + +An example may not generate output before it raises an exception; if +it does, then the traceback message will not be recognized as +signaling an expected exception, so the example will be reported as an +unexpected exception: + + >>> def f(x): + ... ''' + ... >>> x = 12 + ... >>> print 'pre-exception output', x//0 + ... pre-exception output + ... Traceback (most recent call last): + ... ZeroDivisionError: integer division or modulo by zero + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 4, in f + Failed example: + print 'pre-exception output', x//0 + Exception raised: + ... + ZeroDivisionError: integer division or modulo by zero + (1, 2) + +Exception messages may contain newlines: + + >>> def f(x): + ... r''' + ... >>> raise ValueError, 'multi\nline\nmessage' + ... Traceback (most recent call last): + ... ValueError: multi + ... line + ... message + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + (0, 1) + +If an exception is expected, but an exception with the wrong type or +message is raised, then it is reported as a failure: + + >>> def f(x): + ... r''' + ... >>> raise ValueError, 'message' + ... Traceback (most recent call last): + ... ValueError: wrong message + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 3, in f + Failed example: + raise ValueError, 'message' + Expected: + Traceback (most recent call last): + ValueError: wrong message + Got: + Traceback (most recent call last): + ... + ValueError: message + (1, 1) + +However, IGNORE_EXCEPTION_DETAIL can be used to allow a mismatch in the +detail: + + >>> def f(x): + ... r''' + ... >>> raise ValueError, 'message' #doctest: +IGNORE_EXCEPTION_DETAIL + ... Traceback (most recent call last): + ... ValueError: wrong message + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + (0, 1) + +But IGNORE_EXCEPTION_DETAIL does not allow a mismatch in the exception type: + + >>> def f(x): + ... r''' + ... >>> raise ValueError, 'message' #doctest: +IGNORE_EXCEPTION_DETAIL + ... Traceback (most recent call last): + ... TypeError: wrong type + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 3, in f + Failed example: + raise ValueError, 'message' #doctest: +IGNORE_EXCEPTION_DETAIL + Expected: + Traceback (most recent call last): + TypeError: wrong type + Got: + Traceback (most recent call last): + ... + ValueError: message + (1, 1) + +If an exception is raised but not expected, then it is reported as an +unexpected exception: + + >>> def f(x): + ... r''' + ... >>> 1//0 + ... 0 + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 3, in f + Failed example: + 1//0 + Exception raised: + Traceback (most recent call last): + ... + ZeroDivisionError: integer division or modulo by zero + (1, 1) +""" + def optionflags(): r""" +Tests of `DocTestRunner`'s option flag handling. + +Several option flags can be used to customize the behavior of the test +runner. These are defined as module constants in doctest, and passed +to the DocTestRunner constructor (multiple constants should be or-ed +together). + +The DONT_ACCEPT_TRUE_FOR_1 flag disables matches between True/False +and 1/0: + + >>> def f(x): + ... '>>> True\n1\n' + + >>> # Without the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + (0, 1) + + >>> # With the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> flags = doctest.DONT_ACCEPT_TRUE_FOR_1 + >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 2, in f + Failed example: + True + Expected: + 1 + Got: + True + (1, 1) + +The DONT_ACCEPT_BLANKLINE flag disables the match between blank lines +and the '<BLANKLINE>' marker: + + >>> def f(x): + ... '>>> print "a\\n\\nb"\na\n<BLANKLINE>\nb\n' + + >>> # Without the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + (0, 1) + + >>> # With the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> flags = doctest.DONT_ACCEPT_BLANKLINE + >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 2, in f + Failed example: + print "a\n\nb" + Expected: + a + <BLANKLINE> + b + Got: + a + <BLANKLINE> + b + (1, 1) + +The NORMALIZE_WHITESPACE flag causes all sequences of whitespace to be +treated as equal: + + >>> def f(x): + ... '>>> print 1, 2, 3\n 1 2\n 3' + + >>> # Without the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 2, in f + Failed example: + print 1, 2, 3 + Expected: + 1 2 + 3 + Got: + 1 2 3 + (1, 1) + + >>> # With the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> flags = doctest.NORMALIZE_WHITESPACE + >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) + (0, 1) + + An example from the docs: + >>> print range(20) #doctest: +NORMALIZE_WHITESPACE + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + +The ELLIPSIS flag causes ellipsis marker ("...") in the expected +output to match any substring in the actual output: + + >>> def f(x): + ... '>>> print range(15)\n[0, 1, 2, ..., 14]\n' + + >>> # Without the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 2, in f + Failed example: + print range(15) + Expected: + [0, 1, 2, ..., 14] + Got: + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] + (1, 1) + + >>> # With the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> flags = doctest.ELLIPSIS + >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) + (0, 1) + + ... also matches nothing: + + >>> for i in range(100): + ... print i**2, #doctest: +ELLIPSIS + 0 1...4...9 16 ... 36 49 64 ... 9801 + + ... can be surprising; e.g., this test passes: + + >>> for i in range(21): #doctest: +ELLIPSIS + ... print i, + 0 1 2 ...1...2...0 + + Examples from the docs: + + >>> print range(20) # doctest:+ELLIPSIS + [0, 1, ..., 18, 19] + + >>> print range(20) # doctest: +ELLIPSIS + ... # doctest: +NORMALIZE_WHITESPACE + [0, 1, ..., 18, 19] + +The SKIP flag causes an example to be skipped entirely. I.e., the +example is not run. It can be useful in contexts where doctest +examples serve as both documentation and test cases, and an example +should be included for documentation purposes, but should not be +checked (e.g., because its output is random, or depends on resources +which would be unavailable.) The SKIP flag can also be used for +'commenting out' broken examples. + + >>> import unavailable_resource # doctest: +SKIP + >>> unavailable_resource.do_something() # doctest: +SKIP + >>> unavailable_resource.blow_up() # doctest: +SKIP + Traceback (most recent call last): + ... + UncheckedBlowUpError: Nobody checks me. + + >>> import random + >>> print random.random() # doctest: +SKIP + 0.721216923889 + +The REPORT_UDIFF flag causes failures that involve multi-line expected +and actual outputs to be displayed using a unified diff: + + >>> def f(x): + ... r''' + ... >>> print '\n'.join('abcdefg') + ... a + ... B + ... c + ... d + ... f + ... g + ... h + ... ''' + + >>> # Without the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 3, in f + Failed example: + print '\n'.join('abcdefg') + Expected: + a + B + c + d + f + g + h + Got: + a + b + c + d + e + f + g + (1, 1) + + >>> # With the flag: + >>> test = doctest.DocTestFinder().find(f)[0] + >>> flags = doctest.REPORT_UDIFF + >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 3, in f + Failed example: + print '\n'.join('abcdefg') + Differences (unified diff with -expected +actual): + @@ -1,7 +1,7 @@ + a + -B + +b + c + d + +e + f + g + -h + (1, 1) + +The REPORT_CDIFF flag causes failures that involve multi-line expected +and actual outputs to be displayed using a context diff: + + >>> # Reuse f() from the REPORT_UDIFF example, above. + >>> test = doctest.DocTestFinder().find(f)[0] + >>> flags = doctest.REPORT_CDIFF + >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 3, in f + Failed example: + print '\n'.join('abcdefg') + Differences (context diff with expected followed by actual): + *************** + *** 1,7 **** + a + ! B + c + d + f + g + - h + --- 1,7 ---- + a + ! b + c + d + + e + f + g + (1, 1) + + +The REPORT_NDIFF flag causes failures to use the difflib.Differ algorithm +used by the popular ndiff.py utility. This does intraline difference +marking, as well as interline differences. + + >>> def f(x): + ... r''' + ... >>> print "a b c d e f g h i j k l m" + ... a b c d e f g h i j k 1 m + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> flags = doctest.REPORT_NDIFF + >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 3, in f + Failed example: + print "a b c d e f g h i j k l m" + Differences (ndiff with -expected +actual): + - a b c d e f g h i j k 1 m + ? ^ + + a b c d e f g h i j k l m + ? + ++ ^ + (1, 1) + +The REPORT_ONLY_FIRST_FAILURE supresses result output after the first +failing example: + + >>> def f(x): + ... r''' + ... >>> print 1 # first success + ... 1 + ... >>> print 2 # first failure + ... 200 + ... >>> print 3 # second failure + ... 300 + ... >>> print 4 # second success + ... 4 + ... >>> print 5 # third failure + ... 500 + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> flags = doctest.REPORT_ONLY_FIRST_FAILURE + >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 5, in f + Failed example: + print 2 # first failure + Expected: + 200 + Got: + 2 + (3, 5) + +However, output from `report_start` is not supressed: + + >>> doctest.DocTestRunner(verbose=True, optionflags=flags).run(test) + ... # doctest: +ELLIPSIS + Trying: + print 1 # first success + Expecting: + 1 + ok + Trying: + print 2 # first failure + Expecting: + 200 + ********************************************************************** + File ..., line 5, in f + Failed example: + print 2 # first failure + Expected: + 200 + Got: + 2 + (3, 5) + +For the purposes of REPORT_ONLY_FIRST_FAILURE, unexpected exceptions +count as failures: + + >>> def f(x): + ... r''' + ... >>> print 1 # first success + ... 1 + ... >>> raise ValueError(2) # first failure + ... 200 + ... >>> print 3 # second failure + ... 300 + ... >>> print 4 # second success + ... 4 + ... >>> print 5 # third failure + ... 500 + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> flags = doctest.REPORT_ONLY_FIRST_FAILURE + >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 5, in f + Failed example: + raise ValueError(2) # first failure + Exception raised: + ... + ValueError: 2 + (3, 5) + +New option flags can also be registered, via register_optionflag(). Here +we reach into doctest's internals a bit. + + >>> unlikely = "UNLIKELY_OPTION_NAME" + >>> unlikely in doctest.OPTIONFLAGS_BY_NAME + False + >>> new_flag_value = doctest.register_optionflag(unlikely) + >>> unlikely in doctest.OPTIONFLAGS_BY_NAME + True + +Before 2.4.4/2.5, registering a name more than once erroneously created +more than one flag value. Here we verify that's fixed: + + >>> redundant_flag_value = doctest.register_optionflag(unlikely) + >>> redundant_flag_value == new_flag_value + True + +Clean up. + >>> del doctest.OPTIONFLAGS_BY_NAME[unlikely] + + """ + + def option_directives(): r""" +Tests of `DocTestRunner`'s option directive mechanism. + +Option directives can be used to turn option flags on or off for a +single example. To turn an option on for an example, follow that +example with a comment of the form ``# doctest: +OPTION``: + + >>> def f(x): r''' + ... >>> print range(10) # should fail: no ellipsis + ... [0, 1, ..., 9] + ... + ... >>> print range(10) # doctest: +ELLIPSIS + ... [0, 1, ..., 9] + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> doctest.DocTestRunner(verbose=False).run(test) + ... # doctest: +ELLIPSIS + ********************************************************************** + File ..., line 2, in f + Failed example: + print range(10) # should fail: no ellipsis + Expected: + [0, 1, ..., 9] + Got: + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + (1, 2) + +To turn an option off for an example, follow that example with a +comment of the form ``# doctest: -OPTION``: + + >>> def f(x): r''' + ... >>> print range(10) + ... [0, 1, ..., 9] + ... + ... >>> # should fail: ... [truncated message content] |