PageRenderTime 246ms CodeModel.GetById 81ms app.highlight 54ms RepoModel.GetById 107ms app.codeStats 0ms

/external-py3/rope/refactor/importutils/actions.py

https://code.google.com/p/spyderlib/
Python | 359 lines | 290 code | 58 blank | 11 comment | 97 complexity | d3a5495955ff8ce42382cbbadbf8c591 MD5 | raw file
  1import os
  2import sys
  3
  4from rope.base import pyobjects, exceptions, stdmods
  5from rope.refactor import occurrences
  6from rope.refactor.importutils import importinfo
  7
  8
  9class ImportInfoVisitor(object):
 10
 11    def dispatch(self, import_):
 12        try:
 13            method_name = 'visit' + import_.import_info.__class__.__name__
 14            method = getattr(self, method_name)
 15            return method(import_, import_.import_info)
 16        except exceptions.ModuleNotFoundError:
 17            pass
 18
 19    def visitEmptyImport(self, import_stmt, import_info):
 20        pass
 21
 22    def visitNormalImport(self, import_stmt, import_info):
 23        pass
 24
 25    def visitFromImport(self, import_stmt, import_info):
 26        pass
 27
 28
 29class RelativeToAbsoluteVisitor(ImportInfoVisitor):
 30
 31    def __init__(self, pycore, current_folder):
 32        self.to_be_absolute = []
 33        self.pycore = pycore
 34        self.folder = current_folder
 35        self.context = importinfo.ImportContext(pycore, current_folder)
 36
 37    def visitNormalImport(self, import_stmt, import_info):
 38        self.to_be_absolute.extend(self._get_relative_to_absolute_list(import_info))
 39        new_pairs = []
 40        for name, alias in import_info.names_and_aliases:
 41            resource = self.pycore.find_module(name, folder=self.folder)
 42            if resource is None:
 43                new_pairs.append((name, alias))
 44                continue
 45            absolute_name = self.pycore.modname(resource)
 46            new_pairs.append((absolute_name, alias))
 47        if not import_info._are_name_and_alias_lists_equal(
 48            new_pairs, import_info.names_and_aliases):
 49            import_stmt.import_info = importinfo.NormalImport(new_pairs)
 50
 51    def _get_relative_to_absolute_list(self, import_info):
 52        result = []
 53        for name, alias in import_info.names_and_aliases:
 54            if alias is not None:
 55                continue
 56            resource = self.pycore.find_module(name, folder=self.folder)
 57            if resource is None:
 58                continue
 59            absolute_name = self.pycore.modname(resource)
 60            if absolute_name != name:
 61                result.append((name, absolute_name))
 62        return result
 63
 64    def visitFromImport(self, import_stmt, import_info):
 65        resource = import_info.get_imported_resource(self.context)
 66        if resource is None:
 67            return None
 68        absolute_name = self.pycore.modname(resource)
 69        if import_info.module_name != absolute_name:
 70            import_stmt.import_info = importinfo.FromImport(
 71                absolute_name, 0, import_info.names_and_aliases)
 72
 73
 74class FilteringVisitor(ImportInfoVisitor):
 75
 76    def __init__(self, pycore, folder, can_select):
 77        self.to_be_absolute = []
 78        self.pycore = pycore
 79        self.can_select = self._transform_can_select(can_select)
 80        self.context = importinfo.ImportContext(pycore, folder)
 81
 82    def _transform_can_select(self, can_select):
 83        def can_select_name_and_alias(name, alias):
 84            imported = name
 85            if alias is not None:
 86                imported = alias
 87            return can_select(imported)
 88        return can_select_name_and_alias
 89
 90    def visitNormalImport(self, import_stmt, import_info):
 91        new_pairs = []
 92        for name, alias in import_info.names_and_aliases:
 93            if self.can_select(name, alias):
 94                new_pairs.append((name, alias))
 95        return importinfo.NormalImport(new_pairs)
 96
 97    def visitFromImport(self, import_stmt, import_info):
 98        if _is_future(import_info):
 99            return import_info
