source: orange/orange/fixes/fix_orange_imports.py @ 7761:8ac2e36f9363

Revision 7761:8ac2e36f9363, 5.3 KB checked in by lanz <lan.zagar@…>, 3 years ago (diff)

Documentation and code refactoring for the lookup module.

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