<div dir="ltr"><div><div><div><div><div>Hi Laurent<br></div><br></div>Great to see somebody finally tackling refactoring.<br><br></div>I'm
 answering, because I think we're working on the same issue. But we have
 finished two different parts: You have finished a refactoring 
implementation and I have finished the static analysis part. I'm the 
author of Jedi. <a href="https://github.com/davidhalter/jedi/" target="_blank">https://github.com/davidhalter/jedi/</a><br><br>I'm
 currently working on the integration of the lib2to3 parser into Jedi. 
This would make refactoring really easy (I'm about 50% done with the 
parser). It's also well tested and offers a few other advantages.<br></div><div><br></div><div>In a perfect world, we could now combine our projects :-) I will look in detail at Red Baron on Monday.<span class=""><font color="#888888"><br></font></span></div><span class=""><font color="#888888"><div><br></div><div>~ Dave<br></div></font></span><div><br></div>PS:
 If you want to use a tool for static analysis, please use either Jedi 
or astroid, I don't think rope still makes sense, because the project is
 inactive.<br></div></div><div class="gmail_extra"><br><div class="gmail_quote">2014-11-14 13:05 GMT+01:00 Laurent Peuch <span dir="ltr"><<a href="mailto:cortex@worlddomination.be" target="_blank">cortex@worlddomination.be</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello everyone,<br>
<br>
Someone has suggested me to talk about the project I'm working on<br>
right now on this mailing list because this has a lot of chances to<br>
interest you.<br>
<br>
This tool is an answer to a frustration that I've had while trying to<br>
build tools for python and projects I was working on. While there is<br>
already good capacities in python to analyse code (ast.py, astroid<br>
(while it wasn't out at that time)), the "write code that modify<br>
source code" was really missing (in my opinion and my knowledge of the<br>
existing tools).<br>
<br>
I wanted a very intuitive and easy to use library that allows me to<br>
query and modify my source code only in the place I wanted to modify<br>
it without touching the rest of the code. So I've built what can be<br>
describe as "the BeautifulSoup of python source code".<br>
<br>
To do so, I've built what can be called "a lossless AST" for python<br>
(designed to be used by humans), an AST that satisfy this equation:<br>
<br>
    source_code == ast_to_source(source_to_ast(source_code))<br>
<br>
It produces json-serializable python data structures (because data<br>
structures are easier to use and don't hide anything from you).<br>
<br>
And now the part that should interest you more: on top on that AST,<br>
I've built an high level "query and modification" library that wraps<br>
those AST nodes into objects. I've put a lot of efforts in making this<br>
library intuitive and very easy to use while removing you the burden<br>
of having to deal with low level details. This "BeautifulSoup of the<br>
python source code" is called Redbaron.<br>
<br>
It looks like this:<br>
<br>
    from redbaron import RedBaron<br>
<br>
    # simple API<br>
<br>
    # pass string<br>
    red = RedBaron("some_value = 42")<br>
<br>
    # get string back<br>
    red.dumps()<br>
<br>
Queries are like BeautifulSoup:<br>
<br>
    red.find("int", value=4)<br>
    red.find_all("def", name="stuff")<br>
<br>
(You can pass lambda/regex/special syntaxe for globs/regex etc... to<br>
queries, they should be powerful enough for the vast majorities of<br>
your needs).<br>
<br>
Nodes modification is very simple: just pass source code stored in<br>
string and "voilà":<br>
<br>
    red = RedBaron("some_value = 42")<br>
    red[0].value = "1 + 1"  # some_value = 1 + 1<br>
<br>
    red = RedBaron("def stuff():\n    plop")<br>
    red[0].value = "some_code"  # def stuff():\n    some_code<br>
<br>
    # notice that the input is correctly formatting, indented and it<br>
    # also takes care of not breaking the next node indentation<br>
    # works too with decorators and where you expect it to works<br>
<br>
(It is possible to pass it ast datastructure or RedBaron objects<br>
to).<br>
<br>
And I've made an abstraction on top of "list of things" so you don't<br>
have to take care about when you need to put a separator (for eg: a<br>
"," in a list):<br>
<br>
    red = RedBaron("[1, 2, 3]")<br>
    red[0].append("plop")  # [1, 2, 3, plop]<br>
<br>
    # want to add a new django app to INSTALLED_APPS? just do:<br>
    red.find("assignment", target=lambda x: x.dumps() == "INSTALLED_APPLICATIONS").value.append("'another_app'")<br>
    # notice that the formatting of the list is detected<br>
<br>
    # want to add "@profile" to every function of the root level for<br>
    # line_profiler?<br>
    red('def', recursive=False).map(lambda x: x.decorators.insert(0, '@profile'))<br>
<br>
    # and remove them<br>
    red("decorator", lambda x: x.dumps() == "@decorator").map(lambda x: x.parent.parent.decorators.remove(x))<br>
<br>
    # convert every "print a" to "logger.debug(a)<br>
    red('print', value=lambda x: len(x) == 1).map(lambda x: x.replace('logger.debug(%s)' % x.value.dumps())<br>
<br>
    # and print a, b, c to logger.debug("%s %s %s" % (a, b, c))<br>
    red('print', value=lambda x: len(x) == 1).map(lambda x: x.replace('logger.debug("%s" % (%s))' % (" ".join('%s' * len(x.value)))<br>
<br>
Both library and fully tested (more than 2000 tests in total), fully<br>
*documented* (with lots of examples) and under freesoftware licences.<br>
I consider RedBaron to be in alpha stage, it is already very stable<br>
but a significant number of edge cases are probably not handled yet.<br>
<br>
Important point: RedBaron is not and will not do static analysis,<br>
I'm probably going to integrate (or integrate RedBaron into) a tool<br>
that already do that like astroid or rope.<br>
<br>
Links:<br>
<br>
* RedBaron tutorial: <a href="https://redbaron.readthedocs.org/en/latest/tuto.html" target="_blank">https://redbaron.readthedocs.org/en/latest/tuto.html</a><br>
* RedBaron documentation: <a href="https://redbaron.readthedocs.org" target="_blank">https://redbaron.readthedocs.org</a><br>
* RedBaron source code: <a href="https://github.com/psycojoker/redbaron" target="_blank">https://github.com/psycojoker/redbaron</a><br>
<br>
* Baron (the AST) source code: <a href="https://github.com/psycojoker/baron" target="_blank">https://github.com/psycojoker/baron</a><br>
* Baron documentation: <a href="https://baron.readthedocs.org" target="_blank">https://baron.readthedocs.org</a><br>
<br>
I hope that I have trigger your interest and I'm very<br>
interested by your feedback,<br>
<br>
Have a nice day and thanks for your time,<br>
<br>
PS: I've only been aware of the capacities of lib2to3 since 2 months<br>
and was very unhappy to discover it so late (I've spent months or<br>
googling before deciding to start this project), I'll probably swap my<br>
parser with lib2to3 one in the future.<br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
<br>
Laurent Peuch -- Bram<br>
_______________________________________________<br>
code-quality mailing list<br>
<a href="mailto:code-quality@python.org">code-quality@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/code-quality" target="_blank">https://mail.python.org/mailman/listinfo/code-quality</a><br>
</font></span></blockquote></div><br></div>