source: orange/Orange/fixes/fix_orange_imports.py @ 10718:9bedf6bfb4d7

Revision 10718:9bedf6bfb4d7, 5.6 KB checked in by anze <anze.staric@…>, 2 years ago (diff)

Fixed module name 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
28import fix_changed_names
29
30NAMES_MAPPING = fix_changed_names.MAPPING
31   
32
33"""Fix incompatible imports and module references. Modified from the
34fix_imports fixer in lib2to3 by Collin Winter, Nick Edds. """
35
36# Local imports
37from lib2to3 import fixer_base
38from lib2to3.fixer_util import Name, attr_chain
39
40MAPPING = {"orange": "Orange.core",
41           "orngSVM": "Orange.classification.svm",
42           "orngSOM": "Orange.projection.som",
43           "orngBayes":"Orange.classification.bayes",
44           "orngLR":"Orange.classification.logreg",
45           "orngNetwork":"Orange.network",
46           "orngMisc":"Orange.misc",
47           "orngEnsemble":"Orange.ensemble",
48           "orngCN2": "Orange.classification.rules",
49           "orngMDS": "Orange.projection.mds",
50           "orngStat": "Orange.evaluation.scoring",
51           "orngTree": "Orange.classification.tree",
52           "orngImpute": "Orange.feature.imputation",
53           "orngTest": "Orange.evaluation.testing",
54           "orngWrap": "Orange.tuning",
55           "orngClustering": "Orange.clustering",
56           "orngDisc": "Orange.feature.discretization",
57           "orngLookup": "Orange.classification.lookup",
58           "orngLinProj": "Orange.projection.linear",
59           "orngEnviron": "Orange.utils.environ",
60           "orngSQL": "Orange.data.sql"
61           }
62
63def alternates(members):
64    return "(" + "|".join(map(repr, members)) + ")"
65
66
67def build_pattern(mapping=MAPPING):
68    mod_list = ' | '.join(["module_name='%s'" % key for key in mapping])
69    bare_names = alternates(mapping.keys())
70
71    yield """name_import=import_name< 'import' ((%s) |
72               multiple_imports=dotted_as_names< any* (%s) any* >) >
73          """ % (mod_list, mod_list)
74    yield """import_from< 'from' (%s) 'import' ['(']
75              ( any | import_as_name< any 'as' any > |
76                import_as_names< any* >)  [')'] >
77          """ % mod_list
78    yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > |
79               multiple_imports=dotted_as_names<
80                 any* dotted_as_name< (%s) 'as' any > any* >) >
81          """ % (mod_list, mod_list)
82
83    # Find usages of module members in code e.g. thread.foo(bar)
84    yield "power< bare_with_attr=(%s) trailer<'.' any > any* >" % bare_names
85
86
87class FixOrangeImports(fixer_base.BaseFix):
88    mapping = MAPPING
89
90    # We want to run this fixer late, so fix_import doesn't try to make stdlib
91    # renames into relative imports.
92    run_order = 6
93
94    def build_pattern(self):
95        return "|".join(build_pattern(self.mapping))
96
97    def compile_pattern(self):
98        # We override this, so MAPPING can be pragmatically altered and the
99        # changes will be reflected in PATTERN.
100        self.PATTERN = self.build_pattern()
101#        print self.PATTERN
102        super(FixOrangeImports, self).compile_pattern()
103#        print self.pattern
104
105    # Don't match the node if it's within another match.
106    def match(self, node):
107        match = super(FixOrangeImports, self).match
108        results = match(node)
109        if results:
110            # Module usage could be in the trailer of an attribute lookup, so we
111            # might have nested matches when "bare_with_attr" is present.
112            if "bare_with_attr" not in results and \
113                    any(match(obj) for obj in attr_chain(node, "parent")):
114                return False
115            return results
116        return False
117
118    def start_tree(self, tree, filename):
119        super(FixOrangeImports, self).start_tree(tree, filename)
120        self.replace = {}
121
122    def transform(self, node, results):
123        import_mod = results.get("module_name")
124        if import_mod:
125            mod_name = import_mod.value
126            new_name = unicode(self.mapping[mod_name])
127            import_mod.replace(Name(new_name, prefix=import_mod.prefix))
128            if "name_import" in results:
129                # If it's not a "from x import x, y" or "import x as y" import,
130                # marked its usage to be replaced.
131                self.replace[mod_name] = new_name
132            if "multiple_imports" in results:
133                # This is a nasty hack to fix multiple imports on a line (e.g.,
134                # "import StringIO, urlparse"). The problem is that I can't
135                # figure out an easy way to make a pattern recognize the keys of
136                # MAPPING randomly sprinkled in an import statement.
137                results = self.match(node)
138                if results:
139                    self.transform(node, results)
140        else:
141            # Replace usage of the module.
142            bare_name = results["bare_with_attr"][0]
143            new_name = self.replace.get(bare_name.value)
144            if new_name:
145                bare_name.replace(Name(new_name, prefix=bare_name.prefix))
Note: See TracBrowser for help on using the repository browser.