100        new_pairs = []
101        if import_info.is_star_import():
102            for name in import_info.get_imported_names(self.context):
103                if self.can_select(name, None):
104                    new_pairs.append(import_info.names_and_aliases[0])
105                    break
106        else:
107            for name, alias in import_info.names_and_aliases:
108                if self.can_select(name, alias):
109                    new_pairs.append((name, alias))
110        return importinfo.FromImport(
111            import_info.module_name, import_info.level, new_pairs)
112
113
114class RemovingVisitor(ImportInfoVisitor):
115
116    def __init__(self, pycore, folder, can_select):
117        self.to_be_absolute = []
118        self.pycore = pycore
119        self.filtering = FilteringVisitor(pycore, folder, can_select)
120
121    def dispatch(self, import_):
122        result = self.filtering.dispatch(import_)
123        if result is not None:
124            import_.import_info = result
125
126
127class AddingVisitor(ImportInfoVisitor):
128    """A class for adding imports
129
130    Given a list of `ImportInfo`\s, it tries to add each import to the
131    module and returns `True` and gives up when an import can be added
132    to older ones.
133
134    """
135
136    def __init__(self, pycore, import_list):
137        self.pycore = pycore
138        self.import_list = import_list
139        self.import_info = None
140
141    def dispatch(self, import_):
142        for import_info in self.import_list:
143            self.import_info = import_info
144            if ImportInfoVisitor.dispatch(self, import_):
145                return True
146
147    # TODO: Handle adding relative and absolute imports
148    def visitNormalImport(self, import_stmt, import_info):
149        if not isinstance(self.import_info, import_info.__class__):
150            return False
151        # Adding ``import x`` and ``import x.y`` that results ``import x.y``
152        if len(import_info.names_and_aliases) == \
153           len(self.import_info.names_and_aliases) == 1:
154            imported1 = import_info.names_and_aliases[0]
155            imported2 = self.import_info.names_and_aliases[0]
156            if imported1[1] == imported2[1] is None:
157                if imported1[0].startswith(imported2[0] + '.'):
158                    return True
159                if imported2[0].startswith(imported1[0] + '.'):
160                    import_stmt.import_info = self.import_info
161                    return True
162        # Multiple imports using a single import statement is discouraged
163        # so we won't bother adding them.
164        if self.import_info._are_name_and_alias_lists_equal(
165            import_info.names_and_aliases, self.import_info.names_and_aliases):
166            return True
167
168    def visitFromImport(self, import_stmt, import_info):
169        if isinstance(self.import_info, import_info.__class__) and \
170           import_info.module_name == self.import_info.module_name and \
171           import_info.level == self.import_info.level:
172            if import_info.is_star_import():
173                return True
174            if self.import_info.is_star_import():
175                import_stmt.import_info = self.import_info
176                return True
177            new_pairs = list(import_info.names_and_aliases)
178            for pair in self.import_info.names_and_aliases:
179                if pair not in new_pairs:
180                    new_pairs.append(pair)
181            import_stmt.import_info = importinfo.FromImport(
182                import_info.module_name, import_info.level, new_pairs)
183            return True
184
185
186class ExpandStarsVisitor(ImportInfoVisitor):
187
188    def __init__(self, pycore, folder, can_select):
189        self.pycore = pycore
190        self.filtering = FilteringVisitor(pycore, folder, can_select)
191        self.context = importinfo.ImportContext(pycore, folder)
192
193    def visitNormalImport(self, import_stmt, import_info):
194        self.filtering.dispatch(import_stmt)
195
196    def visitFromImport(self, import_stmt, import_info):
197        if import_info.is_star_import():
198            new_pairs = []
199            for name in import_info.get_imported_names(self.context):
200                new_pairs.append((name, None))
201            new_import = importinfo.FromImport(
202                import_info.module_name, import_info.level, new_pairs)
203            import_stmt.import_info = \
204                self.filtering.visitFromImport(None, new_import)
205        else:
206            self.filtering.dispatch(import_stmt)
207
208
209class SelfImportVisitor(ImportInfoVisitor):
210
211    def __init__(self, pycore, current_folder, resource):
212        self.pycore = pycore
213        self.folder = current_folder
214        self.resource = resource
215        self.to_be_fixed = set()
216        self.to_be_renamed = set()
217        self.context = importinfo.ImportContext(pycore, current_folder)
218
219    def visitNormalImport(self, import_stmt, import_info):
220        new_pairs = []
221        for name, alias in import_info.names_and_aliases:
222            resource = self.pycore.find_module(name, folder=self.folder)
223            if resource is not None and resource == self.resource:
224                imported = name
225                if alias is not None:
226                    imported = alias
227                self.to_be_fixed.add(imported)
228            else:
229                new_pairs.append((name, alias))
230        if not import_info._are_name_and_alias_lists_equal(
231            new_pairs, import_info.names_and_aliases):
232            import_stmt.import_info = importinfo.NormalImport(new_pairs)
233
234    def visitFromImport(self, import_stmt, import_info):
235        resource = import_info.get_imported_resource(self.context)
236        if resource is None:
237            return
238        if resource == self.resource:
239            self._importing_names_from_self(import_info, import_stmt)
240            return
241        pymodule = self.pycore.resource_to_pyobject(resource)
242        new_pairs = []
243        for name, alias in import_info.names_and_aliases:
244            try:
245                result = pymodule[name].get_object()
246                if isinstance(result, pyobjects.PyModule) and \
247                   result.get_resource() == self.resource:
248                    imported = name
249                    if alias is not None:
250                        imported = alias
251                    self.to_be_fixed.add(imported)
252                else:
253                    new_pairs.append((name, alias))
254            except exceptions.AttributeNotFoundError:
255                new_pairs.append((name, alias))
256        if not import_info._are_name_and_alias_lists_equal(
257            new_pairs, import_info.names_and_aliases):
258            import_stmt.import_info = importinfo.FromImport(
259                import_info.module_name, import_info.level, new_pairs)
260
261    def _importing_names_from_self(self, import_info, import_stmt):
262        if not import_info.is_star_import():
263            for name, alias in import_info.names_and_aliases:
264                if alias is not None:
265                    self.to_be_renamed.add((alias, name))
266        import_stmt.empty_import()
267
268
269class SortingVisitor(ImportInfoVisitor):
270
271    def __init__(self, pycore, current_folder):
272        self.pycore = pycore
273        self.folder = current_folder
274        self.standard = set()
275        self.third_party = set()
276        self.in_project = set()
277        self.future = set()
278        self.context = importinfo.ImportContext(pycore, current_folder)
279
280    def visitNormalImport(self, import_stmt, import_info):
281        if import_info.names_and_aliases:
282            name, alias = import_info.names_and_aliases[0]
283            resource = self.pycore.find_module(
284                name, folder=self.folder)
285            self._check_imported_resource(import_stmt, resource, name)
286
287    def visitFromImport(self, import_stmt, import_info):
288        resource = import_info.get_imported_resource(self.context)
289        self._check_imported_resource(import_stmt, resource,
290                                      import_info.module_name)
291
292    def _check_imported_resource(self, import_stmt, resource, imported_name):
293        info = import_stmt.import_info
294        if resource is not None and resource.project == self.pycore.project:
295            self.in_project.add(import_stmt)
296        elif _is_future(info):
297            self.future.add(import_stmt)
298        elif imported_name.split('.')[0] in stdmods.standard_modules():
299            self.standard.add(import_stmt)
300        else:
301            self.third_party.add(import_stmt)
302
303
304class LongImportVisitor(ImportInfoVisitor):
305
306    def __init__(self, current_folder, pycore, maxdots, maxlength):
307        self.maxdots = maxdots
308        self.maxlength = maxlength
309        self.to_be_renamed = set()
310        self.current_folder = current_folder
311        self.pycore = pycore
312        self.new_imports = []
313
314    def visitNormalImport(self, import_stmt, import_info):
315        new_pairs = []
316        for name, alias in import_info.names_and_aliases:
317            if alias is None and self._is_long(name):
318                self.to_be_renamed.add(name)
319                last_dot = name.rindex('.')
320                from_ = name[:last_dot]
321                imported = name[last_dot + 1:]
322                self.new_imports.append(
323                    importinfo.FromImport(from_, 0, ((imported, None), )))
324
325    def _is_long(self, name):
326        return name.count('.') > self.maxdots or \
327               ('.' in name and len(name) > self.maxlength)
328
329
330class RemovePyNameVisitor(ImportInfoVisitor):
331
332    def __init__(self, pycore, pymodule, pyname, folder):
333        self.pymodule = pymodule
334        self.pyname = pyname
335        self.context = importinfo.ImportContext(pycore, folder)
336
337    def visitFromImport(self, import_stmt, import_info):
338        new_pairs = []
339        if not import_info.is_star_import():
340            for name, alias in import_info.names_and_aliases:
341                try:
342                    pyname = self.pymodule[alias or name]
343                    if occurrences.same_pyname(self.pyname, pyname):
344                        continue
345                except exceptions.AttributeNotFoundError:
346                    pass
347                new_pairs.append((name, alias))
348        return importinfo.FromImport(
349            import_info.module_name, import_info.level, new_pairs)
350
351    def dispatch(self, import_):
352        result = ImportInfoVisitor.dispatch(self, import_)
353        if result is not None:
354            import_.import_info = result
355
356
357def _is_future(info):
358    return isinstance(info, importinfo.FromImport) and \
359           info.module_name == '__future__'