[Checkins] SVN: z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/ Branch for working on better detection of zcml and doctest dependencies.
Jacob Holm
jh at improva.dk
Fri May 14 12:38:55 EDT 2010
Log message for revision 112301:
Branch for working on better detection of zcml and doctest dependencies.
Changed:
A z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/
U z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/USAGE.txt
U z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/dependencychecker.py
U z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/importchecker.py
U z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/tests/dependencychecker.txt
-=-
Modified: z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/USAGE.txt
===================================================================
--- z3c.dependencychecker/trunk/src/z3c/dependencychecker/USAGE.txt 2010-05-13 20:06:15 UTC (rev 112298)
+++ z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/USAGE.txt 2010-05-14 16:38:54 UTC (rev 112301)
@@ -38,9 +38,9 @@
>>> dependencychecker.main()
Unused imports
==============
- /TESTTEMP/sample1/src/sample1/unusedimports.py:7: tempfile
/TESTTEMP/sample1/src/sample1/unusedimports.py:4: zest.releaser
/TESTTEMP/sample1/src/sample1/unusedimports.py:6: os
+ /TESTTEMP/sample1/src/sample1/unusedimports.py:7: tempfile
<BLANKLINE>
Missing requirements
====================
Modified: z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/dependencychecker.py
===================================================================
--- z3c.dependencychecker/trunk/src/z3c/dependencychecker/dependencychecker.py 2010-05-13 20:06:15 UTC (rev 112298)
+++ z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/dependencychecker.py 2010-05-14 16:38:54 UTC (rev 112301)
@@ -15,85 +15,29 @@
import fnmatch
import optparse
import os
-import re
import sys
+import xml.sax.handler
import pkg_resources
from z3c.dependencychecker import importchecker
-ZCML_PACKAGE_PATTERN = re.compile(r"""
-\s # Whitespace.
-package= #
-['\"] # Single or double quote.
-(?P<import> # Start of 'import' variable.
-\S+ # Non-whitespace string.
-) # End of 'import' variable.
-['\"] # Single or double quote.
-""", re.VERBOSE)
-
-ZCML_COMPONENT_PATTERN = re.compile(r"""
-\s # Whitespace.
-component= #
-['\"] # Single or double quote.
-(?P<import> # Start of 'import' variable.
-\S+ # Non-whitespace string.
-) # End of 'import' variable.
-['\"] # Single or double quote.
-""", 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()):
+ for path in unused_imports.keys():
for (module, line_number) in unused_imports[path]:
found.append((path, line_number, module))
if found:
print "Unused imports"
print "=============="
- for (path, line_number, module) in found:
+ for (path, line_number, module) in sorted(found):
print "%s:%s: %s" % (path, line_number, module)
print
def name_from_setup():
+ os.environ['PYTHONPATH'] = ':'.join(sys.path)
cmd = "%s setup.py --name" % sys.executable
name = commands.getoutput(cmd).strip()
if 'traceback' in name.lower():
@@ -122,13 +66,13 @@
sys.exit(1)
lines = [line.strip() for line in open(requires_filename).readlines()]
lines = [line for line in lines if line]
- install_required = []
- test_required = []
+ install_required = set()
+ test_required = set()
for line in lines:
if line.startswith('['):
break
req = pkg_resources.Requirement.parse(line)
- install_required.append(req.project_name)
+ install_required.add(req.project_name)
start = False
for line in lines:
if line == '[test]':
@@ -139,23 +83,23 @@
if line.startswith('['):
break
req = pkg_resources.Requirement.parse(line)
- test_required.append(req.project_name)
+ test_required.add(req.project_name)
# The project itself is of course both available and needed.
- install_required.append(name)
+ install_required.add(name)
# Distribute says it is setuptools. Setuptools also includes
# pkg_resources.
if 'distribute' in install_required:
- install_required.append('setuptools')
+ install_required.add('setuptools')
if 'setuptools' in install_required:
- install_required.append('pkg_resources')
+ install_required.add('pkg_resources')
return (install_required, test_required)
def filter_missing(imports, required):
- missing = []
+ missing = set()
for needed in imports:
found = False
for req in required:
@@ -166,29 +110,26 @@
# check with an extra dot.
found = True
if not found:
- missing.append(needed)
- missing = sorted(set(missing))
+ missing.add(needed)
+ missing = set(missing)
return missing
def filter_unneeded(imports, required):
name = name_from_setup()
- imports.append(name) # We always use ourselves, obviously.
- imports = set(imports)
- required = set(required)
+ imports.add(name) # We always use ourselves, obviously.
setuptools_and_friends = set(
['distribute', 'setuptools', 'pkg_resources'])
required = required - setuptools_and_friends
- unneeded = []
+ unneeded = set()
for req in required:
found = False
for module in imports:
if module.lower().startswith(req.lower()):
found = True
if not found:
- unneeded.append(req)
- unneeded = sorted(set(unneeded))
+ unneeded.add(req)
return unneeded
@@ -218,55 +159,123 @@
dynload_module = datetime
modules = _detect_modules(py_module) + _detect_modules(dynload_module)
modules.append('sys')
- return list(set(modules))
+ return set(modules)
+def get_import_name(path, _cache={}):
+ import_name = _cache.get(path)
+ if import_name is not None:
+ return import_name
+ # Determine the name of the module/package.
+ parts = []
+ if os.path.isfile(path):
+ path, modulefn = os.path.split(path)
+ parts.append(os.path.splitext(modulefn)[0])
+ while os.path.isfile(os.path.join(path, '__init__.py')):
+ path, name = os.path.split(path)
+ parts.append(name)
+ import_name = '.'.join(reversed(parts))
+ _cache[path] = import_name
+ return import_name
+
+
+class ZCMLDependencyParser(xml.sax.handler.ContentHandler):
+
+ def __init__(self, packagename):
+ self.dependencies = set()
+ self.stack = [packagename]
+
+ def _absolutename(self, relativename):
+ assert relativename
+ for pos,c in enumerate(relativename):
+ if c!='.':
+ break
+ if pos:
+ absolutename = (
+ self.stack[-1].rsplit('.', pos-1)[0] + relativename[pos-1:]
+ )
+ else:
+ absolutename = relativename
+ return absolutename
+
+ def startElement(self, tag, attrib):
+ if tag == 'configure':
+ package = attrib.get('package')
+ if package is None:
+ name = self.stack[-1]
+ else:
+ name = self._absolutename(package)
+ self.stack.append(name)
+ self.dependencies.add(name)
+ else:
+ for attrname in ('allowed_interface',
+ 'class',
+ 'component',
+ 'content_factory',
+ 'factory',
+ 'for',
+ 'handler',
+ 'interface',
+ 'layer',
+ 'like_class',
+ 'module',
+ 'package',
+ 'provides',
+ 'schema',
+ 'set_schema',
+ 'type',
+ 'usedIn',
+ ):
+ attr = attrib.get(attrname)
+ if attr is not None:
+ for name in attr.split():
+ if name!='*':
+ self.dependencies.add(self._absolutename(name))
+
+ def endElement(self, tag):
+ if tag == 'configure':
+ self.stack.pop()
+
+
def includes_from_zcml(path):
- modules = []
- test_modules = []
+ modules = set()
+ test_modules = set()
for path, dirs, files in os.walk(path):
for zcml in [os.path.abspath(os.path.join(path, filename))
for filename in files
if fnmatch.fnmatch(filename, '*.zcml')]:
- contents = open(zcml).read()
- found = [module for module in
- re.findall(ZCML_PACKAGE_PATTERN, contents)
- if not module.startswith('.')]
- found += [module for module in
- re.findall(ZCML_COMPONENT_PATTERN, contents)
- if not module.startswith('.')]
+ packagename = get_import_name(path)
+ target = ZCMLDependencyParser(packagename)
+ xml.sax.parse(zcml, target)
+ found = target.dependencies
if 'test' in zcml:
# ftesting.zcml, mostly.
- test_modules += found
+ test_modules |= found
else:
- modules += found
+ modules |= found
return modules, test_modules
def imports_from_doctests(path):
- test_modules = []
+ test_modules = set()
for path, dirs, files in os.walk(path):
+ dirs[:] = [d for d in dirs if d!='.svn']
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))
+ module = importchecker.Module(filename, True)
+ test_modules.update(module.getImportedModuleNames())
+ return test_modules
def print_modules(modules, heading):
if modules:
print heading
print '=' * len(heading)
- for module in modules:
+ for module in sorted(modules):
print " ", module
print
@@ -308,35 +317,35 @@
print_unused_imports(unused_imports)
- install_missing = filter_missing(install_imports + zcml_imports,
- install_required + stdlib)
+ install_missing = filter_missing(install_imports | zcml_imports,
+ install_required | stdlib)
print_modules(install_missing, "Missing requirements")
test_missing = filter_missing(
- test_imports + zcml_test_imports + doctest_imports,
- install_required + test_required + stdlib)
+ 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_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 + doctest_imports,
+ test_imports | zcml_test_imports | doctest_imports,
install_unneeded)
- move_to_test = sorted(set(install_unneeded) - set(really_unneeded))
+ move_to_test = install_unneeded - 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 + doctest_imports,
+ test_imports | zcml_test_imports | doctest_imports,
test_required)
print_modules(test_unneeded, "Unneeded test requirements")
if install_missing or test_missing or install_unneeded or test_unneeded:
print "Note: requirements are taken from the egginfo dir, so you need"
- print "to re-run buildout (or setup.py or whatever) for changes in "
+ print "to re-run buildout (or setup.py or whatever) for changes in"
print "setup.py to have effect."
print
Modified: z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/importchecker.py
===================================================================
--- z3c.dependencychecker/trunk/src/z3c/dependencychecker/importchecker.py 2010-05-13 20:06:15 UTC (rev 112298)
+++ z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/importchecker.py 2010-05-14 16:38:54 UTC (rev 112301)
@@ -22,6 +22,7 @@
import compiler
import os
import os.path
+import re
def _findDottedNamesHelper(node, result):
@@ -43,8 +44,6 @@
elif name == 'Name':
result.append(node.name)
return
- elif name == 'AssAttr':
- return
for child in more_node.getChildNodes():
_findDottedNamesHelper(child, result)
@@ -85,9 +84,15 @@
else:
name = as_name
names_dict[name] = orig_name
- self._map.setdefault(module_name, {'names': names_dict,
- 'lineno': stmt.lineno,
- 'fromimport': True})
+ record = {
+ 'names': names_dict,
+ 'lineno': stmt.lineno,
+ 'fromimport': True,
+ }
+ records = self._map.get(module_name)
+ if records is None:
+ self._map[module_name] = records = []
+ records.append(record)
def visitImport(self, stmt):
"""Will be called for 'import foo.bar' statements
@@ -97,9 +102,15 @@
name = orig_name
else:
name = as_name
- self._map.setdefault(orig_name, {'names': {name: orig_name},
- 'lineno': stmt.lineno,
- 'fromimport': False})
+ record = {
+ 'names': {name: orig_name},
+ 'lineno': stmt.lineno,
+ 'fromimport': False,
+ }
+ records = self._map.get(orig_name)
+ if records is None:
+ self._map[orig_name] = records = []
+ records.append(record)
def getMap(self):
return self._map
@@ -117,8 +128,19 @@
"""This represents a python module.
"""
- def __init__(self, path):
- mod = compiler.parseFile(path)
+ _doctest_line = re.compile('^\s*(?:>>>|\.\.\.) (.*)$', re.M)
+
+ def __init__(self, path, extract_from_doctest = False):
+ if extract_from_doctest:
+ fd = open(path, 'rU')
+ try:
+ source = fd.read()
+ finally:
+ fd.close()
+ testsource = '\n'.join(self._doctest_line.findall(source))
+ mod = compiler.parse(testsource)
+ else:
+ mod = compiler.parseFile(path)
self._path = path
self._map = findImports(mod)
self._dottednames = findDottedNames(mod)
@@ -132,36 +154,38 @@
"""Return the names of imported modules.
"""
result = []
- for modulename in self._map.keys():
- if not self._map[modulename]['fromimport']:
- # Regular import
- result.append(modulename)
- else:
- # from xyz import abc, return xyz.abc to help with detecting
- # "from zope import interface"-style imports where
- # zope.inteface is the real module and zope just a namespace
- # package. This is for the dependencychecker, btw.
- if len(self._map[modulename]['names'].values()) == 0:
- # from xyz import *
+ for modulename, records in self._map.items():
+ for record in records:
+ if not record['fromimport']:
+ # Regular import
result.append(modulename)
- for submodule in self._map[modulename]['names'].values():
- result.append('.'.join([modulename, submodule]))
+ else:
+ # from xyz import abc, return xyz.abc to help with detecting
+ # "from zope import interface"-style imports where
+ # zope.inteface is the real module and zope just a namespace
+ # package. This is for the dependencychecker, btw.
+ subnames = record['names'].values()
+ if len(subnames) == 0:
+ # from xyz import *
+ result.append(modulename)
+ for subname in subnames:
+ result.append('.'.join([modulename, subname]))
return result
def getImportNames(self):
"""Return the names of imports; add dottednames as well.
"""
result = []
- map = self._map
- for module_name in map.keys():
- for usedname, originalname in map[module_name]['names'].items():
- result.append((originalname, module_name))
- # add any other name that we could be using
- for dottedname in self._dottednames:
- usednamedot = usedname + '.'
- if dottedname.startswith(usednamedot):
- attrname = dottedname[len(usednamedot):].split('.')[0]
- result.append((attrname, module_name))
+ for module_name, records in self._map.items():
+ for record in records:
+ for usedname, originalname in record['names'].items():
+ result.append((originalname, module_name))
+ # add any other name that we could be using
+ for dottedname in self._dottednames:
+ usednamedot = usedname + '.'
+ if dottedname.startswith(usednamedot):
+ attrname = dottedname[len(usednamedot):].split('.', 1)[0]
+ result.append((attrname, module_name))
return result
@@ -169,13 +193,15 @@
"""Get unused imports of this module (the whole import info).
"""
result = []
- for value in self._map.values():
- for usedname, originalname in value['names'].items():
- if usedname not in self._dottednames:
- result.append((originalname, value['lineno']))
+ for records in self._map.values():
+ for record in records:
+ for usedname, originalname in record['names'].items():
+ if usedname not in self._dottednames:
+ result.append((originalname, record['lineno']))
return result
+
class ModuleFinder:
def __init__(self):
@@ -282,7 +308,6 @@
def getImportedModuleNames(self, tests=False):
"""returns all names imported by modules"""
result = set()
- import os
for path, module in self._modules.items():
# remove .py
parts = path[:-3].split(os.path.sep)
@@ -290,15 +315,15 @@
or 'ftests' in parts
if (tests and isTest) or (not tests and not isTest):
result.update(module.getImportedModuleNames())
- return sorted(result)
+ return result
def getUnusedImportsInModule(self, module):
"""Get all unused imports in a module.
"""
- result = []
+ result = set()
for name, lineno in module.getUnusedImports():
if not self.isNameImportedFrom(name, module):
- result.append((name, lineno))
+ result.add((name, lineno))
return result
def isNameImportedFrom(self, name, module):
@@ -309,7 +334,7 @@
def getModulesImportingNameFrom(self, name, module):
"""Return list of known modules that import name from module.
"""
- result = []
+ result = set()
for path in self._names.get((module.getPath(), name), {}).keys():
- result.append(self._modules[path])
+ result.add(self._modules[path])
return result
Modified: z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/tests/dependencychecker.txt
===================================================================
--- z3c.dependencychecker/trunk/src/z3c/dependencychecker/tests/dependencychecker.txt 2010-05-13 20:06:15 UTC (rev 112298)
+++ z3c.dependencychecker/branches/jacobholm-improved-zcml-and-doctest-handling/src/z3c/dependencychecker/tests/dependencychecker.txt 2010-05-14 16:38:54 UTC (rev 112301)
@@ -11,70 +11,56 @@
Empty lists, no problems:
- >>> dependencychecker.filter_missing([], [])
- []
+ >>> dependencychecker.filter_missing(set(), set())
+ set([])
Exact matching lists result in an empty list:
- >>> dependencychecker.filter_missing(['a'], ['a'])
- []
+ >>> dependencychecker.filter_missing(set(['a']), set(['a']))
+ set([])
A missing import is reported:
- >>> imports = ['flup']
- >>> required = []
+ >>> imports = set(['flup'])
+ >>> required = set()
>>> dependencychecker.filter_missing(imports, required)
- ['flup']
+ set(['flup'])
-Everything is reported just once:
-
- >>> imports = ['flup', 'flup']
- >>> required = []
- >>> dependencychecker.filter_missing(imports, required)
- ['flup']
-
-And it sorted for reproducible display:
-
- >>> imports = ['a', 'c', 'b']
- >>> required = []
- >>> dependencychecker.filter_missing(imports, required)
- ['a', 'b', 'c']
-
A requirement for some.thing is assumed to be enough for some.thing.else:
- >>> imports = ['some.thing.else']
- >>> required = ['some.thing']
+ >>> imports = set(['some.thing.else'])
+ >>> required = set(['some.thing'])
>>> dependencychecker.filter_missing(imports, required)
- []
- >>> required = ['Some.Thing'] # case insensitive
+ set([])
+ >>> required = set(['Some.Thing']) # case insensitive
>>> dependencychecker.filter_missing(imports, required)
- []
- >>> required = ['Some']
+ set([])
+ >>> required = set(['Some'])
>>> dependencychecker.filter_missing(imports, required)
- []
+ set([])
But a requirement that is more specific than the import fails:
- >>> imports = ['some.thing']
- >>> required = ['some.thing.else']
+ >>> imports = set(['some.thing'])
+ >>> required = set(['some.thing.else'])
>>> dependencychecker.filter_missing(imports, required)
- ['some.thing']
+ set(['some.thing'])
Watch out with similar names:
- >>> imports = ['zope.app.securitypolicy']
- >>> required = ['zope.app.security']
+ >>> imports = set(['zope.app.securitypolicy'])
+ >>> required = set(['zope.app.security'])
>>> dependencychecker.filter_missing(imports, required)
- ['zope.app.securitypolicy']
+ set(['zope.app.securitypolicy'])
An oft-occurring example is a an import like ``from zope import interface``,
and a requirement for ``zope.interface``. zope is picked up by the
importchecker mechanism (not zope.interface!), so we get the following problem:
- >>> imports = ['zope']
- >>> required = ['zope.interface']
+ >>> imports = set(['zope'])
+ >>> required = set(['zope.interface'])
>>> dependencychecker.filter_missing(imports, required)
- ['zope']
+ set(['zope'])
Filter out unneeded requirements
@@ -82,83 +68,69 @@
Empty lists, no problems:
- >>> dependencychecker.filter_unneeded([], [])
- []
+ >>> dependencychecker.filter_unneeded(set(), set())
+ set([])
Exact matches are fine:
- >>> imports = ['zope.interface']
- >>> required = ['zope.interface']
+ >>> imports = set(['zope.interface'])
+ >>> required = set(['zope.interface'])
>>> dependencychecker.filter_unneeded(imports, required)
- []
+ set([])
Too-specific requirements are reported:
- >>> imports = ['zope']
- >>> required = ['zope.interface']
+ >>> imports = set(['zope'])
+ >>> required = set(['zope.interface'])
>>> dependencychecker.filter_unneeded(imports, required)
- ['zope.interface']
+ set(['zope.interface'])
-There are no duplicates in the output:
- >>> imports = []
- >>> required = ['a', 'a']
- >>> dependencychecker.filter_unneeded(imports, required)
- ['a']
-
-And the output is sorted:
-
- >>> imports = []
- >>> required = ['a', 'c', 'b']
- >>> 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']
+# >>> 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)
- []
+# >>> 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)
- []
+# >>> 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)
+# []
Grabbing the name from setup.py
More information about the checkins
mailing list