[Zope3-checkins] SVN: Zope3/branches/ZopeX3-3.0/ Added a couple of
useful scripts to the distribution.
Stephan Richter
srichter at cosmos.phy.tufts.edu
Wed Sep 1 19:47:48 EDT 2004
Log message for revision 27399:
Added a couple of useful scripts to the distribution.
Changed:
U Zope3/branches/ZopeX3-3.0/src/zope/app/locales/extract.py
A Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nextract.in
A Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nmergeall.in
A Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nstats.in
A Zope3/branches/ZopeX3-3.0/zopeskel/bin/importchecker.in
A Zope3/branches/ZopeX3-3.0/zopeskel/bin/pyskel.in
-=-
Modified: Zope3/branches/ZopeX3-3.0/src/zope/app/locales/extract.py
===================================================================
--- Zope3/branches/ZopeX3-3.0/src/zope/app/locales/extract.py 2004-09-01 21:13:44 UTC (rev 27398)
+++ Zope3/branches/ZopeX3-3.0/src/zope/app/locales/extract.py 2004-09-01 23:47:48 UTC (rev 27399)
@@ -306,14 +306,15 @@
# strings have the domain the user specified.
return eater.getCatalog()
-def zcml_strings(dir, domain="zope"):
+def zcml_strings(dir, domain="zope", site_zcml=None):
"""Retrieve all ZCML messages from dir that are in the domain.
"""
from zope.app.appsetup import config
import zope
dirname = os.path.dirname
- site_zcml = os.path.join(dirname(dirname(dirname(zope.__file__))),
- "site.zcml")
+ if site_zcml is None:
+ site_zcml = os.path.join(dirname(dirname(dirname(zope.__file__))),
+ "site.zcml")
context = config(site_zcml, execute=False)
return context.i18n_strings.get(domain, {})
Added: Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nextract.in
===================================================================
--- Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nextract.in 2004-09-01 21:13:44 UTC (rev 27398)
+++ Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nextract.in 2004-09-01 23:47:48 UTC (rev 27399)
@@ -0,0 +1,158 @@
+#!<<PYTHON>>
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Program to extract internationalization markup from Python Code,
+Page Templates and ZCML.
+
+This tool will extract all findable message strings from all
+internationalizable files in your Zope 3 product. It only extracts message ids
+of the specified domain. It defaults to the 'zope' domain and the zope
+package.
+
+Note: The Python Code extraction tool does not support domain
+ registration, so that all message strings are returned for
+ Python code.
+
+Note: The script expects to be executed either from inside the Zope 3 source
+ tree or with the Zope 3 source tree on the Python path. Execution from
+ a symlinked directory inside the Zope 3 source tree will not work.
+
+Usage: i18nextract.py [options]
+Options:
+ -h / --help
+ Print this message and exit.
+ -d / --domain <domain>
+ Specifies the domain that is supposed to be extracted (i.e. 'zope')
+ -p / --path <path>
+ Specifies the package that is supposed to be searched
+ (i.e. 'zope/app')
+ -o dir
+ Specifies a directory, relative to the package in which to put the
+ output translation template.
+
+$Id$
+"""
+import os, sys, getopt
+
+SOFTWARE_HOME = "<<SOFTWARE_HOME>>"
+INSTANCE_HOME = "<<INSTANCE_HOME>>"
+
+def usage(code, msg=''):
+ # Python 2.1 required
+ print >> sys.stderr, __doc__
+ if msg:
+ print >> sys.stderr, msg
+ sys.exit(code)
+
+def app_dir():
+ try:
+ import zope
+ except ImportError:
+ # Couldn't import zope, need to add something to the Python path
+
+ # Get the path of the src
+ path = os.path.abspath(os.getcwd())
+ while not path.endswith('src'):
+ parentdir = os.path.dirname(path)
+ if path == parentdir:
+ # root directory reached
+ break
+ path = parentdir
+ sys.path.insert(0, path)
+
+ try:
+ import zope
+ except ImportError:
+ usage(1, "Make sure the script has been executed "
+ "inside Zope 3 source tree.")
+
+ return os.path.dirname(zope.__file__)
+
+def main(argv=sys.argv):
+ try:
+ opts, args = getopt.getopt(
+ sys.argv[1:],
+ 'hd:p:o:',
+ ['help', 'domain=', 'path=', 'python-only'])
+ except getopt.error, msg:
+ usage(1, msg)
+
+ domain = 'zope'
+ path = app_dir()
+ include_default_domain = True
+ output_dir = None
+ python_only = None
+ for opt, arg in opts:
+ if opt in ('-h', '--help'):
+ usage(0)
+ elif opt in ('-d', '--domain'):
+ domain = arg
+ include_default_domain = False
+ elif opt in ('-o', ):
+ output_dir = arg
+ elif opt in ('--python-only',):
+ python_only = True
+ elif opt in ('-p', '--path'):
+ if not os.path.exists(arg):
+ usage(1, 'The specified path does not exist.')
+ path = arg
+ # We might not have an absolute path passed in.
+ if not path == os.path.abspath(path):
+ cwd = os.getcwd()
+ # This is for symlinks. Thanks to Fred for this trick.
+ if os.environ.has_key('PWD'):
+ cwd = os.environ['PWD']
+ path = os.path.normpath(os.path.join(cwd, arg))
+
+ # When generating the comments, we will not need the base directory info,
+ # since it is specific to everyone's installation
+ src_start = path.rfind('lib/python')
+ base_dir = path[:src_start]
+
+ output_file = domain+'.pot'
+ if output_dir:
+ output_dir = os.path.join(path, output_dir)
+ if not os.path.exists(output_dir):
+ os.mkdir(output_dir)
+ output_file = os.path.join(output_dir, output_file)
+
+ print "base path: %r\nsearch path: %r\ndomain: %r\noutput file: %r" \
+ % (base_dir, path, domain, output_file)
+
+ from zope.app.locales.extract import POTMaker, \
+ py_strings, tal_strings, zcml_strings
+
+ maker = POTMaker(output_file, path)
+ maker.add(py_strings(path, domain), base_dir)
+ if not python_only:
+ site_zcml = os.path.join(INSTANCE_HOME, 'etc', 'site.zcml')
+ maker.add(zcml_strings(path, domain, site_zcml), base_dir)
+ maker.add(tal_strings(path, domain, include_default_domain), base_dir)
+ maker.write()
+
+
+def run():
+ # This removes the script directory from sys.path, which we do
+ # since there are no modules here.
+ #
+ basepath = filter(None, sys.path)
+
+ sys.path[:] = [os.path.join(INSTANCE_HOME, "lib", "python"),
+ SOFTWARE_HOME] + basepath
+
+ main()
+
+
+if __name__ == '__main__':
+ run()
Property changes on: Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nextract.in
___________________________________________________________________
Name: svn:executable
+ *
Added: Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nmergeall.in
===================================================================
--- Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nmergeall.in 2004-09-01 21:13:44 UTC (rev 27398)
+++ Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nmergeall.in 2004-09-01 23:47:48 UTC (rev 27399)
@@ -0,0 +1,87 @@
+#!<<PYTHON>>
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Merge a POT file with all languages
+
+This utility requires the GNU gettext package to be installed. The command
+'msgmerge' will be executed for each language.
+
+Usage: i18mergeall.py [options]
+Options:
+
+ -h / --help
+ Print this message and exit.
+
+ -l / --locales-dir
+ Specify the 'locales' directory for which to generate the statistics.
+
+$Id: i18nmergeall.py 26446 2004-07-13 16:11:36Z philikon $
+"""
+import sys
+import os
+import getopt
+
+def usage(code, msg=''):
+ """Display help."""
+ print >> sys.stderr, '\n'.join(__doc__.split('\n')[:-2])
+ if msg:
+ print >> sys.stderr, '** Error: ' + str(msg) + ' **'
+ sys.exit(code)
+
+
+def main(path):
+ for language in os.listdir(path):
+ lc_messages_path = os.path.join(path, language, 'LC_MESSAGES')
+
+ # English is the default for Zope, so ignore it
+ if language == 'en':
+ continue
+
+ # Make sure we got a language directory
+ if not os.path.isdir(lc_messages_path):
+ continue
+
+ msgs = []
+ for domain_file in os.listdir(lc_messages_path):
+ if domain_file.endswith('.po'):
+ domain_path = os.path.join(lc_messages_path, domain_file)
+ pot_path = os.path.join(path, domain_file+'t')
+ domain = domain_file.split('.')[0]
+ print 'Merging language "%s", domain "%s"' %(language, domain)
+ os.system('msgmerge -U %s %s' %(domain_path, pot_path))
+
+
+if __name__ == '__main__':
+ try:
+ opts, args = getopt.getopt(
+ sys.argv[1:],
+ 'l:h',
+ ['help', 'locals-dir='])
+ except getopt.error, msg:
+ usage(1, msg)
+
+ path = None
+ for opt, arg in opts:
+ if opt in ('-h', '--help'):
+ usage(0)
+ elif opt in ('-l', '--locales-dir'):
+ cwd = os.getcwd()
+ # This is for symlinks. Thanks to Fred for this trick.
+ if os.environ.has_key('PWD'):
+ cwd = os.environ['PWD']
+ path = os.path.normpath(os.path.join(cwd, arg))
+
+ if path is None:
+ usage(1, 'You must specify the path to the locales directory.')
+ main(path)
Property changes on: Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nmergeall.in
___________________________________________________________________
Name: svn:executable
+ *
Added: Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nstats.in
===================================================================
--- Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nstats.in 2004-09-01 21:13:44 UTC (rev 27398)
+++ Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nstats.in 2004-09-01 23:47:48 UTC (rev 27399)
@@ -0,0 +1,167 @@
+#!<<PYTHON>>
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Translation Statistics Utility
+
+Utility to determine the status of the translations.
+
+Usage: i18nstats.py [options]
+Options:
+
+ -h / --help
+ Print this message and exit.
+
+ -l / --locales-dir
+ Specify the 'locales' directory for which to generate the statistics.
+
+$Id$
+"""
+import sys
+import os
+import getopt
+
+SEARCHING = 0
+COMMENT = 1
+MSGID = 2
+MSGSTR = 3
+MSGDONE = 4
+
+def usage(code, msg=''):
+ """Display help."""
+ print >> sys.stderr, '\n'.join(__doc__.split('\n')[:-2])
+ if msg:
+ print >> sys.stderr, '** Error: ' + str(msg) + ' **'
+ sys.exit(code)
+
+
+def getMessageDictionary(file):
+ """Simple state machine."""
+
+ msgs = []
+ comment = []
+ msgid = []
+ msgstr = []
+ fuzzy = False
+ line_counter = 0
+ status = SEARCHING
+
+ for line in file.readlines():
+ line = line.strip('\n')
+ line_counter += 1
+
+ # Handle Events
+ if line.startswith('#'):
+ status = COMMENT
+
+ elif line.startswith('msgid'):
+ line = line[6:]
+ line_number = line_counter
+ status = MSGID
+
+ elif line.startswith('msgstr'):
+ line = line[7:]
+ status = MSGSTR
+
+ elif line == '':
+ status = MSGDONE
+
+ # Actions based on status
+ if status == MSGID:
+ msgid.append(line.strip('"'))
+
+ elif status == MSGSTR:
+ msgstr.append(line.strip('"'))
+
+ elif status == COMMENT:
+ if line.startswith('#, fuzzy'):
+ fuzzy = True
+ comment.append(line[1:].strip())
+
+ elif status == MSGDONE:
+ status = SEARCHING
+ # Avoid getting the meta-data message string
+ if ''.join(msgid):
+ msgs.append( (''.join(msgid), ''.join(msgstr),
+ line_number, '\n'.join(comment), fuzzy) )
+ comment = []
+ msgid = []
+ msgstr = []
+ fuzzy = False
+
+ return msgs
+
+
+def main(path):
+ print 'Language Total Done Not Done Fuzzy Done %'
+ print '=========================================================='
+ languages = os.listdir(path)
+ languages.sort()
+ for language in languages:
+ lc_messages_path = os.path.join(path, language, 'LC_MESSAGES')
+
+ # Make sure we got a language directory
+ if not os.path.isdir(lc_messages_path):
+ continue
+
+ msgs = []
+ for domain_file in os.listdir(lc_messages_path):
+ if domain_file.endswith('.po'):
+ domain_path = os.path.join(lc_messages_path, domain_file)
+ file = open(domain_path, mode='r')
+ msgs += getMessageDictionary(file)
+
+ # We are dealing with the default language, which always has just one
+ # message string for the meta data (which is not recorded).
+ if len(msgs) == 0:
+ continue
+
+ total = len(msgs)
+ not_done = len([msg for msg in msgs if msg[1] == ''])
+ fuzzy = len([msg for msg in msgs if msg[4] is True])
+ done = total - not_done - fuzzy
+ percent_done = 100.0 * done/total
+
+ line = language + ' '*(8-len(language))
+ line += ' '*(9-len(str(total))) + str(total)
+ line += ' '*(8-len(str(done))) + str(done)
+ line += ' '*(12-len(str(not_done))) + str(not_done)
+ line += ' '*(9-len(str(fuzzy))) + str(fuzzy)
+ pd_str = '%0.2f %%' %percent_done
+ line += ' '*(12-len(pd_str)) + pd_str
+ print line
+
+
+if __name__ == '__main__':
+ try:
+ opts, args = getopt.getopt(
+ sys.argv[1:],
+ 'l:h',
+ ['help', 'locals-dir='])
+ except getopt.error, msg:
+ usage(1, msg)
+
+ path = None
+ for opt, arg in opts:
+ if opt in ('-h', '--help'):
+ usage(0)
+ elif opt in ('-l', '--locales-dir'):
+ cwd = os.getcwd()
+ # This is for symlinks. Thanks to Fred for this trick.
+ if os.environ.has_key('PWD'):
+ cwd = os.environ['PWD']
+ path = os.path.normpath(os.path.join(cwd, arg))
+
+ if path is None:
+ usage(1, 'You must specify the path to the locales directory.')
+ main(path)
Property changes on: Zope3/branches/ZopeX3-3.0/zopeskel/bin/i18nstats.in
___________________________________________________________________
Name: svn:executable
+ *
Added: Zope3/branches/ZopeX3-3.0/zopeskel/bin/importchecker.in
===================================================================
--- Zope3/branches/ZopeX3-3.0/zopeskel/bin/importchecker.in 2004-09-01 21:13:44 UTC (rev 27398)
+++ Zope3/branches/ZopeX3-3.0/zopeskel/bin/importchecker.in 2004-09-01 23:47:48 UTC (rev 27399)
@@ -0,0 +1,313 @@
+#!<<PYTHON>>
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Import checker
+
+This utility finds unused imports in Python modules. Its output is
+grep-like and thus emacs-friendly.
+
+$Id: importchecker.py 26446 2004-07-13 16:11:36Z philikon $
+"""
+import compiler
+import os, os.path
+import sys
+
+def _findDottedNamesHelper(node, result):
+ more_node = node
+ name = node.__class__.__name__
+ if name == 'Getattr':
+ dotted = []
+ while name == 'Getattr':
+ dotted.append(node.attrname)
+ node = node.expr
+ name = node.__class__.__name__
+ if name == 'Name':
+ dotted.append(node.name)
+ dotted.reverse()
+ for i in range(1, len(dotted)):
+ result.append('.'.join(dotted[:i]))
+ result.append('.'.join(dotted))
+ return
+ elif name == 'Name':
+ result.append(node.name)
+ return
+ elif name == 'AssAttr':
+ return
+ for child in more_node.getChildNodes():
+ _findDottedNamesHelper(child, result)
+
+def findDottedNames(node):
+ """Find dotted names in an AST tree node
+ """
+ result = []
+ _findDottedNamesHelper(node, result)
+ return result
+
+class ImportFinder:
+ """An instance of this class will be used to walk over a compiler AST
+ tree (a module). During that operation, the appropriate methods of
+ this visitor will be called
+ """
+
+ def __init__(self):
+ self._map = {}
+
+ def visitFrom(self, stmt):
+ """Will be called for 'from foo import bar' statements
+ """
+ module_name, names = stmt.asList()
+ if module_name == '__future__':
+ # we don't care what's imported from the future
+ return
+ names_dict = {}
+ for orig_name, as_name in names:
+ # we don't care about from import *
+ if orig_name == '*':
+ continue
+ if as_name is None:
+ name = orig_name
+ else:
+ name = as_name
+ names_dict[name] = orig_name
+ self._map.setdefault(module_name, {'names': names_dict,
+ 'lineno': stmt.lineno})
+
+ def visitImport(self, stmt):
+ """Will be called for 'import foo.bar' statements
+ """
+ for orig_name, as_name in stmt.names:
+ if as_name is None:
+ name = orig_name
+ else:
+ name = as_name
+ self._map.setdefault(orig_name, {'names': {name: orig_name},
+ 'lineno': stmt.lineno})
+
+ def getMap(self):
+ return self._map
+
+def findImports(mod):
+ """Find import statements in module and put the result in a mapping.
+ """
+ visitor = ImportFinder()
+ compiler.walk(mod, visitor)
+ return visitor.getMap()
+
+class Module:
+ """This represents a python module.
+ """
+
+ def __init__(self, path):
+ mod = compiler.parseFile(path)
+ self._path = path
+ self._map = findImports(mod)
+ dottednames = {}
+ self._dottednames = findDottedNames(mod)
+
+ def getPath(self):
+ """Return the path to this module's file.
+ """
+ return self._path
+
+ def getImportedModuleNames(self):
+ """Return the names of imported modules.
+ """
+ return self._map.keys()
+
+ 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))
+ return result
+
+ def getUnusedImports(self):
+ """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']))
+ return result
+
+class ModuleFinder:
+
+ def __init__(self):
+ self._files = []
+
+ def visit(self, arg, dirname, names):
+ """This method will be called when we walk the filesystem
+ tree. It looks for python modules and stored their filenames.
+ """
+ for name in names:
+ # get all .py files that aren't weirdo emacs droppings
+ if name.endswith('.py') and not name.startswith('.#'):
+ self._files.append(os.path.join(dirname, name))
+
+ def getModuleFilenames(self):
+ return self._files
+
+def findModules(path):
+ """Find python modules in the given path and return their absolute
+ filenames in a sequence.
+ """
+ finder = ModuleFinder()
+ os.path.walk(path, finder.visit, ())
+ return finder.getModuleFilenames()
+
+class ImportDatabase:
+ """This database keeps tracks of imports.
+
+ It allows to NOT report cases where a module imports something
+ just so that another module can import it (import dependencies).
+ """
+
+ def __init__(self, root_path):
+ self._root_path = root_path
+ self._modules = {}
+ self._names = {}
+
+ def resolveDottedModuleName(self, dotted_name, module):
+ """Return path to file representing module, or None if no such
+ thing. Can do this relative from module.
+ """
+ dotted_path = dotted_name.replace('.', '/')
+ # try relative import first
+ path = os.path.join(os.path.dirname(module.getPath()), dotted_path)
+ path = self._resolveHelper(path)
+ if path is not None:
+ return path
+ # absolute import (assumed to be from this tree)
+ if os.path.isfile(os.path.join(self._root_path, '__init__.py')):
+ startpath, dummy = os.path.split(self._root_path)
+ else:
+ startpath = self._root_path
+ return self._resolveHelper(os.path.join(startpath, dotted_path))
+
+ def _resolveHelper(self, path):
+ if os.path.isfile(path + '.py'):
+ return path + '.py'
+ if os.path.isdir(path):
+ path = os.path.join(path, '__init__.py')
+ if os.path.isfile(path):
+ return path
+ return None
+
+ def findModules(self):
+ """Find modules in the given path.
+ """
+ for modulepath in findModules(self._root_path):
+ module = Module(modulepath)
+ self.addModule(module)
+
+ def addModule(self, module):
+ """Add information about a module to the database. A module in
+ this case is not a python module object, but an instance of
+ the above defined Module class.w
+ """
+ self_path = module.getPath()
+ # do nothing if we already know about it
+ if self._modules.has_key(self_path):
+ return
+
+ self._modules[self_path] = module
+
+ # add imported names to internal names mapping; this will
+ # allow us identify dependent imports later
+ names = self._names
+ for name, from_module_name in module.getImportNames():
+ path = self.resolveDottedModuleName(from_module_name, module)
+ t = (path, name)
+ modulepaths = names.get(t, {})
+ if not modulepaths.has_key(self_path):
+ modulepaths[self_path] = 1
+ names[t] = modulepaths
+
+ def getUnusedImports(self):
+ """Get unused imports of all known modules.
+ """
+ result = {}
+ for path, module in self._modules.items():
+ result[path] = self.getUnusedImportsInModule(module)
+ return result
+
+ def getUnusedImportsInModule(self, module):
+ """Get all unused imports in a module.
+ """
+ result = []
+ for name, lineno in module.getUnusedImports():
+ if not self.isNameImportedFrom(name, module):
+ result.append((name, lineno))
+ return result
+
+ def isNameImportedFrom(self, name, module):
+ """Return true if name is imported from module by another module.
+ """
+ return self._names.has_key((module.getPath(), name))
+
+ def getModulesImportingNameFrom(self, name, module):
+ """Return list of known modules that import name from module.
+ """
+ result = []
+ for path in self._names.get((module.getPath(), name), {}).keys():
+ result.append(self._modules[path])
+ return result
+
+def main():
+ try:
+ path = sys.argv[1]
+ except IndexError:
+ print "No path supplied"
+ sys.exit(1)
+
+ path = os.path.abspath(path)
+ if not os.path.isdir(path):
+ print "Unknown path:", path
+ sys.exit(1)
+
+ l = len(path) + 1
+ db = ImportDatabase(path)
+ db.findModules()
+ unused_imports = db.getUnusedImports()
+ module_paths = unused_imports.keys()
+ module_paths.sort()
+ for path in module_paths:
+ info = unused_imports[path]
+ path = path[l:]
+ if not info:
+ continue
+ line2names = {}
+ for name, line in info:
+ names = line2names.get(line, [])
+ names.append(name)
+ line2names[line] = names
+ lines = line2names.keys()
+ lines.sort()
+ for line in lines:
+ names = ', '.join(line2names[line])
+ print "%s:%s: %s" % (path, line, names)
+
+if __name__ == '__main__':
+ main()
+
Property changes on: Zope3/branches/ZopeX3-3.0/zopeskel/bin/importchecker.in
___________________________________________________________________
Name: svn:executable
+ *
Added: Zope3/branches/ZopeX3-3.0/zopeskel/bin/pyskel.in
===================================================================
--- Zope3/branches/ZopeX3-3.0/zopeskel/bin/pyskel.in 2004-09-01 21:13:44 UTC (rev 27398)
+++ Zope3/branches/ZopeX3-3.0/zopeskel/bin/pyskel.in 2004-09-01 23:47:48 UTC (rev 27399)
@@ -0,0 +1,201 @@
+#!<<PYTHON>>
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Generate method skeletons for intefaces.
+
+Usage: python pyskel.py dotted_name
+
+Example:
+
+ cd lib/python
+ python zope/interface/pyskel.py zope.app.interfaces.pigs.IPigService
+
+The dotted name is the module name and interface object name connected
+with a dot.
+
+$Id: pyskel.py 26446 2004-07-13 16:11:36Z philikon $
+"""
+import sys, os, re
+
+SOFTWARE_HOME = "<<SOFTWARE_HOME>>"
+INSTANCE_HOME = "<<INSTANCE_HOME>>"
+
+sys.path.insert(0, os.getcwd())
+
+from types import ModuleType
+from zope.interface.interface import Method
+from zope.interface import Attribute
+
+class_re = re.compile(r'\s*class\s+([a-zA-Z_][a-zA-Z0-9_]*)')
+def_re = re.compile(r'\s*def\s+([a-zA-Z_][a-zA-Z0-9_]*)')
+attr_re = re.compile(r'\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*Attribute')
+
+
+def rskel(iface, top, print_iface=1):
+ name = "%s.%s" % (iface.__module__, iface.__name__)
+
+ file = resolve(iface.__module__).__file__
+ if file.endswith('pyc'):
+ file = file[:-1]
+ order = guessOrder(open(file))
+ namesAndDescriptions = getAttributesInOrder(iface, order)
+
+ namesAndDescriptions = filter(lambda ades:
+ isinstance(ades[1], Method) or
+ isinstance(ades[1], Attribute),
+ namesAndDescriptions)
+
+ for aname, ades in namesAndDescriptions:
+ if isinstance(ades, Method):
+ sig = ades.getSignatureString()[1:-1]
+ if sig: sig = "self, %s" % sig
+ else: sig = "self"
+ print
+ print " def %s(%s):" % (aname, sig)
+ print ' "See %s"' % name
+
+ elif isinstance(ades, Attribute):
+ print
+ print " # See %s" % name
+ print " %s = None" %aname
+
+ else:
+ print
+ print 'Waaaa', ades
+
+ for base in iface.__bases__:
+ if base.__name__ not in ('Interface',):
+ rskel(base, top)
+
+def skel(name):
+ iface = resolve(name)
+ class_name = iface.__name__
+ if class_name.startswith('I'):
+ class_name = class_name[1:]
+ print "from zope.interface import implements"
+ print "from %s import %s" % (iface.__module__, iface.getName())
+ print
+ print "class %s:" %class_name
+ print " __doc__ = %s.__doc__" % iface.getName()
+ print
+ print " implements(%s)" %iface.getName()
+ print
+
+ rskel(iface, iface, 0)
+
+
+def resolve(name, _silly=('__doc__',), _globals={}):
+ # Support for file path syntax; this way I can use TAB to search for
+ # the module.
+ if '/' in name or name.endswith('.py'):
+ # We got a relative path. Let's try to get the full one and then
+ # make a package path out of it.
+ if not name.startswith('/'):
+ cwd = os.getcwd()
+ for path in sys.path[1:]: # Yeah, we need to exclude the cwd itself
+ path = str(path)
+ if path != '' and cwd.startswith(path):
+ name = os.path.join(cwd[len(path)+1:], name)
+ name = os.path.normpath(name)
+ break
+
+ # get rid of the file ending :)
+ if name.endswith('.py'):
+ name = name[:-3]
+ name = name.replace('/', '.')
+
+ # Now to the regular lookup
+ if name[:1]=='.':
+ name = 'zopeproducts' + name
+
+ if name[-1:] == '.':
+ name = name[:-1]
+ repeat = 1
+ else:
+ repeat = 0
+
+ names=name.split('.')
+ last=names[-1]
+ mod='.'.join(names[:-1])
+
+ while 1:
+ m=__import__(mod, _globals, _globals, _silly)
+ try:
+ a=getattr(m, last)
+ except AttributeError:
+ pass
+ else:
+ if not repeat or (type(a) is not ModuleType):
+ return a
+ mod += '.' + last
+
+
+def guessOrder(source_file):
+ order = {} # { class name -> list of methods }
+ lines = source_file.readlines()
+ class_name = None
+ for line in lines:
+ m = class_re.match(line)
+ if m and m.groups():
+ class_name = m.groups()[0]
+ else:
+ for m in (def_re.match(line),
+ attr_re.match(line)):
+ if m and m.groups():
+ def_name = m.groups()[0]
+ name_order = order.get(class_name)
+ if name_order is None:
+ name_order = []
+ order[class_name] = name_order
+ name_order.append(def_name)
+
+ return order
+
+
+def getAttributesInOrder(interface, order):
+ # order is the dictionary returned from guessOrder().
+ # interface is a metaclass-based interface object.
+ name_order = order.get(interface.getName())
+
+ if name_order is None:
+ # Something's wrong. Oh well.
+ items = interface.namesAndDescriptions()
+ items.sort()
+ return items
+ else:
+ items = []
+ for key, value in interface.namesAndDescriptions():
+ if key in name_order:
+ items.append((name_order.index(key), key, value))
+ else:
+ items.append((99999, key, value)) # Go to end.
+ items.sort()
+ return map(lambda item: item[1:], items)
+
+
+def run():
+ # This removes the script directory from sys.path, which we do
+ # since there are no modules here.
+ #
+ basepath = filter(None, sys.path)
+
+ sys.path[:] = [os.path.join(INSTANCE_HOME, "lib", "python"),
+ SOFTWARE_HOME] + basepath
+
+ for a in sys.argv[1:]:
+ skel(a)
+
+
+if __name__ == '__main__':
+ run()
Property changes on: Zope3/branches/ZopeX3-3.0/zopeskel/bin/pyskel.in
___________________________________________________________________
Name: svn:executable
+ *
More information about the Zope3-Checkins
mailing list