austin bingham. python refactoring. pycon belarus
TRANSCRIPT
ROPE HAS POWERFUL IDE-ORIENTED FEATURES
Code completionFinding definitions and occurrencesOrganizing importsLooking up docstrings
PROJECTRepresents the files and directories containing code that rope
will manipulate.
Project is the root object in rope
RESOURCESThe files and directories in the project
server = project.get_resource('traad/server.py')print(server.name, server.path, server.is_folder())
c1 = project.get_resource('').get_children()[0]print(c1.name, c1.path, c1.is_folder())
WALK PROJECT RESOURCESdef get_all_resources(proj): todo = [''] while todo: res_path = todo[0] todo = todo[1:] res = proj.get_resource(res_path) yield(res.path, res.is_folder())
if res.is_folder(): todo.extend((child.path for child in res.get_children()))
Project.get_resource(path) finds a resource at arelative path
Resource.get_children() returns an iterable overchildren
MANAGE PREFERENCESprefs is a dict-like container of settings and preferences.for p in project.prefs.prefs: print(project.prefs.get(p))
prefs are stored in a file called .ropeproject/config.pyat the project's root directory.
CREATE THE REFACTORINGOBJECT
from rope.refactor.rename import Rename
ren = Rename(project, project.get_resource('traad/state.py'), offset=42)
This can fail if rope can't perform the refactoring
The refactoring is only partially bound
CALCULATE ACTUAL CHANGESchanges = ren.get_changes('TacoCopter')print(changes.description)print(changes.get_changed_resources())
changes represents a fully bound change
THE FULL PROCESSfrom rope.base.project import Projectfrom rope.refactor.rename import Rename
# Create the projectproj = Project('.')
# Create the partially-bound refactoringren = Rename(project, project.get_resource('traad/state.py'), offset=42)
# Calculate the changes for a fully-specified renamingchange = ren.get_changes('TacoCopter')
# Perform the changesproject.do(changes())
HISTORY OBJECTProject.history manages the history of changes that have
been made.
Also remembers what has been undone as well as changedependencies.
UNDOING CHANGESUndo the most recent changes
project.history.undo()
Or select more distance changes to undochange = project.history.undo_list[3]project.history.undo(change)
This will undo all dependent changes.
REDOING CHANGESYou can redo changes that you've previously undone.
change = project.history.redo_list[-2]project.history.redo(change)
THE MULTI-PROJECTREFACTORING CLASS
First create a MultiProjectRefactoring instance.from rope.refactor import multiproject
mpr = multiproject.MultiProjectRefactoring( Rename, # type of refactoring to perform [other_project1, other_project2, other_project3])
Then call that with your main project and the refactoringinitializer arguments
ref = mpr(main_project, some_resource, offset=1337)
CREATE AND PERFORM THE CHANGE# Remember that ̀ref̀ is a renaming operationchanges = ref.get_all_changes( "EnterpriseProxyManagerImplementationFactoryFactory")
multiproject.perform(changes)
SIMPLER INTEGRATION WITHEDITORS
Every corner of the programming universe knows how to speakHTTP+JSON
HTTP IS (WAY) MORE THAN FASTENOUGH FOR THIS WORK
The volume of data is low, and the response time only needs tobe good enough for humans
SUPPORT FOR MULTIPLE PYTHONVERSIONS
The client has zero depenencies on the version of Python thattraad is using
PROPER LEVEL OF ABSTRACTION
The problem domain of traad is Python refactoring, not Pythonintegration with other languages.
TASK STATE{ 1: { 'status': 'pending', 'description': 'Renaming FOO to BAR', 'changed_resources': [. . .]},
2: { 'status': 'failure'},
3: { 'status': 'success', 'calltip': 'uuid1(node=None, clock_seq=None)' }}
Simple mapping of task-ids to dicts
State is an actor and thus threadsafe. Multiple asynchronoustasks could be accessing it at any time.
ASYCHRONOUS VS.SYNCHRONOUS
AsynchronousRenameExtractOrganize importsSynchronousFind definitionGet historyCalltip
EMACSThe emacs lisp for renaming looks like this
; Starts new traad server on the specified directory(traad-open "~/projects/roid_rage")
; Renames whatever is a the point (i.e. under the cursor)(traad-rename "RagingRoid")
And the HTTP message looks like thisPOST /refactor/rename HTTP/1.1User-Agent: curl/7.30.0Host: 127.0.0.1:65172Accept: */*Accept-Encoding: deflate, gzipContent-Type: application/jsonContent-Length: 104
{"name":"RagingRoid", "path":"\/Users\/sixtynorth\/projects\/roid_rage\/roid_rage\/roid.py", "offset":102}
LINKSRope - Traad - Pykka - Bottle -
http://rope.sourceforge.net/http://github.com/abingham/traadhttp://www.pykka.org/http://bottlepy.org/
http://github.com/abingham/traad_rope_presentation