[Checkins] SVN: z3c.dependencychecker/trunk/ Searching in doctests (.py, .txt, .rst) for imports, too. Regex-based by

Reinout van Rees reinout at vanrees.org
Thu Dec 10 09:19:21 EST 2009


Log message for revision 106393:
  Searching in doctests (.py, .txt, .rst) for imports, too.  Regex-based by
  necessity, but it seems to catch what I can test it with.
  

Changed:
  U   z3c.dependencychecker/trunk/CHANGES.txt
  U   z3c.dependencychecker/trunk/TODO.txt
  U   z3c.dependencychecker/trunk/src/z3c/dependencychecker/dependencychecker.py
  U   z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/dependencychecker.txt
  U   z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/sample1/setup.py_in
  U   z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/sample1/src/sample1.egg-info/requires.txt

-=-
Modified: z3c.dependencychecker/trunk/CHANGES.txt
===================================================================
--- z3c.dependencychecker/trunk/CHANGES.txt	2009-12-10 13:53:44 UTC (rev 106392)
+++ z3c.dependencychecker/trunk/CHANGES.txt	2009-12-10 14:19:21 UTC (rev 106393)
@@ -4,7 +4,8 @@
 0.5 (unreleased)
 ----------------
 
-- Nothing changed yet.
+- Searching in doctests (.py, .txt, .rst) for imports, too.  Regex-based by
+  necessity, but it seems to catch what I can test it with.
 
 
 0.4 (2009-12-10)

Modified: z3c.dependencychecker/trunk/TODO.txt
===================================================================
--- z3c.dependencychecker/trunk/TODO.txt	2009-12-10 13:53:44 UTC (rev 106392)
+++ z3c.dependencychecker/trunk/TODO.txt	2009-12-10 14:19:21 UTC (rev 106393)
@@ -10,6 +10,4 @@
 - Add some extra fallbacks for often-used packages like PIL (which is really
   Imaging when you import it).
 
-- Optionally check imports inside doctests.
 
-

