source: orange/orange/fixes/fix_orange_imports.py @ 7631:6b6ff7657b10

Revision 7631:6b6ff7657b10, 5.2 KB checked in by ales_erjavec <ales.erjavec@…>, 3 years ago (diff)
  • added fix_orange_imports_aggressive
  • added modules / changed names mapping
Line 
1""" This fixer changes old orange imports (imports of orange, orngSVM,
2orngClustering ...) to the corresponding package in the new hierarchy.
3It will also fix all occurrences of the module names in the script.
4
5For example it will replace this code::
6    import orange
7    learner = orange.SVMLearner(name='svm')
8
9with:
10    import Orange.core
11    learner = Orange.core.SVMLearner(name='svm')
12   
13.. note:: That this is possible only if the new package is a full
14    replacement for the old module (i.e. it exposes the same interface).
15    If this is not the case use the fix_changed_names fixer and list all
16    package content renames.
17   
18.. note:: This fixer runs last and should be used as a last resort. Use
19    fix_changed_names fixer for fine grain control of name mappings.
20 
21"""
22from lib2to3 import fixer_base
23from lib2to3 import fixer_util
24from lib2to3.fixer_util import Name, attr_chain
25
26from lib2to3.fixes import fix_imports
27   
28
29"""Fix incompatible imports and module references. Modified from the
30fix_imports fixer in lib2to3 by Collin Winter, Nick Edds. """
31
32# Local imports
33from lib2to3 import fixer_base
34from lib2to3.fixer_util import Name, attr_chain
35
36MAPPING = {"orange": "Orange.core",
37           "orngSVM": "Orange.classification.svm",
38           "orngSOM": "Orange.projection.som",
39           "orngBayes":"Orange.classification.bayes",
40           "orngNetwork":"Orange.network",
41           "orngMisc":"Orange.misc",
42           "orngEnsemble":"Orange.ensemble",
43           "orngCN2": "Orange.classification.rules",
44           "orngMDS": "Orange.projection.mds",
45           "orngStat": "Orange.evaluation.scoring",
46           "orngTree": "Orange.classification.tree",
47           "orngImpute": "Orange.feature.imputation",
48           "orngStat": "Orange.evaluation.scoring",
49           "orngWrap": "Orange.optimization",
50           "orngClustering": "Orange.clustering",
51           }
52
53
54def alternates(members):
55    return "(" + "|".join(map(repr, members)) + ")"
56
57
58def build_pattern(mapping=MAPPING):
59    mod_list = ' | '.join(["module_name='%s'" % key for key in mapping])
60    bare_names = alternates(mapping.keys())
61
62    yield """name_import=import_name< 'import' ((%s) |
63               multiple_imports=dotted_as_names< any* (%s) any* >) >
64          """ % (mod_list, mod_list)
65    yield """import_from< 'from' (%s) 'import' ['(']
66              ( any | import_as_name< any 'as' any > |
67                import_as_names< any* >)  [')'] >
68          """ % mod_list
69    yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > |
70               multiple_imports=dotted_as_names<
71                 any* dotted_as_name< (%s) 'as' any > any* >) >
72          """ % (mod_list, mod_list)
73
74    # Find usages of module members in code e.g. thread.foo(bar)
75    yield "power< bare_with_attr=(%s) trailer<'.' any > any* >" % bare_names
76
77
78class FixOrangeImports(fixer_base.BaseFix):
79    mapping = MAPPING
80
81    # We want to run this fixer late, so fix_import doesn't try to make stdlib
82    # renames into relative imports.
83    run_order = 6
84
85    def build_pattern(self):
86        return "|".join(build_pattern(self.mapping))
87
88    def compile_pattern(self):
89        # We override this, so MAPPING can be pragmatically altered and the
90        # changes will be reflected in PATTERN.
91        self.PATTERN = self.build_pattern()
92#        print self.PATTERN
93        super(FixOrangeImports, self).compile_pattern()
94#        print self.pattern
95
96    # Don't match the node if it's within another match.
97    def match(self, node):
98        match = super(FixOrangeImports, self).match
99        results = match(node)
100        if results:
101            # Module usage could be in the trailer of an attribute lookup, so we
102            # might have nested matches when "bare_with_attr" is present.
103            if "bare_with_attr" not in results and \
104                    any(match(obj) for obj in attr_chain(node, "parent")):
105                return False
106            return results
107        return False
108
109    def start_tree(self, tree, filename):
110        super(FixOrangeImports, self).start_tree(tree, filename)
111        self.replace = {}
112
113    def transform(self, node, results):
114        import_mod = results.get("module_name")
115        if import_mod:
116            mod_name = import_mod.value
117            new_name = unicode(self.mapping[mod_name])
118            import_mod.replace(Name(new_name, prefix=import_mod.prefix))
119            if "name_import" in results:
120                # If it's not a "from x import x, y" or "import x as y" import,
121                # marked its usage to be replaced.
122                self.replace[mod_name] = new_name
123            if "multiple_imports" in results:
124                # This is a nasty hack to fix multiple imports on a line (e.g.,
125                # "import StringIO, urlparse"). The problem is that I can't
126                # figure out an easy way to make a pattern recognize the keys of
127                # MAPPING randomly sprinkled in an import statement.
128                results = self.match(node)
129                if results:
130                    self.transform(node, results)
131        else:
132            # Replace usage of the module.
133            bare_name = results["bare_with_attr"][0]
134            new_name = self.replace.get(bare_name.value)
135            if new_name:
136                bare_name.replace(Name(new_name, prefix=bare_name.prefix))
Note: See TracBrowser for help on using the repository browser.