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