Modified: z3c.dependencychecker/trunk/src/z3c/dependencychecker/dependencychecker.py
===================================================================
--- z3c.dependencychecker/trunk/src/z3c/dependencychecker/dependencychecker.py	2009-12-10 13:53:44 UTC (rev 106392)
+++ z3c.dependencychecker/trunk/src/z3c/dependencychecker/dependencychecker.py	2009-12-10 14:19:21 UTC (rev 106393)
@@ -33,6 +33,43 @@
 """, re.VERBOSE)
 
 
+DOCTEST_IMPORT = re.compile(r"""
+^            # From start of line
+\s+          # Whitespace.
+>>>          # Doctestmarker.
+\s+          # Whitespace.
+import       # 'import' keyword
+\s+          # Whitespace
+(?P<module>  # Start of 'module' variable.
+\S+          # Non-whitespace string.
+)            # End of 'import' variable.
+""", re.VERBOSE)
+
+
+DOCTEST_FROM_IMPORT = re.compile(r"""
+^            # From start of line
+\s+          # Whitespace.
+>>>          # Doctestmarker.
+\s+          # Whitespace.
+from         # 'from' keyword
+\s+          # Whitespace
+(?P<module>  # Start of 'module' variable.
+\S+          # Non-whitespace string.
+)            # End of 'import' variable.
+\s+          # Whitespace.
+import       # 'import' keyword
+\s+          # Whitespace.
+(?P<sub>     # Start of 'sub' variable.
+[            # Any of:
+  a-zA-Z     # a-z
+  0-9        # numbers
+  ,          # comma
+  \s         # whitespace
+]+           # more than one.
+)            # End of 'import' variable.
+""", re.VERBOSE)
+
+
 def print_unused_imports(unused_imports):
     found = []
     for path in sorted(unused_imports.keys()):
@@ -193,6 +230,25 @@
     return modules, test_modules
 
 
+def imports_from_doctests(path):
+    test_modules = []
+    for path, dirs, files in os.walk(path):
+        for filename in [
+            os.path.abspath(os.path.join(path, filename))
+            for filename in files
+            if fnmatch.fnmatch(filename, '*.txt')
+            or fnmatch.fnmatch(filename, '*.rst')
+            or fnmatch.fnmatch(filename, '*.py')]:
+            lines = open(filename).readlines()
+            for line in lines:
+                test_modules += re.findall(DOCTEST_IMPORT, line)
+                for (module, sub) in re.findall(DOCTEST_FROM_IMPORT, line):
+                    submodules = [item.strip() for item in sub.split(',')]
+                    for submodule in submodules:
+                        test_modules.append('.'.join([module, submodule]))
+    return sorted(set(test_modules))
+
+
 def print_modules(modules, heading):
     if modules:
         print heading
@@ -222,6 +278,7 @@
     (install_required, test_required) = existing_requirements()
     stdlib = stdlib_modules()
     (zcml_imports, zcml_test_imports) = includes_from_zcml(path)
+    doctest_imports = imports_from_doctests(path)
 
     print_unused_imports(unused_imports)
 
@@ -229,23 +286,26 @@
                                      install_required + stdlib)
     print_modules(install_missing, "Missing requirements")
 
-    test_missing = filter_missing(test_imports + zcml_test_imports,
-                                  install_required + test_required + stdlib)
+    test_missing = filter_missing(
+        test_imports + zcml_test_imports + doctest_imports,
+        install_required + test_required + stdlib)
     print_modules(test_missing, "Missing test requirements")
 
     install_unneeded = filter_unneeded(install_imports + zcml_imports,
                                        install_required)
     # See if one of ours is needed by the tests
-    really_unneeded = filter_unneeded(test_imports + zcml_test_imports,
-                                      install_unneeded)
+    really_unneeded = filter_unneeded(
+        test_imports + zcml_test_imports + doctest_imports,
+        install_unneeded)
     move_to_test = sorted(set(install_unneeded) - set(really_unneeded))
 
     print_modules(really_unneeded, "Unneeded requirements")
     print_modules(move_to_test,
                   "Requirements that should be test requirements")
 
-    test_unneeded = filter_unneeded(test_imports + zcml_test_imports,
-                                    test_required)
+    test_unneeded = filter_unneeded(
+        test_imports + zcml_test_imports + doctest_imports,
+        test_required)
     print_modules(test_unneeded, "Unneeded test requirements")
 
 

Modified: z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/dependencychecker.txt
===================================================================
--- z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/dependencychecker.txt	2009-12-10 13:53:44 UTC (rev 106392)
+++ z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/dependencychecker.txt	2009-12-10 14:19:21 UTC (rev 106393)
@@ -100,4 +100,53 @@
     >>> dependencychecker.filter_unneeded(imports, required)
     ['a', 'b', 'c']
 
+
+Testing the regexes
+-------------------
+
+Finding package="" in zcml files:
+
+    >>> import re
+    >>> input = ''
+    >>> re.findall(dependencychecker.ZCML_PACKAGE_PATTERN, input)
+    []
+    >>> input = '<bla\npackage="zope.interface"/>'
+    >>> re.findall(dependencychecker.ZCML_PACKAGE_PATTERN, input)
+    ['zope.interface']
+
+Finding imports in doctests:
+
+    >>> input = ''
+    >>> re.findall(dependencychecker.DOCTEST_IMPORT, input)
+    []
+    >>> input = '    >>> print 7'
+    >>> re.findall(dependencychecker.DOCTEST_IMPORT, input)
+    []
+    >>> input = '    >>> import zope.interface'
+    >>> re.findall(dependencychecker.DOCTEST_IMPORT, input)
+    ['zope.interface']
+    >>> input = '    >>> #import zope.interface'
+    >>> re.findall(dependencychecker.DOCTEST_IMPORT, input)
+    []
+
+Finding from-imports in doctests:
+
+    >>> input = ''
+    >>> re.findall(dependencychecker.DOCTEST_FROM_IMPORT, input)
+    []
+    >>> input = '    >>> print 7'
+    >>> re.findall(dependencychecker.DOCTEST_FROM_IMPORT, input)
+    []
+    >>> input = '    >>> from zope import interface'
+    >>> re.findall(dependencychecker.DOCTEST_FROM_IMPORT, input)
+    [('zope', 'interface')]
+    >>> input = '    >>> from zope import interface, component'
+    >>> re.findall(dependencychecker.DOCTEST_FROM_IMPORT, input)
+    [('zope', 'interface, component')]
+    >>> input = '    >>> #from zope import interface'
+    >>> re.findall(dependencychecker.DOCTEST_FROM_IMPORT, input)
+    []
+
+
+
 """

Modified: z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/sample1/setup.py_in
===================================================================
--- z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/sample1/setup.py_in	2009-12-10 13:53:44 UTC (rev 106392)
+++ z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/sample1/setup.py_in	2009-12-10 14:19:21 UTC (rev 106393)
@@ -27,7 +27,9 @@
           'test': [
               # Don't forget to add this by hand to the
               # src/sample1.egg-info/requires.txt file!
+              'my.package',
               'z3c.testsetup>=0.3',
+              'zope.testbrowser',
               'zope.testing',
               ],
           },

Modified: z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/sample1/src/sample1.egg-info/requires.txt
===================================================================
--- z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/sample1/src/sample1.egg-info/requires.txt	2009-12-10 13:53:44 UTC (rev 106392)
+++ z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/sample1/src/sample1.egg-info/requires.txt	2009-12-10 14:19:21 UTC (rev 106393)
@@ -4,5 +4,7 @@
 needed.by.test
 
 [test]
+my.package
 z3c.testsetup>=0.3
+zope.testbrowser
 zope.testing
\ No newline at end of file



More information about the checkins mailing list