Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

as_string.py 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. # Copyright (c) 2009-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
  2. # Copyright (c) 2013-2016 Claudiu Popa <pcmanticore@gmail.com>
  3. # Copyright (c) 2013-2014 Google, Inc.
  4. # Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com>
  5. # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
  6. # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
  7. """This module renders Astroid nodes as string:
  8. * :func:`to_code` function return equivalent (hopefully valid) python string
  9. * :func:`dump` function return an internal representation of nodes found
  10. in the tree, useful for debugging or understanding the tree structure
  11. """
  12. import sys
  13. import six
  14. # pylint: disable=unused-argument
  15. class AsStringVisitor(object):
  16. """Visitor to render an Astroid node as a valid python code string"""
  17. def __init__(self, indent):
  18. self.indent = indent
  19. def __call__(self, node):
  20. """Makes this visitor behave as a simple function"""
  21. return node.accept(self)
  22. def _stmt_list(self, stmts):
  23. """return a list of nodes to string"""
  24. stmts = '\n'.join([nstr for nstr in [n.accept(self) for n in stmts] if nstr])
  25. return self.indent + stmts.replace('\n', '\n'+self.indent)
  26. ## visit_<node> methods ###########################################
  27. def visit_arguments(self, node):
  28. """return an astroid.Function node as string"""
  29. return node.format_args()
  30. def visit_assignattr(self, node):
  31. """return an astroid.AssAttr node as string"""
  32. return self.visit_attribute(node)
  33. def visit_assert(self, node):
  34. """return an astroid.Assert node as string"""
  35. if node.fail:
  36. return 'assert %s, %s' % (node.test.accept(self),
  37. node.fail.accept(self))
  38. return 'assert %s' % node.test.accept(self)
  39. def visit_assignname(self, node):
  40. """return an astroid.AssName node as string"""
  41. return node.name
  42. def visit_assign(self, node):
  43. """return an astroid.Assign node as string"""
  44. lhs = ' = '.join([n.accept(self) for n in node.targets])
  45. return '%s = %s' % (lhs, node.value.accept(self))
  46. def visit_augassign(self, node):
  47. """return an astroid.AugAssign node as string"""
  48. return '%s %s %s' % (node.target.accept(self), node.op, node.value.accept(self))
  49. def visit_annassign(self, node):
  50. """Return an astroid.AugAssign node as string"""
  51. target = node.target.accept(self)
  52. annotation = node.annotation.accept(self)
  53. if node.value is None:
  54. return '%s: %s' % (target, annotation)
  55. return '%s: %s = %s' % (target, annotation, node.value.accept(self))
  56. def visit_repr(self, node):
  57. """return an astroid.Repr node as string"""
  58. return '`%s`' % node.value.accept(self)
  59. def visit_binop(self, node):
  60. """return an astroid.BinOp node as string"""
  61. return '(%s) %s (%s)' % (node.left.accept(self), node.op, node.right.accept(self))
  62. def visit_boolop(self, node):
  63. """return an astroid.BoolOp node as string"""
  64. return (' %s ' % node.op).join(['(%s)' % n.accept(self)
  65. for n in node.values])
  66. def visit_break(self, node):
  67. """return an astroid.Break node as string"""
  68. return 'break'
  69. def visit_call(self, node):
  70. """return an astroid.Call node as string"""
  71. expr_str = node.func.accept(self)
  72. args = [arg.accept(self) for arg in node.args]
  73. if node.keywords:
  74. keywords = [kwarg.accept(self) for kwarg in node.keywords]
  75. else:
  76. keywords = []
  77. args.extend(keywords)
  78. return '%s(%s)' % (expr_str, ', '.join(args))
  79. def visit_classdef(self, node):
  80. """return an astroid.ClassDef node as string"""
  81. decorate = node.decorators.accept(self) if node.decorators else ''
  82. bases = ', '.join([n.accept(self) for n in node.bases])
  83. if sys.version_info[0] == 2:
  84. bases = '(%s)' % bases if bases else ''
  85. else:
  86. metaclass = node.metaclass()
  87. if metaclass and not node.has_metaclass_hack():
  88. if bases:
  89. bases = '(%s, metaclass=%s)' % (bases, metaclass.name)
  90. else:
  91. bases = '(metaclass=%s)' % metaclass.name
  92. else:
  93. bases = '(%s)' % bases if bases else ''
  94. docs = '\n%s"""%s"""' % (self.indent, node.doc) if node.doc else ''
  95. return '\n\n%sclass %s%s:%s\n%s\n' % (decorate, node.name, bases, docs,
  96. self._stmt_list(node.body))
  97. def visit_compare(self, node):
  98. """return an astroid.Compare node as string"""
  99. rhs_str = ' '.join(['%s %s' % (op, expr.accept(self))
  100. for op, expr in node.ops])
  101. return '%s %s' % (node.left.accept(self), rhs_str)
  102. def visit_comprehension(self, node):
  103. """return an astroid.Comprehension node as string"""
  104. ifs = ''.join([' if %s' % n.accept(self) for n in node.ifs])
  105. return 'for %s in %s%s' % (node.target.accept(self),
  106. node.iter.accept(self), ifs)
  107. def visit_const(self, node):
  108. """return an astroid.Const node as string"""
  109. return repr(node.value)
  110. def visit_continue(self, node):
  111. """return an astroid.Continue node as string"""
  112. return 'continue'
  113. def visit_delete(self, node): # XXX check if correct
  114. """return an astroid.Delete node as string"""
  115. return 'del %s' % ', '.join([child.accept(self)
  116. for child in node.targets])
  117. def visit_delattr(self, node):
  118. """return an astroid.DelAttr node as string"""
  119. return self.visit_attribute(node)
  120. def visit_delname(self, node):
  121. """return an astroid.DelName node as string"""
  122. return node.name
  123. def visit_decorators(self, node):
  124. """return an astroid.Decorators node as string"""
  125. return '@%s\n' % '\n@'.join([item.accept(self) for item in node.nodes])
  126. def visit_dict(self, node):
  127. """return an astroid.Dict node as string"""
  128. return '{%s}' % ', '.join(self._visit_dict(node))
  129. def _visit_dict(self, node):
  130. for key, value in node.items:
  131. key = key.accept(self)
  132. value = value.accept(self)
  133. if key == '**':
  134. # It can only be a DictUnpack node.
  135. yield key + value
  136. else:
  137. yield '%s: %s' % (key, value)
  138. def visit_dictunpack(self, node):
  139. return '**'
  140. def visit_dictcomp(self, node):
  141. """return an astroid.DictComp node as string"""
  142. return '{%s: %s %s}' % (node.key.accept(self), node.value.accept(self),
  143. ' '.join([n.accept(self) for n in node.generators]))
  144. def visit_expr(self, node):
  145. """return an astroid.Discard node as string"""
  146. return node.value.accept(self)
  147. def visit_emptynode(self, node):
  148. """dummy method for visiting an Empty node"""
  149. return ''
  150. def visit_excepthandler(self, node):
  151. if node.type:
  152. if node.name:
  153. excs = 'except %s, %s' % (node.type.accept(self),
  154. node.name.accept(self))
  155. else:
  156. excs = 'except %s' % node.type.accept(self)
  157. else:
  158. excs = 'except'
  159. return '%s:\n%s' % (excs, self._stmt_list(node.body))
  160. def visit_ellipsis(self, node):
  161. """return an astroid.Ellipsis node as string"""
  162. return '...'
  163. def visit_empty(self, node):
  164. """return an Empty node as string"""
  165. return ''
  166. def visit_exec(self, node):
  167. """return an astroid.Exec node as string"""
  168. if node.locals:
  169. return 'exec %s in %s, %s' % (node.expr.accept(self),
  170. node.locals.accept(self),
  171. node.globals.accept(self))
  172. if node.globals:
  173. return 'exec %s in %s' % (node.expr.accept(self),
  174. node.globals.accept(self))
  175. return 'exec %s' % node.expr.accept(self)
  176. def visit_extslice(self, node):
  177. """return an astroid.ExtSlice node as string"""
  178. return ','.join([dim.accept(self) for dim in node.dims])
  179. def visit_for(self, node):
  180. """return an astroid.For node as string"""
  181. fors = 'for %s in %s:\n%s' % (node.target.accept(self),
  182. node.iter.accept(self),
  183. self._stmt_list(node.body))
  184. if node.orelse:
  185. fors = '%s\nelse:\n%s' % (fors, self._stmt_list(node.orelse))
  186. return fors
  187. def visit_importfrom(self, node):
  188. """return an astroid.ImportFrom node as string"""
  189. return 'from %s import %s' % ('.' * (node.level or 0) + node.modname,
  190. _import_string(node.names))
  191. def visit_functiondef(self, node):
  192. """return an astroid.Function node as string"""
  193. decorate = node.decorators.accept(self) if node.decorators else ''
  194. docs = '\n%s"""%s"""' % (self.indent, node.doc) if node.doc else ''
  195. return_annotation = ''
  196. if six.PY3 and node.returns:
  197. return_annotation = '->' + node.returns.as_string()
  198. trailer = return_annotation + ":"
  199. else:
  200. trailer = ":"
  201. def_format = "\n%sdef %s(%s)%s%s\n%s"
  202. return def_format % (decorate, node.name,
  203. node.args.accept(self),
  204. trailer, docs,
  205. self._stmt_list(node.body))
  206. def visit_generatorexp(self, node):
  207. """return an astroid.GeneratorExp node as string"""
  208. return '(%s %s)' % (node.elt.accept(self),
  209. ' '.join([n.accept(self) for n in node.generators]))
  210. def visit_attribute(self, node):
  211. """return an astroid.Getattr node as string"""
  212. return '%s.%s' % (node.expr.accept(self), node.attrname)
  213. def visit_global(self, node):
  214. """return an astroid.Global node as string"""
  215. return 'global %s' % ', '.join(node.names)
  216. def visit_if(self, node):
  217. """return an astroid.If node as string"""
  218. ifs = ['if %s:\n%s' % (node.test.accept(self), self._stmt_list(node.body))]
  219. if node.orelse:# XXX use elif ???
  220. ifs.append('else:\n%s' % self._stmt_list(node.orelse))
  221. return '\n'.join(ifs)
  222. def visit_ifexp(self, node):
  223. """return an astroid.IfExp node as string"""
  224. return '%s if %s else %s' % (node.body.accept(self),
  225. node.test.accept(self),
  226. node.orelse.accept(self))
  227. def visit_import(self, node):
  228. """return an astroid.Import node as string"""
  229. return 'import %s' % _import_string(node.names)
  230. def visit_keyword(self, node):
  231. """return an astroid.Keyword node as string"""
  232. if node.arg is None:
  233. return '**%s' % node.value.accept(self)
  234. return '%s=%s' % (node.arg, node.value.accept(self))
  235. def visit_lambda(self, node):
  236. """return an astroid.Lambda node as string"""
  237. return 'lambda %s: %s' % (node.args.accept(self),
  238. node.body.accept(self))
  239. def visit_list(self, node):
  240. """return an astroid.List node as string"""
  241. return '[%s]' % ', '.join([child.accept(self) for child in node.elts])
  242. def visit_listcomp(self, node):
  243. """return an astroid.ListComp node as string"""
  244. return '[%s %s]' % (node.elt.accept(self),
  245. ' '.join([n.accept(self) for n in node.generators]))
  246. def visit_module(self, node):
  247. """return an astroid.Module node as string"""
  248. docs = '"""%s"""\n\n' % node.doc if node.doc else ''
  249. return docs + '\n'.join([n.accept(self) for n in node.body]) + '\n\n'
  250. def visit_name(self, node):
  251. """return an astroid.Name node as string"""
  252. return node.name
  253. def visit_pass(self, node):
  254. """return an astroid.Pass node as string"""
  255. return 'pass'
  256. def visit_print(self, node):
  257. """return an astroid.Print node as string"""
  258. nodes = ', '.join([n.accept(self) for n in node.values])
  259. if not node.nl:
  260. nodes = '%s,' % nodes
  261. if node.dest:
  262. return 'print >> %s, %s' % (node.dest.accept(self), nodes)
  263. return 'print %s' % nodes
  264. def visit_raise(self, node):
  265. """return an astroid.Raise node as string"""
  266. if node.exc:
  267. if node.inst:
  268. if node.tback:
  269. return 'raise %s, %s, %s' % (node.exc.accept(self),
  270. node.inst.accept(self),
  271. node.tback.accept(self))
  272. return 'raise %s, %s' % (node.exc.accept(self),
  273. node.inst.accept(self))
  274. return 'raise %s' % node.exc.accept(self)
  275. return 'raise'
  276. def visit_return(self, node):
  277. """return an astroid.Return node as string"""
  278. if node.value:
  279. return 'return %s' % node.value.accept(self)
  280. return 'return'
  281. def visit_index(self, node):
  282. """return a astroid.Index node as string"""
  283. return node.value.accept(self)
  284. def visit_set(self, node):
  285. """return an astroid.Set node as string"""
  286. return '{%s}' % ', '.join([child.accept(self) for child in node.elts])
  287. def visit_setcomp(self, node):
  288. """return an astroid.SetComp node as string"""
  289. return '{%s %s}' % (node.elt.accept(self),
  290. ' '.join([n.accept(self) for n in node.generators]))
  291. def visit_slice(self, node):
  292. """return a astroid.Slice node as string"""
  293. lower = node.lower.accept(self) if node.lower else ''
  294. upper = node.upper.accept(self) if node.upper else''
  295. step = node.step.accept(self) if node.step else ''
  296. if step:
  297. return '%s:%s:%s' % (lower, upper, step)
  298. return '%s:%s' % (lower, upper)
  299. def visit_subscript(self, node):
  300. """return an astroid.Subscript node as string"""
  301. return '%s[%s]' % (node.value.accept(self), node.slice.accept(self))
  302. def visit_tryexcept(self, node):
  303. """return an astroid.TryExcept node as string"""
  304. trys = ['try:\n%s' % self._stmt_list(node.body)]
  305. for handler in node.handlers:
  306. trys.append(handler.accept(self))
  307. if node.orelse:
  308. trys.append('else:\n%s' % self._stmt_list(node.orelse))
  309. return '\n'.join(trys)
  310. def visit_tryfinally(self, node):
  311. """return an astroid.TryFinally node as string"""
  312. return 'try:\n%s\nfinally:\n%s' % (self._stmt_list(node.body),
  313. self._stmt_list(node.finalbody))
  314. def visit_tuple(self, node):
  315. """return an astroid.Tuple node as string"""
  316. if len(node.elts) == 1:
  317. return '(%s, )' % node.elts[0].accept(self)
  318. return '(%s)' % ', '.join([child.accept(self) for child in node.elts])
  319. def visit_unaryop(self, node):
  320. """return an astroid.UnaryOp node as string"""
  321. if node.op == 'not':
  322. operator = 'not '
  323. else:
  324. operator = node.op
  325. return '%s%s' % (operator, node.operand.accept(self))
  326. def visit_while(self, node):
  327. """return an astroid.While node as string"""
  328. whiles = 'while %s:\n%s' % (node.test.accept(self),
  329. self._stmt_list(node.body))
  330. if node.orelse:
  331. whiles = '%s\nelse:\n%s' % (whiles, self._stmt_list(node.orelse))
  332. return whiles
  333. def visit_with(self, node): # 'with' without 'as' is possible
  334. """return an astroid.With node as string"""
  335. items = ', '.join(('(%s)' % expr.accept(self)) +
  336. (vars and ' as (%s)' % (vars.accept(self)) or '')
  337. for expr, vars in node.items)
  338. return 'with %s:\n%s' % (items, self._stmt_list(node.body))
  339. def visit_yield(self, node):
  340. """yield an ast.Yield node as string"""
  341. yi_val = (" " + node.value.accept(self)) if node.value else ""
  342. expr = 'yield' + yi_val
  343. if node.parent.is_statement:
  344. return expr
  345. return "(%s)" % (expr,)
  346. def visit_starred(self, node):
  347. """return Starred node as string"""
  348. return "*" + node.value.accept(self)
  349. # These aren't for real AST nodes, but for inference objects.
  350. def visit_frozenset(self, node):
  351. return node.parent.accept(self)
  352. def visit_super(self, node):
  353. return node.parent.accept(self)
  354. def visit_uninferable(self, node):
  355. return str(node)
  356. class AsStringVisitor3(AsStringVisitor):
  357. """AsStringVisitor3 overwrites some AsStringVisitor methods"""
  358. def visit_excepthandler(self, node):
  359. if node.type:
  360. if node.name:
  361. excs = 'except %s as %s' % (node.type.accept(self),
  362. node.name.accept(self))
  363. else:
  364. excs = 'except %s' % node.type.accept(self)
  365. else:
  366. excs = 'except'
  367. return '%s:\n%s' % (excs, self._stmt_list(node.body))
  368. def visit_nonlocal(self, node):
  369. """return an astroid.Nonlocal node as string"""
  370. return 'nonlocal %s' % ', '.join(node.names)
  371. def visit_raise(self, node):
  372. """return an astroid.Raise node as string"""
  373. if node.exc:
  374. if node.cause:
  375. return 'raise %s from %s' % (node.exc.accept(self),
  376. node.cause.accept(self))
  377. return 'raise %s' % node.exc.accept(self)
  378. return 'raise'
  379. def visit_yieldfrom(self, node):
  380. """ Return an astroid.YieldFrom node as string. """
  381. yi_val = (" " + node.value.accept(self)) if node.value else ""
  382. expr = 'yield from' + yi_val
  383. if node.parent.is_statement:
  384. return expr
  385. return "(%s)" % (expr,)
  386. def visit_asyncfunctiondef(self, node):
  387. function = super(AsStringVisitor3, self).visit_functiondef(node)
  388. return 'async ' + function.strip()
  389. def visit_await(self, node):
  390. return 'await %s' % node.value.accept(self)
  391. def visit_asyncwith(self, node):
  392. return 'async %s' % self.visit_with(node)
  393. def visit_asyncfor(self, node):
  394. return 'async %s' % self.visit_for(node)
  395. def visit_joinedstr(self, node):
  396. # Special treatment for constants,
  397. # as we want to join literals not reprs
  398. string = ''.join(
  399. value.value if type(value).__name__ == 'Const'
  400. else value.accept(self)
  401. for value in node.values
  402. )
  403. return "f'%s'" % string
  404. def visit_formattedvalue(self, node):
  405. return '{%s}' % node.value.accept(self)
  406. def visit_comprehension(self, node):
  407. """return an astroid.Comprehension node as string"""
  408. return '%s%s' % ('async ' if node.is_async else '',
  409. super(AsStringVisitor3, self).visit_comprehension(node))
  410. def _import_string(names):
  411. """return a list of (name, asname) formatted as a string"""
  412. _names = []
  413. for name, asname in names:
  414. if asname is not None:
  415. _names.append('%s as %s' % (name, asname))
  416. else:
  417. _names.append(name)
  418. return ', '.join(_names)
  419. if sys.version_info >= (3, 0):
  420. AsStringVisitor = AsStringVisitor3
  421. # This sets the default indent to 4 spaces.
  422. to_code = AsStringVisitor(' ')