summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2010-10-25 10:34:49 -0400
committerChris McDonough <chrism@plope.com>2010-10-25 10:34:49 -0400
commit68a7110cda84e74f828f51d199f2e6872ba17f21 (patch)
tree8cf0284c413353f73550c981c559b316709195b2
parent30d55eb56a6171e03febceff65145a5c0c6aa3d3 (diff)
downloadpyramid-68a7110cda84e74f828f51d199f2e6872ba17f21.tar.gz
pyramid-68a7110cda84e74f828f51d199f2e6872ba17f21.tar.bz2
pyramid-68a7110cda84e74f828f51d199f2e6872ba17f21.zip
add 2to3 fixer script for repoze.bfg imports
-rw-r--r--pyramid/fixers/__init__.py1
-rw-r--r--pyramid/fixers/fix_bfg_imports.py178
-rw-r--r--setup.py2
3 files changed, 181 insertions, 0 deletions
diff --git a/pyramid/fixers/__init__.py b/pyramid/fixers/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/pyramid/fixers/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/pyramid/fixers/fix_bfg_imports.py b/pyramid/fixers/fix_bfg_imports.py
new file mode 100644
index 000000000..e93181be4
--- /dev/null
+++ b/pyramid/fixers/fix_bfg_imports.py
@@ -0,0 +1,178 @@
+import sys
+
+from lib2to3.refactor import get_fixers_from_package
+from lib2to3.refactor import RefactoringTool
+from lib2to3.fixer_util import Name
+from lib2to3.fixer_util import attr_chain
+from lib2to3 import fixer_base
+
+MAPPING = {'repoze.bfg':'pyramid'}
+
+for name in (
+ 'compat',
+ 'configuration',
+ 'authentication',
+ 'authorization',
+ 'chameleon_text',
+ 'chameleon_zpt',
+ 'decorator',
+ 'encode',
+ 'events',
+ 'exceptions',
+ 'i18n',
+ 'includes',
+ 'interfaces',
+ 'location',
+ 'log',
+ 'paster',
+ 'path',
+ 'registry',
+ 'renderers',
+ 'request',
+ 'resource',
+ 'router',
+ 'scripting',
+ 'security',
+ 'settings',
+ 'static',
+ 'testing',
+ 'tests',
+ 'tests.test_configuration',
+ 'tests.ccbugapp',
+ 'tests.exceptionviewapp',
+ 'repoze.bfg.tests.exceptionviewapp.models',
+ 'tests.fixtureapp',
+ 'tests.fixtureapp.models',
+ 'tests.grokkedapp',
+ 'tests.hybridapp',
+ 'tests.localeapp',
+ 'tests.restbugapp',
+ 'tests.routesapp',
+ 'threadlocal',
+ 'traversal',
+ 'urldispatch',
+ 'url',
+ 'view',
+ 'wsgi',
+ 'zcml',
+ ):
+ frm = 'repoze.bfg.' + name
+ to = 'pyramid.' + name
+ MAPPING[frm] = to
+
+def alternates(members):
+ return "(" + "|".join(map(str, members)) + ")"
+
+def build_pattern(mapping=MAPPING):
+ mod_list = []
+
+ for key in mapping:
+ splitted = key.split('.')
+ joined = " '.' ".join(["'%s'" %s for s in splitted])
+ mod_list.append(joined)
+
+ mod_list = ' | '.join(
+ ['module_name=dotted_name< %s >' %s for s in mod_list])
+
+ yield """name_import=import_name< 'import' ((%s) |
+ multiple_imports=dotted_as_names< any* (%s) any* >) >
+ """ % (mod_list, mod_list)
+ yield """import_from< 'from' (%s) 'import' ['(']
+ ( any | import_as_name< any 'as' any > |
+ import_as_names< any* >) [')'] >
+ """ % mod_list
+ yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > |
+ multiple_imports=dotted_as_names<
+ any* dotted_as_name< (%s) 'as' any > any* >) >
+ """ % (mod_list, mod_list)
+
+ # Find usages of module members in code e.g. ``repoze.bfg`` or
+ # ``repoze.bfg.configuration``
+ # 'repoze' trailer< '.' 'bfg' > trailer< '.' 'configuration' >
+ bare_names = []
+ for key in mapping:
+ splitted = key.split('.')
+ tmp = ["'%s'" % splitted[0]]
+ for thing in splitted[1:]:
+ tmp.append(" trailer< '.' '%s' > " % thing)
+ bare_name = ''.join(tmp)
+ bare_names.append(bare_name)
+
+ names = alternates(bare_names)
+ yield "power< bare_with_attr=%s >" % names
+
+class FixBfgImports(fixer_base.BaseFix):
+
+ mapping = MAPPING
+ run_order = 8
+
+ def build_pattern(self):
+ pattern = "|".join(build_pattern(self.mapping))
+ return pattern
+
+ def compile_pattern(self):
+ # We override this, so MAPPING can be pragmatically altered and the
+ # changes will be reflected in PATTERN.
+ self.PATTERN = self.build_pattern()
+ super(FixBfgImports, self).compile_pattern()
+
+ # Don't match the node if it's within another match.
+ def match(self, node):
+ match = super(FixBfgImports, self).match
+ results = match(node)
+ if results:
+ # Module usage could be in the trailer of an attribute lookup, so we
+ # might have nested matches when "bare_with_attr" is present.
+ if "bare_with_attr" not in results and \
+ any(match(obj) for obj in attr_chain(node, "parent")):
+ return False
+ return results
+ return False
+
+ def start_tree(self, tree, filename):
+ super(FixBfgImports, self).start_tree(tree, filename)
+ self.replace = {}
+
+ def transform(self, node, results):
+ # Mostly copied from fix_imports.py
+ import_mod = results.get("module_name")
+ if import_mod:
+ try:
+ mod_name = import_mod.value
+ except AttributeError:
+ # XXX: A hack to remove whitespace prefixes and suffixes
+ mod_name = str(import_mod).strip()
+ new_name = self.mapping[mod_name]
+ import_mod.replace(Name(new_name, prefix=import_mod.prefix))
+ if "name_import" in results:
+ # If it's not a "from x import x, y" or "import x as y" import,
+ # marked its usage to be replaced.
+ self.replace[mod_name] = new_name
+ if "multiple_imports" in results:
+ # This is a nasty hack to fix multiple imports on a line (e.g.,
+ # "import StringIO, urlparse"). The problem is that I can't
+ # figure out an easy way to make a pattern recognize the keys of
+ # MAPPING randomly sprinkled in an import statement.
+ results = self.match(node)
+ if results:
+ self.transform(node, results)
+ else:
+ # Replace usage of the module.
+ bare_name_text = ''.join(map(str,results['bare_with_attr'])).strip()
+ new_name = self.replace.get(bare_name_text)
+ bare_name = results["bare_with_attr"][0]
+
+ if new_name:
+ node.replace(Name(new_name, prefix=bare_name.prefix))
+
+def main(argv=None):
+ if argv is None:
+ argv = sys.argv
+ path = argv[1]
+ fixer_names = get_fixers_from_package('repoze.bfg.fixers')
+ tool = RefactoringTool(fixer_names)
+ tool.refactor([path], write=True)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/setup.py b/setup.py
index 1dbabe5f4..ceac5f9b2 100644
--- a/setup.py
+++ b/setup.py
@@ -83,6 +83,8 @@ setup(name='pyramid',
pyramid_alchemy=pyramid.paster:AlchemyProjectTemplate
[paste.paster_command]
pyramid_shell=pyramid.paster:BFGShellCommand
+ [console_scripts]
+ bfg2pyramid = pyramid.fixers.fix_bfg_imports:main
"""
)