En beaucoup trop détaillé : http://worlddomination.be/about/about.html
Pas lossless !
ast_to_code(code_to_ast(code_source)) != source_code
(Commentaires, formatting)
(Et ast_to_code n'existe même pas de manière standard).
API Sax like
1 class KeyAttributesFinder(ast.NodeVisitor):
2 def visit_Assign(self, assign_node):
3 # ...
4
5 def visit_FunctionDef(self, function_node):
6 # ...
7
8 # visit_...
Super chiant, impossible à utiliser dans IPython efficacement.
Auto formater du code python
Django (memopol et co) :
donnees.json -> models.py + import.py
Autre projet :
Générer du boiler plate en lisant des models de db
1 from baron.helpers import show
2
3 print show("1 + 2")
4
5 [
6 {
7 "first_formatting": [
8 {
9 "type": "space",
10 "value": " "
11 }
12 ],
13 "value": "+",
14 "second_formatting": [
15 {
16 "type": "space",
17 "value": " "
18 }
19 ],
20 "second": {
21 "section": "number",
22 "type": "int",
23 "value": "2"
24 },
25 "type": "binary_operator",
26 "first": {
27 "section": "number",
28 "type": "int",
29 "value": "1"
30 }
31 }
32 ]
1 an de boulot (j'ai dû apprendre)
API super simple :
1 from redbaron import RedBaron
2
3 red = RedBaron("string représentant du code source")
4 # ...
5 red.dumps() # code source
Surcharge de __repr__ :
BeautifulSoup :
Surcharge de __repr__ :
BeautifulSoup :
RedBaron :
RedBaron :
RedBaron :
".help()"
Comme BeautifulSoup :
1 red = RedBaron("a = 42\ndef test_chocolat(): pass")
2 red.find("name")
3 red.find("int", value=42)
4 red.find("def", name="g:test_*")
5 red.find("def", name="re:test_*")
6 red.find("assignment", lambda x: x.target.dumps() == "INSTALLED_APPS")
7
8 red.find_all("name")
9 red.find_all(("name", "int"))
10 red.find_all("def", arguments=lambda x: len(x) == 3)
11 red.find_all("def", recursive=False)
Comme BeautifulSoup :
1 red = RedBaron("a = 42\ndef test_chocolat(): pass")
2 red.find("name")
3 red.find("int", value=42)
4 red.find("def", name="g:test_*")
5 red.find("def", name="re:test_*")
6 red.find("assignment", lambda x: x.target.dumps() == "INSTALLED_APPS")
7
8 red.find_all("name")
9 red.find_all(("name", "int"))
10 red.find_all("def", arguments=lambda x: len(x) == 3)
11 red.find_all("def", recursive=False)
Raccourcis (comme BeautifulSoup) :
1 red = RedBaron("a = 42\ndef test_chocolat(): pass")
2 red.name
3 red.int
4 red.else_
5
6 red("name")
7 red(("name", "int"))
8 red("def", arguments=lambda x: len(x) == 3)
Comment modifier une node ?
1 from redbaron import RedBaron, BinaryOperatorNode
2
3 red = RedBaron("a = 'plop'")
4 red[O].value # 'plop'
5 red[0].value = BinaryOperatorNode({'first_formatting':[{'type': 'space',
6 'value': ' '}], 'value': '+', 'second_formatting': [{'type': 'space',
7 'value': ' '}], 'second': {'section': 'number', 'type': 'int', 'value':
8 '1'}, 'type': 'binary_operator', 'first': {'section': 'number', 'type':
9 'int', 'value': '1'}})
Pas hyper pratique ...
1 from redbaron import RedBaron, BinaryOperatorNode
2
3 red = RedBaron("a = 'plop'")
4 red[0].value = "1 + 1"
5
6 # marche aussi avec : nodes redbaron et ast
Marche pour toutes les nodes.
Autre problème : quel est le corps/body de la fonction "bar" ?
1 class Foo():
2 def bar(self):
3 pass
4
5 def baz(self):
6 pass
Autre problème : quel est le corps/body de la fonction "bar" ?
1 class Foo():
2 def bar(self):
3 pass
4
5 def baz(self):
6 pass
Expected :
Autre problème : quel est le corps/body de la fonction "bar" ?
1 class Foo():
2 def bar(self):
3 pass
4
5 def baz(self):
6 pass
Expected :
Reality :
1 red.find("def", name="bar").value = "pass"
2 red.find("def", name="bar").value = "pass\n"
3 red.find("def", name="bar").value = " pass\n"
4 red.find("def", name="bar").value = " pass\n "
5 red.find("def", name="bar").value = " pass\n "
6 red.find("def", name="bar").value = "\n pass\n "
7 # etc ..
Pareil pour les : else, exceptions, finally, elif etc ...
Problème : combien d'éléments dans le corps de cette liste ? ['a', 'b', 'c']
Problème : combien d'éléments dans le corps de cette liste ?
Expected :
Problème : combien d'éléments dans le corps de cette liste ?
Expected :
Reality :
Solution : des "proxy" de listes qui donnent la même API que les listes python et gèrent le formatting pour vous.
Reality again :
Marche pour les :
a.b.c().pouet[stuff]
.map
.apply
.filter
.next
, .previous
, .parent
.replace
1 # renommer un 'name' (attention : renommera pas tout)
2 for i in red('name', value='pouet'): i.value = 'plop'
1 # installer une django app
2 red.find("assign", target=lambda x: x.dumps() == 'INSTALLED_APPS').\
3 value.append("'debug_toolbar.apps.DebugToolbarConfig'")
1 # lines_profiler
2 red('def', recursive=False).\
3 map(lambda x: x.decorators.insert(0, '@profile'))
1 # lines_profiler
2 red('def', recursive=False).\
3 map(lambda x: x.decorators.insert(0, '@profile'))
4
5 # les retirer
6 red("decorator", lambda x: x.dumps() == "@decorator").\
7 map(lambda x: x.parent.parent.decorators.remove(x))
1 # print a -> logger.debug(a)
2 red('print', value=lambda x: len(x) == 1).\
3 map(lambda x: x.replace('logger.debug(%s)' % x.value.dumps())
4
5 # print a, b, c -> logger.debug("%s %s %s" % (a, b, c))
6 red('print', value=lambda x: len(x) == 1).\
7 map(lambda x: x.replace('logger.debug("%s" % (%s))' %
8 (" ".join('%s' * len(x.value)))
Exemples executés à la compilation :
Usage:
1 from pyfmt import format_code
2
3 format_code(source_code)
1 red *.py # dans un shell bash/zsh/autre
Qui lance un shell:
1 red
2 red[0]
3 red["./test_redflyingbaron.py"]
4 red["test_redflyingbaron.py"]
5 red["test_redflyingbaron"]
6 red[1:]
7
8 red.display()
9
10 red[0].save()
11 red.save()
12 red[0].reload()
13 red.reload()
14
15 red["f:redflyingbaron"]
16 red[re.compile(r'[^_]+')]
17 red["re:[^_]+"]
18 red[lambda key, value: "red" in key]
19
20 red.find("stuff")
21 red.find_all("stuff")
22
23 red.add("/path/to/file", "/path/to/another/file", "again.py")
RedBaron :
pip install redbaron
Baron :
pip install baron
Contacts :
Table of Contents | t |
---|---|
Exposé | ESC |
Full screen slides | e |
Presenter View | p |
Source Files | s |
Slide Numbers | n |
Toggle screen blanking | b |
Show/hide slide context | c |
Notes | 2 |
Help | h |