source: orange/Orange/fixes/fix_orange_imports.py @ 9818:2ec8ecdb81e5

Revision 9818:2ec8ecdb81e5, 5.6 KB checked in by Matija Polajnar <matija.polajnar@…>, 2 years ago (diff)

Finish the logreg refactoring, along with documentation improvement.

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.optimization",
55           "orngClustering": "Orange.clustering",
56           "orngDisc": "Orange.feature.discretization",
57           "orngLookup": "Orange.classification.lookup",
58           "orngLinProj": "Orange.projection.linear",
59           "orngEnviron": "Orange.misc.environ",
60           }
61
62def alternates(members):
63    return "(" + "|".join(map(repr, members)) + ")"
64
65
66def build_pattern(mapping=MAPPING):
67    mod_list = ' | '.join(["module_name='%s'" % key for key in mapping])
68    bare_names = alternates(mapping.keys())
69
70    yield """name_import=import_name< 'import' ((%s) |
71               multiple_imports=dotted_as_names< any* (%s) any* >) >
72          """ % (mod_list, mod_list)
73    yield """import_from< 'from' (%s) 'import' ['(']
74              ( any | import_as_name< any 'as' any > |
75                import_as_names< any* >)  [')'] >
76          """ % mod_list
77    yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > |
78               multiple_imports=dotted_as_names<
79                 any* dotted_as_name< (%s) 'as' any > any* >) >
80          """ % (mod_list, mod_list)
81
82    # Find usages of module members in code e.g. thread.foo(bar)
83    yield "power< bare_with_attr=(%s) trailer<'.' any > any* >" % bare_names
84
85
86class FixOrangeImports(fixer_base.BaseFix):
87    mapping = MAPPING
88
89    # We want to run this fixer late, so fix_import doesn't try to make stdlib
90    # renames into relative imports.
91    run_order = 6
92
93    def build_pattern(self):
94        return "|".join(build_pattern(self.mapping))
95
96    def compile_pattern(self):
97        # We override this, so MAPPING can be pragmatically altered and the
98        # changes will be reflected in PATTERN.
99        self.PATTERN = self.build_pattern()
100#        print self.PATTERN
101        super(FixOrangeImports, self).compile_pattern()
102#        print self.pattern
103
104    # Don't match the node if it's within another match.
105    def match(self, node):
106        match = super(FixOrangeImports, self).match
107        results = match(node)
108        if results:
109            # Module usage could be in the trailer of an attribute lookup, so we
110            # might have nested matches when "bare_with_attr" is present.
111            if "bare_with_attr" not in results and \
112                    any(match(obj) for obj in attr_chain(node, "parent")):
113                return False
114            return results
115        return False
116
117    def start_tree(self, tree, filename):
118        super(FixOrangeImports, self).start_tree(tree, filename)
119        self.replace = {}
120
121    def transform(self, node, results):
122        import_mod = results.get("module_name")
123        if import_mod:
124            mod_name = import_mod.value
125            new_name = unicode(self.mapping[mod_name])
126            import_mod.replace(Name(new_name, prefix=import_mod.prefix))
127            if "name_import" in results:
128                # If it's not a "from x import x, y" or "import x as y" import,
129                # marked its usage to be replaced.
130                self.replace[mod_name] = new_name
131            if "multiple_imports" in results:
132                # This is a nasty hack to fix multiple imports on a line (e.g.,
133                # "import StringIO, urlparse"). The problem is that I can't
134                # figure out an easy way to make a pattern recognize the keys of
135                # MAPPING randomly sprinkled in an import statement.
136                results = self.match(node)
137                if results:
138                    self.transform(node, results)
139        else:
140            # Replace usage of the module.
141            bare_name = results["bare_with_attr"][0]
142            new_name = self.replace.get(bare_name.value)
143            if new_name:
144                bare_name.replace(Name(new_name, prefix=bare_name.prefix))
Note: See TracBrowser for help on using the repository browser.